1 // Rar3Decoder.h
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 #ifndef __COMPRESS_RAR3_DECODER_H
8 #define __COMPRESS_RAR3_DECODER_H
9 
10 #include "../../../C/Ppmd7.h"
11 
12 #include "../../Common/MyCom.h"
13 
14 #include "../ICoder.h"
15 
16 #include "../Common/InBuffer.h"
17 
18 #include "BitmDecoder.h"
19 #include "HuffmanDecoder.h"
20 #include "Rar3Vm.h"
21 
22 namespace NCompress {
23 namespace NRar3 {
24 
25 const UInt32 kWindowSize = 1 << 22;
26 const UInt32 kWindowMask = (kWindowSize - 1);
27 
28 const UInt32 kNumReps = 4;
29 const UInt32 kNumLen2Symbols = 8;
30 const UInt32 kLenTableSize = 28;
31 const UInt32 kMainTableSize = 256 + 1 + 1 + 1 + kNumReps + kNumLen2Symbols + kLenTableSize;
32 const UInt32 kDistTableSize = 60;
33 
34 const unsigned kNumAlignBits = 4;
35 const UInt32 kAlignTableSize = (1 << kNumAlignBits) + 1;
36 
37 const UInt32 kLevelTableSize = 20;
38 
39 const UInt32 kTablesSizesSum = kMainTableSize + kDistTableSize + kAlignTableSize + kLenTableSize;
40 
41 class CBitDecoder
42 {
43   UInt32 _value;
44   unsigned _bitPos;
45 public:
46   CInBuffer Stream;
47 
Create(UInt32 bufSize)48   bool Create(UInt32 bufSize) { return Stream.Create(bufSize); }
SetStream(ISequentialInStream * inStream)49   void SetStream(ISequentialInStream *inStream) { Stream.SetStream(inStream);}
50 
Init()51   void Init()
52   {
53     Stream.Init();
54     _bitPos = 0;
55     _value = 0;
56   }
57 
ExtraBitsWereRead()58   bool ExtraBitsWereRead() const
59   {
60     return (Stream.NumExtraBytes > 4 || _bitPos < (Stream.NumExtraBytes << 3));
61   }
62 
GetProcessedSize()63   UInt64 GetProcessedSize() const { return Stream.GetProcessedSize() - (_bitPos >> 3); }
64 
AlignToByte()65   void AlignToByte()
66   {
67     _bitPos &= ~(unsigned)7;
68     _value = _value & ((1 << _bitPos) - 1);
69   }
70 
GetValue(unsigned numBits)71   UInt32 GetValue(unsigned numBits)
72   {
73     if (_bitPos < numBits)
74     {
75       _bitPos += 8;
76       _value = (_value << 8) | Stream.ReadByte();
77       if (_bitPos < numBits)
78       {
79         _bitPos += 8;
80         _value = (_value << 8) | Stream.ReadByte();
81       }
82     }
83     return _value >> (_bitPos - numBits);
84   }
85 
MovePos(unsigned numBits)86   void MovePos(unsigned numBits)
87   {
88     _bitPos -= numBits;
89     _value = _value & ((1 << _bitPos) - 1);
90   }
91 
ReadBits(unsigned numBits)92   UInt32 ReadBits(unsigned numBits)
93   {
94     UInt32 res = GetValue(numBits);
95     MovePos(numBits);
96     return res;
97   }
98 };
99 
100 const UInt32 kTopValue = (1 << 24);
101 const UInt32 kBot = (1 << 15);
102 
103 struct CRangeDecoder
104 {
105   IPpmd7_RangeDec vt;
106   UInt32 Range;
107   UInt32 Code;
108   UInt32 Low;
109   CBitDecoder BitDecoder;
110   SRes Res;
111 
112 public:
InitRangeCoderCRangeDecoder113   void InitRangeCoder()
114   {
115     Code = 0;
116     Low = 0;
117     Range = 0xFFFFFFFF;
118     for (int i = 0; i < 4; i++)
119       Code = (Code << 8) | BitDecoder.ReadBits(8);
120   }
121 
NormalizeCRangeDecoder122   void Normalize()
123   {
124     while ((Low ^ (Low + Range)) < kTopValue ||
125        Range < kBot && ((Range = (0 - Low) & (kBot - 1)), 1))
126     {
127       Code = (Code << 8) | BitDecoder.Stream.ReadByte();
128       Range <<= 8;
129       Low <<= 8;
130     }
131   }
132 
133   CRangeDecoder() throw();
134 };
135 
136 struct CFilter: public NVm::CProgram
137 {
138   CRecordVector<Byte> GlobalData;
139   UInt32 BlockStart;
140   UInt32 BlockSize;
141   UInt32 ExecCount;
142 
CFilterCFilter143   CFilter(): BlockStart(0), BlockSize(0), ExecCount(0) {}
144 };
145 
146 struct CTempFilter: public NVm::CProgramInitState
147 {
148   UInt32 BlockStart;
149   UInt32 BlockSize;
150   bool NextWindow;
151 
152   UInt32 FilterIndex;
153 
CTempFilterCTempFilter154   CTempFilter()
155   {
156     // all filters must contain at least FixedGlobal block
157     AllocateEmptyFixedGlobal();
158   }
159 };
160 
161 const unsigned kNumHuffmanBits = 15;
162 
163 class CDecoder:
164   public ICompressCoder,
165   public ICompressSetDecoderProperties2,
166   public CMyUnknownImp
167 {
168   CRangeDecoder m_InBitStream;
169   Byte *_window;
170   UInt32 _winPos;
171   UInt32 _wrPtr;
172   UInt64 _lzSize;
173   UInt64 _unpackSize;
174   UInt64 _writtenFileSize; // if it's > _unpackSize, then _unpackSize only written
175   ISequentialOutStream *_outStream;
176   NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
177   NHuffman::CDecoder<kNumHuffmanBits, kDistTableSize> m_DistDecoder;
178   NHuffman::CDecoder<kNumHuffmanBits, kAlignTableSize> m_AlignDecoder;
179   NHuffman::CDecoder<kNumHuffmanBits, kLenTableSize> m_LenDecoder;
180   NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
181 
182   UInt32 _reps[kNumReps];
183   UInt32 _lastLength;
184 
185   Byte m_LastLevels[kTablesSizesSum];
186 
187   Byte *_vmData;
188   Byte *_vmCode;
189   NVm::CVm _vm;
190   CRecordVector<CFilter *> _filters;
191   CRecordVector<CTempFilter *>  _tempFilters;
192   UInt32 _lastFilter;
193 
194   bool m_IsSolid;
195   bool _errorMode;
196 
197   bool _lzMode;
198   bool _unsupportedFilter;
199 
200   UInt32 PrevAlignBits;
201   UInt32 PrevAlignCount;
202 
203   bool TablesRead;
204   bool TablesOK;
205 
206   CPpmd7 _ppmd;
207   int PpmEscChar;
208   bool PpmError;
209 
210   HRESULT WriteDataToStream(const Byte *data, UInt32 size);
211   HRESULT WriteData(const Byte *data, UInt32 size);
212   HRESULT WriteArea(UInt32 startPtr, UInt32 endPtr);
213   void ExecuteFilter(unsigned tempFilterIndex, NVm::CBlockRef &outBlockRef);
214   HRESULT WriteBuf();
215 
216   void InitFilters();
217   bool AddVmCode(UInt32 firstByte, UInt32 codeSize);
218   bool ReadVmCodeLZ();
219   bool ReadVmCodePPM();
220 
221   UInt32 ReadBits(unsigned numBits);
222 
223   HRESULT InitPPM();
224   int DecodePpmSymbol();
225   HRESULT DecodePPM(Int32 num, bool &keepDecompressing);
226 
227   HRESULT ReadTables(bool &keepDecompressing);
228   HRESULT ReadEndOfBlock(bool &keepDecompressing);
229   HRESULT DecodeLZ(bool &keepDecompressing);
230   HRESULT CodeReal(ICompressProgressInfo *progress);
231 
InputEofError()232   bool InputEofError() const { return m_InBitStream.BitDecoder.ExtraBitsWereRead(); }
InputEofError_Fast()233   bool InputEofError_Fast() const { return (m_InBitStream.BitDecoder.Stream.NumExtraBytes > 2); }
234 
235 public:
236   CDecoder();
237   ~CDecoder();
238 
239   MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2)
240 
241   STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
242       const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
243 
244   STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
245 
CopyBlock(UInt32 distance,UInt32 len)246   void CopyBlock(UInt32 distance, UInt32 len)
247   {
248     _lzSize += len;
249     UInt32 pos = (_winPos - distance - 1) & kWindowMask;
250     Byte *window = _window;
251     UInt32 winPos = _winPos;
252     if (kWindowSize - winPos > len && kWindowSize - pos > len)
253     {
254       const Byte *src = window + pos;
255       Byte *dest = window + winPos;
256       _winPos += len;
257       do
258         *dest++ = *src++;
259       while (--len != 0);
260       return;
261     }
262     do
263     {
264       window[winPos] = window[pos];
265       winPos = (winPos + 1) & kWindowMask;
266       pos = (pos + 1) & kWindowMask;
267     }
268     while (--len != 0);
269     _winPos = winPos;
270   }
271 
PutByte(Byte b)272   void PutByte(Byte b)
273   {
274     _window[_winPos] = b;
275     _winPos = (_winPos + 1) & kWindowMask;
276     _lzSize++;
277   }
278 
279 
280 };
281 
282 }}
283 
284 #endif
285