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 
Read(void * data,UInt32 size,UInt32 * processedSize)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 
Seek(Int64 offset,UInt32 seekOrigin,UInt64 * newPosition)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 
Read(void * data,UInt32 size,UInt32 * processedSize)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 
Seek(Int64 offset,UInt32 seekOrigin,UInt64 * newPosition)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 
Create_BufInStream_WithReference(const void * data,size_t size,IUnknown * ref,ISequentialInStream ** stream)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 
Create_BufInStream_WithNewBuffer(const void * data,size_t size,ISequentialInStream ** stream)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 
Free()100 void CByteDynBuffer::Free() throw()
101 {
102   free(_buf);
103   _buf = 0;
104   _capacity = 0;
105 }
106 
EnsureCapacity(size_t cap)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 
GetBufPtrForWriting(size_t addSize)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 
CopyToBuffer(CByteBuffer & dest) const137 void CDynBufSeqOutStream::CopyToBuffer(CByteBuffer &dest) const
138 {
139   dest.CopyFrom((const Byte *)_buffer, _size);
140 }
141 
Write(const void * data,UInt32 size,UInt32 * processedSize)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 
Write(const void * data,UInt32 size,UInt32 * processedSize)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 
Write(const void * data,UInt32 size,UInt32 * processedSize)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 
Free()185 void CCachedInStream::Free() throw()
186 {
187   MyFree(_tags);
188   _tags = 0;
189   MidFree(_data);
190   _data = 0;
191 }
192 
Alloc(unsigned blockSizeLog,unsigned numBlocksLog)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 
Init(UInt64 size)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 
Read(void * data,UInt32 size,UInt32 * processedSize)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 
Seek(Int64 offset,UInt32 seekOrigin,UInt64 * newPosition)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