1 // Lzma2Decoder.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../C/Alloc.h"
6
7 #include "../Common/StreamUtils.h"
8
9 #include "Lzma2Decoder.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_PROGRESS: return E_ABORT;
19 case SZ_ERROR_DATA: return S_FALSE;
20 }
21 return E_FAIL;
22 }
23
24 namespace NCompress {
25 namespace NLzma2 {
26
27 static const UInt32 kInBufSize = 1 << 20;
28
CDecoder()29 CDecoder::CDecoder(): _inBuf(0), _outSizeDefined(false)
30 {
31 Lzma2Dec_Construct(&_state);
32 }
33
SzAlloc(void * p,size_t size)34 static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
SzFree(void * p,void * address)35 static void SzFree(void *p, void *address) { p = p; MyFree(address); }
36 static ISzAlloc g_Alloc = { SzAlloc, SzFree };
37
~CDecoder()38 CDecoder::~CDecoder()
39 {
40 Lzma2Dec_Free(&_state, &g_Alloc);
41 MyFree(_inBuf);
42 }
43
SetDecoderProperties2(const Byte * prop,UInt32 size)44 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)
45 {
46 if (size != 1) return SZ_ERROR_UNSUPPORTED;
47 RINOK(SResToHRESULT(Lzma2Dec_Allocate(&_state, prop[0], &g_Alloc)));
48 if (_inBuf == 0)
49 {
50 _inBuf = (Byte *)MyAlloc(kInBufSize);
51 if (_inBuf == 0)
52 return E_OUTOFMEMORY;
53 }
54
55 return S_OK;
56 }
57
GetInStreamProcessedSize(UInt64 * value)58 STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value) { *value = _inSizeProcessed; return S_OK; }
SetInStream(ISequentialInStream * inStream)59 STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }
ReleaseInStream()60 STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }
61
SetOutStreamSize(const UInt64 * outSize)62 STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
63 {
64 _outSizeDefined = (outSize != NULL);
65 if (_outSizeDefined)
66 _outSize = *outSize;
67
68 Lzma2Dec_Init(&_state);
69
70 _inPos = _inSize = 0;
71 _inSizeProcessed = _outSizeProcessed = 0;
72 return S_OK;
73 }
74
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 * outSize,ICompressProgressInfo * progress)75 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream,
76 ISequentialOutStream *outStream, const UInt64 * /* inSize */,
77 const UInt64 *outSize, ICompressProgressInfo *progress)
78 {
79 if (_inBuf == 0)
80 return S_FALSE;
81 SetOutStreamSize(outSize);
82
83 for (;;)
84 {
85 if (_inPos == _inSize)
86 {
87 _inPos = _inSize = 0;
88 RINOK(inStream->Read(_inBuf, kInBufSize, &_inSize));
89 }
90
91 SizeT dicPos = _state.decoder.dicPos;
92 SizeT curSize = _state.decoder.dicBufSize - dicPos;
93 const UInt32 kStepSize = ((UInt32)1 << 22);
94 if (curSize > kStepSize)
95 curSize = (SizeT)kStepSize;
96
97 ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
98 if (_outSizeDefined)
99 {
100 const UInt64 rem = _outSize - _outSizeProcessed;
101 if (rem < curSize)
102 {
103 curSize = (SizeT)rem;
104 /*
105 // finishMode = LZMA_FINISH_END;
106 we can't use LZMA_FINISH_END here to allow partial decoding
107 */
108 }
109 }
110
111 SizeT inSizeProcessed = _inSize - _inPos;
112 ELzmaStatus status;
113 SRes res = Lzma2Dec_DecodeToDic(&_state, dicPos + curSize, _inBuf + _inPos, &inSizeProcessed, finishMode, &status);
114
115 _inPos += (UInt32)inSizeProcessed;
116 _inSizeProcessed += inSizeProcessed;
117 SizeT outSizeProcessed = _state.decoder.dicPos - dicPos;
118 _outSizeProcessed += outSizeProcessed;
119
120 bool finished = (inSizeProcessed == 0 && outSizeProcessed == 0);
121 bool stopDecoding = (_outSizeDefined && _outSizeProcessed >= _outSize);
122
123 if (res != 0 || _state.decoder.dicPos == _state.decoder.dicBufSize || finished || stopDecoding)
124 {
125 HRESULT res2 = WriteStream(outStream, _state.decoder.dic, _state.decoder.dicPos);
126 if (res != 0)
127 return S_FALSE;
128 RINOK(res2);
129 if (stopDecoding)
130 return S_OK;
131 if (finished)
132 return (status == LZMA_STATUS_FINISHED_WITH_MARK ? S_OK : S_FALSE);
133 }
134 if (_state.decoder.dicPos == _state.decoder.dicBufSize)
135 _state.decoder.dicPos = 0;
136
137 if (progress != NULL)
138 {
139 RINOK(progress->SetRatioInfo(&_inSizeProcessed, &_outSizeProcessed));
140 }
141 }
142 }
143
144 #ifndef NO_READ_FROM_CODER
145
Read(void * data,UInt32 size,UInt32 * processedSize)146 STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
147 {
148 if (processedSize)
149 *processedSize = 0;
150 do
151 {
152 if (_inPos == _inSize)
153 {
154 _inPos = _inSize = 0;
155 RINOK(_inStream->Read(_inBuf, kInBufSize, &_inSize));
156 }
157 {
158 SizeT inProcessed = _inSize - _inPos;
159
160 if (_outSizeDefined)
161 {
162 const UInt64 rem = _outSize - _outSizeProcessed;
163 if (rem < size)
164 size = (UInt32)rem;
165 }
166
167 SizeT outProcessed = size;
168 ELzmaStatus status;
169 SRes res = Lzma2Dec_DecodeToBuf(&_state, (Byte *)data, &outProcessed,
170 _inBuf + _inPos, &inProcessed, LZMA_FINISH_ANY, &status);
171 _inPos += (UInt32)inProcessed;
172 _inSizeProcessed += inProcessed;
173 _outSizeProcessed += outProcessed;
174 size -= (UInt32)outProcessed;
175 data = (Byte *)data + outProcessed;
176 if (processedSize)
177 *processedSize += (UInt32)outProcessed;
178 RINOK(SResToHRESULT(res));
179 if (inProcessed == 0 && outProcessed == 0)
180 return S_OK;
181 }
182 }
183 while (size != 0);
184 return S_OK;
185 }
186
187 #endif
188
189 }}
190