1// LimitedStreams.cpp
2
3#include "StdAfx.h"
4
5#include <string.h>
6
7#include "LimitedStreams.h"
8
9Z7_COM7F_IMF(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
30Z7_COM7F_IMF(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
59Z7_COM7F_IMF(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
76HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream)
77{
78  *resStream = NULL;
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
88Z7_COM7F_IMF(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
133Z7_COM7F_IMF(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
153Z7_COM7F_IMF(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(InStream_SeekSet(Stream, phy))
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
221Z7_COM7F_IMF(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
239Z7_COM7F_IMF(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
266Z7_COM7F_IMF(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
276Z7_COM7F_IMF(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 InStream_SeekSet(Stream, Offset + _virtPos);
301}
302
303Z7_COM7F_IMF(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
343Z7_COM7F_IMF(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
360Z7_COM7F_IMF(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
372Z7_COM7F_IMF(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
389Z7_COM7F_IMF(CTailOutStream::SetSize(UInt64 newSize))
390{
391  _virtSize = newSize;
392  return Stream->SetSize(Offset + newSize);
393}
394