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