1 // Rar2Decoder.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 <stdlib.h>
8 
9 #include "Rar2Decoder.h"
10 
11 namespace NCompress {
12 namespace NRar2 {
13 
14 namespace NMultimedia {
15 
Decode(int & channelDelta,Byte deltaByte)16 Byte CFilter::Decode(int &channelDelta, Byte deltaByte)
17 {
18   D4 = D3;
19   D3 = D2;
20   D2 = LastDelta - D1;
21   D1 = LastDelta;
22   int predictedValue = ((8 * LastChar + K1 * D1 + K2 * D2 + K3 * D3 + K4 * D4 + K5 * channelDelta) >> 3);
23 
24   Byte realValue = (Byte)(predictedValue - deltaByte);
25 
26   {
27     int i = ((int)(signed char)deltaByte) << 3;
28 
29     Dif[0] += abs(i);
30     Dif[1] += abs(i - D1);
31     Dif[2] += abs(i + D1);
32     Dif[3] += abs(i - D2);
33     Dif[4] += abs(i + D2);
34     Dif[5] += abs(i - D3);
35     Dif[6] += abs(i + D3);
36     Dif[7] += abs(i - D4);
37     Dif[8] += abs(i + D4);
38     Dif[9] += abs(i - channelDelta);
39     Dif[10] += abs(i + channelDelta);
40   }
41 
42   channelDelta = LastDelta = (signed char)(realValue - LastChar);
43   LastChar = realValue;
44 
45   if (((++ByteCount) & 0x1F) == 0)
46   {
47     UInt32 minDif = Dif[0];
48     UInt32 numMinDif = 0;
49     Dif[0] = 0;
50 
51     for (unsigned i = 1; i < ARRAY_SIZE(Dif); i++)
52     {
53       if (Dif[i] < minDif)
54       {
55         minDif = Dif[i];
56         numMinDif = i;
57       }
58       Dif[i] = 0;
59     }
60 
61     switch (numMinDif)
62     {
63       case 1: if (K1 >= -16) K1--; break;
64       case 2: if (K1 <   16) K1++; break;
65       case 3: if (K2 >= -16) K2--; break;
66       case 4: if (K2 <   16) K2++; break;
67       case 5: if (K3 >= -16) K3--; break;
68       case 6: if (K3 <   16) K3++; break;
69       case 7: if (K4 >= -16) K4--; break;
70       case 8: if (K4 <   16) K4++; break;
71       case 9: if (K5 >= -16) K5--; break;
72       case 10:if (K5 <   16) K5++; break;
73     }
74   }
75 
76   return realValue;
77 }
78 }
79 
80 static const UInt32 kHistorySize = 1 << 20;
81 
82 // static const UInt32 kWindowReservSize = (1 << 22) + 256;
83 
CDecoder()84 CDecoder::CDecoder():
85   _isSolid(false),
86   _solidAllowed(false),
87   m_TablesOK(false)
88 {
89 }
90 
InitStructures()91 void CDecoder::InitStructures()
92 {
93   m_MmFilter.Init();
94   for (unsigned i = 0; i < kNumRepDists; i++)
95     m_RepDists[i] = 0;
96   m_RepDistPtr = 0;
97   m_LastLength = 0;
98   memset(m_LastLevels, 0, kMaxTableSize);
99 }
100 
ReadBits(unsigned numBits)101 UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); }
102 
103 #define RIF(x) { if (!(x)) return false; }
104 
ReadTables(void)105 bool CDecoder::ReadTables(void)
106 {
107   m_TablesOK = false;
108 
109   Byte levelLevels[kLevelTableSize];
110   Byte lens[kMaxTableSize];
111 
112   m_AudioMode = (ReadBits(1) == 1);
113 
114   if (ReadBits(1) == 0)
115     memset(m_LastLevels, 0, kMaxTableSize);
116 
117   unsigned numLevels;
118 
119   if (m_AudioMode)
120   {
121     m_NumChannels = ReadBits(2) + 1;
122     if (m_MmFilter.CurrentChannel >= m_NumChannels)
123       m_MmFilter.CurrentChannel = 0;
124     numLevels = m_NumChannels * kMMTableSize;
125   }
126   else
127     numLevels = kHeapTablesSizesSum;
128 
129   unsigned i;
130   for (i = 0; i < kLevelTableSize; i++)
131     levelLevels[i] = (Byte)ReadBits(4);
132   RIF(m_LevelDecoder.Build(levelLevels));
133 
134   i = 0;
135 
136   do
137   {
138     UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream);
139     if (sym < kTableDirectLevels)
140     {
141       lens[i] = (Byte)((sym + m_LastLevels[i]) & kLevelMask);
142       i++;
143     }
144     else
145     {
146       if (sym == kTableLevelRepNumber)
147       {
148         unsigned num = ReadBits(2) + 3;
149         if (i == 0)
150           return false;
151         num += i;
152         if (num > numLevels)
153         {
154           // return false;
155           num = numLevels; // original unRAR
156         }
157         Byte v = lens[(size_t)i - 1];
158         do
159           lens[i++] = v;
160         while (i < num);
161       }
162       else
163       {
164         unsigned num;
165         if (sym == kTableLevel0Number)
166           num = ReadBits(3) + 3;
167         else if (sym == kTableLevel0Number2)
168           num = ReadBits(7) + 11;
169         else
170           return false;
171         num += i;
172         if (num > numLevels)
173         {
174           // return false;
175           num = numLevels; // original unRAR
176         }
177         do
178           lens[i++] = 0;
179         while (i < num);
180       }
181     }
182   }
183   while (i < numLevels);
184 
185   if (m_InBitStream.ExtraBitsWereRead())
186     return false;
187 
188   if (m_AudioMode)
189     for (i = 0; i < m_NumChannels; i++)
190     {
191       RIF(m_MMDecoders[i].Build(&lens[i * kMMTableSize]));
192     }
193   else
194   {
195     RIF(m_MainDecoder.Build(&lens[0]));
196     RIF(m_DistDecoder.Build(&lens[kMainTableSize]));
197     RIF(m_LenDecoder.Build(&lens[kMainTableSize + kDistTableSize]));
198   }
199 
200   memcpy(m_LastLevels, lens, kMaxTableSize);
201 
202   m_TablesOK = true;
203 
204   return true;
205 }
206 
ReadLastTables()207 bool CDecoder::ReadLastTables()
208 {
209   // it differs a little from pure RAR sources;
210   // UInt64 ttt = m_InBitStream.GetProcessedSize() + 2;
211   // + 2 works for: return 0xFF; in CInBuffer::ReadByte.
212   if (m_InBitStream.GetProcessedSize() + 7 <= m_PackSize) // test it: probably incorrect;
213   // if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect;
214   {
215     if (m_AudioMode)
216     {
217       UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream);
218       if (symbol == 256)
219         return ReadTables();
220       if (symbol >= kMMTableSize)
221         return false;
222     }
223     else
224     {
225       UInt32 sym = m_MainDecoder.Decode(&m_InBitStream);
226       if (sym == kReadTableNumber)
227         return ReadTables();
228       if (sym >= kMainTableSize)
229         return false;
230     }
231   }
232   return true;
233 }
234 
235 
DecodeMm(UInt32 pos)236 bool CDecoder::DecodeMm(UInt32 pos)
237 {
238   while (pos-- != 0)
239   {
240     UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream);
241     if (m_InBitStream.ExtraBitsWereRead())
242       return false;
243     if (symbol >= 256)
244       return symbol == 256;
245     /*
246     Byte byPredict = m_Predictor.Predict();
247     Byte byReal = (Byte)(byPredict - (Byte)symbol);
248     m_Predictor.Update(byReal, byPredict);
249     */
250     Byte byReal = m_MmFilter.Decode((Byte)symbol);
251     m_OutWindowStream.PutByte(byReal);
252     if (++m_MmFilter.CurrentChannel == m_NumChannels)
253       m_MmFilter.CurrentChannel = 0;
254   }
255   return true;
256 }
257 
DecodeLz(Int32 pos)258 bool CDecoder::DecodeLz(Int32 pos)
259 {
260   while (pos > 0)
261   {
262     UInt32 sym = m_MainDecoder.Decode(&m_InBitStream);
263     if (m_InBitStream.ExtraBitsWereRead())
264       return false;
265     UInt32 length, distance;
266     if (sym < 256)
267     {
268       m_OutWindowStream.PutByte(Byte(sym));
269       pos--;
270       continue;
271     }
272     else if (sym >= kMatchNumber)
273     {
274       if (sym >= kMainTableSize)
275         return false;
276       sym -= kMatchNumber;
277       length = kNormalMatchMinLen + UInt32(kLenStart[sym]) +
278         m_InBitStream.ReadBits(kLenDirectBits[sym]);
279       sym = m_DistDecoder.Decode(&m_InBitStream);
280       if (sym >= kDistTableSize)
281         return false;
282       distance = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]);
283       if (distance >= kDistLimit3)
284       {
285         length += 2 - ((distance - kDistLimit4) >> 31);
286         // length++;
287         // if (distance >= kDistLimit4)
288         //  length++;
289       }
290     }
291     else if (sym == kRepBothNumber)
292     {
293       length = m_LastLength;
294       if (length == 0)
295         return false;
296       distance = m_RepDists[(m_RepDistPtr + 4 - 1) & 3];
297     }
298     else if (sym < kLen2Number)
299     {
300       distance = m_RepDists[(m_RepDistPtr - (sym - kRepNumber + 1)) & 3];
301       sym = m_LenDecoder.Decode(&m_InBitStream);
302       if (sym >= kLenTableSize)
303         return false;
304       length = 2 + kLenStart[sym] + m_InBitStream.ReadBits(kLenDirectBits[sym]);
305       if (distance >= kDistLimit2)
306       {
307         length++;
308         if (distance >= kDistLimit3)
309         {
310           length += 2 - ((distance - kDistLimit4) >> 31);
311           // length++;
312           // if (distance >= kDistLimit4)
313           //   length++;
314         }
315       }
316     }
317     else if (sym < kReadTableNumber)
318     {
319       sym -= kLen2Number;
320       distance = kLen2DistStarts[sym] +
321         m_InBitStream.ReadBits(kLen2DistDirectBits[sym]);
322       length = 2;
323     }
324     else // (sym == kReadTableNumber)
325       return true;
326 
327     m_RepDists[m_RepDistPtr++ & 3] = distance;
328     m_LastLength = length;
329     if (!m_OutWindowStream.CopyBlock(distance, length))
330       return false;
331     pos -= length;
332   }
333   return true;
334 }
335 
CodeReal(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress)336 HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
337     const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
338 {
339   if (!inSize || !outSize)
340     return E_INVALIDARG;
341 
342   if (_isSolid && !_solidAllowed)
343     return S_FALSE;
344   _solidAllowed = false;
345 
346   if (!m_OutWindowStream.Create(kHistorySize))
347     return E_OUTOFMEMORY;
348   if (!m_InBitStream.Create(1 << 20))
349     return E_OUTOFMEMORY;
350 
351   m_PackSize = *inSize;
352 
353   UInt64 pos = 0, unPackSize = *outSize;
354 
355   m_OutWindowStream.SetStream(outStream);
356   m_OutWindowStream.Init(_isSolid);
357   m_InBitStream.SetStream(inStream);
358   m_InBitStream.Init();
359 
360   // CCoderReleaser coderReleaser(this);
361   if (!_isSolid)
362   {
363     InitStructures();
364     if (unPackSize == 0)
365     {
366       if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect;
367         if (!ReadTables())
368           return S_FALSE;
369       _solidAllowed = true;
370       return S_OK;
371     }
372     ReadTables();
373   }
374 
375   if (!m_TablesOK)
376     return S_FALSE;
377 
378   UInt64 startPos = m_OutWindowStream.GetProcessedSize();
379   while (pos < unPackSize)
380   {
381     UInt32 blockSize = 1 << 20;
382     if (blockSize > unPackSize - pos)
383       blockSize = (UInt32)(unPackSize - pos);
384     UInt64 blockStartPos = m_OutWindowStream.GetProcessedSize();
385     if (m_AudioMode)
386     {
387       if (!DecodeMm(blockSize))
388         return S_FALSE;
389     }
390     else
391     {
392       if (!DecodeLz((Int32)blockSize))
393         return S_FALSE;
394     }
395 
396     if (m_InBitStream.ExtraBitsWereRead())
397       return S_FALSE;
398 
399     UInt64 globalPos = m_OutWindowStream.GetProcessedSize();
400     pos = globalPos - blockStartPos;
401     if (pos < blockSize)
402       if (!ReadTables())
403         return S_FALSE;
404     pos = globalPos - startPos;
405     if (progress)
406     {
407       const UInt64 packSize = m_InBitStream.GetProcessedSize();
408       RINOK(progress->SetRatioInfo(&packSize, &pos));
409     }
410   }
411   if (pos > unPackSize)
412     return S_FALSE;
413 
414   if (!ReadLastTables())
415     return S_FALSE;
416 
417   _solidAllowed = true;
418 
419   return m_OutWindowStream.Flush();
420 }
421 
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress)422 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
423     const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
424 {
425   try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
426   catch(const CInBufferException &e) { return e.ErrorCode; }
427   catch(const CLzOutWindowException &e) { return e.ErrorCode; }
428   catch(...) { return S_FALSE; }
429 }
430 
SetDecoderProperties2(const Byte * data,UInt32 size)431 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
432 {
433   if (size < 1)
434     return E_INVALIDARG;
435   _isSolid = ((data[0] & 1) != 0);
436   return S_OK;
437 }
438 
439 }}
440