xref: /aosp_15_r20/external/lzma/CPP/7zip/Compress/LzmaDecoder.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // LzmaDecoder.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../C/Alloc.h"
6 
7 #include "../Common/StreamUtils.h"
8 
9 #include "LzmaDecoder.h"
10 
SResToHRESULT(SRes res)11 static HRESULT SResToHRESULT(SRes res)
12 {
13   switch (res)
14   {
15     case SZ_OK: return S_OK;
16     case SZ_ERROR_MEM: return E_OUTOFMEMORY;
17     case SZ_ERROR_PARAM: return E_INVALIDARG;
18     case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL;
19     case SZ_ERROR_DATA: return S_FALSE;
20     default: break;
21   }
22   return E_FAIL;
23 }
24 
25 namespace NCompress {
26 namespace NLzma {
27 
CDecoder()28 CDecoder::CDecoder():
29     FinishStream(false),
30     _propsWereSet(false),
31     _outSizeDefined(false),
32     _outStep(1 << 20),
33     _inBufSize(0),
34     _inBufSizeNew(1 << 20),
35     _lzmaStatus(LZMA_STATUS_NOT_SPECIFIED),
36     _inBuf(NULL)
37 {
38   _inProcessed = 0;
39   _inPos = _inLim = 0;
40 
41   /*
42   AlignOffsetAlloc_CreateVTable(&_alloc);
43   _alloc.numAlignBits = 7;
44   _alloc.offset = 0;
45   */
46   LzmaDec_CONSTRUCT(&_state)
47 }
48 
~CDecoder()49 CDecoder::~CDecoder()
50 {
51   LzmaDec_Free(&_state, &g_AlignedAlloc); // &_alloc.vt
52   MyFree(_inBuf);
53 }
54 
Z7_COM7F_IMF(CDecoder::SetInBufSize (UInt32,UInt32 size))55 Z7_COM7F_IMF(CDecoder::SetInBufSize(UInt32 , UInt32 size))
56   { _inBufSizeNew = size; return S_OK; }
Z7_COM7F_IMF(CDecoder::SetOutBufSize (UInt32,UInt32 size))57 Z7_COM7F_IMF(CDecoder::SetOutBufSize(UInt32 , UInt32 size))
58   { _outStep = size; return S_OK; }
59 
CreateInputBuffer()60 HRESULT CDecoder::CreateInputBuffer()
61 {
62   if (!_inBuf || _inBufSizeNew != _inBufSize)
63   {
64     MyFree(_inBuf);
65     _inBufSize = 0;
66     _inBuf = (Byte *)MyAlloc(_inBufSizeNew);
67     if (!_inBuf)
68       return E_OUTOFMEMORY;
69     _inBufSize = _inBufSizeNew;
70   }
71   return S_OK;
72 }
73 
74 
Z7_COM7F_IMF(CDecoder::SetDecoderProperties2 (const Byte * prop,UInt32 size))75 Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size))
76 {
77   RINOK(SResToHRESULT(LzmaDec_Allocate(&_state, prop, size, &g_AlignedAlloc))) // &_alloc.vt
78   _propsWereSet = true;
79   return CreateInputBuffer();
80 }
81 
82 
SetOutStreamSizeResume(const UInt64 * outSize)83 void CDecoder::SetOutStreamSizeResume(const UInt64 *outSize)
84 {
85   _outSizeDefined = (outSize != NULL);
86   _outSize = 0;
87   if (_outSizeDefined)
88     _outSize = *outSize;
89   _outProcessed = 0;
90   _lzmaStatus = LZMA_STATUS_NOT_SPECIFIED;
91 
92   LzmaDec_Init(&_state);
93 }
94 
95 
Z7_COM7F_IMF(CDecoder::SetOutStreamSize (const UInt64 * outSize))96 Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize))
97 {
98   _inProcessed = 0;
99   _inPos = _inLim = 0;
100   SetOutStreamSizeResume(outSize);
101   return S_OK;
102 }
103 
104 
Z7_COM7F_IMF(CDecoder::SetFinishMode (UInt32 finishMode))105 Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
106 {
107   FinishStream = (finishMode != 0);
108   return S_OK;
109 }
110 
111 
Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize (UInt64 * value))112 Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value))
113 {
114   *value = _inProcessed;
115   return S_OK;
116 }
117 
118 
CodeSpec(ISequentialInStream * inStream,ISequentialOutStream * outStream,ICompressProgressInfo * progress)119 HRESULT CDecoder::CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress)
120 {
121   if (!_inBuf || !_propsWereSet)
122     return S_FALSE;
123 
124   const UInt64 startInProgress = _inProcessed;
125   SizeT wrPos = _state.dicPos;
126   HRESULT readRes = S_OK;
127 
128   for (;;)
129   {
130     if (_inPos == _inLim && readRes == S_OK)
131     {
132       _inPos = _inLim = 0;
133       readRes = inStream->Read(_inBuf, _inBufSize, &_inLim);
134     }
135 
136     const SizeT dicPos = _state.dicPos;
137     SizeT size;
138     {
139       SizeT next = _state.dicBufSize;
140       if (next - wrPos > _outStep)
141         next = wrPos + _outStep;
142       size = next - dicPos;
143     }
144 
145     ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
146     if (_outSizeDefined)
147     {
148       const UInt64 rem = _outSize - _outProcessed;
149       if (size >= rem)
150       {
151         size = (SizeT)rem;
152         if (FinishStream)
153           finishMode = LZMA_FINISH_END;
154       }
155     }
156 
157     SizeT inProcessed = _inLim - _inPos;
158     ELzmaStatus status;
159 
160     const SRes res = LzmaDec_DecodeToDic(&_state, dicPos + size, _inBuf + _inPos, &inProcessed, finishMode, &status);
161 
162     _lzmaStatus = status;
163     _inPos += (UInt32)inProcessed;
164     _inProcessed += inProcessed;
165     const SizeT outProcessed = _state.dicPos - dicPos;
166     _outProcessed += outProcessed;
167 
168     // we check for LZMA_STATUS_NEEDS_MORE_INPUT to allow RangeCoder initialization, if (_outSizeDefined && _outSize == 0)
169     const bool outFinished = (_outSizeDefined && _outProcessed >= _outSize);
170 
171     const bool needStop = (res != 0
172         || (inProcessed == 0 && outProcessed == 0)
173         || status == LZMA_STATUS_FINISHED_WITH_MARK
174         || (outFinished && status != LZMA_STATUS_NEEDS_MORE_INPUT));
175 
176     if (needStop || outProcessed >= size)
177     {
178       const HRESULT res2 = WriteStream(outStream, _state.dic + wrPos, _state.dicPos - wrPos);
179 
180       if (_state.dicPos == _state.dicBufSize)
181         _state.dicPos = 0;
182       wrPos = _state.dicPos;
183 
184       RINOK(res2)
185 
186       if (needStop)
187       {
188         if (res != 0)
189         {
190           // return SResToHRESULT(res);
191           return S_FALSE;
192         }
193 
194         if (status == LZMA_STATUS_FINISHED_WITH_MARK)
195         {
196           if (FinishStream)
197             if (_outSizeDefined && _outSize != _outProcessed)
198               return S_FALSE;
199           return readRes;
200         }
201 
202         if (outFinished && status != LZMA_STATUS_NEEDS_MORE_INPUT)
203           if (!FinishStream || status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
204             return readRes;
205 
206         return S_FALSE;
207       }
208     }
209 
210     if (progress)
211     {
212       const UInt64 inSize = _inProcessed - startInProgress;
213       RINOK(progress->SetRatioInfo(&inSize, &_outProcessed))
214     }
215   }
216 }
217 
218 
Z7_COM7F_IMF(CDecoder::Code (ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress))219 Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
220     const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
221 {
222   if (!_inBuf)
223     return E_INVALIDARG;
224   SetOutStreamSize(outSize);
225   HRESULT res = CodeSpec(inStream, outStream, progress);
226   if (res == S_OK)
227     if (FinishStream && inSize && *inSize != _inProcessed)
228       res = S_FALSE;
229   return res;
230 }
231 
232 
233 #ifndef Z7_NO_READ_FROM_CODER
234 
Z7_COM7F_IMF(CDecoder::SetInStream (ISequentialInStream * inStream))235 Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream))
236   { _inStream = inStream; return S_OK; }
Z7_COM7F_IMF(CDecoder::ReleaseInStream ())237 Z7_COM7F_IMF(CDecoder::ReleaseInStream())
238   { _inStream.Release(); return S_OK; }
239 
Z7_COM7F_IMF(CDecoder::Read (void * data,UInt32 size,UInt32 * processedSize))240 Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize))
241 {
242   if (processedSize)
243     *processedSize = 0;
244 
245   ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
246   if (_outSizeDefined)
247   {
248     const UInt64 rem = _outSize - _outProcessed;
249     if (size >= rem)
250     {
251       size = (UInt32)rem;
252       if (FinishStream)
253         finishMode = LZMA_FINISH_END;
254     }
255   }
256 
257   HRESULT readRes = S_OK;
258 
259   for (;;)
260   {
261     if (_inPos == _inLim && readRes == S_OK)
262     {
263       _inPos = _inLim = 0;
264       readRes = _inStream->Read(_inBuf, _inBufSize, &_inLim);
265     }
266 
267     SizeT inProcessed = _inLim - _inPos;
268     SizeT outProcessed = size;
269     ELzmaStatus status;
270 
271     const SRes res = LzmaDec_DecodeToBuf(&_state, (Byte *)data, &outProcessed,
272         _inBuf + _inPos, &inProcessed, finishMode, &status);
273 
274     _lzmaStatus = status;
275     _inPos += (UInt32)inProcessed;
276     _inProcessed += inProcessed;
277     _outProcessed += outProcessed;
278     size -= (UInt32)outProcessed;
279     data = (Byte *)data + outProcessed;
280     if (processedSize)
281       *processedSize += (UInt32)outProcessed;
282 
283     if (res != 0)
284       return S_FALSE;
285 
286     /*
287     if (status == LZMA_STATUS_FINISHED_WITH_MARK)
288       return readRes;
289 
290     if (size == 0 && status != LZMA_STATUS_NEEDS_MORE_INPUT)
291     {
292       if (FinishStream
293           && _outSizeDefined && _outProcessed >= _outSize
294           && status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
295         return S_FALSE;
296       return readRes;
297     }
298     */
299 
300     if (inProcessed == 0 && outProcessed == 0)
301       return readRes;
302   }
303 }
304 
305 
CodeResume(ISequentialOutStream * outStream,const UInt64 * outSize,ICompressProgressInfo * progress)306 HRESULT CDecoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)
307 {
308   SetOutStreamSizeResume(outSize);
309   return CodeSpec(_inStream, outStream, progress);
310 }
311 
312 
ReadFromInputStream(void * data,UInt32 size,UInt32 * processedSize)313 HRESULT CDecoder::ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize)
314 {
315   RINOK(CreateInputBuffer())
316 
317   if (processedSize)
318     *processedSize = 0;
319 
320   HRESULT readRes = S_OK;
321 
322   while (size != 0)
323   {
324     if (_inPos == _inLim)
325     {
326       _inPos = _inLim = 0;
327       if (readRes == S_OK)
328         readRes = _inStream->Read(_inBuf, _inBufSize, &_inLim);
329       if (_inLim == 0)
330         break;
331     }
332 
333     UInt32 cur = _inLim - _inPos;
334     if (cur > size)
335       cur = size;
336     memcpy(data, _inBuf + _inPos, cur);
337     _inPos += cur;
338     _inProcessed += cur;
339     size -= cur;
340     data = (Byte *)data + cur;
341     if (processedSize)
342       *processedSize += cur;
343   }
344 
345   return readRes;
346 }
347 
348 #endif
349 
350 }}
351