Home | History | Annotate | Download | only in Common
      1 // LimitedStreams.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #include "LimitedStreams.h"
      6 #include "../../Common/Defs.h"
      7 
      8 STDMETHODIMP CLimitedSequentialInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
      9 {
     10   UInt32 realProcessedSize = 0;
     11   UInt32 sizeToRead = (UInt32)MyMin((_size - _pos), (UInt64)size);
     12   HRESULT result = S_OK;
     13   if (sizeToRead > 0)
     14   {
     15     result = _stream->Read(data, sizeToRead, &realProcessedSize);
     16     _pos += realProcessedSize;
     17     if (realProcessedSize == 0)
     18       _wasFinished = true;
     19   }
     20   if (processedSize)
     21     *processedSize = realProcessedSize;
     22   return result;
     23 }
     24 
     25 STDMETHODIMP CLimitedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
     26 {
     27   if (processedSize)
     28     *processedSize = 0;
     29   if (_virtPos >= _size)
     30   {
     31     // 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case.
     32     return S_OK;
     33     // return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF
     34   }
     35   UInt64 rem = _size - _virtPos;
     36   if (rem < size)
     37     size = (UInt32)rem;
     38   UInt64 newPos = _startOffset + _virtPos;
     39   if (newPos != _physPos)
     40   {
     41     _physPos = newPos;
     42     RINOK(SeekToPhys());
     43   }
     44   HRESULT res = _stream->Read(data, size, &size);
     45   if (processedSize)
     46     *processedSize = size;
     47   _physPos += size;
     48   _virtPos += size;
     49   return res;
     50 }
     51 
     52 STDMETHODIMP CLimitedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
     53 {
     54   switch (seekOrigin)
     55   {
     56     case STREAM_SEEK_SET: break;
     57     case STREAM_SEEK_CUR: offset += _virtPos; break;
     58     case STREAM_SEEK_END: offset += _size; break;
     59     default: return STG_E_INVALIDFUNCTION;
     60   }
     61   if (offset < 0)
     62     return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
     63   _virtPos = offset;
     64   if (newPosition)
     65     *newPosition = _virtPos;
     66   return S_OK;
     67 }
     68 
     69 HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream)
     70 {
     71   *resStream = 0;
     72   CLimitedInStream *streamSpec = new CLimitedInStream;
     73   CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
     74   streamSpec->SetStream(inStream);
     75   RINOK(streamSpec->InitAndSeek(pos, size));
     76   streamSpec->SeekToStart();
     77   *resStream = streamTemp.Detach();
     78   return S_OK;
     79 }
     80 
     81 STDMETHODIMP CClusterInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
     82 {
     83   if (processedSize)
     84     *processedSize = 0;
     85   if (_virtPos >= Size)
     86     return S_OK;
     87 
     88   if (_curRem == 0)
     89   {
     90     UInt32 blockSize = (UInt32)1 << BlockSizeLog;
     91     UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog);
     92     UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1);
     93     UInt32 phyBlock = Vector[virtBlock];
     94     UInt64 newPos = StartOffset + ((UInt64)phyBlock << BlockSizeLog) + offsetInBlock;
     95     if (newPos != _physPos)
     96     {
     97       _physPos = newPos;
     98       RINOK(SeekToPhys());
     99     }
    100     _curRem = blockSize - offsetInBlock;
    101     for (int i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++)
    102       _curRem += (UInt32)1 << BlockSizeLog;
    103     UInt64 rem = Size - _virtPos;
    104     if (_curRem > rem)
    105       _curRem = (UInt32)rem;
    106   }
    107   if (size > _curRem)
    108     size = _curRem;
    109   HRESULT res = Stream->Read(data, size, &size);
    110   if (processedSize)
    111     *processedSize = size;
    112   _physPos += size;
    113   _virtPos += size;
    114   _curRem -= size;
    115   return res;
    116 }
    117 
    118 STDMETHODIMP CClusterInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
    119 {
    120   switch (seekOrigin)
    121   {
    122     case STREAM_SEEK_SET: break;
    123     case STREAM_SEEK_CUR: offset += _virtPos; break;
    124     case STREAM_SEEK_END: offset += Size; break;
    125     default: return STG_E_INVALIDFUNCTION;
    126   }
    127   if (offset < 0)
    128     return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
    129   if (_virtPos != (UInt64)offset)
    130     _curRem = 0;
    131   _virtPos = offset;
    132   if (newPosition)
    133     *newPosition = offset;
    134   return S_OK;
    135 }
    136 
    137 
    138 STDMETHODIMP CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize)
    139 {
    140   if (processedSize)
    141     *processedSize = 0;
    142   if (_virtPos >= Extents.Back().Virt)
    143     return S_OK;
    144   if (size == 0)
    145     return S_OK;
    146 
    147   unsigned left = 0, right = Extents.Size() - 1;
    148   for (;;)
    149   {
    150     unsigned mid = (left + right) / 2;
    151     if (mid == left)
    152       break;
    153     if (_virtPos < Extents[mid].Virt)
    154       right = mid;
    155     else
    156       left = mid;
    157   }
    158 
    159   const CSeekExtent &extent = Extents[left];
    160   UInt64 phyPos = extent.Phy + (_virtPos - extent.Virt);
    161   if (_needStartSeek || _phyPos != phyPos)
    162   {
    163     _needStartSeek = false;
    164     _phyPos = phyPos;
    165     RINOK(SeekToPhys());
    166   }
    167 
    168   UInt64 rem = Extents[left + 1].Virt - _virtPos;
    169   if (size > rem)
    170     size = (UInt32)rem;
    171 
    172   HRESULT res = Stream->Read(data, size, &size);
    173   _phyPos += size;
    174   _virtPos += size;
    175   if (processedSize)
    176     *processedSize = size;
    177   return res;
    178 }
    179 
    180 STDMETHODIMP CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
    181 {
    182   switch (seekOrigin)
    183   {
    184     case STREAM_SEEK_SET: break;
    185     case STREAM_SEEK_CUR: offset += _virtPos; break;
    186     case STREAM_SEEK_END: offset += Extents.Back().Virt; break;
    187     default: return STG_E_INVALIDFUNCTION;
    188   }
    189   if (offset < 0)
    190     return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
    191   _virtPos = offset;
    192   if (newPosition)
    193     *newPosition = _virtPos;
    194   return S_OK;
    195 }
    196 
    197 
    198 STDMETHODIMP CLimitedSequentialOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
    199 {
    200   HRESULT result = S_OK;
    201   if (processedSize)
    202     *processedSize = 0;
    203   if (size > _size)
    204   {
    205     if (_size == 0)
    206     {
    207       _overflow = true;
    208       if (!_overflowIsAllowed)
    209         return E_FAIL;
    210       if (processedSize)
    211         *processedSize = size;
    212       return S_OK;
    213     }
    214     size = (UInt32)_size;
    215   }
    216   if (_stream)
    217     result = _stream->Write(data, size, &size);
    218   _size -= size;
    219   if (processedSize)
    220     *processedSize = size;
    221   return result;
    222 }
    223 
    224 
    225 STDMETHODIMP CTailInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
    226 {
    227   UInt32 cur;
    228   HRESULT res = Stream->Read(data, size, &cur);
    229   if (processedSize)
    230     *processedSize = cur;
    231   _virtPos += cur;
    232   return res;
    233 }
    234 
    235 STDMETHODIMP CTailInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
    236 {
    237   switch (seekOrigin)
    238   {
    239     case STREAM_SEEK_SET: break;
    240     case STREAM_SEEK_CUR: offset += _virtPos; break;
    241     case STREAM_SEEK_END:
    242     {
    243       UInt64 pos = 0;
    244       RINOK(Stream->Seek(offset, STREAM_SEEK_END, &pos));
    245       if (pos < Offset)
    246         return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
    247       _virtPos = pos - Offset;
    248       if (newPosition)
    249         *newPosition = _virtPos;
    250       return S_OK;
    251     }
    252     default: return STG_E_INVALIDFUNCTION;
    253   }
    254   if (offset < 0)
    255     return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
    256   _virtPos = offset;
    257   if (newPosition)
    258     *newPosition = _virtPos;
    259   return Stream->Seek(Offset + _virtPos, STREAM_SEEK_SET, NULL);
    260 }
    261 
    262 STDMETHODIMP CLimitedCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
    263 {
    264   if (processedSize)
    265     *processedSize = 0;
    266   if (_virtPos >= _size)
    267   {
    268     // 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case.
    269     return S_OK;
    270     // return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF
    271   }
    272   UInt64 rem = _size - _virtPos;
    273   if (rem < size)
    274     size = (UInt32)rem;
    275 
    276   UInt64 newPos = _startOffset + _virtPos;
    277   UInt64 offsetInCache = newPos - _cachePhyPos;
    278   HRESULT res = S_OK;
    279   if (newPos >= _cachePhyPos &&
    280       offsetInCache <= _cacheSize &&
    281       size <= _cacheSize - (size_t)offsetInCache)
    282     memcpy(data, _cache + (size_t)offsetInCache, size);
    283   else
    284   {
    285     if (newPos != _physPos)
    286     {
    287       _physPos = newPos;
    288       RINOK(SeekToPhys());
    289     }
    290     res = _stream->Read(data, size, &size);
    291     _physPos += size;
    292   }
    293   if (processedSize)
    294     *processedSize = size;
    295   _virtPos += size;
    296   return res;
    297 }
    298 
    299 STDMETHODIMP CLimitedCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
    300 {
    301   switch (seekOrigin)
    302   {
    303     case STREAM_SEEK_SET: break;
    304     case STREAM_SEEK_CUR: offset += _virtPos; break;
    305     case STREAM_SEEK_END: offset += _size; break;
    306     default: return STG_E_INVALIDFUNCTION;
    307   }
    308   if (offset < 0)
    309     return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
    310   _virtPos = offset;
    311   if (newPosition)
    312     *newPosition = _virtPos;
    313   return S_OK;
    314 }
    315 
    316 STDMETHODIMP CTailOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
    317 {
    318   UInt32 cur;
    319   HRESULT res = Stream->Write(data, size, &cur);
    320   if (processedSize)
    321     *processedSize = cur;
    322   _virtPos += cur;
    323   if (_virtSize < _virtPos)
    324     _virtSize = _virtPos;
    325   return res;
    326 }
    327 
    328 STDMETHODIMP CTailOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
    329 {
    330   switch (seekOrigin)
    331   {
    332     case STREAM_SEEK_SET: break;
    333     case STREAM_SEEK_CUR: offset += _virtPos; break;
    334     case STREAM_SEEK_END: offset += _virtSize; break;
    335     default: return STG_E_INVALIDFUNCTION;
    336   }
    337   if (offset < 0)
    338     return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
    339   _virtPos = offset;
    340   if (newPosition)
    341     *newPosition = _virtPos;
    342   return Stream->Seek(Offset + _virtPos, STREAM_SEEK_SET, NULL);
    343 }
    344 
    345 STDMETHODIMP CTailOutStream::SetSize(UInt64 newSize)
    346 {
    347   _virtSize = newSize;
    348   return Stream->SetSize(Offset + newSize);
    349 }
    350