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