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 
ReadBits_upto8(unsigned numBits)99   UInt32 ReadBits_upto8(unsigned numBits)
100   {
101     if (_bitPos < numBits)
102     {
103       _bitPos += 8;
104       _value = (_value << 8) | Stream.ReadByte();
105     }
106     _bitPos -= numBits;
107     UInt32 res = _value >> _bitPos;
108     _value = _value & ((1 << _bitPos) - 1);
109     return res;
110   }
111 
ReadByteFromAligned()112   Byte ReadByteFromAligned()
113   {
114     if (_bitPos == 0)
115       return Stream.ReadByte();
116     unsigned bitsPos = _bitPos - 8;
117     Byte b = (Byte)(_value >> bitsPos);
118     _value = _value & ((1 << bitsPos) - 1);
119     _bitPos = bitsPos;
120     return b;
121   }
122 };
123 
124 
125 struct CByteIn
126 {
127   IByteIn IByteIn_obj;
128   CBitDecoder BitDecoder;
129 };
130 
131 
132 struct CFilter: public NVm::CProgram
133 {
134   CRecordVector<Byte> GlobalData;
135   UInt32 BlockStart;
136   UInt32 BlockSize;
137   UInt32 ExecCount;
138 
CFilterCFilter139   CFilter(): BlockStart(0), BlockSize(0), ExecCount(0) {}
140 };
141 
142 struct CTempFilter: public NVm::CProgramInitState
143 {
144   UInt32 BlockStart;
145   UInt32 BlockSize;
146   bool NextWindow;
147 
148   UInt32 FilterIndex;
149 
CTempFilterCTempFilter150   CTempFilter()
151   {
152     // all filters must contain at least FixedGlobal block
153     AllocateEmptyFixedGlobal();
154   }
155 };
156 
157 const unsigned kNumHuffmanBits = 15;
158 
159 class CDecoder:
160   public ICompressCoder,
161   public ICompressSetDecoderProperties2,
162   public CMyUnknownImp
163 {
164   CByteIn m_InBitStream;
165   Byte *_window;
166   UInt32 _winPos;
167   UInt32 _wrPtr;
168   UInt64 _lzSize;
169   UInt64 _unpackSize;
170   UInt64 _writtenFileSize; // if it's > _unpackSize, then _unpackSize only written
171   ISequentialOutStream *_outStream;
172   NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
173   UInt32 kDistStart[kDistTableSize];
174   NHuffman::CDecoder<kNumHuffmanBits, kDistTableSize> m_DistDecoder;
175   NHuffman::CDecoder<kNumHuffmanBits, kAlignTableSize> m_AlignDecoder;
176   NHuffman::CDecoder<kNumHuffmanBits, kLenTableSize> m_LenDecoder;
177   NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
178 
179   UInt32 _reps[kNumReps];
180   UInt32 _lastLength;
181 
182   Byte m_LastLevels[kTablesSizesSum];
183 
184   Byte *_vmData;
185   Byte *_vmCode;
186   NVm::CVm _vm;
187   CRecordVector<CFilter *> _filters;
188   CRecordVector<CTempFilter *>  _tempFilters;
189   unsigned _numEmptyTempFilters;
190   UInt32 _lastFilter;
191 
192   bool _isSolid;
193   bool _solidAllowed;
194   // bool _errorMode;
195 
196   bool _lzMode;
197   bool _unsupportedFilter;
198 
199   UInt32 PrevAlignBits;
200   UInt32 PrevAlignCount;
201 
202   bool TablesRead;
203   bool TablesOK;
204 
205   CPpmd7 _ppmd;
206   int PpmEscChar;
207   bool PpmError;
208 
209   HRESULT WriteDataToStream(const Byte *data, UInt32 size);
210   HRESULT WriteData(const Byte *data, UInt32 size);
211   HRESULT WriteArea(UInt32 startPtr, UInt32 endPtr);
212   void ExecuteFilter(unsigned tempFilterIndex, NVm::CBlockRef &outBlockRef);
213   HRESULT WriteBuf();
214 
215   void InitFilters();
216   bool AddVmCode(UInt32 firstByte, UInt32 codeSize);
217   bool ReadVmCodeLZ();
218   bool ReadVmCodePPM();
219 
220   UInt32 ReadBits(unsigned numBits);
221 
222   HRESULT InitPPM();
223   // int DecodePpmSymbol();
224   HRESULT DecodePPM(Int32 num, bool &keepDecompressing);
225 
226   HRESULT ReadTables(bool &keepDecompressing);
227   HRESULT ReadEndOfBlock(bool &keepDecompressing);
228   HRESULT DecodeLZ(bool &keepDecompressing);
229   HRESULT CodeReal(ICompressProgressInfo *progress);
230 
InputEofError()231   bool InputEofError() const { return m_InBitStream.BitDecoder.ExtraBitsWereRead(); }
InputEofError_Fast()232   bool InputEofError_Fast() const { return (m_InBitStream.BitDecoder.Stream.NumExtraBytes > 2); }
233 
234 public:
235   CDecoder();
236   ~CDecoder();
237 
238   MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2)
239 
240   STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
241       const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
242 
243   STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
244 
CopyBlock(UInt32 dist,UInt32 len)245   void CopyBlock(UInt32 dist, UInt32 len)
246   {
247     _lzSize += len;
248     UInt32 pos = (_winPos - dist - 1) & kWindowMask;
249     Byte *window = _window;
250     UInt32 winPos = _winPos;
251     if (kWindowSize - winPos > len && kWindowSize - pos > len)
252     {
253       const Byte *src = window + pos;
254       Byte *dest = window + winPos;
255       _winPos += len;
256       do
257         *dest++ = *src++;
258       while (--len != 0);
259       return;
260     }
261     do
262     {
263       window[winPos] = window[pos];
264       winPos = (winPos + 1) & kWindowMask;
265       pos = (pos + 1) & kWindowMask;
266     }
267     while (--len != 0);
268     _winPos = winPos;
269   }
270 
PutByte(Byte b)271   void PutByte(Byte b)
272   {
273     UInt32 wp = _winPos;
274     _window[wp] = b;
275     _winPos = (wp + 1) & kWindowMask;
276     _lzSize++;
277   }
278 };
279 
280 }}
281 
282 #endif
283