1 // Rar3Decoder.cpp
2 // According to unRAR license, this code may not be used to develop
3 // a program that creates RAR archives
4 
5 /* This code uses Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
6 
7 #include "StdAfx.h"
8 
9 #include "../../../C/Alloc.h"
10 
11 #include "../Common/StreamUtils.h"
12 
13 #include "Rar3Decoder.h"
14 
15 namespace NCompress {
16 namespace NRar3 {
17 
18 static const UInt32 kNumAlignReps = 15;
19 
20 static const UInt32 kSymbolReadTable = 256;
21 static const UInt32 kSymbolRep = 259;
22 static const UInt32 kSymbolLen2 = kSymbolRep + kNumReps;
23 
24 static const Byte kLenStart     [kLenTableSize] = {0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224};
25 static const Byte kLenDirectBits[kLenTableSize] = {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,  4,  5,  5,  5,  5};
26 
27 static const Byte kDistDirectBits[kDistTableSize] =
28   {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,
29   16,16,16,16,16,16,16,16,16,16,16,16,16,16,
30   18,18,18,18,18,18,18,18,18,18,18,18};
31 
32 static const Byte kLevelDirectBits[kLevelTableSize] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
33 
34 static const Byte kLen2DistStarts[kNumLen2Symbols]={0,4,8,16,32,64,128,192};
35 static const Byte kLen2DistDirectBits[kNumLen2Symbols]={2,2,3, 4, 5, 6,  6,  6};
36 
37 static const UInt32 kDistLimit3 = 0x2000 - 2;
38 static const UInt32 kDistLimit4 = 0x40000 - 2;
39 
40 static const UInt32 kNormalMatchMinLen = 3;
41 
42 static const UInt32 kVmDataSizeMax = 1 << 16;
43 static const UInt32 kVmCodeSizeMax = 1 << 16;
44 
45 extern "C" {
46 
47 #define GET_RangeDecoder CRangeDecoder *p = CONTAINER_FROM_VTBL_CLS(pp, CRangeDecoder, vt);
48 
Range_GetThreshold(const IPpmd7_RangeDec * pp,UInt32 total)49 static UInt32 Range_GetThreshold(const IPpmd7_RangeDec *pp, UInt32 total)
50 {
51   GET_RangeDecoder;
52   return p->Code / (p->Range /= total);
53 }
54 
Range_Decode(const IPpmd7_RangeDec * pp,UInt32 start,UInt32 size)55 static void Range_Decode(const IPpmd7_RangeDec *pp, UInt32 start, UInt32 size)
56 {
57   GET_RangeDecoder;
58   start *= p->Range;
59   p->Low += start;
60   p->Code -= start;
61   p->Range *= size;
62   p->Normalize();
63 }
64 
Range_DecodeBit(const IPpmd7_RangeDec * pp,UInt32 size0)65 static UInt32 Range_DecodeBit(const IPpmd7_RangeDec *pp, UInt32 size0)
66 {
67   GET_RangeDecoder;
68   if (p->Code / (p->Range >>= 14) < size0)
69   {
70     Range_Decode(&p->vt, 0, size0);
71     return 0;
72   }
73   else
74   {
75     Range_Decode(&p->vt, size0, (1 << 14) - size0);
76     return 1;
77   }
78 }
79 
80 }
81 
CRangeDecoder()82 CRangeDecoder::CRangeDecoder() throw()
83 {
84   vt.GetThreshold = Range_GetThreshold;
85   vt.Decode = Range_Decode;
86   vt.DecodeBit = Range_DecodeBit;
87 }
88 
CDecoder()89 CDecoder::CDecoder():
90   _window(0),
91   _winPos(0),
92   _wrPtr(0),
93   _lzSize(0),
94   _writtenFileSize(0),
95   _vmData(0),
96   _vmCode(0),
97   m_IsSolid(false),
98   _errorMode(false)
99 {
100   Ppmd7_Construct(&_ppmd);
101 }
102 
~CDecoder()103 CDecoder::~CDecoder()
104 {
105   InitFilters();
106   ::MidFree(_vmData);
107   ::MidFree(_window);
108   Ppmd7_Free(&_ppmd, &g_BigAlloc);
109 }
110 
WriteDataToStream(const Byte * data,UInt32 size)111 HRESULT CDecoder::WriteDataToStream(const Byte *data, UInt32 size)
112 {
113   return WriteStream(_outStream, data, size);
114 }
115 
WriteData(const Byte * data,UInt32 size)116 HRESULT CDecoder::WriteData(const Byte *data, UInt32 size)
117 {
118   HRESULT res = S_OK;
119   if (_writtenFileSize < _unpackSize)
120   {
121     UInt32 curSize = size;
122     UInt64 remain = _unpackSize - _writtenFileSize;
123     if (remain < curSize)
124       curSize = (UInt32)remain;
125     res = WriteDataToStream(data, curSize);
126   }
127   _writtenFileSize += size;
128   return res;
129 }
130 
WriteArea(UInt32 startPtr,UInt32 endPtr)131 HRESULT CDecoder::WriteArea(UInt32 startPtr, UInt32 endPtr)
132 {
133   if (startPtr <= endPtr)
134     return WriteData(_window + startPtr, endPtr - startPtr);
135   RINOK(WriteData(_window + startPtr, kWindowSize - startPtr));
136   return WriteData(_window, endPtr);
137 }
138 
ExecuteFilter(unsigned tempFilterIndex,NVm::CBlockRef & outBlockRef)139 void CDecoder::ExecuteFilter(unsigned tempFilterIndex, NVm::CBlockRef &outBlockRef)
140 {
141   CTempFilter *tempFilter = _tempFilters[tempFilterIndex];
142   tempFilter->InitR[6] = (UInt32)_writtenFileSize;
143   NVm::SetValue32(&tempFilter->GlobalData[0x24], (UInt32)_writtenFileSize);
144   NVm::SetValue32(&tempFilter->GlobalData[0x28], (UInt32)(_writtenFileSize >> 32));
145   CFilter *filter = _filters[tempFilter->FilterIndex];
146   if (!filter->IsSupported)
147     _unsupportedFilter = true;
148   if (!_vm.Execute(filter, tempFilter, outBlockRef, filter->GlobalData))
149     _unsupportedFilter = true;
150   delete tempFilter;
151   _tempFilters[tempFilterIndex] = 0;
152 }
153 
WriteBuf()154 HRESULT CDecoder::WriteBuf()
155 {
156   UInt32 writtenBorder = _wrPtr;
157   UInt32 writeSize = (_winPos - writtenBorder) & kWindowMask;
158   FOR_VECTOR (i, _tempFilters)
159   {
160     CTempFilter *filter = _tempFilters[i];
161     if (!filter)
162       continue;
163     if (filter->NextWindow)
164     {
165       filter->NextWindow = false;
166       continue;
167     }
168     UInt32 blockStart = filter->BlockStart;
169     UInt32 blockSize = filter->BlockSize;
170     if (((blockStart - writtenBorder) & kWindowMask) < writeSize)
171     {
172       if (writtenBorder != blockStart)
173       {
174         RINOK(WriteArea(writtenBorder, blockStart));
175         writtenBorder = blockStart;
176         writeSize = (_winPos - writtenBorder) & kWindowMask;
177       }
178       if (blockSize <= writeSize)
179       {
180         UInt32 blockEnd = (blockStart + blockSize) & kWindowMask;
181         if (blockStart < blockEnd || blockEnd == 0)
182           _vm.SetMemory(0, _window + blockStart, blockSize);
183         else
184         {
185           UInt32 tailSize = kWindowSize - blockStart;
186           _vm.SetMemory(0, _window + blockStart, tailSize);
187           _vm.SetMemory(tailSize, _window, blockEnd);
188         }
189         NVm::CBlockRef outBlockRef;
190         ExecuteFilter(i, outBlockRef);
191         while (i + 1 < _tempFilters.Size())
192         {
193           CTempFilter *nextFilter = _tempFilters[i + 1];
194           if (!nextFilter
195               || nextFilter->BlockStart != blockStart
196               || nextFilter->BlockSize != outBlockRef.Size
197               || nextFilter->NextWindow)
198             break;
199           _vm.SetMemory(0, _vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size);
200           ExecuteFilter(++i, outBlockRef);
201         }
202         WriteDataToStream(_vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size);
203         _writtenFileSize += outBlockRef.Size;
204         writtenBorder = blockEnd;
205         writeSize = (_winPos - writtenBorder) & kWindowMask;
206       }
207       else
208       {
209         for (unsigned j = i; j < _tempFilters.Size(); j++)
210         {
211           CTempFilter *filter2 = _tempFilters[j];
212           if (filter2 && filter2->NextWindow)
213             filter2->NextWindow = false;
214         }
215         _wrPtr = writtenBorder;
216         return S_OK; // check it
217       }
218     }
219   }
220 
221   _wrPtr = _winPos;
222   return WriteArea(writtenBorder, _winPos);
223 }
224 
InitFilters()225 void CDecoder::InitFilters()
226 {
227   _lastFilter = 0;
228   unsigned i;
229   for (i = 0; i < _tempFilters.Size(); i++)
230     delete _tempFilters[i];
231   _tempFilters.Clear();
232   for (i = 0; i < _filters.Size(); i++)
233     delete _filters[i];
234   _filters.Clear();
235 }
236 
237 static const unsigned MAX_UNPACK_FILTERS = 8192;
238 
AddVmCode(UInt32 firstByte,UInt32 codeSize)239 bool CDecoder::AddVmCode(UInt32 firstByte, UInt32 codeSize)
240 {
241   CMemBitDecoder inp;
242   inp.Init(_vmData, codeSize);
243 
244   UInt32 filterIndex;
245 
246   if (firstByte & 0x80)
247   {
248     filterIndex = inp.ReadEncodedUInt32();
249     if (filterIndex == 0)
250       InitFilters();
251     else
252       filterIndex--;
253   }
254   else
255     filterIndex = _lastFilter;
256 
257   if (filterIndex > (UInt32)_filters.Size())
258     return false;
259   _lastFilter = filterIndex;
260   bool newFilter = (filterIndex == (UInt32)_filters.Size());
261 
262   CFilter *filter;
263   if (newFilter)
264   {
265     // check if too many filters
266     if (filterIndex > MAX_UNPACK_FILTERS)
267       return false;
268     filter = new CFilter;
269     _filters.Add(filter);
270   }
271   else
272   {
273     filter = _filters[filterIndex];
274     filter->ExecCount++;
275   }
276 
277   unsigned numEmptyItems = 0;
278   {
279     FOR_VECTOR (i, _tempFilters)
280     {
281       _tempFilters[i - numEmptyItems] = _tempFilters[i];
282       if (!_tempFilters[i])
283         numEmptyItems++;
284       if (numEmptyItems != 0)
285         _tempFilters[i] = NULL;
286     }
287   }
288   if (numEmptyItems == 0)
289   {
290     _tempFilters.Add(NULL);
291     numEmptyItems = 1;
292   }
293   CTempFilter *tempFilter = new CTempFilter;
294   _tempFilters[_tempFilters.Size() - numEmptyItems] = tempFilter;
295   tempFilter->FilterIndex = filterIndex;
296 
297   UInt32 blockStart = inp.ReadEncodedUInt32();
298   if (firstByte & 0x40)
299     blockStart += 258;
300   tempFilter->BlockStart = (blockStart + _winPos) & kWindowMask;
301   if (firstByte & 0x20)
302     filter->BlockSize = inp.ReadEncodedUInt32();
303   tempFilter->BlockSize = filter->BlockSize;
304   tempFilter->NextWindow = _wrPtr != _winPos && ((_wrPtr - _winPos) & kWindowMask) <= blockStart;
305 
306   memset(tempFilter->InitR, 0, sizeof(tempFilter->InitR));
307   tempFilter->InitR[3] = NVm::kGlobalOffset;
308   tempFilter->InitR[4] = tempFilter->BlockSize;
309   tempFilter->InitR[5] = filter->ExecCount;
310   if (firstByte & 0x10)
311   {
312     UInt32 initMask = inp.ReadBits(NVm::kNumGpRegs);
313     for (unsigned i = 0; i < NVm::kNumGpRegs; i++)
314       if (initMask & (1 << i))
315         tempFilter->InitR[i] = inp.ReadEncodedUInt32();
316   }
317 
318   bool isOK = true;
319   if (newFilter)
320   {
321     UInt32 vmCodeSize = inp.ReadEncodedUInt32();
322     if (vmCodeSize >= kVmCodeSizeMax || vmCodeSize == 0)
323       return false;
324     for (UInt32 i = 0; i < vmCodeSize; i++)
325       _vmCode[i] = (Byte)inp.ReadBits(8);
326     isOK = filter->PrepareProgram(_vmCode, vmCodeSize);
327   }
328 
329   {
330     Byte *globalData = &tempFilter->GlobalData[0];
331     for (unsigned i = 0; i < NVm::kNumGpRegs; i++)
332       NVm::SetValue32(&globalData[i * 4], tempFilter->InitR[i]);
333     NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockSize], tempFilter->BlockSize);
334     NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockPos], 0); // It was commented. why?
335     NVm::SetValue32(&globalData[NVm::NGlobalOffset::kExecCount], filter->ExecCount);
336   }
337 
338   if (firstByte & 8)
339   {
340     UInt32 dataSize = inp.ReadEncodedUInt32();
341     if (dataSize > NVm::kGlobalSize - NVm::kFixedGlobalSize)
342       return false;
343     CRecordVector<Byte> &globalData = tempFilter->GlobalData;
344     unsigned requiredSize = (unsigned)(dataSize + NVm::kFixedGlobalSize);
345     if (globalData.Size() < requiredSize)
346       globalData.ChangeSize_KeepData(requiredSize);
347     Byte *dest = &globalData[NVm::kFixedGlobalSize];
348     for (UInt32 i = 0; i < dataSize; i++)
349       dest[i] = (Byte)inp.ReadBits(8);
350   }
351 
352   return isOK;
353 }
354 
ReadVmCodeLZ()355 bool CDecoder::ReadVmCodeLZ()
356 {
357   UInt32 firstByte = ReadBits(8);
358   UInt32 length = (firstByte & 7) + 1;
359   if (length == 7)
360     length = ReadBits(8) + 7;
361   else if (length == 8)
362     length = ReadBits(16);
363   if (length > kVmDataSizeMax)
364     return false;
365   for (UInt32 i = 0; i < length; i++)
366     _vmData[i] = (Byte)ReadBits(8);
367   return AddVmCode(firstByte, length);
368 }
369 
ReadVmCodePPM()370 bool CDecoder::ReadVmCodePPM()
371 {
372   int firstByte = DecodePpmSymbol();
373   if (firstByte < 0)
374     return false;
375   UInt32 length = (firstByte & 7) + 1;
376   if (length == 7)
377   {
378     int b1 = DecodePpmSymbol();
379     if (b1 < 0)
380       return false;
381     length = b1 + 7;
382   }
383   else if (length == 8)
384   {
385     int b1 = DecodePpmSymbol();
386     if (b1 < 0)
387       return false;
388     int b2 = DecodePpmSymbol();
389     if (b2 < 0)
390       return false;
391     length = b1 * 256 + b2;
392   }
393   if (length > kVmDataSizeMax)
394     return false;
395   if (InputEofError_Fast())
396     return false;
397   for (UInt32 i = 0; i < length; i++)
398   {
399     int b = DecodePpmSymbol();
400     if (b < 0)
401       return false;
402     _vmData[i] = (Byte)b;
403   }
404   return AddVmCode(firstByte, length);
405 }
406 
407 #define RIF(x) { if (!(x)) return S_FALSE; }
408 
ReadBits(unsigned numBits)409 UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.BitDecoder.ReadBits(numBits); }
410 
411 // ---------- PPM ----------
412 
InitPPM()413 HRESULT CDecoder::InitPPM()
414 {
415   unsigned maxOrder = (unsigned)ReadBits(7);
416 
417   bool reset = ((maxOrder & 0x20) != 0);
418   UInt32 maxMB = 0;
419   if (reset)
420     maxMB = (Byte)ReadBits(8);
421   else
422   {
423     if (PpmError || !Ppmd7_WasAllocated(&_ppmd))
424       return S_FALSE;
425   }
426   if (maxOrder & 0x40)
427     PpmEscChar = (Byte)ReadBits(8);
428   m_InBitStream.InitRangeCoder();
429   /*
430   if (m_InBitStream.m_BitPos != 0)
431     return S_FALSE;
432   */
433   if (reset)
434   {
435     PpmError = true;
436     maxOrder = (maxOrder & 0x1F) + 1;
437     if (maxOrder > 16)
438       maxOrder = 16 + (maxOrder - 16) * 3;
439     if (maxOrder == 1)
440     {
441       Ppmd7_Free(&_ppmd, &g_BigAlloc);
442       return S_FALSE;
443     }
444     if (!Ppmd7_Alloc(&_ppmd, (maxMB + 1) << 20, &g_BigAlloc))
445       return E_OUTOFMEMORY;
446     Ppmd7_Init(&_ppmd, maxOrder);
447     PpmError = false;
448   }
449   return S_OK;
450 }
451 
DecodePpmSymbol()452 int CDecoder::DecodePpmSymbol() { return Ppmd7_DecodeSymbol(&_ppmd, &m_InBitStream.vt); }
453 
DecodePPM(Int32 num,bool & keepDecompressing)454 HRESULT CDecoder::DecodePPM(Int32 num, bool &keepDecompressing)
455 {
456   keepDecompressing = false;
457   if (PpmError)
458     return S_FALSE;
459   do
460   {
461     if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos)
462     {
463       RINOK(WriteBuf());
464       if (_writtenFileSize > _unpackSize)
465       {
466         keepDecompressing = false;
467         return S_OK;
468       }
469     }
470     if (InputEofError_Fast())
471       return false;
472     int c = DecodePpmSymbol();
473     if (c < 0)
474     {
475       PpmError = true;
476       return S_FALSE;
477     }
478     if (c == PpmEscChar)
479     {
480       int nextCh = DecodePpmSymbol();
481       if (nextCh < 0)
482       {
483         PpmError = true;
484         return S_FALSE;
485       }
486       if (nextCh == 0)
487         return ReadTables(keepDecompressing);
488       if (nextCh == 2 || nextCh == -1)
489         return S_OK;
490       if (nextCh == 3)
491       {
492         if (!ReadVmCodePPM())
493         {
494           PpmError = true;
495           return S_FALSE;
496         }
497         continue;
498       }
499       if (nextCh == 4 || nextCh == 5)
500       {
501         UInt32 distance = 0;
502         UInt32 length = 4;
503         if (nextCh == 4)
504         {
505           for (int i = 0; i < 3; i++)
506           {
507             int c2 = DecodePpmSymbol();
508             if (c2 < 0)
509             {
510               PpmError = true;
511               return S_FALSE;
512             }
513             distance = (distance << 8) + (Byte)c2;
514           }
515           distance++;
516           length += 28;
517         }
518         int c2 = DecodePpmSymbol();
519         if (c2 < 0)
520         {
521           PpmError = true;
522           return S_FALSE;
523         }
524         length += c2;
525         if (distance >= _lzSize)
526           return S_FALSE;
527         CopyBlock(distance, length);
528         num -= (Int32)length;
529         continue;
530       }
531     }
532     PutByte((Byte)c);
533     num--;
534   }
535   while (num >= 0);
536   keepDecompressing = true;
537   return S_OK;
538 }
539 
540 // ---------- LZ ----------
541 
ReadTables(bool & keepDecompressing)542 HRESULT CDecoder::ReadTables(bool &keepDecompressing)
543 {
544   keepDecompressing = true;
545   m_InBitStream.BitDecoder.AlignToByte();
546   if (ReadBits(1) != 0)
547   {
548     _lzMode = false;
549     return InitPPM();
550   }
551 
552   TablesRead = false;
553   TablesOK = false;
554 
555   _lzMode = true;
556   PrevAlignBits = 0;
557   PrevAlignCount = 0;
558 
559   Byte levelLevels[kLevelTableSize];
560   Byte lens[kTablesSizesSum];
561 
562   if (ReadBits(1) == 0)
563     memset(m_LastLevels, 0, kTablesSizesSum);
564 
565   unsigned i;
566 
567   for (i = 0; i < kLevelTableSize; i++)
568   {
569     UInt32 length = ReadBits(4);
570     if (length == 15)
571     {
572       UInt32 zeroCount = ReadBits(4);
573       if (zeroCount != 0)
574       {
575         zeroCount += 2;
576         while (zeroCount-- > 0 && i < kLevelTableSize)
577           levelLevels[i++]=0;
578         i--;
579         continue;
580       }
581     }
582     levelLevels[i] = (Byte)length;
583   }
584 
585   RIF(m_LevelDecoder.Build(levelLevels));
586 
587   i = 0;
588 
589   do
590   {
591     UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream.BitDecoder);
592     if (sym < 16)
593     {
594       lens[i] = Byte((sym + m_LastLevels[i]) & 15);
595       i++;
596     }
597     else if (sym > kLevelTableSize)
598       return S_FALSE;
599     else
600     {
601       unsigned num = ((sym - 16) & 1) * 4;
602       num += num + 3 + (unsigned)ReadBits(num + 3);
603       num += i;
604       if (num > kTablesSizesSum)
605         num = kTablesSizesSum;
606       Byte v = 0;
607       if (sym < 16 + 2)
608       {
609         if (i == 0)
610           return S_FALSE;
611         v = lens[(size_t)i - 1];
612       }
613       do
614         lens[i++] = v;
615       while (i < num);
616     }
617   }
618   while (i < kTablesSizesSum);
619 
620   if (InputEofError())
621     return S_FALSE;
622 
623   TablesRead = true;
624 
625   // original code has check here:
626   /*
627   if (InAddr > ReadTop)
628   {
629     keepDecompressing = false;
630     return true;
631   }
632   */
633 
634   RIF(m_MainDecoder.Build(&lens[0]));
635   RIF(m_DistDecoder.Build(&lens[kMainTableSize]));
636   RIF(m_AlignDecoder.Build(&lens[kMainTableSize + kDistTableSize]));
637   RIF(m_LenDecoder.Build(&lens[kMainTableSize + kDistTableSize + kAlignTableSize]));
638 
639   memcpy(m_LastLevels, lens, kTablesSizesSum);
640 
641   TablesOK = true;
642 
643   return S_OK;
644 }
645 
646 /*
647 class CCoderReleaser
648 {
649   CDecoder *m_Coder;
650 public:
651   CCoderReleaser(CDecoder *coder): m_Coder(coder) {}
652   ~CCoderReleaser()
653   {
654     m_Coder->ReleaseStreams();
655   }
656 };
657 */
658 
ReadEndOfBlock(bool & keepDecompressing)659 HRESULT CDecoder::ReadEndOfBlock(bool &keepDecompressing)
660 {
661   if (ReadBits(1) == 0)
662   {
663     // new file
664     keepDecompressing = false;
665     TablesRead = (ReadBits(1) == 0);
666     return S_OK;
667   }
668   TablesRead = false;
669   return ReadTables(keepDecompressing);
670 }
671 
672 UInt32 kDistStart[kDistTableSize];
673 
674 class CDistInit
675 {
676 public:
CDistInit()677   CDistInit() { Init(); }
Init()678   void Init()
679   {
680     UInt32 start = 0;
681     for (UInt32 i = 0; i < kDistTableSize; i++)
682     {
683       kDistStart[i] = start;
684       start += (1 << kDistDirectBits[i]);
685     }
686   }
687 } g_DistInit;
688 
DecodeLZ(bool & keepDecompressing)689 HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
690 {
691   UInt32 rep0 = _reps[0];
692   UInt32 rep1 = _reps[1];
693   UInt32 rep2 = _reps[2];
694   UInt32 rep3 = _reps[3];
695   UInt32 length = _lastLength;
696   for (;;)
697   {
698     if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos)
699     {
700       RINOK(WriteBuf());
701       if (_writtenFileSize > _unpackSize)
702       {
703         keepDecompressing = false;
704         return S_OK;
705       }
706     }
707 
708     if (InputEofError_Fast())
709       return S_FALSE;
710 
711     UInt32 sym = m_MainDecoder.Decode(&m_InBitStream.BitDecoder);
712     if (sym < 256)
713     {
714       PutByte((Byte)sym);
715       continue;
716     }
717     else if (sym == kSymbolReadTable)
718     {
719       RINOK(ReadEndOfBlock(keepDecompressing));
720       break;
721     }
722     else if (sym == 257)
723     {
724       if (!ReadVmCodeLZ())
725         return S_FALSE;
726       continue;
727     }
728     else if (sym == 258)
729     {
730       if (length == 0)
731         return S_FALSE;
732     }
733     else if (sym < kSymbolRep + 4)
734     {
735       if (sym != kSymbolRep)
736       {
737         UInt32 distance;
738         if (sym == kSymbolRep + 1)
739           distance = rep1;
740         else
741         {
742           if (sym == kSymbolRep + 2)
743             distance = rep2;
744           else
745           {
746             distance = rep3;
747             rep3 = rep2;
748           }
749           rep2 = rep1;
750         }
751         rep1 = rep0;
752         rep0 = distance;
753       }
754 
755       const UInt32 sym2 = m_LenDecoder.Decode(&m_InBitStream.BitDecoder);
756       if (sym2 >= kLenTableSize)
757         return S_FALSE;
758       length = 2 + kLenStart[sym2] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[sym2]);
759     }
760     else
761     {
762       rep3 = rep2;
763       rep2 = rep1;
764       rep1 = rep0;
765       if (sym < 271)
766       {
767         sym -= 263;
768         rep0 = kLen2DistStarts[sym] + m_InBitStream.BitDecoder.ReadBits(kLen2DistDirectBits[sym]);
769         length = 2;
770       }
771       else if (sym < 299)
772       {
773         sym -= 271;
774         length = kNormalMatchMinLen + (UInt32)kLenStart[sym] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[sym]);
775         const UInt32 sym2 = m_DistDecoder.Decode(&m_InBitStream.BitDecoder);
776         if (sym2 >= kDistTableSize)
777           return S_FALSE;
778         rep0 = kDistStart[sym2];
779         unsigned numBits = kDistDirectBits[sym2];
780         if (sym2 >= (kNumAlignBits * 2) + 2)
781         {
782           if (numBits > kNumAlignBits)
783             rep0 += (m_InBitStream.BitDecoder.ReadBits(numBits - kNumAlignBits) << kNumAlignBits);
784           if (PrevAlignCount > 0)
785           {
786             PrevAlignCount--;
787             rep0 += PrevAlignBits;
788           }
789           else
790           {
791             const UInt32 sym3 = m_AlignDecoder.Decode(&m_InBitStream.BitDecoder);
792             if (sym3 < (1 << kNumAlignBits))
793             {
794               rep0 += sym3;
795               PrevAlignBits = sym3;
796             }
797             else if (sym3 == (1 << kNumAlignBits))
798             {
799               PrevAlignCount = kNumAlignReps;
800               rep0 += PrevAlignBits;
801             }
802             else
803               return S_FALSE;
804           }
805         }
806         else
807           rep0 += m_InBitStream.BitDecoder.ReadBits(numBits);
808         length += ((kDistLimit4 - rep0) >> 31) + ((kDistLimit3 - rep0) >> 31);
809       }
810       else
811         return S_FALSE;
812     }
813     if (rep0 >= _lzSize)
814       return S_FALSE;
815     CopyBlock(rep0, length);
816   }
817   _reps[0] = rep0;
818   _reps[1] = rep1;
819   _reps[2] = rep2;
820   _reps[3] = rep3;
821   _lastLength = length;
822 
823   return S_OK;
824 }
825 
826 
CodeReal(ICompressProgressInfo * progress)827 HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress)
828 {
829   _writtenFileSize = 0;
830   _unsupportedFilter = false;
831 
832   if (!m_IsSolid)
833   {
834     _lzSize = 0;
835     _winPos = 0;
836     _wrPtr = 0;
837     for (int i = 0; i < kNumReps; i++)
838       _reps[i] = 0;
839     _lastLength = 0;
840     memset(m_LastLevels, 0, kTablesSizesSum);
841     TablesRead = false;
842     PpmEscChar = 2;
843     PpmError = true;
844     InitFilters();
845     _errorMode = false;
846   }
847 
848   if (_errorMode)
849     return S_FALSE;
850 
851   if (!m_IsSolid || !TablesRead)
852   {
853     bool keepDecompressing;
854     RINOK(ReadTables(keepDecompressing));
855     if (!keepDecompressing)
856       return S_OK;
857   }
858 
859   for (;;)
860   {
861     bool keepDecompressing;
862     if (_lzMode)
863     {
864       if (!TablesOK)
865         return S_FALSE;
866       RINOK(DecodeLZ(keepDecompressing))
867     }
868     else
869     {
870       RINOK(DecodePPM(1 << 18, keepDecompressing))
871     }
872 
873     if (InputEofError())
874       return S_FALSE;
875 
876     UInt64 packSize = m_InBitStream.BitDecoder.GetProcessedSize();
877     RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize));
878     if (!keepDecompressing)
879       break;
880   }
881   RINOK(WriteBuf());
882   UInt64 packSize = m_InBitStream.BitDecoder.GetProcessedSize();
883   RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize));
884   if (_writtenFileSize < _unpackSize)
885     return S_FALSE;
886 
887   if (_unsupportedFilter)
888     return E_NOTIMPL;
889 
890   return S_OK;
891 }
892 
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress)893 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
894     const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
895 {
896   try
897   {
898     if (!inSize)
899       return E_INVALIDARG;
900 
901     if (!_vmData)
902     {
903       _vmData = (Byte *)::MidAlloc(kVmDataSizeMax + kVmCodeSizeMax);
904       if (!_vmData)
905         return E_OUTOFMEMORY;
906       _vmCode = _vmData + kVmDataSizeMax;
907     }
908 
909     if (!_window)
910     {
911       _window = (Byte *)::MidAlloc(kWindowSize);
912       if (!_window)
913         return E_OUTOFMEMORY;
914     }
915     if (!m_InBitStream.BitDecoder.Create(1 << 20))
916       return E_OUTOFMEMORY;
917     if (!_vm.Create())
918       return E_OUTOFMEMORY;
919 
920 
921     m_InBitStream.BitDecoder.SetStream(inStream);
922     m_InBitStream.BitDecoder.Init();
923     _outStream = outStream;
924 
925     // CCoderReleaser coderReleaser(this);
926     _unpackSize = outSize ? *outSize : (UInt64)(Int64)-1;
927     return CodeReal(progress);
928   }
929   catch(const CInBufferException &e)  { _errorMode = true; return e.ErrorCode; }
930   catch(...) { _errorMode = true; return S_FALSE; }
931   // CNewException is possible here. But probably CNewException is caused
932   // by error in data stream.
933 }
934 
SetDecoderProperties2(const Byte * data,UInt32 size)935 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
936 {
937   if (size < 1)
938     return E_INVALIDARG;
939   m_IsSolid = ((data[0] & 1) != 0);
940   return S_OK;
941 }
942 
943 }}
944