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