1*f6dc9357SAndroid Build Coastguard Worker // ImplodeDecoder.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 "../../Common/Defs.h"
6*f6dc9357SAndroid Build Coastguard Worker
7*f6dc9357SAndroid Build Coastguard Worker #include "ImplodeDecoder.h"
8*f6dc9357SAndroid Build Coastguard Worker
9*f6dc9357SAndroid Build Coastguard Worker namespace NCompress {
10*f6dc9357SAndroid Build Coastguard Worker namespace NImplode {
11*f6dc9357SAndroid Build Coastguard Worker namespace NDecoder {
12*f6dc9357SAndroid Build Coastguard Worker
Build(const Byte * lens,unsigned numSymbols)13*f6dc9357SAndroid Build Coastguard Worker bool CHuffmanDecoder::Build(const Byte *lens, unsigned numSymbols) throw()
14*f6dc9357SAndroid Build Coastguard Worker {
15*f6dc9357SAndroid Build Coastguard Worker unsigned counts[kNumHuffmanBits + 1];
16*f6dc9357SAndroid Build Coastguard Worker unsigned i;
17*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i <= kNumHuffmanBits; i++)
18*f6dc9357SAndroid Build Coastguard Worker counts[i] = 0;
19*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < numSymbols; i++)
20*f6dc9357SAndroid Build Coastguard Worker counts[lens[i]]++;
21*f6dc9357SAndroid Build Coastguard Worker
22*f6dc9357SAndroid Build Coastguard Worker const UInt32 kMaxValue = (UInt32)1 << kNumHuffmanBits;
23*f6dc9357SAndroid Build Coastguard Worker // _limits[0] = kMaxValue;
24*f6dc9357SAndroid Build Coastguard Worker UInt32 startPos = kMaxValue;
25*f6dc9357SAndroid Build Coastguard Worker unsigned sum = 0;
26*f6dc9357SAndroid Build Coastguard Worker
27*f6dc9357SAndroid Build Coastguard Worker for (i = 1; i <= kNumHuffmanBits; i++)
28*f6dc9357SAndroid Build Coastguard Worker {
29*f6dc9357SAndroid Build Coastguard Worker const unsigned cnt = counts[i];
30*f6dc9357SAndroid Build Coastguard Worker const UInt32 range = (UInt32)cnt << (kNumHuffmanBits - i);
31*f6dc9357SAndroid Build Coastguard Worker if (startPos < range)
32*f6dc9357SAndroid Build Coastguard Worker return false;
33*f6dc9357SAndroid Build Coastguard Worker startPos -= range;
34*f6dc9357SAndroid Build Coastguard Worker _limits[i] = startPos;
35*f6dc9357SAndroid Build Coastguard Worker _poses[i] = sum;
36*f6dc9357SAndroid Build Coastguard Worker sum += cnt;
37*f6dc9357SAndroid Build Coastguard Worker counts[i] = sum;
38*f6dc9357SAndroid Build Coastguard Worker }
39*f6dc9357SAndroid Build Coastguard Worker // counts[0] += sum;
40*f6dc9357SAndroid Build Coastguard Worker if (startPos != 0)
41*f6dc9357SAndroid Build Coastguard Worker return false;
42*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < numSymbols; i++)
43*f6dc9357SAndroid Build Coastguard Worker {
44*f6dc9357SAndroid Build Coastguard Worker const unsigned len = lens[i];
45*f6dc9357SAndroid Build Coastguard Worker if (len != 0)
46*f6dc9357SAndroid Build Coastguard Worker _symbols[--counts[len]] = (Byte)i;
47*f6dc9357SAndroid Build Coastguard Worker }
48*f6dc9357SAndroid Build Coastguard Worker return true;
49*f6dc9357SAndroid Build Coastguard Worker }
50*f6dc9357SAndroid Build Coastguard Worker
51*f6dc9357SAndroid Build Coastguard Worker
Decode(CInBit * inStream) const52*f6dc9357SAndroid Build Coastguard Worker unsigned CHuffmanDecoder::Decode(CInBit *inStream) const throw()
53*f6dc9357SAndroid Build Coastguard Worker {
54*f6dc9357SAndroid Build Coastguard Worker const UInt32 val = inStream->GetValue(kNumHuffmanBits);
55*f6dc9357SAndroid Build Coastguard Worker size_t numBits;
56*f6dc9357SAndroid Build Coastguard Worker for (numBits = 1; val < _limits[numBits]; numBits++);
57*f6dc9357SAndroid Build Coastguard Worker const unsigned sym = _symbols[_poses[numBits]
58*f6dc9357SAndroid Build Coastguard Worker + (unsigned)((val - _limits[numBits]) >> (kNumHuffmanBits - numBits))];
59*f6dc9357SAndroid Build Coastguard Worker inStream->MovePos(numBits);
60*f6dc9357SAndroid Build Coastguard Worker return sym;
61*f6dc9357SAndroid Build Coastguard Worker }
62*f6dc9357SAndroid Build Coastguard Worker
63*f6dc9357SAndroid Build Coastguard Worker
64*f6dc9357SAndroid Build Coastguard Worker
65*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumLenDirectBits = 8;
66*f6dc9357SAndroid Build Coastguard Worker
67*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumDistDirectBitsSmall = 6;
68*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumDistDirectBitsBig = 7;
69*f6dc9357SAndroid Build Coastguard Worker
70*f6dc9357SAndroid Build Coastguard Worker static const unsigned kLitTableSize = (1 << 8);
71*f6dc9357SAndroid Build Coastguard Worker static const unsigned kDistTableSize = 64;
72*f6dc9357SAndroid Build Coastguard Worker static const unsigned kLenTableSize = 64;
73*f6dc9357SAndroid Build Coastguard Worker
74*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kHistorySize = (1 << kNumDistDirectBitsBig) * kDistTableSize; // 8 KB
75*f6dc9357SAndroid Build Coastguard Worker
76*f6dc9357SAndroid Build Coastguard Worker
CCoder()77*f6dc9357SAndroid Build Coastguard Worker CCoder::CCoder():
78*f6dc9357SAndroid Build Coastguard Worker _flags(0),
79*f6dc9357SAndroid Build Coastguard Worker _fullStreamMode(false)
80*f6dc9357SAndroid Build Coastguard Worker {}
81*f6dc9357SAndroid Build Coastguard Worker
82*f6dc9357SAndroid Build Coastguard Worker
BuildHuff(CHuffmanDecoder & decoder,unsigned numSymbols)83*f6dc9357SAndroid Build Coastguard Worker bool CCoder::BuildHuff(CHuffmanDecoder &decoder, unsigned numSymbols)
84*f6dc9357SAndroid Build Coastguard Worker {
85*f6dc9357SAndroid Build Coastguard Worker Byte levels[kMaxHuffTableSize];
86*f6dc9357SAndroid Build Coastguard Worker unsigned numRecords = (unsigned)_inBitStream.ReadAlignedByte() + 1;
87*f6dc9357SAndroid Build Coastguard Worker unsigned index = 0;
88*f6dc9357SAndroid Build Coastguard Worker do
89*f6dc9357SAndroid Build Coastguard Worker {
90*f6dc9357SAndroid Build Coastguard Worker const unsigned b = (unsigned)_inBitStream.ReadAlignedByte();
91*f6dc9357SAndroid Build Coastguard Worker const unsigned level = (b & 0xF) + 1;
92*f6dc9357SAndroid Build Coastguard Worker const unsigned rep = ((unsigned)b >> 4) + 1;
93*f6dc9357SAndroid Build Coastguard Worker if (index + rep > numSymbols)
94*f6dc9357SAndroid Build Coastguard Worker return false;
95*f6dc9357SAndroid Build Coastguard Worker for (unsigned j = 0; j < rep; j++)
96*f6dc9357SAndroid Build Coastguard Worker levels[index++] = (Byte)level;
97*f6dc9357SAndroid Build Coastguard Worker }
98*f6dc9357SAndroid Build Coastguard Worker while (--numRecords);
99*f6dc9357SAndroid Build Coastguard Worker
100*f6dc9357SAndroid Build Coastguard Worker if (index != numSymbols)
101*f6dc9357SAndroid Build Coastguard Worker return false;
102*f6dc9357SAndroid Build Coastguard Worker return decoder.Build(levels, numSymbols);
103*f6dc9357SAndroid Build Coastguard Worker }
104*f6dc9357SAndroid Build Coastguard Worker
105*f6dc9357SAndroid Build Coastguard Worker
CodeReal(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress)106*f6dc9357SAndroid Build Coastguard Worker HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
107*f6dc9357SAndroid Build Coastguard Worker const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
108*f6dc9357SAndroid Build Coastguard Worker {
109*f6dc9357SAndroid Build Coastguard Worker if (!_inBitStream.Create(1 << 18))
110*f6dc9357SAndroid Build Coastguard Worker return E_OUTOFMEMORY;
111*f6dc9357SAndroid Build Coastguard Worker if (!_outWindowStream.Create(kHistorySize << 1)) // 16 KB
112*f6dc9357SAndroid Build Coastguard Worker return E_OUTOFMEMORY;
113*f6dc9357SAndroid Build Coastguard Worker if (!outSize)
114*f6dc9357SAndroid Build Coastguard Worker return E_INVALIDARG;
115*f6dc9357SAndroid Build Coastguard Worker
116*f6dc9357SAndroid Build Coastguard Worker _outWindowStream.SetStream(outStream);
117*f6dc9357SAndroid Build Coastguard Worker _outWindowStream.Init(false);
118*f6dc9357SAndroid Build Coastguard Worker _inBitStream.SetStream(inStream);
119*f6dc9357SAndroid Build Coastguard Worker _inBitStream.Init();
120*f6dc9357SAndroid Build Coastguard Worker
121*f6dc9357SAndroid Build Coastguard Worker const unsigned numDistDirectBits = (_flags & 2) ?
122*f6dc9357SAndroid Build Coastguard Worker kNumDistDirectBitsBig:
123*f6dc9357SAndroid Build Coastguard Worker kNumDistDirectBitsSmall;
124*f6dc9357SAndroid Build Coastguard Worker const bool literalsOn = ((_flags & 4) != 0);
125*f6dc9357SAndroid Build Coastguard Worker const UInt32 minMatchLen = (literalsOn ? 3 : 2);
126*f6dc9357SAndroid Build Coastguard Worker
127*f6dc9357SAndroid Build Coastguard Worker if (literalsOn)
128*f6dc9357SAndroid Build Coastguard Worker if (!BuildHuff(_litDecoder, kLitTableSize))
129*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
130*f6dc9357SAndroid Build Coastguard Worker if (!BuildHuff(_lenDecoder, kLenTableSize))
131*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
132*f6dc9357SAndroid Build Coastguard Worker if (!BuildHuff(_distDecoder, kDistTableSize))
133*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
134*f6dc9357SAndroid Build Coastguard Worker
135*f6dc9357SAndroid Build Coastguard Worker UInt64 prevProgress = 0;
136*f6dc9357SAndroid Build Coastguard Worker bool moreOut = false;
137*f6dc9357SAndroid Build Coastguard Worker UInt64 pos = 0, unPackSize = *outSize;
138*f6dc9357SAndroid Build Coastguard Worker
139*f6dc9357SAndroid Build Coastguard Worker while (pos < unPackSize)
140*f6dc9357SAndroid Build Coastguard Worker {
141*f6dc9357SAndroid Build Coastguard Worker if (pos - prevProgress >= (1u << 18) && progress)
142*f6dc9357SAndroid Build Coastguard Worker {
143*f6dc9357SAndroid Build Coastguard Worker prevProgress = pos;
144*f6dc9357SAndroid Build Coastguard Worker const UInt64 packSize = _inBitStream.GetProcessedSize();
145*f6dc9357SAndroid Build Coastguard Worker RINOK(progress->SetRatioInfo(&packSize, &pos))
146*f6dc9357SAndroid Build Coastguard Worker }
147*f6dc9357SAndroid Build Coastguard Worker
148*f6dc9357SAndroid Build Coastguard Worker if (_inBitStream.ReadBits(1) != 0)
149*f6dc9357SAndroid Build Coastguard Worker {
150*f6dc9357SAndroid Build Coastguard Worker Byte b;
151*f6dc9357SAndroid Build Coastguard Worker if (literalsOn)
152*f6dc9357SAndroid Build Coastguard Worker {
153*f6dc9357SAndroid Build Coastguard Worker const unsigned sym = _litDecoder.Decode(&_inBitStream);
154*f6dc9357SAndroid Build Coastguard Worker // if (sym >= kLitTableSize) break;
155*f6dc9357SAndroid Build Coastguard Worker b = (Byte)sym;
156*f6dc9357SAndroid Build Coastguard Worker }
157*f6dc9357SAndroid Build Coastguard Worker else
158*f6dc9357SAndroid Build Coastguard Worker b = (Byte)_inBitStream.ReadBits(8);
159*f6dc9357SAndroid Build Coastguard Worker _outWindowStream.PutByte(b);
160*f6dc9357SAndroid Build Coastguard Worker pos++;
161*f6dc9357SAndroid Build Coastguard Worker }
162*f6dc9357SAndroid Build Coastguard Worker else
163*f6dc9357SAndroid Build Coastguard Worker {
164*f6dc9357SAndroid Build Coastguard Worker const UInt32 lowDistBits = _inBitStream.ReadBits(numDistDirectBits);
165*f6dc9357SAndroid Build Coastguard Worker UInt32 dist = (UInt32)_distDecoder.Decode(&_inBitStream);
166*f6dc9357SAndroid Build Coastguard Worker // if (dist >= kDistTableSize) break;
167*f6dc9357SAndroid Build Coastguard Worker dist = (dist << numDistDirectBits) + lowDistBits;
168*f6dc9357SAndroid Build Coastguard Worker unsigned len = _lenDecoder.Decode(&_inBitStream);
169*f6dc9357SAndroid Build Coastguard Worker // if (len >= kLenTableSize) break;
170*f6dc9357SAndroid Build Coastguard Worker if (len == kLenTableSize - 1)
171*f6dc9357SAndroid Build Coastguard Worker len += _inBitStream.ReadBits(kNumLenDirectBits);
172*f6dc9357SAndroid Build Coastguard Worker len += minMatchLen;
173*f6dc9357SAndroid Build Coastguard Worker {
174*f6dc9357SAndroid Build Coastguard Worker const UInt64 limit = unPackSize - pos;
175*f6dc9357SAndroid Build Coastguard Worker // limit != 0
176*f6dc9357SAndroid Build Coastguard Worker if (len > limit)
177*f6dc9357SAndroid Build Coastguard Worker {
178*f6dc9357SAndroid Build Coastguard Worker moreOut = true;
179*f6dc9357SAndroid Build Coastguard Worker len = (UInt32)limit;
180*f6dc9357SAndroid Build Coastguard Worker }
181*f6dc9357SAndroid Build Coastguard Worker }
182*f6dc9357SAndroid Build Coastguard Worker do
183*f6dc9357SAndroid Build Coastguard Worker {
184*f6dc9357SAndroid Build Coastguard Worker // len != 0
185*f6dc9357SAndroid Build Coastguard Worker if (dist < pos)
186*f6dc9357SAndroid Build Coastguard Worker {
187*f6dc9357SAndroid Build Coastguard Worker _outWindowStream.CopyBlock(dist, len);
188*f6dc9357SAndroid Build Coastguard Worker pos += len;
189*f6dc9357SAndroid Build Coastguard Worker break;
190*f6dc9357SAndroid Build Coastguard Worker }
191*f6dc9357SAndroid Build Coastguard Worker _outWindowStream.PutByte(0);
192*f6dc9357SAndroid Build Coastguard Worker pos++;
193*f6dc9357SAndroid Build Coastguard Worker }
194*f6dc9357SAndroid Build Coastguard Worker while (--len);
195*f6dc9357SAndroid Build Coastguard Worker }
196*f6dc9357SAndroid Build Coastguard Worker }
197*f6dc9357SAndroid Build Coastguard Worker
198*f6dc9357SAndroid Build Coastguard Worker HRESULT res = _outWindowStream.Flush();
199*f6dc9357SAndroid Build Coastguard Worker
200*f6dc9357SAndroid Build Coastguard Worker if (res == S_OK)
201*f6dc9357SAndroid Build Coastguard Worker {
202*f6dc9357SAndroid Build Coastguard Worker if (_fullStreamMode)
203*f6dc9357SAndroid Build Coastguard Worker {
204*f6dc9357SAndroid Build Coastguard Worker if (moreOut)
205*f6dc9357SAndroid Build Coastguard Worker res = S_FALSE;
206*f6dc9357SAndroid Build Coastguard Worker if (inSize && *inSize != _inBitStream.GetProcessedSize())
207*f6dc9357SAndroid Build Coastguard Worker res = S_FALSE;
208*f6dc9357SAndroid Build Coastguard Worker }
209*f6dc9357SAndroid Build Coastguard Worker if (pos != unPackSize)
210*f6dc9357SAndroid Build Coastguard Worker res = S_FALSE;
211*f6dc9357SAndroid Build Coastguard Worker }
212*f6dc9357SAndroid Build Coastguard Worker
213*f6dc9357SAndroid Build Coastguard Worker return res;
214*f6dc9357SAndroid Build Coastguard Worker }
215*f6dc9357SAndroid Build Coastguard Worker
216*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CCoder::Code (ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress))217*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
218*f6dc9357SAndroid Build Coastguard Worker const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
219*f6dc9357SAndroid Build Coastguard Worker {
220*f6dc9357SAndroid Build Coastguard Worker try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
221*f6dc9357SAndroid Build Coastguard Worker // catch(const CInBufferException &e) { return e.ErrorCode; }
222*f6dc9357SAndroid Build Coastguard Worker // catch(const CLzOutWindowException &e) { return e.ErrorCode; }
223*f6dc9357SAndroid Build Coastguard Worker catch(const CSystemException &e) { return e.ErrorCode; }
224*f6dc9357SAndroid Build Coastguard Worker catch(...) { return S_FALSE; }
225*f6dc9357SAndroid Build Coastguard Worker }
226*f6dc9357SAndroid Build Coastguard Worker
227*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CCoder::SetDecoderProperties2 (const Byte * data,UInt32 size))228*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::SetDecoderProperties2(const Byte *data, UInt32 size))
229*f6dc9357SAndroid Build Coastguard Worker {
230*f6dc9357SAndroid Build Coastguard Worker if (size == 0)
231*f6dc9357SAndroid Build Coastguard Worker return E_NOTIMPL;
232*f6dc9357SAndroid Build Coastguard Worker _flags = data[0];
233*f6dc9357SAndroid Build Coastguard Worker return S_OK;
234*f6dc9357SAndroid Build Coastguard Worker }
235*f6dc9357SAndroid Build Coastguard Worker
236*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CCoder::SetFinishMode (UInt32 finishMode))237*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::SetFinishMode(UInt32 finishMode))
238*f6dc9357SAndroid Build Coastguard Worker {
239*f6dc9357SAndroid Build Coastguard Worker _fullStreamMode = (finishMode != 0);
240*f6dc9357SAndroid Build Coastguard Worker return S_OK;
241*f6dc9357SAndroid Build Coastguard Worker }
242*f6dc9357SAndroid Build Coastguard Worker
243*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CCoder::GetInStreamProcessedSize (UInt64 * value))244*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::GetInStreamProcessedSize(UInt64 *value))
245*f6dc9357SAndroid Build Coastguard Worker {
246*f6dc9357SAndroid Build Coastguard Worker *value = _inBitStream.GetProcessedSize();
247*f6dc9357SAndroid Build Coastguard Worker return S_OK;
248*f6dc9357SAndroid Build Coastguard Worker }
249*f6dc9357SAndroid Build Coastguard Worker
250*f6dc9357SAndroid Build Coastguard Worker }}}
251