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