Home | History | Annotate | Download | only in Common
      1 // StreamObjects.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #include "../../../C/Alloc.h"
      6 
      7 #include "StreamObjects.h"
      8 
      9 STDMETHODIMP CBufInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
     10 {
     11   if (processedSize)
     12     *processedSize = 0;
     13   if (size == 0)
     14     return S_OK;
     15   if (_pos > _size)
     16     return E_FAIL;
     17   size_t rem = _size - (size_t)_pos;
     18   if (rem > size)
     19     rem = (size_t)size;
     20   memcpy(data, _data + (size_t)_pos, rem);
     21   _pos += rem;
     22   if (processedSize)
     23     *processedSize = (UInt32)rem;
     24   return S_OK;
     25 }
     26 
     27 STDMETHODIMP CBufInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
     28 {
     29   switch(seekOrigin)
     30   {
     31     case STREAM_SEEK_SET: _pos = offset; break;
     32     case STREAM_SEEK_CUR: _pos += offset; break;
     33     case STREAM_SEEK_END: _pos = _size + offset; break;
     34     default: return STG_E_INVALIDFUNCTION;
     35   }
     36   if (newPosition)
     37     *newPosition = _pos;
     38   return S_OK;
     39 }
     40 
     41 void CByteDynBuffer::Free()
     42 {
     43   free(_buf);
     44   _buf = 0;
     45   _capacity = 0;
     46 }
     47 
     48 bool CByteDynBuffer::EnsureCapacity(size_t cap)
     49 {
     50   if (cap <= _capacity)
     51     return true;
     52   size_t delta;
     53   if (_capacity > 64)
     54     delta = _capacity / 4;
     55   else if (_capacity > 8)
     56     delta = 16;
     57   else
     58     delta = 4;
     59   cap = MyMax(_capacity + delta, cap);
     60   Byte *buf = (Byte *)realloc(_buf, cap);
     61   if (!buf)
     62     return false;
     63   _buf = buf;
     64   _capacity = cap;
     65   return true;
     66 }
     67 
     68 Byte *CDynBufSeqOutStream::GetBufPtrForWriting(size_t addSize)
     69 {
     70   addSize += _size;
     71   if (addSize < _size)
     72     return NULL;
     73   if (!_buffer.EnsureCapacity(addSize))
     74     return NULL;
     75   return (Byte *)_buffer + _size;
     76 }
     77 
     78 void CDynBufSeqOutStream::CopyToBuffer(CByteBuffer &dest) const
     79 {
     80   dest.SetCapacity(_size);
     81   memcpy(dest, _buffer, _size);
     82 }
     83 
     84 STDMETHODIMP CDynBufSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
     85 {
     86   if (processedSize)
     87     *processedSize = 0;
     88   if (size == 0)
     89     return S_OK;
     90   Byte *buf = GetBufPtrForWriting(size);
     91   if (!buf)
     92     return E_OUTOFMEMORY;
     93   memcpy(buf, data, size);
     94   UpdateSize(size);
     95   if (processedSize)
     96     *processedSize = size;
     97   return S_OK;
     98 }
     99 
    100 STDMETHODIMP CBufPtrSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
    101 {
    102   size_t rem = _size - _pos;
    103   if (rem > size)
    104     rem = (size_t)size;
    105   memcpy(_buffer + _pos, data, rem);
    106   _pos += rem;
    107   if (processedSize)
    108     *processedSize = (UInt32)rem;
    109   return (rem != 0 || size == 0) ? S_OK : E_FAIL;
    110 }
    111 
    112 STDMETHODIMP CSequentialOutStreamSizeCount::Write(const void *data, UInt32 size, UInt32 *processedSize)
    113 {
    114   UInt32 realProcessedSize;
    115   HRESULT result = _stream->Write(data, size, &realProcessedSize);
    116   _size += realProcessedSize;
    117   if (processedSize)
    118     *processedSize = realProcessedSize;
    119   return result;
    120 }
    121 
    122 static const UInt64 kEmptyTag = (UInt64)(Int64)-1;
    123 
    124 void CCachedInStream::Free()
    125 {
    126   MyFree(_tags);
    127   _tags = 0;
    128   MidFree(_data);
    129   _data = 0;
    130 }
    131 
    132 bool CCachedInStream::Alloc(unsigned blockSizeLog, unsigned numBlocksLog)
    133 {
    134   unsigned sizeLog = blockSizeLog + numBlocksLog;
    135   if (sizeLog >= sizeof(size_t) * 8)
    136     return false;
    137   size_t dataSize = (size_t)1 << sizeLog;
    138   if (_data == 0 || dataSize != _dataSize)
    139   {
    140     MidFree(_data);
    141     _data = (Byte *)MidAlloc(dataSize);
    142     if (_data == 0)
    143       return false;
    144     _dataSize = dataSize;
    145   }
    146   if (_tags == 0 || numBlocksLog != _numBlocksLog)
    147   {
    148     MyFree(_tags);
    149     _tags = (UInt64 *)MyAlloc(sizeof(UInt64) << numBlocksLog);
    150     if (_tags == 0)
    151       return false;
    152     _numBlocksLog = numBlocksLog;
    153   }
    154   _blockSizeLog = blockSizeLog;
    155   return true;
    156 }
    157 
    158 void CCachedInStream::Init(UInt64 size)
    159 {
    160   _size = size;
    161   _pos = 0;
    162   size_t numBlocks = (size_t)1 << _numBlocksLog;
    163   for (size_t i = 0; i < numBlocks; i++)
    164     _tags[i] = kEmptyTag;
    165 }
    166 
    167 STDMETHODIMP CCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
    168 {
    169   if (processedSize)
    170     *processedSize = 0;
    171   if (size == 0)
    172     return S_OK;
    173   if (_pos > _size)
    174     return E_FAIL;
    175 
    176   {
    177     UInt64 rem = _size - _pos;
    178     if (size > rem)
    179       size = (UInt32)rem;
    180   }
    181 
    182   while (size != 0)
    183   {
    184     UInt64 cacheTag = _pos >> _blockSizeLog;
    185     size_t cacheIndex = (size_t)cacheTag & (((size_t)1 << _numBlocksLog) - 1);
    186     Byte *p = _data + (cacheIndex << _blockSizeLog);
    187     if (_tags[cacheIndex] != cacheTag)
    188     {
    189       UInt64 remInBlock = _size - (cacheTag << _blockSizeLog);
    190       size_t blockSize = (size_t)1 << _blockSizeLog;
    191       if (blockSize > remInBlock)
    192         blockSize = (size_t)remInBlock;
    193       RINOK(ReadBlock(cacheTag, p, blockSize));
    194       _tags[cacheIndex] = cacheTag;
    195     }
    196     size_t offset = (size_t)_pos & (((size_t)1 << _blockSizeLog) - 1);
    197     UInt32 cur = (UInt32)MyMin(((size_t)1 << _blockSizeLog) - offset, (size_t)size);
    198     memcpy(data, p + offset, cur);
    199     if (processedSize)
    200       *processedSize += cur;
    201     data = (void *)((const Byte *)data + cur);
    202     _pos += cur;
    203     size -= cur;
    204   }
    205 
    206   return S_OK;
    207 }
    208 
    209 STDMETHODIMP CCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
    210 {
    211   switch(seekOrigin)
    212   {
    213     case STREAM_SEEK_SET: _pos = offset; break;
    214     case STREAM_SEEK_CUR: _pos = _pos + offset; break;
    215     case STREAM_SEEK_END: _pos = _size + offset; break;
    216     default: return STG_E_INVALIDFUNCTION;
    217   }
    218   if (newPosition != 0)
    219     *newPosition = _pos;
    220   return S_OK;
    221 }
    222