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