• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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