1// LimitedStreams.cpp
2
3#include "StdAfx.h"
4
5#include "LimitedStreams.h"
6#include "../../Common/Defs.h"
7
8STDMETHODIMP 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 != NULL)
21    *processedSize = realProcessedSize;
22  return result;
23}
24
25STDMETHODIMP CLimitedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
26{
27  if (processedSize != NULL)
28    *processedSize = 0;
29  if (_virtPos >= _size)
30    return (_virtPos == _size) ? S_OK: E_FAIL;
31  UInt64 rem = _size - _virtPos;
32  if (rem < size)
33    size = (UInt32)rem;
34  UInt64 newPos = _startOffset + _virtPos;
35  if (newPos != _physPos)
36  {
37    _physPos = newPos;
38    RINOK(SeekToPhys());
39  }
40  HRESULT res = _stream->Read(data, size, &size);
41  if (processedSize != NULL)
42    *processedSize = size;
43  _physPos += size;
44  _virtPos += size;
45  return res;
46}
47
48STDMETHODIMP CLimitedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
49{
50  switch(seekOrigin)
51  {
52    case STREAM_SEEK_SET: _virtPos = offset; break;
53    case STREAM_SEEK_CUR: _virtPos += offset; break;
54    case STREAM_SEEK_END: _virtPos = _size + offset; break;
55    default: return STG_E_INVALIDFUNCTION;
56  }
57  if (newPosition)
58    *newPosition = _virtPos;
59  return S_OK;
60}
61
62STDMETHODIMP CClusterInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
63{
64  if (processedSize != NULL)
65    *processedSize = 0;
66  if (_virtPos >= Size)
67    return (_virtPos == Size) ? S_OK: E_FAIL;
68
69  if (_curRem == 0)
70  {
71    UInt32 blockSize = (UInt32)1 << BlockSizeLog;
72    UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog);
73    UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1);
74    UInt32 phyBlock = Vector[virtBlock];
75    UInt64 newPos = StartOffset + ((UInt64)phyBlock << BlockSizeLog) + offsetInBlock;
76    if (newPos != _physPos)
77    {
78      _physPos = newPos;
79      RINOK(SeekToPhys());
80    }
81    _curRem = blockSize - offsetInBlock;
82    for (int i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++)
83      _curRem += (UInt32)1 << BlockSizeLog;
84    UInt64 rem = Size - _virtPos;
85    if (_curRem > rem)
86      _curRem = (UInt32)rem;
87  }
88  if (size > _curRem)
89    size = _curRem;
90  HRESULT res = Stream->Read(data, size, &size);
91  if (processedSize != NULL)
92    *processedSize = size;
93  _physPos += size;
94  _virtPos += size;
95  _curRem -= size;
96  return res;
97}
98
99STDMETHODIMP CClusterInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
100{
101  UInt64 newVirtPos = offset;
102  switch(seekOrigin)
103  {
104    case STREAM_SEEK_SET: break;
105    case STREAM_SEEK_CUR: newVirtPos += _virtPos; break;
106    case STREAM_SEEK_END: newVirtPos += Size; break;
107    default: return STG_E_INVALIDFUNCTION;
108  }
109  if (_virtPos != newVirtPos)
110    _curRem = 0;
111  _virtPos = newVirtPos;
112  if (newPosition)
113    *newPosition = newVirtPos;
114  return S_OK;
115}
116
117
118HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream)
119{
120  *resStream = 0;
121  CLimitedInStream *streamSpec = new CLimitedInStream;
122  CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
123  streamSpec->SetStream(inStream);
124  RINOK(streamSpec->InitAndSeek(pos, size));
125  streamSpec->SeekToStart();
126  *resStream = streamTemp.Detach();
127  return S_OK;
128}
129
130STDMETHODIMP CLimitedSequentialOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
131{
132  HRESULT result = S_OK;
133  if (processedSize != NULL)
134    *processedSize = 0;
135  if (size > _size)
136  {
137    if (_size == 0)
138    {
139      _overflow = true;
140      if (!_overflowIsAllowed)
141        return E_FAIL;
142      if (processedSize != NULL)
143        *processedSize = size;
144      return S_OK;
145    }
146    size = (UInt32)_size;
147  }
148  if (_stream)
149    result = _stream->Write(data, size, &size);
150  _size -= size;
151  if (processedSize != NULL)
152    *processedSize = size;
153  return result;
154}
155