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