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