xref: /aosp_15_r20/external/lzma/CPP/7zip/Compress/Rar1Decoder.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // Rar1Decoder.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 "Rar1Decoder.h"
8*f6dc9357SAndroid Build Coastguard Worker 
9*f6dc9357SAndroid Build Coastguard Worker namespace NCompress {
10*f6dc9357SAndroid Build Coastguard Worker namespace NRar1 {
11*f6dc9357SAndroid Build Coastguard Worker 
12*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumBits = 12;
13*f6dc9357SAndroid Build Coastguard Worker 
14*f6dc9357SAndroid Build Coastguard Worker static const Byte kShortLen1[16 * 3] =
15*f6dc9357SAndroid Build Coastguard Worker {
16*f6dc9357SAndroid Build Coastguard Worker   0,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff,0xc0,0x80,0x90,0x98,0x9c,0xb0,0,
17*f6dc9357SAndroid Build Coastguard Worker   1,3,4,4,5,6,7,8,8,4,4,5,6,6,0,0,
18*f6dc9357SAndroid Build Coastguard Worker   1,4,4,4,5,6,7,8,8,4,4,5,6,6,4,0
19*f6dc9357SAndroid Build Coastguard Worker };
20*f6dc9357SAndroid Build Coastguard Worker 
21*f6dc9357SAndroid Build Coastguard Worker static const Byte kShortLen2[16 * 3] =
22*f6dc9357SAndroid Build Coastguard Worker {
23*f6dc9357SAndroid Build Coastguard Worker   0,0x40,0x60,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xc0,0x80,0x90,0x98,0x9c,0xb0,0,
24*f6dc9357SAndroid Build Coastguard Worker   2,3,3,3,4,4,5,6,6,4,4,5,6,6,0,0,
25*f6dc9357SAndroid Build Coastguard Worker   2,3,3,4,4,4,5,6,6,4,4,5,6,6,4,0
26*f6dc9357SAndroid Build Coastguard Worker };
27*f6dc9357SAndroid Build Coastguard Worker 
28*f6dc9357SAndroid Build Coastguard Worker static const Byte PosL1[kNumBits + 1]  = { 0,0,2,1,2,2,4,5,4,4,8,0,224 };
29*f6dc9357SAndroid Build Coastguard Worker static const Byte PosL2[kNumBits + 1]  = { 0,0,0,5,2,2,4,5,4,4,8,2,220 };
30*f6dc9357SAndroid Build Coastguard Worker 
31*f6dc9357SAndroid Build Coastguard Worker static const Byte PosHf0[kNumBits + 1] = { 0,0,0,0,8,8,8,9,0,0,0,0,224 };
32*f6dc9357SAndroid Build Coastguard Worker static const Byte PosHf1[kNumBits + 1] = { 0,0,0,0,0,4,40,16,16,4,0,47,130 };
33*f6dc9357SAndroid Build Coastguard Worker static const Byte PosHf2[kNumBits + 1] = { 0,0,0,0,0,2,5,46,64,116,24,0,0 };
34*f6dc9357SAndroid Build Coastguard Worker static const Byte PosHf3[kNumBits + 1] = { 0,0,0,0,0,0,2,14,202,33,6,0,0 };
35*f6dc9357SAndroid Build Coastguard Worker static const Byte PosHf4[kNumBits + 1] = { 0,0,0,0,0,0,0,0,255,2,0,0,0 };
36*f6dc9357SAndroid Build Coastguard Worker 
37*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kHistorySize = (1 << 16);
38*f6dc9357SAndroid Build Coastguard Worker 
CDecoder()39*f6dc9357SAndroid Build Coastguard Worker CDecoder::CDecoder():
40*f6dc9357SAndroid Build Coastguard Worker    _isSolid(false),
41*f6dc9357SAndroid Build Coastguard Worker    _solidAllowed(false)
42*f6dc9357SAndroid Build Coastguard Worker    {}
43*f6dc9357SAndroid Build Coastguard Worker 
ReadBits(unsigned numBits)44*f6dc9357SAndroid Build Coastguard Worker UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); }
45*f6dc9357SAndroid Build Coastguard Worker 
CopyBlock(UInt32 distance,UInt32 len)46*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::CopyBlock(UInt32 distance, UInt32 len)
47*f6dc9357SAndroid Build Coastguard Worker {
48*f6dc9357SAndroid Build Coastguard Worker   if (len == 0)
49*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
50*f6dc9357SAndroid Build Coastguard Worker   if (m_UnpackSize < len)
51*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
52*f6dc9357SAndroid Build Coastguard Worker   m_UnpackSize -= len;
53*f6dc9357SAndroid Build Coastguard Worker   return m_OutWindowStream.CopyBlock(distance, len) ? S_OK : S_FALSE;
54*f6dc9357SAndroid Build Coastguard Worker }
55*f6dc9357SAndroid Build Coastguard Worker 
56*f6dc9357SAndroid Build Coastguard Worker 
DecodeNum(const Byte * numTab)57*f6dc9357SAndroid Build Coastguard Worker UInt32 CDecoder::DecodeNum(const Byte *numTab)
58*f6dc9357SAndroid Build Coastguard Worker {
59*f6dc9357SAndroid Build Coastguard Worker   /*
60*f6dc9357SAndroid Build Coastguard Worker   {
61*f6dc9357SAndroid Build Coastguard Worker     // we can check that tables are correct
62*f6dc9357SAndroid Build Coastguard Worker     UInt32 sum = 0;
63*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 0; i <= kNumBits; i++)
64*f6dc9357SAndroid Build Coastguard Worker       sum += ((UInt32)numTab[i] << (kNumBits - i));
65*f6dc9357SAndroid Build Coastguard Worker     if (sum != (1 << kNumBits))
66*f6dc9357SAndroid Build Coastguard Worker       throw 111;
67*f6dc9357SAndroid Build Coastguard Worker   }
68*f6dc9357SAndroid Build Coastguard Worker   */
69*f6dc9357SAndroid Build Coastguard Worker 
70*f6dc9357SAndroid Build Coastguard Worker   UInt32 val = m_InBitStream.GetValue(kNumBits);
71*f6dc9357SAndroid Build Coastguard Worker   UInt32 sum = 0;
72*f6dc9357SAndroid Build Coastguard Worker   unsigned i = 2;
73*f6dc9357SAndroid Build Coastguard Worker 
74*f6dc9357SAndroid Build Coastguard Worker   for (;;)
75*f6dc9357SAndroid Build Coastguard Worker   {
76*f6dc9357SAndroid Build Coastguard Worker     const UInt32 num = numTab[i];
77*f6dc9357SAndroid Build Coastguard Worker     const UInt32 cur = num << (kNumBits - i);
78*f6dc9357SAndroid Build Coastguard Worker     if (val < cur)
79*f6dc9357SAndroid Build Coastguard Worker       break;
80*f6dc9357SAndroid Build Coastguard Worker     i++;
81*f6dc9357SAndroid Build Coastguard Worker     val -= cur;
82*f6dc9357SAndroid Build Coastguard Worker     sum += num;
83*f6dc9357SAndroid Build Coastguard Worker   }
84*f6dc9357SAndroid Build Coastguard Worker   m_InBitStream.MovePos(i);
85*f6dc9357SAndroid Build Coastguard Worker   return ((val >> (kNumBits - i)) + sum);
86*f6dc9357SAndroid Build Coastguard Worker }
87*f6dc9357SAndroid Build Coastguard Worker 
88*f6dc9357SAndroid Build Coastguard Worker 
ShortLZ()89*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::ShortLZ()
90*f6dc9357SAndroid Build Coastguard Worker {
91*f6dc9357SAndroid Build Coastguard Worker   NumHuf = 0;
92*f6dc9357SAndroid Build Coastguard Worker 
93*f6dc9357SAndroid Build Coastguard Worker   if (LCount == 2)
94*f6dc9357SAndroid Build Coastguard Worker   {
95*f6dc9357SAndroid Build Coastguard Worker     if (ReadBits(1))
96*f6dc9357SAndroid Build Coastguard Worker       return CopyBlock(LastDist, LastLength);
97*f6dc9357SAndroid Build Coastguard Worker     LCount = 0;
98*f6dc9357SAndroid Build Coastguard Worker   }
99*f6dc9357SAndroid Build Coastguard Worker 
100*f6dc9357SAndroid Build Coastguard Worker   UInt32 bitField = m_InBitStream.GetValue(8);
101*f6dc9357SAndroid Build Coastguard Worker 
102*f6dc9357SAndroid Build Coastguard Worker   UInt32 len, dist;
103*f6dc9357SAndroid Build Coastguard Worker   {
104*f6dc9357SAndroid Build Coastguard Worker     const Byte *xors = (AvrLn1 < 37) ? kShortLen1 : kShortLen2;
105*f6dc9357SAndroid Build Coastguard Worker     const Byte *lens = xors + 16 + Buf60;
106*f6dc9357SAndroid Build Coastguard Worker     for (len = 0; ((bitField ^ xors[len]) >> (8 - lens[len])) != 0; len++);
107*f6dc9357SAndroid Build Coastguard Worker     m_InBitStream.MovePos(lens[len]);
108*f6dc9357SAndroid Build Coastguard Worker   }
109*f6dc9357SAndroid Build Coastguard Worker 
110*f6dc9357SAndroid Build Coastguard Worker   if (len >= 9)
111*f6dc9357SAndroid Build Coastguard Worker   {
112*f6dc9357SAndroid Build Coastguard Worker     if (len == 9)
113*f6dc9357SAndroid Build Coastguard Worker     {
114*f6dc9357SAndroid Build Coastguard Worker       LCount++;
115*f6dc9357SAndroid Build Coastguard Worker       return CopyBlock(LastDist, LastLength);
116*f6dc9357SAndroid Build Coastguard Worker     }
117*f6dc9357SAndroid Build Coastguard Worker 
118*f6dc9357SAndroid Build Coastguard Worker     LCount = 0;
119*f6dc9357SAndroid Build Coastguard Worker 
120*f6dc9357SAndroid Build Coastguard Worker     if (len == 14)
121*f6dc9357SAndroid Build Coastguard Worker     {
122*f6dc9357SAndroid Build Coastguard Worker       len = DecodeNum(PosL2) + 5;
123*f6dc9357SAndroid Build Coastguard Worker       dist = 0x8000 + ReadBits(15) - 1;
124*f6dc9357SAndroid Build Coastguard Worker       LastLength = len;
125*f6dc9357SAndroid Build Coastguard Worker       LastDist = dist;
126*f6dc9357SAndroid Build Coastguard Worker       return CopyBlock(dist, len);
127*f6dc9357SAndroid Build Coastguard Worker     }
128*f6dc9357SAndroid Build Coastguard Worker 
129*f6dc9357SAndroid Build Coastguard Worker     const UInt32 saveLen = len;
130*f6dc9357SAndroid Build Coastguard Worker     dist = m_RepDists[(m_RepDistPtr - (len - 9)) & 3];
131*f6dc9357SAndroid Build Coastguard Worker 
132*f6dc9357SAndroid Build Coastguard Worker     len = DecodeNum(PosL1);
133*f6dc9357SAndroid Build Coastguard Worker 
134*f6dc9357SAndroid Build Coastguard Worker     if (len == 0xff && saveLen == 10)
135*f6dc9357SAndroid Build Coastguard Worker     {
136*f6dc9357SAndroid Build Coastguard Worker       Buf60 ^= 16;
137*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
138*f6dc9357SAndroid Build Coastguard Worker     }
139*f6dc9357SAndroid Build Coastguard Worker     if (dist >= 256)
140*f6dc9357SAndroid Build Coastguard Worker     {
141*f6dc9357SAndroid Build Coastguard Worker       len++;
142*f6dc9357SAndroid Build Coastguard Worker       if (dist >= MaxDist3 - 1)
143*f6dc9357SAndroid Build Coastguard Worker         len++;
144*f6dc9357SAndroid Build Coastguard Worker     }
145*f6dc9357SAndroid Build Coastguard Worker   }
146*f6dc9357SAndroid Build Coastguard Worker   else
147*f6dc9357SAndroid Build Coastguard Worker   {
148*f6dc9357SAndroid Build Coastguard Worker     LCount = 0;
149*f6dc9357SAndroid Build Coastguard Worker     AvrLn1 += len;
150*f6dc9357SAndroid Build Coastguard Worker     AvrLn1 -= AvrLn1 >> 4;
151*f6dc9357SAndroid Build Coastguard Worker 
152*f6dc9357SAndroid Build Coastguard Worker     unsigned distancePlace = DecodeNum(PosHf2) & 0xff;
153*f6dc9357SAndroid Build Coastguard Worker 
154*f6dc9357SAndroid Build Coastguard Worker     dist = ChSetA[distancePlace];
155*f6dc9357SAndroid Build Coastguard Worker 
156*f6dc9357SAndroid Build Coastguard Worker     if (distancePlace != 0)
157*f6dc9357SAndroid Build Coastguard Worker     {
158*f6dc9357SAndroid Build Coastguard Worker       PlaceA[dist]--;
159*f6dc9357SAndroid Build Coastguard Worker       UInt32 lastDistance = ChSetA[(size_t)distancePlace - 1];
160*f6dc9357SAndroid Build Coastguard Worker       PlaceA[lastDistance]++;
161*f6dc9357SAndroid Build Coastguard Worker       ChSetA[distancePlace] = lastDistance;
162*f6dc9357SAndroid Build Coastguard Worker       ChSetA[(size_t)distancePlace - 1] = dist;
163*f6dc9357SAndroid Build Coastguard Worker     }
164*f6dc9357SAndroid Build Coastguard Worker   }
165*f6dc9357SAndroid Build Coastguard Worker 
166*f6dc9357SAndroid Build Coastguard Worker   m_RepDists[m_RepDistPtr++] = dist;
167*f6dc9357SAndroid Build Coastguard Worker   m_RepDistPtr &= 3;
168*f6dc9357SAndroid Build Coastguard Worker   len += 2;
169*f6dc9357SAndroid Build Coastguard Worker   LastLength = len;
170*f6dc9357SAndroid Build Coastguard Worker   LastDist = dist;
171*f6dc9357SAndroid Build Coastguard Worker   return CopyBlock(dist, len);
172*f6dc9357SAndroid Build Coastguard Worker }
173*f6dc9357SAndroid Build Coastguard Worker 
174*f6dc9357SAndroid Build Coastguard Worker 
LongLZ()175*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::LongLZ()
176*f6dc9357SAndroid Build Coastguard Worker {
177*f6dc9357SAndroid Build Coastguard Worker   UInt32 len;
178*f6dc9357SAndroid Build Coastguard Worker   UInt32 dist;
179*f6dc9357SAndroid Build Coastguard Worker   UInt32 distancePlace, newDistancePlace;
180*f6dc9357SAndroid Build Coastguard Worker   UInt32 oldAvr2, oldAvr3;
181*f6dc9357SAndroid Build Coastguard Worker 
182*f6dc9357SAndroid Build Coastguard Worker   NumHuf = 0;
183*f6dc9357SAndroid Build Coastguard Worker   Nlzb += 16;
184*f6dc9357SAndroid Build Coastguard Worker   if (Nlzb > 0xff)
185*f6dc9357SAndroid Build Coastguard Worker   {
186*f6dc9357SAndroid Build Coastguard Worker     Nlzb = 0x90;
187*f6dc9357SAndroid Build Coastguard Worker     Nhfb >>= 1;
188*f6dc9357SAndroid Build Coastguard Worker   }
189*f6dc9357SAndroid Build Coastguard Worker   oldAvr2 = AvrLn2;
190*f6dc9357SAndroid Build Coastguard Worker 
191*f6dc9357SAndroid Build Coastguard Worker   if (AvrLn2 >= 64)
192*f6dc9357SAndroid Build Coastguard Worker     len = DecodeNum(AvrLn2 < 122 ? PosL1 : PosL2);
193*f6dc9357SAndroid Build Coastguard Worker   else
194*f6dc9357SAndroid Build Coastguard Worker   {
195*f6dc9357SAndroid Build Coastguard Worker     UInt32 bitField = m_InBitStream.GetValue(16);
196*f6dc9357SAndroid Build Coastguard Worker     if (bitField < 0x100)
197*f6dc9357SAndroid Build Coastguard Worker     {
198*f6dc9357SAndroid Build Coastguard Worker       len = bitField;
199*f6dc9357SAndroid Build Coastguard Worker       m_InBitStream.MovePos(16);
200*f6dc9357SAndroid Build Coastguard Worker     }
201*f6dc9357SAndroid Build Coastguard Worker     else
202*f6dc9357SAndroid Build Coastguard Worker     {
203*f6dc9357SAndroid Build Coastguard Worker       for (len = 0; ((bitField << len) & 0x8000) == 0; len++);
204*f6dc9357SAndroid Build Coastguard Worker 
205*f6dc9357SAndroid Build Coastguard Worker       m_InBitStream.MovePos(len + 1);
206*f6dc9357SAndroid Build Coastguard Worker     }
207*f6dc9357SAndroid Build Coastguard Worker   }
208*f6dc9357SAndroid Build Coastguard Worker 
209*f6dc9357SAndroid Build Coastguard Worker   AvrLn2 += len;
210*f6dc9357SAndroid Build Coastguard Worker   AvrLn2 -= AvrLn2 >> 5;
211*f6dc9357SAndroid Build Coastguard Worker 
212*f6dc9357SAndroid Build Coastguard Worker   {
213*f6dc9357SAndroid Build Coastguard Worker     const Byte *tab;
214*f6dc9357SAndroid Build Coastguard Worker          if (AvrPlcB >= 0x2900) tab = PosHf2;
215*f6dc9357SAndroid Build Coastguard Worker     else if (AvrPlcB >= 0x0700) tab = PosHf1;
216*f6dc9357SAndroid Build Coastguard Worker     else                        tab = PosHf0;
217*f6dc9357SAndroid Build Coastguard Worker     distancePlace = DecodeNum(tab); // [0, 256]
218*f6dc9357SAndroid Build Coastguard Worker   }
219*f6dc9357SAndroid Build Coastguard Worker 
220*f6dc9357SAndroid Build Coastguard Worker   AvrPlcB += distancePlace;
221*f6dc9357SAndroid Build Coastguard Worker   AvrPlcB -= AvrPlcB >> 8;
222*f6dc9357SAndroid Build Coastguard Worker 
223*f6dc9357SAndroid Build Coastguard Worker   distancePlace &= 0xff;
224*f6dc9357SAndroid Build Coastguard Worker 
225*f6dc9357SAndroid Build Coastguard Worker   for (;;)
226*f6dc9357SAndroid Build Coastguard Worker   {
227*f6dc9357SAndroid Build Coastguard Worker     dist = ChSetB[distancePlace];
228*f6dc9357SAndroid Build Coastguard Worker     newDistancePlace = NToPlB[dist++ & 0xff]++;
229*f6dc9357SAndroid Build Coastguard Worker     if (dist & 0xff)
230*f6dc9357SAndroid Build Coastguard Worker       break;
231*f6dc9357SAndroid Build Coastguard Worker     CorrHuff(ChSetB,NToPlB);
232*f6dc9357SAndroid Build Coastguard Worker   }
233*f6dc9357SAndroid Build Coastguard Worker 
234*f6dc9357SAndroid Build Coastguard Worker   ChSetB[distancePlace] = ChSetB[newDistancePlace];
235*f6dc9357SAndroid Build Coastguard Worker   ChSetB[newDistancePlace] = dist;
236*f6dc9357SAndroid Build Coastguard Worker 
237*f6dc9357SAndroid Build Coastguard Worker   dist = ((dist & 0xff00) >> 1) | ReadBits(7);
238*f6dc9357SAndroid Build Coastguard Worker 
239*f6dc9357SAndroid Build Coastguard Worker   oldAvr3 = AvrLn3;
240*f6dc9357SAndroid Build Coastguard Worker 
241*f6dc9357SAndroid Build Coastguard Worker   if (len != 1 && len != 4)
242*f6dc9357SAndroid Build Coastguard Worker   {
243*f6dc9357SAndroid Build Coastguard Worker     if (len == 0 && dist <= MaxDist3)
244*f6dc9357SAndroid Build Coastguard Worker     {
245*f6dc9357SAndroid Build Coastguard Worker       AvrLn3++;
246*f6dc9357SAndroid Build Coastguard Worker       AvrLn3 -= AvrLn3 >> 8;
247*f6dc9357SAndroid Build Coastguard Worker     }
248*f6dc9357SAndroid Build Coastguard Worker     else if (AvrLn3 > 0)
249*f6dc9357SAndroid Build Coastguard Worker       AvrLn3--;
250*f6dc9357SAndroid Build Coastguard Worker   }
251*f6dc9357SAndroid Build Coastguard Worker 
252*f6dc9357SAndroid Build Coastguard Worker   len += 3;
253*f6dc9357SAndroid Build Coastguard Worker 
254*f6dc9357SAndroid Build Coastguard Worker   if (dist >= MaxDist3)
255*f6dc9357SAndroid Build Coastguard Worker     len++;
256*f6dc9357SAndroid Build Coastguard Worker   if (dist <= 256)
257*f6dc9357SAndroid Build Coastguard Worker     len += 8;
258*f6dc9357SAndroid Build Coastguard Worker 
259*f6dc9357SAndroid Build Coastguard Worker   if (oldAvr3 > 0xb0 || (AvrPlc >= 0x2a00 && oldAvr2 < 0x40))
260*f6dc9357SAndroid Build Coastguard Worker     MaxDist3 = 0x7f00;
261*f6dc9357SAndroid Build Coastguard Worker   else
262*f6dc9357SAndroid Build Coastguard Worker     MaxDist3 = 0x2001;
263*f6dc9357SAndroid Build Coastguard Worker 
264*f6dc9357SAndroid Build Coastguard Worker   m_RepDists[m_RepDistPtr++] = --dist;
265*f6dc9357SAndroid Build Coastguard Worker   m_RepDistPtr &= 3;
266*f6dc9357SAndroid Build Coastguard Worker   LastLength = len;
267*f6dc9357SAndroid Build Coastguard Worker   LastDist = dist;
268*f6dc9357SAndroid Build Coastguard Worker 
269*f6dc9357SAndroid Build Coastguard Worker   return CopyBlock(dist, len);
270*f6dc9357SAndroid Build Coastguard Worker }
271*f6dc9357SAndroid Build Coastguard Worker 
272*f6dc9357SAndroid Build Coastguard Worker 
HuffDecode()273*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::HuffDecode()
274*f6dc9357SAndroid Build Coastguard Worker {
275*f6dc9357SAndroid Build Coastguard Worker   UInt32 curByte, newBytePlace;
276*f6dc9357SAndroid Build Coastguard Worker   UInt32 len;
277*f6dc9357SAndroid Build Coastguard Worker   UInt32 dist;
278*f6dc9357SAndroid Build Coastguard Worker   unsigned bytePlace;
279*f6dc9357SAndroid Build Coastguard Worker   {
280*f6dc9357SAndroid Build Coastguard Worker     const Byte *tab;
281*f6dc9357SAndroid Build Coastguard Worker 
282*f6dc9357SAndroid Build Coastguard Worker     if      (AvrPlc >= 0x7600)  tab = PosHf4;
283*f6dc9357SAndroid Build Coastguard Worker     else if (AvrPlc >= 0x5e00)  tab = PosHf3;
284*f6dc9357SAndroid Build Coastguard Worker     else if (AvrPlc >= 0x3600)  tab = PosHf2;
285*f6dc9357SAndroid Build Coastguard Worker     else if (AvrPlc >= 0x0e00)  tab = PosHf1;
286*f6dc9357SAndroid Build Coastguard Worker     else                        tab = PosHf0;
287*f6dc9357SAndroid Build Coastguard Worker 
288*f6dc9357SAndroid Build Coastguard Worker     bytePlace = DecodeNum(tab); // [0, 256]
289*f6dc9357SAndroid Build Coastguard Worker   }
290*f6dc9357SAndroid Build Coastguard Worker 
291*f6dc9357SAndroid Build Coastguard Worker   if (StMode)
292*f6dc9357SAndroid Build Coastguard Worker   {
293*f6dc9357SAndroid Build Coastguard Worker     if (bytePlace == 0)
294*f6dc9357SAndroid Build Coastguard Worker     {
295*f6dc9357SAndroid Build Coastguard Worker       if (ReadBits(1))
296*f6dc9357SAndroid Build Coastguard Worker       {
297*f6dc9357SAndroid Build Coastguard Worker         NumHuf = 0;
298*f6dc9357SAndroid Build Coastguard Worker         StMode = false;
299*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
300*f6dc9357SAndroid Build Coastguard Worker       }
301*f6dc9357SAndroid Build Coastguard Worker       len = ReadBits(1) + 3;
302*f6dc9357SAndroid Build Coastguard Worker       dist = DecodeNum(PosHf2);
303*f6dc9357SAndroid Build Coastguard Worker       dist = (dist << 5) | ReadBits(5);
304*f6dc9357SAndroid Build Coastguard Worker       if (dist == 0)
305*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
306*f6dc9357SAndroid Build Coastguard Worker       return CopyBlock(dist - 1, len);
307*f6dc9357SAndroid Build Coastguard Worker     }
308*f6dc9357SAndroid Build Coastguard Worker     bytePlace--; // bytePlace is [0, 255]
309*f6dc9357SAndroid Build Coastguard Worker   }
310*f6dc9357SAndroid Build Coastguard Worker   else if (NumHuf++ >= 16 && FlagsCnt == 0)
311*f6dc9357SAndroid Build Coastguard Worker     StMode = true;
312*f6dc9357SAndroid Build Coastguard Worker 
313*f6dc9357SAndroid Build Coastguard Worker   bytePlace &= 0xff;
314*f6dc9357SAndroid Build Coastguard Worker   AvrPlc += bytePlace;
315*f6dc9357SAndroid Build Coastguard Worker   AvrPlc -= AvrPlc >> 8;
316*f6dc9357SAndroid Build Coastguard Worker   Nhfb += 16;
317*f6dc9357SAndroid Build Coastguard Worker 
318*f6dc9357SAndroid Build Coastguard Worker   if (Nhfb > 0xff)
319*f6dc9357SAndroid Build Coastguard Worker   {
320*f6dc9357SAndroid Build Coastguard Worker     Nhfb = 0x90;
321*f6dc9357SAndroid Build Coastguard Worker     Nlzb >>= 1;
322*f6dc9357SAndroid Build Coastguard Worker   }
323*f6dc9357SAndroid Build Coastguard Worker 
324*f6dc9357SAndroid Build Coastguard Worker   m_UnpackSize--;
325*f6dc9357SAndroid Build Coastguard Worker   m_OutWindowStream.PutByte((Byte)(ChSet[bytePlace] >> 8));
326*f6dc9357SAndroid Build Coastguard Worker 
327*f6dc9357SAndroid Build Coastguard Worker   for (;;)
328*f6dc9357SAndroid Build Coastguard Worker   {
329*f6dc9357SAndroid Build Coastguard Worker     curByte = ChSet[bytePlace];
330*f6dc9357SAndroid Build Coastguard Worker     newBytePlace = NToPl[curByte++ & 0xff]++;
331*f6dc9357SAndroid Build Coastguard Worker     if ((curByte & 0xff) <= 0xa1)
332*f6dc9357SAndroid Build Coastguard Worker       break;
333*f6dc9357SAndroid Build Coastguard Worker     CorrHuff(ChSet, NToPl);
334*f6dc9357SAndroid Build Coastguard Worker   }
335*f6dc9357SAndroid Build Coastguard Worker 
336*f6dc9357SAndroid Build Coastguard Worker   ChSet[bytePlace] = ChSet[newBytePlace];
337*f6dc9357SAndroid Build Coastguard Worker   ChSet[newBytePlace] = curByte;
338*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
339*f6dc9357SAndroid Build Coastguard Worker }
340*f6dc9357SAndroid Build Coastguard Worker 
341*f6dc9357SAndroid Build Coastguard Worker 
GetFlagsBuf()342*f6dc9357SAndroid Build Coastguard Worker void CDecoder::GetFlagsBuf()
343*f6dc9357SAndroid Build Coastguard Worker {
344*f6dc9357SAndroid Build Coastguard Worker   UInt32 flags, newFlagsPlace;
345*f6dc9357SAndroid Build Coastguard Worker   const UInt32 flagsPlace = DecodeNum(PosHf2); // [0, 256]
346*f6dc9357SAndroid Build Coastguard Worker 
347*f6dc9357SAndroid Build Coastguard Worker   if (flagsPlace >= Z7_ARRAY_SIZE(ChSetC))
348*f6dc9357SAndroid Build Coastguard Worker     return;
349*f6dc9357SAndroid Build Coastguard Worker 
350*f6dc9357SAndroid Build Coastguard Worker   for (;;)
351*f6dc9357SAndroid Build Coastguard Worker   {
352*f6dc9357SAndroid Build Coastguard Worker     flags = ChSetC[flagsPlace];
353*f6dc9357SAndroid Build Coastguard Worker     FlagBuf = flags >> 8;
354*f6dc9357SAndroid Build Coastguard Worker     newFlagsPlace = NToPlC[flags++ & 0xff]++;
355*f6dc9357SAndroid Build Coastguard Worker     if ((flags & 0xff) != 0)
356*f6dc9357SAndroid Build Coastguard Worker       break;
357*f6dc9357SAndroid Build Coastguard Worker     CorrHuff(ChSetC, NToPlC);
358*f6dc9357SAndroid Build Coastguard Worker   }
359*f6dc9357SAndroid Build Coastguard Worker 
360*f6dc9357SAndroid Build Coastguard Worker   ChSetC[flagsPlace] = ChSetC[newFlagsPlace];
361*f6dc9357SAndroid Build Coastguard Worker   ChSetC[newFlagsPlace] = flags;
362*f6dc9357SAndroid Build Coastguard Worker }
363*f6dc9357SAndroid Build Coastguard Worker 
364*f6dc9357SAndroid Build Coastguard Worker 
CorrHuff(UInt32 * CharSet,UInt32 * NumToPlace)365*f6dc9357SAndroid Build Coastguard Worker void CDecoder::CorrHuff(UInt32 *CharSet, UInt32 *NumToPlace)
366*f6dc9357SAndroid Build Coastguard Worker {
367*f6dc9357SAndroid Build Coastguard Worker   int i;
368*f6dc9357SAndroid Build Coastguard Worker   for (i = 7; i >= 0; i--)
369*f6dc9357SAndroid Build Coastguard Worker     for (unsigned j = 0; j < 32; j++, CharSet++)
370*f6dc9357SAndroid Build Coastguard Worker       *CharSet = (*CharSet & ~(UInt32)0xff) | (unsigned)i;
371*f6dc9357SAndroid Build Coastguard Worker   memset(NumToPlace, 0, sizeof(NToPl));
372*f6dc9357SAndroid Build Coastguard Worker   for (i = 6; i >= 0; i--)
373*f6dc9357SAndroid Build Coastguard Worker     NumToPlace[i] = (7 - (unsigned)i) * 32;
374*f6dc9357SAndroid Build Coastguard Worker }
375*f6dc9357SAndroid Build Coastguard Worker 
376*f6dc9357SAndroid Build Coastguard Worker 
377*f6dc9357SAndroid Build Coastguard Worker 
CodeReal(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo *)378*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
379*f6dc9357SAndroid Build Coastguard Worker     const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo * /* progress */)
380*f6dc9357SAndroid Build Coastguard Worker {
381*f6dc9357SAndroid Build Coastguard Worker   if (!inSize || !outSize)
382*f6dc9357SAndroid Build Coastguard Worker     return E_INVALIDARG;
383*f6dc9357SAndroid Build Coastguard Worker 
384*f6dc9357SAndroid Build Coastguard Worker   if (_isSolid && !_solidAllowed)
385*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
386*f6dc9357SAndroid Build Coastguard Worker 
387*f6dc9357SAndroid Build Coastguard Worker   _solidAllowed = false;
388*f6dc9357SAndroid Build Coastguard Worker 
389*f6dc9357SAndroid Build Coastguard Worker   if (!m_OutWindowStream.Create(kHistorySize))
390*f6dc9357SAndroid Build Coastguard Worker     return E_OUTOFMEMORY;
391*f6dc9357SAndroid Build Coastguard Worker   if (!m_InBitStream.Create(1 << 20))
392*f6dc9357SAndroid Build Coastguard Worker     return E_OUTOFMEMORY;
393*f6dc9357SAndroid Build Coastguard Worker 
394*f6dc9357SAndroid Build Coastguard Worker   m_UnpackSize = *outSize;
395*f6dc9357SAndroid Build Coastguard Worker 
396*f6dc9357SAndroid Build Coastguard Worker   m_OutWindowStream.SetStream(outStream);
397*f6dc9357SAndroid Build Coastguard Worker   m_OutWindowStream.Init(_isSolid);
398*f6dc9357SAndroid Build Coastguard Worker   m_InBitStream.SetStream(inStream);
399*f6dc9357SAndroid Build Coastguard Worker   m_InBitStream.Init();
400*f6dc9357SAndroid Build Coastguard Worker 
401*f6dc9357SAndroid Build Coastguard Worker   // InitData
402*f6dc9357SAndroid Build Coastguard Worker 
403*f6dc9357SAndroid Build Coastguard Worker   FlagsCnt = 0;
404*f6dc9357SAndroid Build Coastguard Worker   FlagBuf = 0;
405*f6dc9357SAndroid Build Coastguard Worker   StMode = false;
406*f6dc9357SAndroid Build Coastguard Worker   LCount = 0;
407*f6dc9357SAndroid Build Coastguard Worker 
408*f6dc9357SAndroid Build Coastguard Worker   if (!_isSolid)
409*f6dc9357SAndroid Build Coastguard Worker   {
410*f6dc9357SAndroid Build Coastguard Worker     AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = NumHuf = Buf60 = 0;
411*f6dc9357SAndroid Build Coastguard Worker     AvrPlc = 0x3500;
412*f6dc9357SAndroid Build Coastguard Worker     MaxDist3 = 0x2001;
413*f6dc9357SAndroid Build Coastguard Worker     Nhfb = Nlzb = 0x80;
414*f6dc9357SAndroid Build Coastguard Worker 
415*f6dc9357SAndroid Build Coastguard Worker     {
416*f6dc9357SAndroid Build Coastguard Worker       // InitStructures
417*f6dc9357SAndroid Build Coastguard Worker       for (unsigned i = 0; i < kNumRepDists; i++)
418*f6dc9357SAndroid Build Coastguard Worker         m_RepDists[i] = 0;
419*f6dc9357SAndroid Build Coastguard Worker       m_RepDistPtr = 0;
420*f6dc9357SAndroid Build Coastguard Worker       LastLength = 0;
421*f6dc9357SAndroid Build Coastguard Worker       LastDist = 0;
422*f6dc9357SAndroid Build Coastguard Worker     }
423*f6dc9357SAndroid Build Coastguard Worker 
424*f6dc9357SAndroid Build Coastguard Worker     // InitHuff
425*f6dc9357SAndroid Build Coastguard Worker 
426*f6dc9357SAndroid Build Coastguard Worker     for (UInt32 i = 0; i < 256; i++)
427*f6dc9357SAndroid Build Coastguard Worker     {
428*f6dc9357SAndroid Build Coastguard Worker       Place[i] = PlaceA[i] = PlaceB[i] = i;
429*f6dc9357SAndroid Build Coastguard Worker       UInt32 c = (~i + 1) & 0xff;
430*f6dc9357SAndroid Build Coastguard Worker       PlaceC[i] = c;
431*f6dc9357SAndroid Build Coastguard Worker       ChSet[i] = ChSetB[i] = i << 8;
432*f6dc9357SAndroid Build Coastguard Worker       ChSetA[i] = i;
433*f6dc9357SAndroid Build Coastguard Worker       ChSetC[i] = c << 8;
434*f6dc9357SAndroid Build Coastguard Worker     }
435*f6dc9357SAndroid Build Coastguard Worker     memset(NToPl, 0, sizeof(NToPl));
436*f6dc9357SAndroid Build Coastguard Worker     memset(NToPlB, 0, sizeof(NToPlB));
437*f6dc9357SAndroid Build Coastguard Worker     memset(NToPlC, 0, sizeof(NToPlC));
438*f6dc9357SAndroid Build Coastguard Worker     CorrHuff(ChSetB, NToPlB);
439*f6dc9357SAndroid Build Coastguard Worker   }
440*f6dc9357SAndroid Build Coastguard Worker 
441*f6dc9357SAndroid Build Coastguard Worker   if (m_UnpackSize > 0)
442*f6dc9357SAndroid Build Coastguard Worker   {
443*f6dc9357SAndroid Build Coastguard Worker     GetFlagsBuf();
444*f6dc9357SAndroid Build Coastguard Worker     FlagsCnt = 8;
445*f6dc9357SAndroid Build Coastguard Worker   }
446*f6dc9357SAndroid Build Coastguard Worker 
447*f6dc9357SAndroid Build Coastguard Worker   while (m_UnpackSize != 0)
448*f6dc9357SAndroid Build Coastguard Worker   {
449*f6dc9357SAndroid Build Coastguard Worker     if (!StMode)
450*f6dc9357SAndroid Build Coastguard Worker     {
451*f6dc9357SAndroid Build Coastguard Worker       if (--FlagsCnt < 0)
452*f6dc9357SAndroid Build Coastguard Worker       {
453*f6dc9357SAndroid Build Coastguard Worker         GetFlagsBuf();
454*f6dc9357SAndroid Build Coastguard Worker         FlagsCnt = 7;
455*f6dc9357SAndroid Build Coastguard Worker       }
456*f6dc9357SAndroid Build Coastguard Worker 
457*f6dc9357SAndroid Build Coastguard Worker       if (FlagBuf & 0x80)
458*f6dc9357SAndroid Build Coastguard Worker       {
459*f6dc9357SAndroid Build Coastguard Worker         FlagBuf <<= 1;
460*f6dc9357SAndroid Build Coastguard Worker         if (Nlzb > Nhfb)
461*f6dc9357SAndroid Build Coastguard Worker         {
462*f6dc9357SAndroid Build Coastguard Worker           RINOK(LongLZ())
463*f6dc9357SAndroid Build Coastguard Worker           continue;
464*f6dc9357SAndroid Build Coastguard Worker         }
465*f6dc9357SAndroid Build Coastguard Worker       }
466*f6dc9357SAndroid Build Coastguard Worker       else
467*f6dc9357SAndroid Build Coastguard Worker       {
468*f6dc9357SAndroid Build Coastguard Worker         FlagBuf <<= 1;
469*f6dc9357SAndroid Build Coastguard Worker 
470*f6dc9357SAndroid Build Coastguard Worker         if (--FlagsCnt < 0)
471*f6dc9357SAndroid Build Coastguard Worker         {
472*f6dc9357SAndroid Build Coastguard Worker           GetFlagsBuf();
473*f6dc9357SAndroid Build Coastguard Worker           FlagsCnt = 7;
474*f6dc9357SAndroid Build Coastguard Worker         }
475*f6dc9357SAndroid Build Coastguard Worker 
476*f6dc9357SAndroid Build Coastguard Worker         if ((FlagBuf & 0x80) == 0)
477*f6dc9357SAndroid Build Coastguard Worker         {
478*f6dc9357SAndroid Build Coastguard Worker           FlagBuf <<= 1;
479*f6dc9357SAndroid Build Coastguard Worker           RINOK(ShortLZ())
480*f6dc9357SAndroid Build Coastguard Worker           continue;
481*f6dc9357SAndroid Build Coastguard Worker         }
482*f6dc9357SAndroid Build Coastguard Worker 
483*f6dc9357SAndroid Build Coastguard Worker         FlagBuf <<= 1;
484*f6dc9357SAndroid Build Coastguard Worker 
485*f6dc9357SAndroid Build Coastguard Worker         if (Nlzb <= Nhfb)
486*f6dc9357SAndroid Build Coastguard Worker         {
487*f6dc9357SAndroid Build Coastguard Worker           RINOK(LongLZ())
488*f6dc9357SAndroid Build Coastguard Worker           continue;
489*f6dc9357SAndroid Build Coastguard Worker         }
490*f6dc9357SAndroid Build Coastguard Worker       }
491*f6dc9357SAndroid Build Coastguard Worker     }
492*f6dc9357SAndroid Build Coastguard Worker 
493*f6dc9357SAndroid Build Coastguard Worker     RINOK(HuffDecode())
494*f6dc9357SAndroid Build Coastguard Worker   }
495*f6dc9357SAndroid Build Coastguard Worker 
496*f6dc9357SAndroid Build Coastguard Worker   _solidAllowed = true;
497*f6dc9357SAndroid Build Coastguard Worker   return m_OutWindowStream.Flush();
498*f6dc9357SAndroid Build Coastguard Worker }
499*f6dc9357SAndroid Build Coastguard Worker 
500*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CDecoder::Code (ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress))501*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
502*f6dc9357SAndroid Build Coastguard Worker     const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
503*f6dc9357SAndroid Build Coastguard Worker {
504*f6dc9357SAndroid Build Coastguard Worker   try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
505*f6dc9357SAndroid Build Coastguard Worker   catch(const CInBufferException &e) { return e.ErrorCode; }
506*f6dc9357SAndroid Build Coastguard Worker   catch(const CLzOutWindowException &e) { return e.ErrorCode; }
507*f6dc9357SAndroid Build Coastguard Worker   catch(...) { return S_FALSE; }
508*f6dc9357SAndroid Build Coastguard Worker }
509*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CDecoder::SetDecoderProperties2 (const Byte * data,UInt32 size))510*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size))
511*f6dc9357SAndroid Build Coastguard Worker {
512*f6dc9357SAndroid Build Coastguard Worker   if (size < 1)
513*f6dc9357SAndroid Build Coastguard Worker     return E_INVALIDARG;
514*f6dc9357SAndroid Build Coastguard Worker   _isSolid = ((data[0] & 1) != 0);
515*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
516*f6dc9357SAndroid Build Coastguard Worker }
517*f6dc9357SAndroid Build Coastguard Worker 
518*f6dc9357SAndroid Build Coastguard Worker }}
519