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