1 // DeflateDecoder.cpp
2
3 #include "StdAfx.h"
4
5 #include "DeflateDecoder.h"
6
7 namespace NCompress {
8 namespace NDeflate {
9 namespace NDecoder {
10
CCoder(bool deflate64Mode)11 CCoder::CCoder(bool deflate64Mode):
12 _deflate64Mode(deflate64Mode),
13 _deflateNSIS(false),
14 _keepHistory(false),
15 _needFinishInput(false),
16 _needInitInStream(true),
17 _outSizeDefined(false),
18 _outStartPos(0),
19 ZlibMode(false) {}
20
ReadBits(unsigned numBits)21 UInt32 CCoder::ReadBits(unsigned numBits)
22 {
23 return m_InBitStream.ReadBits(numBits);
24 }
25
ReadAlignedByte()26 Byte CCoder::ReadAlignedByte()
27 {
28 return m_InBitStream.ReadAlignedByte();
29 }
30
DecodeLevels(Byte * levels,unsigned numSymbols)31 bool CCoder::DecodeLevels(Byte *levels, unsigned numSymbols)
32 {
33 unsigned i = 0;
34
35 do
36 {
37 UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream);
38 if (sym < kTableDirectLevels)
39 levels[i++] = (Byte)sym;
40 else
41 {
42 if (sym >= kLevelTableSize)
43 return false;
44
45 unsigned num;
46 unsigned numBits;
47 Byte symbol;
48
49 if (sym == kTableLevelRepNumber)
50 {
51 if (i == 0)
52 return false;
53 numBits = 2;
54 num = 0;
55 symbol = levels[(size_t)i - 1];
56 }
57 else
58 {
59 sym -= kTableLevel0Number;
60 sym <<= 2;
61 numBits = 3 + (unsigned)sym;
62 num = ((unsigned)sym << 1);
63 symbol = 0;
64 }
65
66 num += i + 3 + ReadBits(numBits);
67 if (num > numSymbols)
68 return false;
69 do
70 levels[i++] = symbol;
71 while (i < num);
72 }
73 }
74 while (i < numSymbols);
75
76 return true;
77 }
78
79 #define RIF(x) { if (!(x)) return false; }
80
ReadTables(void)81 bool CCoder::ReadTables(void)
82 {
83 m_FinalBlock = (ReadBits(kFinalBlockFieldSize) == NFinalBlockField::kFinalBlock);
84 if (m_InBitStream.ExtraBitsWereRead())
85 return false;
86 UInt32 blockType = ReadBits(kBlockTypeFieldSize);
87 if (blockType > NBlockType::kDynamicHuffman)
88 return false;
89 if (m_InBitStream.ExtraBitsWereRead())
90 return false;
91
92 if (blockType == NBlockType::kStored)
93 {
94 m_StoredMode = true;
95 m_InBitStream.AlignToByte();
96 m_StoredBlockSize = ReadAligned_UInt16(); // ReadBits(kStoredBlockLengthFieldSize)
97 if (_deflateNSIS)
98 return true;
99 return (m_StoredBlockSize == (UInt16)~ReadAligned_UInt16());
100 }
101
102 m_StoredMode = false;
103
104 CLevels levels;
105 if (blockType == NBlockType::kFixedHuffman)
106 {
107 levels.SetFixedLevels();
108 _numDistLevels = _deflate64Mode ? kDistTableSize64 : kDistTableSize32;
109 }
110 else
111 {
112 unsigned numLitLenLevels = ReadBits(kNumLenCodesFieldSize) + kNumLitLenCodesMin;
113 _numDistLevels = ReadBits(kNumDistCodesFieldSize) + kNumDistCodesMin;
114 unsigned numLevelCodes = ReadBits(kNumLevelCodesFieldSize) + kNumLevelCodesMin;
115
116 if (!_deflate64Mode)
117 if (_numDistLevels > kDistTableSize32)
118 return false;
119
120 Byte levelLevels[kLevelTableSize];
121 for (unsigned i = 0; i < kLevelTableSize; i++)
122 {
123 unsigned position = kCodeLengthAlphabetOrder[i];
124 if (i < numLevelCodes)
125 levelLevels[position] = (Byte)ReadBits(kLevelFieldSize);
126 else
127 levelLevels[position] = 0;
128 }
129
130 if (m_InBitStream.ExtraBitsWereRead())
131 return false;
132
133 RIF(m_LevelDecoder.Build(levelLevels));
134
135 Byte tmpLevels[kFixedMainTableSize + kFixedDistTableSize];
136 if (!DecodeLevels(tmpLevels, numLitLenLevels + _numDistLevels))
137 return false;
138
139 if (m_InBitStream.ExtraBitsWereRead())
140 return false;
141
142 levels.SubClear();
143 memcpy(levels.litLenLevels, tmpLevels, numLitLenLevels);
144 memcpy(levels.distLevels, tmpLevels + numLitLenLevels, _numDistLevels);
145 }
146 RIF(m_MainDecoder.Build(levels.litLenLevels));
147 return m_DistDecoder.Build(levels.distLevels);
148 }
149
150
InitInStream(bool needInit)151 HRESULT CCoder::InitInStream(bool needInit)
152 {
153 if (needInit)
154 {
155 // for HDD-Windows:
156 // (1 << 15) - best for reading only prefetch
157 // (1 << 22) - best for real reading / writing
158 if (!m_InBitStream.Create(1 << 20))
159 return E_OUTOFMEMORY;
160 m_InBitStream.Init();
161 _needInitInStream = false;
162 }
163 return S_OK;
164 }
165
166
CodeSpec(UInt32 curSize,bool finishInputStream,UInt32 inputProgressLimit)167 HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream, UInt32 inputProgressLimit)
168 {
169 if (_remainLen == kLenIdFinished)
170 return S_OK;
171
172 if (_remainLen == kLenIdNeedInit)
173 {
174 if (!_keepHistory)
175 if (!m_OutWindowStream.Create(_deflate64Mode ? kHistorySize64: kHistorySize32))
176 return E_OUTOFMEMORY;
177 RINOK(InitInStream(_needInitInStream));
178 m_OutWindowStream.Init(_keepHistory);
179
180 m_FinalBlock = false;
181 _remainLen = 0;
182 _needReadTable = true;
183 }
184
185 while (_remainLen > 0 && curSize > 0)
186 {
187 _remainLen--;
188 Byte b = m_OutWindowStream.GetByte(_rep0);
189 m_OutWindowStream.PutByte(b);
190 curSize--;
191 }
192
193 UInt64 inputStart = 0;
194 if (inputProgressLimit != 0)
195 inputStart = m_InBitStream.GetProcessedSize();
196
197 while (curSize > 0 || finishInputStream)
198 {
199 if (m_InBitStream.ExtraBitsWereRead())
200 return S_FALSE;
201
202 if (_needReadTable)
203 {
204 if (m_FinalBlock)
205 {
206 _remainLen = kLenIdFinished;
207 break;
208 }
209
210 if (inputProgressLimit != 0)
211 if (m_InBitStream.GetProcessedSize() - inputStart >= inputProgressLimit)
212 return S_OK;
213
214 if (!ReadTables())
215 return S_FALSE;
216 if (m_InBitStream.ExtraBitsWereRead())
217 return S_FALSE;
218 _needReadTable = false;
219 }
220
221 if (m_StoredMode)
222 {
223 if (finishInputStream && curSize == 0 && m_StoredBlockSize != 0)
224 return S_FALSE;
225 /* NSIS version contains some bits in bitl bits buffer.
226 So we must read some first bytes via ReadAlignedByte */
227 for (; m_StoredBlockSize > 0 && curSize > 0 && m_InBitStream.ThereAreDataInBitsBuffer(); m_StoredBlockSize--, curSize--)
228 m_OutWindowStream.PutByte(ReadAlignedByte());
229 for (; m_StoredBlockSize > 0 && curSize > 0; m_StoredBlockSize--, curSize--)
230 m_OutWindowStream.PutByte(m_InBitStream.ReadDirectByte());
231 _needReadTable = (m_StoredBlockSize == 0);
232 continue;
233 }
234
235 while (curSize > 0)
236 {
237 if (m_InBitStream.ExtraBitsWereRead_Fast())
238 return S_FALSE;
239
240 UInt32 sym = m_MainDecoder.Decode(&m_InBitStream);
241
242 if (sym < 0x100)
243 {
244 m_OutWindowStream.PutByte((Byte)sym);
245 curSize--;
246 continue;
247 }
248 else if (sym == kSymbolEndOfBlock)
249 {
250 _needReadTable = true;
251 break;
252 }
253 else if (sym < kMainTableSize)
254 {
255 sym -= kSymbolMatch;
256 UInt32 len;
257 {
258 unsigned numBits;
259 if (_deflate64Mode)
260 {
261 len = kLenStart64[sym];
262 numBits = kLenDirectBits64[sym];
263 }
264 else
265 {
266 len = kLenStart32[sym];
267 numBits = kLenDirectBits32[sym];
268 }
269 len += kMatchMinLen + m_InBitStream.ReadBits(numBits);
270 }
271 UInt32 locLen = len;
272 if (locLen > curSize)
273 locLen = (UInt32)curSize;
274 sym = m_DistDecoder.Decode(&m_InBitStream);
275 if (sym >= _numDistLevels)
276 return S_FALSE;
277 UInt32 distance = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]);
278 if (!m_OutWindowStream.CopyBlock(distance, locLen))
279 return S_FALSE;
280 curSize -= locLen;
281 len -= locLen;
282 if (len != 0)
283 {
284 _remainLen = (Int32)len;
285 _rep0 = distance;
286 break;
287 }
288 }
289 else
290 return S_FALSE;
291 }
292
293 if (finishInputStream && curSize == 0)
294 {
295 if (m_MainDecoder.Decode(&m_InBitStream) != kSymbolEndOfBlock)
296 return S_FALSE;
297 _needReadTable = true;
298 }
299 }
300
301 if (m_InBitStream.ExtraBitsWereRead())
302 return S_FALSE;
303
304 return S_OK;
305 }
306
307
308 #ifdef _NO_EXCEPTIONS
309
310 #define DEFLATE_TRY_BEGIN
311 #define DEFLATE_TRY_END(res)
312
313 #else
314
315 #define DEFLATE_TRY_BEGIN try {
316 #define DEFLATE_TRY_END(res) } \
317 catch(const CSystemException &e) { res = e.ErrorCode; } \
318 catch(...) { res = S_FALSE; }
319
320 // catch(const CInBufferException &e) { res = e.ErrorCode; }
321 // catch(const CLzOutWindowException &e) { res = e.ErrorCode; }
322
323 #endif
324
325
CodeReal(ISequentialOutStream * outStream,ICompressProgressInfo * progress)326 HRESULT CCoder::CodeReal(ISequentialOutStream *outStream, ICompressProgressInfo *progress)
327 {
328 HRESULT res;
329
330 DEFLATE_TRY_BEGIN
331
332 m_OutWindowStream.SetStream(outStream);
333 CCoderReleaser flusher(this);
334
335 const UInt64 inStart = _needInitInStream ? 0 : m_InBitStream.GetProcessedSize();
336
337 for (;;)
338 {
339 const UInt32 kInputProgressLimit = 1 << 21;
340 UInt32 curSize = 1 << 20;
341 bool finishInputStream = false;
342 if (_outSizeDefined)
343 {
344 const UInt64 rem = _outSize - GetOutProcessedCur();
345 if (curSize >= rem)
346 {
347 curSize = (UInt32)rem;
348 if (ZlibMode || _needFinishInput)
349 finishInputStream = true;
350 }
351 }
352 if (!finishInputStream && curSize == 0)
353 break;
354
355 RINOK(CodeSpec(curSize, finishInputStream, progress ? kInputProgressLimit : 0));
356
357 if (_remainLen == kLenIdFinished)
358 break;
359
360 if (progress)
361 {
362 const UInt64 inSize = m_InBitStream.GetProcessedSize() - inStart;
363 const UInt64 nowPos64 = GetOutProcessedCur();
364 RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
365 }
366 }
367
368 if (_remainLen == kLenIdFinished && ZlibMode)
369 {
370 m_InBitStream.AlignToByte();
371 for (unsigned i = 0; i < 4; i++)
372 ZlibFooter[i] = ReadAlignedByte();
373 }
374
375 flusher.NeedFlush = false;
376 res = Flush();
377 if (res == S_OK && _remainLen != kLenIdNeedInit && InputEofError())
378 return S_FALSE;
379
380 DEFLATE_TRY_END(res)
381
382 return res;
383 }
384
385
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 * outSize,ICompressProgressInfo * progress)386 HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
387 const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
388 {
389 SetInStream(inStream);
390 SetOutStreamSize(outSize);
391 HRESULT res = CodeReal(outStream, progress);
392 ReleaseInStream();
393 /*
394 if (res == S_OK)
395 if (_needFinishInput && inSize && *inSize != m_InBitStream.GetProcessedSize())
396 res = S_FALSE;
397 */
398 return res;
399 }
400
401
SetFinishMode(UInt32 finishMode)402 STDMETHODIMP CCoder::SetFinishMode(UInt32 finishMode)
403 {
404 Set_NeedFinishInput(finishMode != 0);
405 return S_OK;
406 }
407
408
GetInStreamProcessedSize(UInt64 * value)409 STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value)
410 {
411 if (!value)
412 return E_INVALIDARG;
413 *value = m_InBitStream.GetProcessedSize();
414 return S_OK;
415 }
416
417
SetInStream(ISequentialInStream * inStream)418 STDMETHODIMP CCoder::SetInStream(ISequentialInStream *inStream)
419 {
420 m_InStreamRef = inStream;
421 m_InBitStream.SetStream(inStream);
422 return S_OK;
423 }
424
425
ReleaseInStream()426 STDMETHODIMP CCoder::ReleaseInStream()
427 {
428 m_InStreamRef.Release();
429 return S_OK;
430 }
431
432
SetOutStreamSizeResume(const UInt64 * outSize)433 void CCoder::SetOutStreamSizeResume(const UInt64 *outSize)
434 {
435 _outSizeDefined = (outSize != NULL);
436 _outSize = 0;
437 if (_outSizeDefined)
438 _outSize = *outSize;
439
440 m_OutWindowStream.Init(_keepHistory);
441 _outStartPos = m_OutWindowStream.GetProcessedSize();
442
443 _remainLen = kLenIdNeedInit;
444 }
445
446
SetOutStreamSize(const UInt64 * outSize)447 STDMETHODIMP CCoder::SetOutStreamSize(const UInt64 *outSize)
448 {
449 _needInitInStream = true;
450 SetOutStreamSizeResume(outSize);
451 return S_OK;
452 }
453
454
455 #ifndef NO_READ_FROM_CODER
456
Read(void * data,UInt32 size,UInt32 * processedSize)457 STDMETHODIMP CCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
458 {
459 HRESULT res;
460
461 if (processedSize)
462 *processedSize = 0;
463 const UInt64 outPos = GetOutProcessedCur();
464
465 bool finishInputStream = false;
466 if (_outSizeDefined)
467 {
468 const UInt64 rem = _outSize - outPos;
469 if (size >= rem)
470 {
471 size = (UInt32)rem;
472 if (ZlibMode || _needFinishInput)
473 finishInputStream = true;
474 }
475 }
476 if (!finishInputStream && size == 0)
477 return S_OK;
478
479 DEFLATE_TRY_BEGIN
480
481 m_OutWindowStream.SetMemStream((Byte *)data);
482
483 res = CodeSpec(size, finishInputStream);
484
485 DEFLATE_TRY_END(res)
486
487 {
488 HRESULT res2 = Flush();
489 if (res2 != S_OK)
490 res = res2;
491 }
492
493 if (processedSize)
494 *processedSize = (UInt32)(GetOutProcessedCur() - outPos);
495
496 m_OutWindowStream.SetMemStream(NULL);
497 return res;
498 }
499
500 #endif
501
502
CodeResume(ISequentialOutStream * outStream,const UInt64 * outSize,ICompressProgressInfo * progress)503 HRESULT CCoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)
504 {
505 SetOutStreamSizeResume(outSize);
506 return CodeReal(outStream, progress);
507 }
508
509 }}}
510