1 // LimitedStreams.cpp
2
3 #include "StdAfx.h"
4
5 #include <string.h>
6
7 #include "LimitedStreams.h"
8
Read(void * data,UInt32 size,UInt32 * processedSize)9 STDMETHODIMP CLimitedSequentialInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
10 {
11 UInt32 realProcessedSize = 0;
12 {
13 const UInt64 rem = _size - _pos;
14 if (size > rem)
15 size = (UInt32)rem;
16 }
17 HRESULT result = S_OK;
18 if (size != 0)
19 {
20 result = _stream->Read(data, size, &realProcessedSize);
21 _pos += realProcessedSize;
22 if (realProcessedSize == 0)
23 _wasFinished = true;
24 }
25 if (processedSize)
26 *processedSize = realProcessedSize;
27 return result;
28 }
29
Read(void * data,UInt32 size,UInt32 * processedSize)30 STDMETHODIMP CLimitedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
31 {
32 if (processedSize)
33 *processedSize = 0;
34 if (_virtPos >= _size)
35 {
36 // 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case.
37 return S_OK;
38 // return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF
39 }
40 {
41 const UInt64 rem = _size - _virtPos;
42 if (size > rem)
43 size = (UInt32)rem;
44 }
45 UInt64 newPos = _startOffset + _virtPos;
46 if (newPos != _physPos)
47 {
48 _physPos = newPos;
49 RINOK(SeekToPhys());
50 }
51 HRESULT res = _stream->Read(data, size, &size);
52 if (processedSize)
53 *processedSize = size;
54 _physPos += size;
55 _virtPos += size;
56 return res;
57 }
58
Seek(Int64 offset,UInt32 seekOrigin,UInt64 * newPosition)59 STDMETHODIMP CLimitedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
60 {
61 switch (seekOrigin)
62 {
63 case STREAM_SEEK_SET: break;
64 case STREAM_SEEK_CUR: offset += _virtPos; break;
65 case STREAM_SEEK_END: offset += _size; break;
66 default: return STG_E_INVALIDFUNCTION;
67 }
68 if (offset < 0)
69 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
70 _virtPos = (UInt64)offset;
71 if (newPosition)
72 *newPosition = _virtPos;
73 return S_OK;
74 }
75
CreateLimitedInStream(IInStream * inStream,UInt64 pos,UInt64 size,ISequentialInStream ** resStream)76 HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream)
77 {
78 *resStream = 0;
79 CLimitedInStream *streamSpec = new CLimitedInStream;
80 CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
81 streamSpec->SetStream(inStream);
82 RINOK(streamSpec->InitAndSeek(pos, size));
83 streamSpec->SeekToStart();
84 *resStream = streamTemp.Detach();
85 return S_OK;
86 }
87
Read(void * data,UInt32 size,UInt32 * processedSize)88 STDMETHODIMP CClusterInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
89 {
90 if (processedSize)
91 *processedSize = 0;
92 if (_virtPos >= Size)
93 return S_OK;
94 {
95 UInt64 rem = Size - _virtPos;
96 if (size > rem)
97 size = (UInt32)rem;
98 }
99 if (size == 0)
100 return S_OK;
101
102 if (_curRem == 0)
103 {
104 const UInt32 blockSize = (UInt32)1 << BlockSizeLog;
105 const UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog);
106 const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1);
107 const UInt32 phyBlock = Vector[virtBlock];
108
109 UInt64 newPos = StartOffset + ((UInt64)phyBlock << BlockSizeLog) + offsetInBlock;
110 if (newPos != _physPos)
111 {
112 _physPos = newPos;
113 RINOK(SeekToPhys());
114 }
115
116 _curRem = blockSize - offsetInBlock;
117
118 for (unsigned i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++)
119 _curRem += (UInt32)1 << BlockSizeLog;
120 }
121
122 if (size > _curRem)
123 size = _curRem;
124 HRESULT res = Stream->Read(data, size, &size);
125 if (processedSize)
126 *processedSize = size;
127 _physPos += size;
128 _virtPos += size;
129 _curRem -= size;
130 return res;
131 }
132
Seek(Int64 offset,UInt32 seekOrigin,UInt64 * newPosition)133 STDMETHODIMP CClusterInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
134 {
135 switch (seekOrigin)
136 {
137 case STREAM_SEEK_SET: break;
138 case STREAM_SEEK_CUR: offset += _virtPos; break;
139 case STREAM_SEEK_END: offset += Size; break;
140 default: return STG_E_INVALIDFUNCTION;
141 }
142 if (offset < 0)
143 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
144 if (_virtPos != (UInt64)offset)
145 _curRem = 0;
146 _virtPos = (UInt64)offset;
147 if (newPosition)
148 *newPosition = (UInt64)offset;
149 return S_OK;
150 }
151
152
Read(void * data,UInt32 size,UInt32 * processedSize)153 STDMETHODIMP CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize)
154 {
155 if (processedSize)
156 *processedSize = 0;
157 const UInt64 virt = _virtPos;
158 if (virt >= Extents.Back().Virt)
159 return S_OK;
160 if (size == 0)
161 return S_OK;
162
163 unsigned left = _prevExtentIndex;
164 if (virt < Extents[left].Virt ||
165 virt >= Extents[left + 1].Virt)
166 {
167 left = 0;
168 unsigned right = Extents.Size() - 1;
169 for (;;)
170 {
171 const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
172 if (mid == left)
173 break;
174 if (virt < Extents[mid].Virt)
175 right = mid;
176 else
177 left = mid;
178 }
179 _prevExtentIndex = left;
180 }
181
182 {
183 const UInt64 rem = Extents[left + 1].Virt - virt;
184 if (size > rem)
185 size = (UInt32)rem;
186 }
187
188 const CSeekExtent &extent = Extents[left];
189
190 if (extent.Is_ZeroFill())
191 {
192 memset(data, 0, size);
193 _virtPos += size;
194 if (processedSize)
195 *processedSize = size;
196 return S_OK;
197 }
198
199 {
200 const UInt64 phy = extent.Phy + (virt - extent.Virt);
201 if (_phyPos != phy)
202 {
203 _phyPos = (UInt64)0 - 1; // we don't trust seek_pos in case of error
204 RINOK(Stream->Seek((Int64)phy, STREAM_SEEK_SET, NULL));
205 _phyPos = phy;
206 }
207 }
208
209 const HRESULT res = Stream->Read(data, size, &size);
210 _virtPos += size;
211 if (res == S_OK)
212 _phyPos += size;
213 else
214 _phyPos = (UInt64)0 - 1; // we don't trust seek_pos in case of error
215 if (processedSize)
216 *processedSize = size;
217 return res;
218 }
219
220
Seek(Int64 offset,UInt32 seekOrigin,UInt64 * newPosition)221 STDMETHODIMP CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
222 {
223 switch (seekOrigin)
224 {
225 case STREAM_SEEK_SET: break;
226 case STREAM_SEEK_CUR: offset += _virtPos; break;
227 case STREAM_SEEK_END: offset += Extents.Back().Virt; break;
228 default: return STG_E_INVALIDFUNCTION;
229 }
230 if (offset < 0)
231 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
232 _virtPos = (UInt64)offset;
233 if (newPosition)
234 *newPosition = _virtPos;
235 return S_OK;
236 }
237
238
Write(const void * data,UInt32 size,UInt32 * processedSize)239 STDMETHODIMP CLimitedSequentialOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
240 {
241 HRESULT result = S_OK;
242 if (processedSize)
243 *processedSize = 0;
244 if (size > _size)
245 {
246 if (_size == 0)
247 {
248 _overflow = true;
249 if (!_overflowIsAllowed)
250 return E_FAIL;
251 if (processedSize)
252 *processedSize = size;
253 return S_OK;
254 }
255 size = (UInt32)_size;
256 }
257 if (_stream)
258 result = _stream->Write(data, size, &size);
259 _size -= size;
260 if (processedSize)
261 *processedSize = size;
262 return result;
263 }
264
265
Read(void * data,UInt32 size,UInt32 * processedSize)266 STDMETHODIMP CTailInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
267 {
268 UInt32 cur;
269 HRESULT res = Stream->Read(data, size, &cur);
270 if (processedSize)
271 *processedSize = cur;
272 _virtPos += cur;
273 return res;
274 }
275
Seek(Int64 offset,UInt32 seekOrigin,UInt64 * newPosition)276 STDMETHODIMP CTailInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
277 {
278 switch (seekOrigin)
279 {
280 case STREAM_SEEK_SET: break;
281 case STREAM_SEEK_CUR: offset += _virtPos; break;
282 case STREAM_SEEK_END:
283 {
284 UInt64 pos = 0;
285 RINOK(Stream->Seek(offset, STREAM_SEEK_END, &pos));
286 if (pos < Offset)
287 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
288 _virtPos = pos - Offset;
289 if (newPosition)
290 *newPosition = _virtPos;
291 return S_OK;
292 }
293 default: return STG_E_INVALIDFUNCTION;
294 }
295 if (offset < 0)
296 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
297 _virtPos = (UInt64)offset;
298 if (newPosition)
299 *newPosition = _virtPos;
300 return Stream->Seek((Int64)(Offset + _virtPos), STREAM_SEEK_SET, NULL);
301 }
302
Read(void * data,UInt32 size,UInt32 * processedSize)303 STDMETHODIMP CLimitedCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
304 {
305 if (processedSize)
306 *processedSize = 0;
307 if (_virtPos >= _size)
308 {
309 // 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case.
310 return S_OK;
311 // return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF
312 }
313 UInt64 rem = _size - _virtPos;
314 if (rem < size)
315 size = (UInt32)rem;
316
317 UInt64 newPos = _startOffset + _virtPos;
318 UInt64 offsetInCache = newPos - _cachePhyPos;
319 HRESULT res = S_OK;
320 if (newPos >= _cachePhyPos &&
321 offsetInCache <= _cacheSize &&
322 size <= _cacheSize - (size_t)offsetInCache)
323 {
324 if (size != 0)
325 memcpy(data, _cache + (size_t)offsetInCache, size);
326 }
327 else
328 {
329 if (newPos != _physPos)
330 {
331 _physPos = newPos;
332 RINOK(SeekToPhys());
333 }
334 res = _stream->Read(data, size, &size);
335 _physPos += size;
336 }
337 if (processedSize)
338 *processedSize = size;
339 _virtPos += size;
340 return res;
341 }
342
Seek(Int64 offset,UInt32 seekOrigin,UInt64 * newPosition)343 STDMETHODIMP CLimitedCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
344 {
345 switch (seekOrigin)
346 {
347 case STREAM_SEEK_SET: break;
348 case STREAM_SEEK_CUR: offset += _virtPos; break;
349 case STREAM_SEEK_END: offset += _size; break;
350 default: return STG_E_INVALIDFUNCTION;
351 }
352 if (offset < 0)
353 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
354 _virtPos = (UInt64)offset;
355 if (newPosition)
356 *newPosition = _virtPos;
357 return S_OK;
358 }
359
Write(const void * data,UInt32 size,UInt32 * processedSize)360 STDMETHODIMP CTailOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
361 {
362 UInt32 cur;
363 HRESULT res = Stream->Write(data, size, &cur);
364 if (processedSize)
365 *processedSize = cur;
366 _virtPos += cur;
367 if (_virtSize < _virtPos)
368 _virtSize = _virtPos;
369 return res;
370 }
371
Seek(Int64 offset,UInt32 seekOrigin,UInt64 * newPosition)372 STDMETHODIMP CTailOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
373 {
374 switch (seekOrigin)
375 {
376 case STREAM_SEEK_SET: break;
377 case STREAM_SEEK_CUR: offset += _virtPos; break;
378 case STREAM_SEEK_END: offset += _virtSize; break;
379 default: return STG_E_INVALIDFUNCTION;
380 }
381 if (offset < 0)
382 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
383 _virtPos = (UInt64)offset;
384 if (newPosition)
385 *newPosition = _virtPos;
386 return Stream->Seek((Int64)(Offset + _virtPos), STREAM_SEEK_SET, NULL);
387 }
388
SetSize(UInt64 newSize)389 STDMETHODIMP CTailOutStream::SetSize(UInt64 newSize)
390 {
391 _virtSize = newSize;
392 return Stream->SetSize(Offset + newSize);
393 }
394