tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

LimitedStreams.cpp (9521B)


      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 }