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
CDecoder()27 CDecoder::CDecoder():
28 _inBuf(NULL),
29 _inBufSize(0),
30 _inBufSizeNew(1 << 20),
31 _outStepSize(1 << 22),
32 _outSizeDefined(false),
33 _finishMode(false)
34 {
35 Lzma2Dec_Construct(&_state);
36 }
37
SetInBufSize(UInt32,UInt32 size)38 STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSizeNew = size; return S_OK; }
SetOutBufSize(UInt32,UInt32 size)39 STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outStepSize = size; return S_OK; }
40
~CDecoder()41 CDecoder::~CDecoder()
42 {
43 Lzma2Dec_Free(&_state, &g_Alloc);
44 MidFree(_inBuf);
45 }
46
SetDecoderProperties2(const Byte * prop,UInt32 size)47 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)
48 {
49 if (size != 1)
50 return E_NOTIMPL;
51
52 RINOK(SResToHRESULT(Lzma2Dec_Allocate(&_state, prop[0], &g_Alloc)));
53 if (!_inBuf || _inBufSize != _inBufSizeNew)
54 {
55 MidFree(_inBuf);
56 _inBufSize = 0;
57 _inBuf = (Byte *)MidAlloc(_inBufSizeNew);
58 if (!_inBuf)
59 return E_OUTOFMEMORY;
60 _inBufSize = _inBufSizeNew;
61 }
62
63 return S_OK;
64 }
65
GetInStreamProcessedSize(UInt64 * value)66 STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value) { *value = _inSizeProcessed; return S_OK; }
SetInStream(ISequentialInStream * inStream)67 STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }
ReleaseInStream()68 STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }
69
SetOutStreamSize(const UInt64 * outSize)70 STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
71 {
72 _outSizeDefined = (outSize != NULL);
73 _outSize = 0;
74 if (_outSizeDefined)
75 _outSize = *outSize;
76
77 Lzma2Dec_Init(&_state);
78
79 _inPos = _inSize = 0;
80 _inSizeProcessed = _outSizeProcessed = 0;
81 return S_OK;
82 }
83
SetFinishMode(UInt32 finishMode)84 STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)
85 {
86 _finishMode = (finishMode != 0);
87 return S_OK;
88 }
89
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress)90 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream,
91 ISequentialOutStream *outStream, const UInt64 *inSize,
92 const UInt64 *outSize, ICompressProgressInfo *progress)
93 {
94 if (!_inBuf)
95 return S_FALSE;
96 SetOutStreamSize(outSize);
97
98 UInt32 step = _outStepSize;
99 const UInt32 kOutStepSize_Min = 1 << 12;
100 if (step < kOutStepSize_Min)
101 step = kOutStepSize_Min;
102
103 SizeT wrPos = _state.decoder.dicPos;
104
105 SizeT next = (_state.decoder.dicBufSize - _state.decoder.dicPos < step) ?
106 _state.decoder.dicBufSize :
107 _state.decoder.dicPos + step;
108
109 HRESULT hres = S_OK;
110
111 for (;;)
112 {
113 if (_inPos == _inSize)
114 {
115 _inPos = _inSize = 0;
116 hres = inStream->Read(_inBuf, _inBufSize, &_inSize);
117 if (hres != S_OK)
118 break;
119 }
120
121 SizeT dicPos = _state.decoder.dicPos;
122 SizeT curSize = next - dicPos;
123
124 ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
125 if (_outSizeDefined)
126 {
127 const UInt64 rem = _outSize - _outSizeProcessed;
128 if (curSize >= rem)
129 {
130 curSize = (SizeT)rem;
131 if (_finishMode)
132 finishMode = LZMA_FINISH_END;
133 }
134 }
135
136 SizeT inSizeProcessed = _inSize - _inPos;
137 ELzmaStatus status;
138 SRes res = Lzma2Dec_DecodeToDic(&_state, dicPos + curSize, _inBuf + _inPos, &inSizeProcessed, finishMode, &status);
139
140 _inPos += (UInt32)inSizeProcessed;
141 _inSizeProcessed += inSizeProcessed;
142 SizeT outSizeProcessed = _state.decoder.dicPos - dicPos;
143 _outSizeProcessed += outSizeProcessed;
144
145 bool finished = (inSizeProcessed == 0 && outSizeProcessed == 0
146 || status == LZMA_STATUS_FINISHED_WITH_MARK);
147 bool outFinished = (_outSizeDefined && _outSizeProcessed >= _outSize);
148
149 if (res != 0
150 || _state.decoder.dicPos >= next
151 || finished
152 || outFinished)
153 {
154 HRESULT res2 = WriteStream(outStream, _state.decoder.dic + wrPos, _state.decoder.dicPos - wrPos);
155
156 if (_state.decoder.dicPos == _state.decoder.dicBufSize)
157 _state.decoder.dicPos = 0;
158
159 wrPos = _state.decoder.dicPos;
160
161 next = (_state.decoder.dicBufSize - _state.decoder.dicPos < step) ?
162 _state.decoder.dicBufSize :
163 _state.decoder.dicPos + step;
164
165 if (res != 0)
166 return S_FALSE;
167 RINOK(res2);
168
169 if (finished)
170 {
171 if (status == LZMA_STATUS_FINISHED_WITH_MARK)
172 {
173 if (_finishMode && inSize && *inSize != _inSizeProcessed)
174 return S_FALSE;
175 if (finishMode == LZMA_FINISH_END && !outFinished)
176 return S_FALSE;
177 return S_OK;
178 }
179 return (finishMode == LZMA_FINISH_END) ? S_FALSE : S_OK;
180 }
181
182 if (outFinished && finishMode == LZMA_FINISH_ANY)
183 return S_OK;
184 }
185
186 if (progress)
187 {
188 RINOK(progress->SetRatioInfo(&_inSizeProcessed, &_outSizeProcessed));
189 }
190 }
191
192 HRESULT res2 = WriteStream(outStream, _state.decoder.dic + wrPos, _state.decoder.dicPos - wrPos);
193 if (hres != S_OK)
194 return hres;
195 return res2;
196 }
197
198 #ifndef NO_READ_FROM_CODER
199
Read(void * data,UInt32 size,UInt32 * processedSize)200 STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
201 {
202 UInt32 totalProcessed = 0;
203
204 if (processedSize)
205 *processedSize = 0;
206
207 for (;;)
208 {
209 if (_inPos == _inSize)
210 {
211 _inPos = _inSize = 0;
212 RINOK(_inStream->Read(_inBuf, _inBufSize, &_inSize));
213 }
214 {
215 ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
216 if (_outSizeDefined)
217 {
218 const UInt64 rem = _outSize - _outSizeProcessed;
219 if (rem <= size)
220 {
221 size = (UInt32)rem;
222 if (_finishMode)
223 finishMode = LZMA_FINISH_END;
224 }
225 }
226
227 SizeT outProcessed = size;
228 SizeT inProcessed = _inSize - _inPos;
229
230 ELzmaStatus status;
231 SRes res = Lzma2Dec_DecodeToBuf(&_state, (Byte *)data, &outProcessed,
232 _inBuf + _inPos, &inProcessed, finishMode, &status);
233
234 _inPos += (UInt32)inProcessed;
235 _inSizeProcessed += inProcessed;
236 _outSizeProcessed += outProcessed;
237 size -= (UInt32)outProcessed;
238 data = (Byte *)data + outProcessed;
239
240 totalProcessed += (UInt32)outProcessed;
241 if (processedSize)
242 *processedSize = totalProcessed;
243
244 if (res != SZ_OK)
245 {
246 if (totalProcessed != 0)
247 return S_OK;
248 return SResToHRESULT(res);
249 }
250
251 if (inProcessed == 0 && outProcessed == 0)
252 return S_OK;
253 if (status == LZMA_STATUS_FINISHED_WITH_MARK)
254 return S_OK;
255 if (outProcessed != 0)
256 {
257 if (finishMode != LZMA_FINISH_END || _outSize != _outSizeProcessed)
258 return S_OK;
259 }
260 }
261 }
262 }
263
264 #endif
265
266 }}
267