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 CBufInStream::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 >= _size)
18 return S_OK;
19 size_t rem = _size - (size_t)_pos;
20 if (rem > size)
21 rem = (size_t)size;
22 memcpy(data, _data + (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 CBufInStream::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 += _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
46 /*
47 void Create_BufInStream_WithReference(const void *data, size_t size, ISequentialInStream **stream)
48 {
49 CBufInStream *inStreamSpec = new CBufInStream;
50 CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec;
51 inStreamSpec->Init((const Byte *)data, size);
52 *stream = streamTemp.Detach();
53 }
54 */
55
Create_BufInStream_WithNewBuf(const void * data,size_t size,ISequentialInStream ** stream)56 void Create_BufInStream_WithNewBuf(const void *data, size_t size, ISequentialInStream **stream)
57 {
58 CReferenceBuf *referenceBuf = new CReferenceBuf;
59 CMyComPtr<IUnknown> ref = referenceBuf;
60 referenceBuf->Buf.CopyFrom((const Byte *)data, size);
61
62 CBufInStream *inStreamSpec = new CBufInStream;
63 CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec;
64 inStreamSpec->Init(referenceBuf);
65 *stream = streamTemp.Detach();
66 }
67
Free()68 void CByteDynBuffer::Free() throw()
69 {
70 free(_buf);
71 _buf = 0;
72 _capacity = 0;
73 }
74
EnsureCapacity(size_t cap)75 bool CByteDynBuffer::EnsureCapacity(size_t cap) throw()
76 {
77 if (cap <= _capacity)
78 return true;
79 size_t delta;
80 if (_capacity > 64)
81 delta = _capacity / 4;
82 else if (_capacity > 8)
83 delta = 16;
84 else
85 delta = 4;
86 cap = MyMax(_capacity + delta, cap);
87 Byte *buf = (Byte *)realloc(_buf, cap);
88 if (!buf)
89 return false;
90 _buf = buf;
91 _capacity = cap;
92 return true;
93 }
94
GetBufPtrForWriting(size_t addSize)95 Byte *CDynBufSeqOutStream::GetBufPtrForWriting(size_t addSize)
96 {
97 addSize += _size;
98 if (addSize < _size)
99 return NULL;
100 if (!_buffer.EnsureCapacity(addSize))
101 return NULL;
102 return (Byte *)_buffer + _size;
103 }
104
CopyToBuffer(CByteBuffer & dest) const105 void CDynBufSeqOutStream::CopyToBuffer(CByteBuffer &dest) const
106 {
107 dest.CopyFrom((const Byte *)_buffer, _size);
108 }
109
Write(const void * data,UInt32 size,UInt32 * processedSize)110 STDMETHODIMP CDynBufSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
111 {
112 if (processedSize)
113 *processedSize = 0;
114 if (size == 0)
115 return S_OK;
116 Byte *buf = GetBufPtrForWriting(size);
117 if (!buf)
118 return E_OUTOFMEMORY;
119 memcpy(buf, data, size);
120 UpdateSize(size);
121 if (processedSize)
122 *processedSize = size;
123 return S_OK;
124 }
125
Write(const void * data,UInt32 size,UInt32 * processedSize)126 STDMETHODIMP CBufPtrSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
127 {
128 size_t rem = _size - _pos;
129 if (rem > size)
130 rem = (size_t)size;
131 memcpy(_buffer + _pos, data, rem);
132 _pos += rem;
133 if (processedSize)
134 *processedSize = (UInt32)rem;
135 return (rem != 0 || size == 0) ? S_OK : E_FAIL;
136 }
137
Write(const void * data,UInt32 size,UInt32 * processedSize)138 STDMETHODIMP CSequentialOutStreamSizeCount::Write(const void *data, UInt32 size, UInt32 *processedSize)
139 {
140 UInt32 realProcessedSize;
141 HRESULT result = _stream->Write(data, size, &realProcessedSize);
142 _size += realProcessedSize;
143 if (processedSize)
144 *processedSize = realProcessedSize;
145 return result;
146 }
147
148 static const UInt64 kEmptyTag = (UInt64)(Int64)-1;
149
Free()150 void CCachedInStream::Free() throw()
151 {
152 MyFree(_tags);
153 _tags = 0;
154 MidFree(_data);
155 _data = 0;
156 }
157
Alloc(unsigned blockSizeLog,unsigned numBlocksLog)158 bool CCachedInStream::Alloc(unsigned blockSizeLog, unsigned numBlocksLog) throw()
159 {
160 unsigned sizeLog = blockSizeLog + numBlocksLog;
161 if (sizeLog >= sizeof(size_t) * 8)
162 return false;
163 size_t dataSize = (size_t)1 << sizeLog;
164 if (_data == 0 || dataSize != _dataSize)
165 {
166 MidFree(_data);
167 _data = (Byte *)MidAlloc(dataSize);
168 if (_data == 0)
169 return false;
170 _dataSize = dataSize;
171 }
172 if (_tags == 0 || numBlocksLog != _numBlocksLog)
173 {
174 MyFree(_tags);
175 _tags = (UInt64 *)MyAlloc(sizeof(UInt64) << numBlocksLog);
176 if (_tags == 0)
177 return false;
178 _numBlocksLog = numBlocksLog;
179 }
180 _blockSizeLog = blockSizeLog;
181 return true;
182 }
183
Init(UInt64 size)184 void CCachedInStream::Init(UInt64 size) throw()
185 {
186 _size = size;
187 _pos = 0;
188 size_t numBlocks = (size_t)1 << _numBlocksLog;
189 for (size_t i = 0; i < numBlocks; i++)
190 _tags[i] = kEmptyTag;
191 }
192
Read(void * data,UInt32 size,UInt32 * processedSize)193 STDMETHODIMP CCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
194 {
195 if (processedSize)
196 *processedSize = 0;
197 if (size == 0)
198 return S_OK;
199 if (_pos >= _size)
200 return S_OK;
201
202 {
203 UInt64 rem = _size - _pos;
204 if (size > rem)
205 size = (UInt32)rem;
206 }
207
208 while (size != 0)
209 {
210 UInt64 cacheTag = _pos >> _blockSizeLog;
211 size_t cacheIndex = (size_t)cacheTag & (((size_t)1 << _numBlocksLog) - 1);
212 Byte *p = _data + (cacheIndex << _blockSizeLog);
213 if (_tags[cacheIndex] != cacheTag)
214 {
215 UInt64 remInBlock = _size - (cacheTag << _blockSizeLog);
216 size_t blockSize = (size_t)1 << _blockSizeLog;
217 if (blockSize > remInBlock)
218 blockSize = (size_t)remInBlock;
219 RINOK(ReadBlock(cacheTag, p, blockSize));
220 _tags[cacheIndex] = cacheTag;
221 }
222 size_t offset = (size_t)_pos & (((size_t)1 << _blockSizeLog) - 1);
223 UInt32 cur = (UInt32)MyMin(((size_t)1 << _blockSizeLog) - offset, (size_t)size);
224 memcpy(data, p + offset, cur);
225 if (processedSize)
226 *processedSize += cur;
227 data = (void *)((const Byte *)data + cur);
228 _pos += cur;
229 size -= cur;
230 }
231
232 return S_OK;
233 }
234
Seek(Int64 offset,UInt32 seekOrigin,UInt64 * newPosition)235 STDMETHODIMP CCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
236 {
237 switch (seekOrigin)
238 {
239 case STREAM_SEEK_SET: break;
240 case STREAM_SEEK_CUR: offset += _pos; break;
241 case STREAM_SEEK_END: offset += _size; break;
242 default: return STG_E_INVALIDFUNCTION;
243 }
244 if (offset < 0)
245 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
246 _pos = offset;
247 if (newPosition)
248 *newPosition = offset;
249 return S_OK;
250 }
251