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 != NULL)
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 != 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
Seek(Int64 offset,UInt32 seekOrigin,UInt64 * newPosition)48 STDMETHODIMP 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
Read(void * data,UInt32 size,UInt32 * processedSize)62 STDMETHODIMP 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
Seek(Int64 offset,UInt32 seekOrigin,UInt64 * newPosition)99 STDMETHODIMP 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
CreateLimitedInStream(IInStream * inStream,UInt64 pos,UInt64 size,ISequentialInStream ** resStream)118 HRESULT 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
Write(const void * data,UInt32 size,UInt32 * processedSize)130 STDMETHODIMP 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