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