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