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