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