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