1 // StreamObjects.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../C/Alloc.h"
6 
7 #include "StreamObjects.h"
8 
Read(void * data,UInt32 size,UInt32 * processedSize)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 
Seek(Int64 offset,UInt32 seekOrigin,UInt64 * newPosition)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 
Free()41 void CByteDynBuffer::Free()
42 {
43   free(_buf);
44   _buf = 0;
45   _capacity = 0;
46 }
47 
EnsureCapacity(size_t cap)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 
GetBufPtrForWriting(size_t addSize)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 
CopyToBuffer(CByteBuffer & dest) const78 void CDynBufSeqOutStream::CopyToBuffer(CByteBuffer &dest) const
79 {
80   dest.SetCapacity(_size);
81   memcpy(dest, _buffer, _size);
82 }
83 
Write(const void * data,UInt32 size,UInt32 * processedSize)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 
Write(const void * data,UInt32 size,UInt32 * processedSize)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 
Write(const void * data,UInt32 size,UInt32 * processedSize)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 
Free()124 void CCachedInStream::Free()
125 {
126   MyFree(_tags);
127   _tags = 0;
128   MidFree(_data);
129   _data = 0;
130 }
131 
Alloc(unsigned blockSizeLog,unsigned numBlocksLog)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 
Init(UInt64 size)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 
Read(void * data,UInt32 size,UInt32 * processedSize)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 
Seek(Int64 offset,UInt32 seekOrigin,UInt64 * newPosition)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