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 = (UInt64)offset;
41   if (newPosition)
42     *newPosition = (UInt64)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 = (UInt64)offset;
76   if (newPosition)
77     *newPosition = (UInt64)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 = _capacity / 4;
112   size_t cap2 = _capacity + delta;
113   if (cap < cap2)
114     cap = cap2;
115   Byte *buf = (Byte *)realloc(_buf, cap);
116   if (!buf)
117     return false;
118   _buf = buf;
119   _capacity = cap;
120   return true;
121 }
122 
GetBufPtrForWriting(size_t addSize)123 Byte *CDynBufSeqOutStream::GetBufPtrForWriting(size_t addSize)
124 {
125   addSize += _size;
126   if (addSize < _size)
127     return NULL;
128   if (!_buffer.EnsureCapacity(addSize))
129     return NULL;
130   return (Byte *)_buffer + _size;
131 }
132 
CopyToBuffer(CByteBuffer & dest) const133 void CDynBufSeqOutStream::CopyToBuffer(CByteBuffer &dest) const
134 {
135   dest.CopyFrom((const Byte *)_buffer, _size);
136 }
137 
Write(const void * data,UInt32 size,UInt32 * processedSize)138 STDMETHODIMP CDynBufSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
139 {
140   if (processedSize)
141     *processedSize = 0;
142   if (size == 0)
143     return S_OK;
144   Byte *buf = GetBufPtrForWriting(size);
145   if (!buf)
146     return E_OUTOFMEMORY;
147   memcpy(buf, data, size);
148   UpdateSize(size);
149   if (processedSize)
150     *processedSize = size;
151   return S_OK;
152 }
153 
Write(const void * data,UInt32 size,UInt32 * processedSize)154 STDMETHODIMP CBufPtrSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
155 {
156   size_t rem = _size - _pos;
157   if (rem > size)
158     rem = (size_t)size;
159   if (rem != 0)
160   {
161     memcpy(_buffer + _pos, data, rem);
162     _pos += rem;
163   }
164   if (processedSize)
165     *processedSize = (UInt32)rem;
166   return (rem != 0 || size == 0) ? S_OK : E_FAIL;
167 }
168 
Write(const void * data,UInt32 size,UInt32 * processedSize)169 STDMETHODIMP CSequentialOutStreamSizeCount::Write(const void *data, UInt32 size, UInt32 *processedSize)
170 {
171   UInt32 realProcessedSize;
172   HRESULT result = _stream->Write(data, size, &realProcessedSize);
173   _size += realProcessedSize;
174   if (processedSize)
175     *processedSize = realProcessedSize;
176   return result;
177 }
178 
179 static const UInt64 kEmptyTag = (UInt64)(Int64)-1;
180 
Free()181 void CCachedInStream::Free() throw()
182 {
183   MyFree(_tags);
184   _tags = NULL;
185   MidFree(_data);
186   _data = NULL;
187 }
188 
Alloc(unsigned blockSizeLog,unsigned numBlocksLog)189 bool CCachedInStream::Alloc(unsigned blockSizeLog, unsigned numBlocksLog) throw()
190 {
191   unsigned sizeLog = blockSizeLog + numBlocksLog;
192   if (sizeLog >= sizeof(size_t) * 8)
193     return false;
194   size_t dataSize = (size_t)1 << sizeLog;
195   if (!_data || dataSize != _dataSize)
196   {
197     MidFree(_data);
198     _data = (Byte *)MidAlloc(dataSize);
199     if (!_data)
200       return false;
201     _dataSize = dataSize;
202   }
203   if (!_tags || numBlocksLog != _numBlocksLog)
204   {
205     MyFree(_tags);
206     _tags = (UInt64 *)MyAlloc(sizeof(UInt64) << numBlocksLog);
207     if (!_tags)
208       return false;
209     _numBlocksLog = numBlocksLog;
210   }
211   _blockSizeLog = blockSizeLog;
212   return true;
213 }
214 
Init(UInt64 size)215 void CCachedInStream::Init(UInt64 size) throw()
216 {
217   _size = size;
218   _pos = 0;
219   size_t numBlocks = (size_t)1 << _numBlocksLog;
220   for (size_t i = 0; i < numBlocks; i++)
221     _tags[i] = kEmptyTag;
222 }
223 
Read(void * data,UInt32 size,UInt32 * processedSize)224 STDMETHODIMP CCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
225 {
226   if (processedSize)
227     *processedSize = 0;
228   if (size == 0)
229     return S_OK;
230   if (_pos >= _size)
231     return S_OK;
232 
233   {
234     UInt64 rem = _size - _pos;
235     if (size > rem)
236       size = (UInt32)rem;
237   }
238 
239   while (size != 0)
240   {
241     const UInt64 cacheTag = _pos >> _blockSizeLog;
242     const size_t cacheIndex = (size_t)cacheTag & (((size_t)1 << _numBlocksLog) - 1);
243     Byte *p = _data + (cacheIndex << _blockSizeLog);
244 
245     if (_tags[cacheIndex] != cacheTag)
246     {
247       _tags[cacheIndex] = kEmptyTag;
248       UInt64 remInBlock = _size - (cacheTag << _blockSizeLog);
249       size_t blockSize = (size_t)1 << _blockSizeLog;
250       if (blockSize > remInBlock)
251         blockSize = (size_t)remInBlock;
252 
253       RINOK(ReadBlock(cacheTag, p, blockSize));
254 
255       _tags[cacheIndex] = cacheTag;
256     }
257 
258     const size_t kBlockSize = (size_t)1 << _blockSizeLog;
259     const size_t offset = (size_t)_pos & (kBlockSize - 1);
260     UInt32 cur = size;
261     const size_t rem = kBlockSize - offset;
262     if (cur > rem)
263       cur = (UInt32)rem;
264 
265     memcpy(data, p + offset, cur);
266 
267     if (processedSize)
268       *processedSize += cur;
269     data = (void *)((const Byte *)data + cur);
270     _pos += cur;
271     size -= cur;
272   }
273 
274   return S_OK;
275 }
276 
277 
Seek(Int64 offset,UInt32 seekOrigin,UInt64 * newPosition)278 STDMETHODIMP CCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
279 {
280   switch (seekOrigin)
281   {
282     case STREAM_SEEK_SET: break;
283     case STREAM_SEEK_CUR: offset += _pos; break;
284     case STREAM_SEEK_END: offset += _size; break;
285     default: return STG_E_INVALIDFUNCTION;
286   }
287   if (offset < 0)
288     return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
289   _pos = (UInt64)offset;
290   if (newPosition)
291     *newPosition = (UInt64)offset;
292   return S_OK;
293 }
294