xref: /aosp_15_r20/external/lzma/CPP/7zip/Common/LimitedStreams.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // LimitedStreams.cpp
2 
3 #include "StdAfx.h"
4 
5 #include <string.h>
6 
7 #include "LimitedStreams.h"
8 
Z7_COM7F_IMF(CLimitedSequentialInStream::Read (void * data,UInt32 size,UInt32 * processedSize))9 Z7_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 
Z7_COM7F_IMF(CLimitedInStream::Read (void * data,UInt32 size,UInt32 * processedSize))30 Z7_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 
Z7_COM7F_IMF(CLimitedInStream::Seek (Int64 offset,UInt32 seekOrigin,UInt64 * newPosition))59 Z7_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 
CreateLimitedInStream(IInStream * inStream,UInt64 pos,UInt64 size,ISequentialInStream ** resStream)76 HRESULT 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 
Z7_COM7F_IMF(CClusterInStream::Read (void * data,UInt32 size,UInt32 * processedSize))88 Z7_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 
Z7_COM7F_IMF(CClusterInStream::Seek (Int64 offset,UInt32 seekOrigin,UInt64 * newPosition))133 Z7_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 
Z7_COM7F_IMF(CExtentsStream::Read (void * data,UInt32 size,UInt32 * processedSize))153 Z7_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 
Z7_COM7F_IMF(CExtentsStream::Seek (Int64 offset,UInt32 seekOrigin,UInt64 * newPosition))221 Z7_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 
Z7_COM7F_IMF(CLimitedSequentialOutStream::Write (const void * data,UInt32 size,UInt32 * processedSize))239 Z7_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 
Z7_COM7F_IMF(CTailInStream::Read (void * data,UInt32 size,UInt32 * processedSize))266 Z7_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 
Z7_COM7F_IMF(CTailInStream::Seek (Int64 offset,UInt32 seekOrigin,UInt64 * newPosition))276 Z7_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 
Z7_COM7F_IMF(CLimitedCachedInStream::Read (void * data,UInt32 size,UInt32 * processedSize))303 Z7_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 
Z7_COM7F_IMF(CLimitedCachedInStream::Seek (Int64 offset,UInt32 seekOrigin,UInt64 * newPosition))343 Z7_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 
Z7_COM7F_IMF(CTailOutStream::Write (const void * data,UInt32 size,UInt32 * processedSize))360 Z7_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 
Z7_COM7F_IMF(CTailOutStream::Seek (Int64 offset,UInt32 seekOrigin,UInt64 * newPosition))372 Z7_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 
Z7_COM7F_IMF(CTailOutStream::SetSize (UInt64 newSize))389 Z7_COM7F_IMF(CTailOutStream::SetSize(UInt64 newSize))
390 {
391   _virtSize = newSize;
392   return Stream->SetSize(Offset + newSize);
393 }
394