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