1*f6dc9357SAndroid Build Coastguard Worker // LzhDecoder.cpp
2*f6dc9357SAndroid Build Coastguard Worker
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker
5*f6dc9357SAndroid Build Coastguard Worker #include "LzhDecoder.h"
6*f6dc9357SAndroid Build Coastguard Worker
7*f6dc9357SAndroid Build Coastguard Worker namespace NCompress{
8*f6dc9357SAndroid Build Coastguard Worker namespace NLzh {
9*f6dc9357SAndroid Build Coastguard Worker namespace NDecoder {
10*f6dc9357SAndroid Build Coastguard Worker
11*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kWindowSizeMin = 1 << 16;
12*f6dc9357SAndroid Build Coastguard Worker
ReadTP(unsigned num,unsigned numBits,int spec)13*f6dc9357SAndroid Build Coastguard Worker bool CCoder::ReadTP(unsigned num, unsigned numBits, int spec)
14*f6dc9357SAndroid Build Coastguard Worker {
15*f6dc9357SAndroid Build Coastguard Worker _symbolT = -1;
16*f6dc9357SAndroid Build Coastguard Worker
17*f6dc9357SAndroid Build Coastguard Worker const unsigned n = (unsigned)_inBitStream.ReadBits(numBits);
18*f6dc9357SAndroid Build Coastguard Worker if (n == 0)
19*f6dc9357SAndroid Build Coastguard Worker {
20*f6dc9357SAndroid Build Coastguard Worker const unsigned s = (unsigned)_inBitStream.ReadBits(numBits);
21*f6dc9357SAndroid Build Coastguard Worker _symbolT = (int)s;
22*f6dc9357SAndroid Build Coastguard Worker return (s < num);
23*f6dc9357SAndroid Build Coastguard Worker }
24*f6dc9357SAndroid Build Coastguard Worker if (n > num)
25*f6dc9357SAndroid Build Coastguard Worker return false;
26*f6dc9357SAndroid Build Coastguard Worker
27*f6dc9357SAndroid Build Coastguard Worker {
28*f6dc9357SAndroid Build Coastguard Worker Byte lens[NPT];
29*f6dc9357SAndroid Build Coastguard Worker unsigned i;
30*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < NPT; i++)
31*f6dc9357SAndroid Build Coastguard Worker lens[i] = 0;
32*f6dc9357SAndroid Build Coastguard Worker i = 0;
33*f6dc9357SAndroid Build Coastguard Worker do
34*f6dc9357SAndroid Build Coastguard Worker {
35*f6dc9357SAndroid Build Coastguard Worker unsigned val = (unsigned)_inBitStream.GetValue(16);
36*f6dc9357SAndroid Build Coastguard Worker unsigned c = val >> 13;
37*f6dc9357SAndroid Build Coastguard Worker unsigned mov = 3;
38*f6dc9357SAndroid Build Coastguard Worker if (c == 7)
39*f6dc9357SAndroid Build Coastguard Worker {
40*f6dc9357SAndroid Build Coastguard Worker while (val & (1 << 12))
41*f6dc9357SAndroid Build Coastguard Worker {
42*f6dc9357SAndroid Build Coastguard Worker val += val;
43*f6dc9357SAndroid Build Coastguard Worker c++;
44*f6dc9357SAndroid Build Coastguard Worker }
45*f6dc9357SAndroid Build Coastguard Worker if (c > 16)
46*f6dc9357SAndroid Build Coastguard Worker return false;
47*f6dc9357SAndroid Build Coastguard Worker mov = c - 3;
48*f6dc9357SAndroid Build Coastguard Worker }
49*f6dc9357SAndroid Build Coastguard Worker lens[i++] = (Byte)c;
50*f6dc9357SAndroid Build Coastguard Worker _inBitStream.MovePos(mov);
51*f6dc9357SAndroid Build Coastguard Worker if ((int)i == spec)
52*f6dc9357SAndroid Build Coastguard Worker i += _inBitStream.ReadBits(2);
53*f6dc9357SAndroid Build Coastguard Worker }
54*f6dc9357SAndroid Build Coastguard Worker while (i < n);
55*f6dc9357SAndroid Build Coastguard Worker
56*f6dc9357SAndroid Build Coastguard Worker return _decoderT.Build(lens, NHuffman::k_BuildMode_Full);
57*f6dc9357SAndroid Build Coastguard Worker }
58*f6dc9357SAndroid Build Coastguard Worker }
59*f6dc9357SAndroid Build Coastguard Worker
60*f6dc9357SAndroid Build Coastguard Worker static const unsigned NUM_C_BITS = 9;
61*f6dc9357SAndroid Build Coastguard Worker
ReadC()62*f6dc9357SAndroid Build Coastguard Worker bool CCoder::ReadC()
63*f6dc9357SAndroid Build Coastguard Worker {
64*f6dc9357SAndroid Build Coastguard Worker _symbolC = -1;
65*f6dc9357SAndroid Build Coastguard Worker
66*f6dc9357SAndroid Build Coastguard Worker const unsigned n = (unsigned)_inBitStream.ReadBits(NUM_C_BITS);
67*f6dc9357SAndroid Build Coastguard Worker if (n == 0)
68*f6dc9357SAndroid Build Coastguard Worker {
69*f6dc9357SAndroid Build Coastguard Worker const unsigned s = (unsigned)_inBitStream.ReadBits(NUM_C_BITS);
70*f6dc9357SAndroid Build Coastguard Worker _symbolC = (int)s;
71*f6dc9357SAndroid Build Coastguard Worker return (s < NC);
72*f6dc9357SAndroid Build Coastguard Worker }
73*f6dc9357SAndroid Build Coastguard Worker if (n > NC)
74*f6dc9357SAndroid Build Coastguard Worker return false;
75*f6dc9357SAndroid Build Coastguard Worker
76*f6dc9357SAndroid Build Coastguard Worker {
77*f6dc9357SAndroid Build Coastguard Worker Byte lens[NC];
78*f6dc9357SAndroid Build Coastguard Worker unsigned i = 0;
79*f6dc9357SAndroid Build Coastguard Worker do
80*f6dc9357SAndroid Build Coastguard Worker {
81*f6dc9357SAndroid Build Coastguard Worker unsigned c = (unsigned)_symbolT;
82*f6dc9357SAndroid Build Coastguard Worker if (_symbolT < 0)
83*f6dc9357SAndroid Build Coastguard Worker c = _decoderT.DecodeFull(&_inBitStream);
84*f6dc9357SAndroid Build Coastguard Worker
85*f6dc9357SAndroid Build Coastguard Worker if (c <= 2)
86*f6dc9357SAndroid Build Coastguard Worker {
87*f6dc9357SAndroid Build Coastguard Worker if (c == 0)
88*f6dc9357SAndroid Build Coastguard Worker c = 1;
89*f6dc9357SAndroid Build Coastguard Worker else if (c == 1)
90*f6dc9357SAndroid Build Coastguard Worker c = _inBitStream.ReadBits(4) + 3;
91*f6dc9357SAndroid Build Coastguard Worker else
92*f6dc9357SAndroid Build Coastguard Worker c = _inBitStream.ReadBits(NUM_C_BITS) + 20;
93*f6dc9357SAndroid Build Coastguard Worker
94*f6dc9357SAndroid Build Coastguard Worker if (i + c > n)
95*f6dc9357SAndroid Build Coastguard Worker return false;
96*f6dc9357SAndroid Build Coastguard Worker
97*f6dc9357SAndroid Build Coastguard Worker do
98*f6dc9357SAndroid Build Coastguard Worker lens[i++] = 0;
99*f6dc9357SAndroid Build Coastguard Worker while (--c);
100*f6dc9357SAndroid Build Coastguard Worker }
101*f6dc9357SAndroid Build Coastguard Worker else
102*f6dc9357SAndroid Build Coastguard Worker lens[i++] = (Byte)(c - 2);
103*f6dc9357SAndroid Build Coastguard Worker }
104*f6dc9357SAndroid Build Coastguard Worker while (i < n);
105*f6dc9357SAndroid Build Coastguard Worker
106*f6dc9357SAndroid Build Coastguard Worker while (i < NC) lens[i++] = 0;
107*f6dc9357SAndroid Build Coastguard Worker return _decoderC.Build(lens, /* n, */ NHuffman::k_BuildMode_Full);
108*f6dc9357SAndroid Build Coastguard Worker }
109*f6dc9357SAndroid Build Coastguard Worker }
110*f6dc9357SAndroid Build Coastguard Worker
CodeReal(UInt32 rem,ICompressProgressInfo * progress)111*f6dc9357SAndroid Build Coastguard Worker HRESULT CCoder::CodeReal(UInt32 rem, ICompressProgressInfo *progress)
112*f6dc9357SAndroid Build Coastguard Worker {
113*f6dc9357SAndroid Build Coastguard Worker UInt32 blockSize = 0;
114*f6dc9357SAndroid Build Coastguard Worker
115*f6dc9357SAndroid Build Coastguard Worker while (rem != 0)
116*f6dc9357SAndroid Build Coastguard Worker {
117*f6dc9357SAndroid Build Coastguard Worker if (blockSize == 0)
118*f6dc9357SAndroid Build Coastguard Worker {
119*f6dc9357SAndroid Build Coastguard Worker if (_inBitStream.ExtraBitsWereRead())
120*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
121*f6dc9357SAndroid Build Coastguard Worker if (progress)
122*f6dc9357SAndroid Build Coastguard Worker {
123*f6dc9357SAndroid Build Coastguard Worker const UInt64 packSize = _inBitStream.GetProcessedSize();
124*f6dc9357SAndroid Build Coastguard Worker const UInt64 pos = _outWindow.GetProcessedSize();
125*f6dc9357SAndroid Build Coastguard Worker RINOK(progress->SetRatioInfo(&packSize, &pos))
126*f6dc9357SAndroid Build Coastguard Worker }
127*f6dc9357SAndroid Build Coastguard Worker
128*f6dc9357SAndroid Build Coastguard Worker blockSize = _inBitStream.ReadBits(16);
129*f6dc9357SAndroid Build Coastguard Worker if (blockSize == 0)
130*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
131*f6dc9357SAndroid Build Coastguard Worker
132*f6dc9357SAndroid Build Coastguard Worker if (!ReadTP(NT, 5, 3))
133*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
134*f6dc9357SAndroid Build Coastguard Worker if (!ReadC())
135*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
136*f6dc9357SAndroid Build Coastguard Worker const unsigned pbit = (DictSize <= (1 << 14) ? 4 : 5);
137*f6dc9357SAndroid Build Coastguard Worker if (!ReadTP(NP, pbit, -1))
138*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
139*f6dc9357SAndroid Build Coastguard Worker }
140*f6dc9357SAndroid Build Coastguard Worker
141*f6dc9357SAndroid Build Coastguard Worker blockSize--;
142*f6dc9357SAndroid Build Coastguard Worker
143*f6dc9357SAndroid Build Coastguard Worker unsigned number = (unsigned)_symbolC;
144*f6dc9357SAndroid Build Coastguard Worker if (_symbolC < 0)
145*f6dc9357SAndroid Build Coastguard Worker number = _decoderC.DecodeFull(&_inBitStream);
146*f6dc9357SAndroid Build Coastguard Worker
147*f6dc9357SAndroid Build Coastguard Worker if (number < 256)
148*f6dc9357SAndroid Build Coastguard Worker {
149*f6dc9357SAndroid Build Coastguard Worker _outWindow.PutByte((Byte)number);
150*f6dc9357SAndroid Build Coastguard Worker rem--;
151*f6dc9357SAndroid Build Coastguard Worker }
152*f6dc9357SAndroid Build Coastguard Worker else
153*f6dc9357SAndroid Build Coastguard Worker {
154*f6dc9357SAndroid Build Coastguard Worker const unsigned len = number - 256 + kMatchMinLen;
155*f6dc9357SAndroid Build Coastguard Worker
156*f6dc9357SAndroid Build Coastguard Worker UInt32 dist = (UInt32)(unsigned)_symbolT;
157*f6dc9357SAndroid Build Coastguard Worker if (_symbolT < 0)
158*f6dc9357SAndroid Build Coastguard Worker dist = (UInt32)_decoderT.DecodeFull(&_inBitStream);
159*f6dc9357SAndroid Build Coastguard Worker
160*f6dc9357SAndroid Build Coastguard Worker if (dist > 1)
161*f6dc9357SAndroid Build Coastguard Worker {
162*f6dc9357SAndroid Build Coastguard Worker dist--;
163*f6dc9357SAndroid Build Coastguard Worker dist = ((UInt32)1 << dist) + _inBitStream.ReadBits((unsigned)dist);
164*f6dc9357SAndroid Build Coastguard Worker }
165*f6dc9357SAndroid Build Coastguard Worker
166*f6dc9357SAndroid Build Coastguard Worker if (dist >= DictSize)
167*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
168*f6dc9357SAndroid Build Coastguard Worker
169*f6dc9357SAndroid Build Coastguard Worker if (len > rem)
170*f6dc9357SAndroid Build Coastguard Worker {
171*f6dc9357SAndroid Build Coastguard Worker // if (FinishMode)
172*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
173*f6dc9357SAndroid Build Coastguard Worker // len = (unsigned)rem;
174*f6dc9357SAndroid Build Coastguard Worker }
175*f6dc9357SAndroid Build Coastguard Worker
176*f6dc9357SAndroid Build Coastguard Worker if (!_outWindow.CopyBlock(dist, len))
177*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
178*f6dc9357SAndroid Build Coastguard Worker rem -= len;
179*f6dc9357SAndroid Build Coastguard Worker }
180*f6dc9357SAndroid Build Coastguard Worker }
181*f6dc9357SAndroid Build Coastguard Worker
182*f6dc9357SAndroid Build Coastguard Worker // if (FinishMode)
183*f6dc9357SAndroid Build Coastguard Worker {
184*f6dc9357SAndroid Build Coastguard Worker if (blockSize != 0)
185*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
186*f6dc9357SAndroid Build Coastguard Worker if (_inBitStream.ReadAlignBits() != 0)
187*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
188*f6dc9357SAndroid Build Coastguard Worker }
189*f6dc9357SAndroid Build Coastguard Worker if (_inBitStream.ExtraBitsWereRead())
190*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
191*f6dc9357SAndroid Build Coastguard Worker return S_OK;
192*f6dc9357SAndroid Build Coastguard Worker }
193*f6dc9357SAndroid Build Coastguard Worker
194*f6dc9357SAndroid Build Coastguard Worker
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt32 outSize,ICompressProgressInfo * progress)195*f6dc9357SAndroid Build Coastguard Worker HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
196*f6dc9357SAndroid Build Coastguard Worker const UInt32 outSize, ICompressProgressInfo *progress)
197*f6dc9357SAndroid Build Coastguard Worker {
198*f6dc9357SAndroid Build Coastguard Worker try
199*f6dc9357SAndroid Build Coastguard Worker {
200*f6dc9357SAndroid Build Coastguard Worker if (!_outWindow.Create(DictSize > kWindowSizeMin ? DictSize : kWindowSizeMin))
201*f6dc9357SAndroid Build Coastguard Worker return E_OUTOFMEMORY;
202*f6dc9357SAndroid Build Coastguard Worker if (!_inBitStream.Create(1 << 17))
203*f6dc9357SAndroid Build Coastguard Worker return E_OUTOFMEMORY;
204*f6dc9357SAndroid Build Coastguard Worker _outWindow.SetStream(outStream);
205*f6dc9357SAndroid Build Coastguard Worker _outWindow.Init(false);
206*f6dc9357SAndroid Build Coastguard Worker _inBitStream.SetStream(inStream);
207*f6dc9357SAndroid Build Coastguard Worker _inBitStream.Init();
208*f6dc9357SAndroid Build Coastguard Worker {
209*f6dc9357SAndroid Build Coastguard Worker CCoderReleaser coderReleaser(this);
210*f6dc9357SAndroid Build Coastguard Worker RINOK(CodeReal(outSize, progress))
211*f6dc9357SAndroid Build Coastguard Worker coderReleaser.Disable();
212*f6dc9357SAndroid Build Coastguard Worker }
213*f6dc9357SAndroid Build Coastguard Worker return _outWindow.Flush();
214*f6dc9357SAndroid Build Coastguard Worker }
215*f6dc9357SAndroid Build Coastguard Worker catch(const CInBufferException &e) { return e.ErrorCode; }
216*f6dc9357SAndroid Build Coastguard Worker catch(const CLzOutWindowException &e) { return e.ErrorCode; }
217*f6dc9357SAndroid Build Coastguard Worker catch(...) { return S_FALSE; }
218*f6dc9357SAndroid Build Coastguard Worker }
219*f6dc9357SAndroid Build Coastguard Worker
220*f6dc9357SAndroid Build Coastguard Worker }}}
221