1*f6dc9357SAndroid Build Coastguard Worker // ZDecoder.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 <stdio.h>
6*f6dc9357SAndroid Build Coastguard Worker
7*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/Alloc.h"
8*f6dc9357SAndroid Build Coastguard Worker
9*f6dc9357SAndroid Build Coastguard Worker #include "../Common/InBuffer.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../Common/OutBuffer.h"
11*f6dc9357SAndroid Build Coastguard Worker
12*f6dc9357SAndroid Build Coastguard Worker #include "ZDecoder.h"
13*f6dc9357SAndroid Build Coastguard Worker
14*f6dc9357SAndroid Build Coastguard Worker namespace NCompress {
15*f6dc9357SAndroid Build Coastguard Worker namespace NZ {
16*f6dc9357SAndroid Build Coastguard Worker
17*f6dc9357SAndroid Build Coastguard Worker static const size_t kBufferSize = 1 << 20;
18*f6dc9357SAndroid Build Coastguard Worker static const Byte kNumBitsMask = 0x1F;
19*f6dc9357SAndroid Build Coastguard Worker static const Byte kBlockModeMask = 0x80;
20*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumMinBits = 9;
21*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumMaxBits = 16;
22*f6dc9357SAndroid Build Coastguard Worker
Free()23*f6dc9357SAndroid Build Coastguard Worker void CDecoder::Free()
24*f6dc9357SAndroid Build Coastguard Worker {
25*f6dc9357SAndroid Build Coastguard Worker MyFree(_parents); _parents = NULL;
26*f6dc9357SAndroid Build Coastguard Worker MyFree(_suffixes); _suffixes = NULL;
27*f6dc9357SAndroid Build Coastguard Worker MyFree(_stack); _stack = NULL;
28*f6dc9357SAndroid Build Coastguard Worker }
29*f6dc9357SAndroid Build Coastguard Worker
~CDecoder()30*f6dc9357SAndroid Build Coastguard Worker CDecoder::~CDecoder() { Free(); }
31*f6dc9357SAndroid Build Coastguard Worker
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,ICompressProgressInfo * progress)32*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
33*f6dc9357SAndroid Build Coastguard Worker ICompressProgressInfo *progress)
34*f6dc9357SAndroid Build Coastguard Worker {
35*f6dc9357SAndroid Build Coastguard Worker try {
36*f6dc9357SAndroid Build Coastguard Worker // PackSize = 0;
37*f6dc9357SAndroid Build Coastguard Worker
38*f6dc9357SAndroid Build Coastguard Worker CInBuffer inBuffer;
39*f6dc9357SAndroid Build Coastguard Worker COutBuffer outBuffer;
40*f6dc9357SAndroid Build Coastguard Worker
41*f6dc9357SAndroid Build Coastguard Worker if (!inBuffer.Create(kBufferSize))
42*f6dc9357SAndroid Build Coastguard Worker return E_OUTOFMEMORY;
43*f6dc9357SAndroid Build Coastguard Worker inBuffer.SetStream(inStream);
44*f6dc9357SAndroid Build Coastguard Worker inBuffer.Init();
45*f6dc9357SAndroid Build Coastguard Worker
46*f6dc9357SAndroid Build Coastguard Worker if (!outBuffer.Create(kBufferSize))
47*f6dc9357SAndroid Build Coastguard Worker return E_OUTOFMEMORY;
48*f6dc9357SAndroid Build Coastguard Worker outBuffer.SetStream(outStream);
49*f6dc9357SAndroid Build Coastguard Worker outBuffer.Init();
50*f6dc9357SAndroid Build Coastguard Worker
51*f6dc9357SAndroid Build Coastguard Worker Byte buf[kNumMaxBits + 4];
52*f6dc9357SAndroid Build Coastguard Worker {
53*f6dc9357SAndroid Build Coastguard Worker if (inBuffer.ReadBytes(buf, 3) < 3)
54*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
55*f6dc9357SAndroid Build Coastguard Worker if (buf[0] != 0x1F || buf[1] != 0x9D)
56*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
57*f6dc9357SAndroid Build Coastguard Worker }
58*f6dc9357SAndroid Build Coastguard Worker const Byte prop = buf[2];
59*f6dc9357SAndroid Build Coastguard Worker
60*f6dc9357SAndroid Build Coastguard Worker if ((prop & 0x60) != 0)
61*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
62*f6dc9357SAndroid Build Coastguard Worker const unsigned maxbits = prop & kNumBitsMask;
63*f6dc9357SAndroid Build Coastguard Worker if (maxbits < kNumMinBits || maxbits > kNumMaxBits)
64*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
65*f6dc9357SAndroid Build Coastguard Worker const UInt32 numItems = (UInt32)1 << maxbits;
66*f6dc9357SAndroid Build Coastguard Worker // Speed optimization: blockSymbol can contain unused velue.
67*f6dc9357SAndroid Build Coastguard Worker
68*f6dc9357SAndroid Build Coastguard Worker if (maxbits != _numMaxBits || !_parents || !_suffixes || !_stack)
69*f6dc9357SAndroid Build Coastguard Worker {
70*f6dc9357SAndroid Build Coastguard Worker Free();
71*f6dc9357SAndroid Build Coastguard Worker _parents = (UInt16 *)MyAlloc(numItems * sizeof(UInt16)); if (!_parents) return E_OUTOFMEMORY;
72*f6dc9357SAndroid Build Coastguard Worker _suffixes = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (!_suffixes) return E_OUTOFMEMORY;
73*f6dc9357SAndroid Build Coastguard Worker _stack = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (!_stack) return E_OUTOFMEMORY;
74*f6dc9357SAndroid Build Coastguard Worker _numMaxBits = maxbits;
75*f6dc9357SAndroid Build Coastguard Worker }
76*f6dc9357SAndroid Build Coastguard Worker
77*f6dc9357SAndroid Build Coastguard Worker UInt64 prevPos = 0;
78*f6dc9357SAndroid Build Coastguard Worker const UInt32 blockSymbol = ((prop & kBlockModeMask) != 0) ? 256 : ((UInt32)1 << kNumMaxBits);
79*f6dc9357SAndroid Build Coastguard Worker unsigned numBits = kNumMinBits;
80*f6dc9357SAndroid Build Coastguard Worker UInt32 head = (blockSymbol == 256) ? 257 : 256;
81*f6dc9357SAndroid Build Coastguard Worker bool needPrev = false;
82*f6dc9357SAndroid Build Coastguard Worker unsigned bitPos = 0;
83*f6dc9357SAndroid Build Coastguard Worker unsigned numBufBits = 0;
84*f6dc9357SAndroid Build Coastguard Worker
85*f6dc9357SAndroid Build Coastguard Worker _parents[256] = 0; // virus protection
86*f6dc9357SAndroid Build Coastguard Worker _suffixes[256] = 0;
87*f6dc9357SAndroid Build Coastguard Worker HRESULT res = S_OK;
88*f6dc9357SAndroid Build Coastguard Worker
89*f6dc9357SAndroid Build Coastguard Worker for (;;)
90*f6dc9357SAndroid Build Coastguard Worker {
91*f6dc9357SAndroid Build Coastguard Worker if (numBufBits == bitPos)
92*f6dc9357SAndroid Build Coastguard Worker {
93*f6dc9357SAndroid Build Coastguard Worker numBufBits = (unsigned)inBuffer.ReadBytes(buf, numBits) * 8;
94*f6dc9357SAndroid Build Coastguard Worker bitPos = 0;
95*f6dc9357SAndroid Build Coastguard Worker const UInt64 nowPos = outBuffer.GetProcessedSize();
96*f6dc9357SAndroid Build Coastguard Worker if (progress && nowPos - prevPos >= (1 << 13))
97*f6dc9357SAndroid Build Coastguard Worker {
98*f6dc9357SAndroid Build Coastguard Worker prevPos = nowPos;
99*f6dc9357SAndroid Build Coastguard Worker const UInt64 packSize = inBuffer.GetProcessedSize();
100*f6dc9357SAndroid Build Coastguard Worker RINOK(progress->SetRatioInfo(&packSize, &nowPos))
101*f6dc9357SAndroid Build Coastguard Worker }
102*f6dc9357SAndroid Build Coastguard Worker }
103*f6dc9357SAndroid Build Coastguard Worker const unsigned bytePos = bitPos >> 3;
104*f6dc9357SAndroid Build Coastguard Worker UInt32 symbol = buf[bytePos] | ((UInt32)buf[(size_t)bytePos + 1] << 8) | ((UInt32)buf[(size_t)bytePos + 2] << 16);
105*f6dc9357SAndroid Build Coastguard Worker symbol >>= (bitPos & 7);
106*f6dc9357SAndroid Build Coastguard Worker symbol &= ((UInt32)1 << numBits) - 1;
107*f6dc9357SAndroid Build Coastguard Worker bitPos += numBits;
108*f6dc9357SAndroid Build Coastguard Worker if (bitPos > numBufBits)
109*f6dc9357SAndroid Build Coastguard Worker break;
110*f6dc9357SAndroid Build Coastguard Worker if (symbol >= head)
111*f6dc9357SAndroid Build Coastguard Worker {
112*f6dc9357SAndroid Build Coastguard Worker res = S_FALSE;
113*f6dc9357SAndroid Build Coastguard Worker break;
114*f6dc9357SAndroid Build Coastguard Worker }
115*f6dc9357SAndroid Build Coastguard Worker if (symbol == blockSymbol)
116*f6dc9357SAndroid Build Coastguard Worker {
117*f6dc9357SAndroid Build Coastguard Worker numBufBits = bitPos = 0;
118*f6dc9357SAndroid Build Coastguard Worker numBits = kNumMinBits;
119*f6dc9357SAndroid Build Coastguard Worker head = 257;
120*f6dc9357SAndroid Build Coastguard Worker needPrev = false;
121*f6dc9357SAndroid Build Coastguard Worker continue;
122*f6dc9357SAndroid Build Coastguard Worker }
123*f6dc9357SAndroid Build Coastguard Worker UInt32 cur = symbol;
124*f6dc9357SAndroid Build Coastguard Worker unsigned i = 0;
125*f6dc9357SAndroid Build Coastguard Worker while (cur >= 256)
126*f6dc9357SAndroid Build Coastguard Worker {
127*f6dc9357SAndroid Build Coastguard Worker _stack[i++] = _suffixes[cur];
128*f6dc9357SAndroid Build Coastguard Worker cur = _parents[cur];
129*f6dc9357SAndroid Build Coastguard Worker }
130*f6dc9357SAndroid Build Coastguard Worker _stack[i++] = (Byte)cur;
131*f6dc9357SAndroid Build Coastguard Worker if (needPrev)
132*f6dc9357SAndroid Build Coastguard Worker {
133*f6dc9357SAndroid Build Coastguard Worker _suffixes[(size_t)head - 1] = (Byte)cur;
134*f6dc9357SAndroid Build Coastguard Worker if (symbol == head - 1)
135*f6dc9357SAndroid Build Coastguard Worker _stack[0] = (Byte)cur;
136*f6dc9357SAndroid Build Coastguard Worker }
137*f6dc9357SAndroid Build Coastguard Worker do
138*f6dc9357SAndroid Build Coastguard Worker outBuffer.WriteByte((_stack[--i]));
139*f6dc9357SAndroid Build Coastguard Worker while (i > 0);
140*f6dc9357SAndroid Build Coastguard Worker if (head < numItems)
141*f6dc9357SAndroid Build Coastguard Worker {
142*f6dc9357SAndroid Build Coastguard Worker needPrev = true;
143*f6dc9357SAndroid Build Coastguard Worker _parents[head++] = (UInt16)symbol;
144*f6dc9357SAndroid Build Coastguard Worker if (head > ((UInt32)1 << numBits))
145*f6dc9357SAndroid Build Coastguard Worker {
146*f6dc9357SAndroid Build Coastguard Worker if (numBits < maxbits)
147*f6dc9357SAndroid Build Coastguard Worker {
148*f6dc9357SAndroid Build Coastguard Worker numBufBits = bitPos = 0;
149*f6dc9357SAndroid Build Coastguard Worker numBits++;
150*f6dc9357SAndroid Build Coastguard Worker }
151*f6dc9357SAndroid Build Coastguard Worker }
152*f6dc9357SAndroid Build Coastguard Worker }
153*f6dc9357SAndroid Build Coastguard Worker else
154*f6dc9357SAndroid Build Coastguard Worker needPrev = false;
155*f6dc9357SAndroid Build Coastguard Worker }
156*f6dc9357SAndroid Build Coastguard Worker // PackSize = inBuffer.GetProcessedSize();
157*f6dc9357SAndroid Build Coastguard Worker const HRESULT res2 = outBuffer.Flush();
158*f6dc9357SAndroid Build Coastguard Worker return (res == S_OK) ? res2 : res;
159*f6dc9357SAndroid Build Coastguard Worker
160*f6dc9357SAndroid Build Coastguard Worker }
161*f6dc9357SAndroid Build Coastguard Worker catch(const CInBufferException &e) { return e.ErrorCode; }
162*f6dc9357SAndroid Build Coastguard Worker catch(const COutBufferException &e) { return e.ErrorCode; }
163*f6dc9357SAndroid Build Coastguard Worker catch(...) { return S_FALSE; }
164*f6dc9357SAndroid Build Coastguard Worker }
165*f6dc9357SAndroid Build Coastguard Worker
166*f6dc9357SAndroid Build Coastguard Worker
CheckStream(const Byte * data,size_t size)167*f6dc9357SAndroid Build Coastguard Worker bool CheckStream(const Byte *data, size_t size)
168*f6dc9357SAndroid Build Coastguard Worker {
169*f6dc9357SAndroid Build Coastguard Worker if (size < 3)
170*f6dc9357SAndroid Build Coastguard Worker return false;
171*f6dc9357SAndroid Build Coastguard Worker if (data[0] != 0x1F || data[1] != 0x9D)
172*f6dc9357SAndroid Build Coastguard Worker return false;
173*f6dc9357SAndroid Build Coastguard Worker const Byte prop = data[2];
174*f6dc9357SAndroid Build Coastguard Worker if ((prop & 0x60) != 0)
175*f6dc9357SAndroid Build Coastguard Worker return false;
176*f6dc9357SAndroid Build Coastguard Worker const unsigned maxbits = prop & kNumBitsMask;
177*f6dc9357SAndroid Build Coastguard Worker if (maxbits < kNumMinBits || maxbits > kNumMaxBits)
178*f6dc9357SAndroid Build Coastguard Worker return false;
179*f6dc9357SAndroid Build Coastguard Worker const UInt32 numItems = (UInt32)1 << maxbits;
180*f6dc9357SAndroid Build Coastguard Worker const UInt32 blockSymbol = ((prop & kBlockModeMask) != 0) ? 256 : ((UInt32)1 << kNumMaxBits);
181*f6dc9357SAndroid Build Coastguard Worker unsigned numBits = kNumMinBits;
182*f6dc9357SAndroid Build Coastguard Worker UInt32 head = (blockSymbol == 256) ? 257 : 256;
183*f6dc9357SAndroid Build Coastguard Worker unsigned bitPos = 0;
184*f6dc9357SAndroid Build Coastguard Worker unsigned numBufBits = 0;
185*f6dc9357SAndroid Build Coastguard Worker Byte buf[kNumMaxBits + 4];
186*f6dc9357SAndroid Build Coastguard Worker data += 3;
187*f6dc9357SAndroid Build Coastguard Worker size -= 3;
188*f6dc9357SAndroid Build Coastguard Worker // printf("\n\n");
189*f6dc9357SAndroid Build Coastguard Worker for (;;)
190*f6dc9357SAndroid Build Coastguard Worker {
191*f6dc9357SAndroid Build Coastguard Worker if (numBufBits == bitPos)
192*f6dc9357SAndroid Build Coastguard Worker {
193*f6dc9357SAndroid Build Coastguard Worker const unsigned num = (numBits < size) ? numBits : (unsigned)size;
194*f6dc9357SAndroid Build Coastguard Worker memcpy(buf, data, num);
195*f6dc9357SAndroid Build Coastguard Worker data += num;
196*f6dc9357SAndroid Build Coastguard Worker size -= num;
197*f6dc9357SAndroid Build Coastguard Worker numBufBits = num * 8;
198*f6dc9357SAndroid Build Coastguard Worker bitPos = 0;
199*f6dc9357SAndroid Build Coastguard Worker }
200*f6dc9357SAndroid Build Coastguard Worker const unsigned bytePos = bitPos >> 3;
201*f6dc9357SAndroid Build Coastguard Worker UInt32 symbol = buf[bytePos] | ((UInt32)buf[bytePos + 1] << 8) | ((UInt32)buf[bytePos + 2] << 16);
202*f6dc9357SAndroid Build Coastguard Worker symbol >>= (bitPos & 7);
203*f6dc9357SAndroid Build Coastguard Worker symbol &= ((UInt32)1 << numBits) - 1;
204*f6dc9357SAndroid Build Coastguard Worker bitPos += numBits;
205*f6dc9357SAndroid Build Coastguard Worker if (bitPos > numBufBits)
206*f6dc9357SAndroid Build Coastguard Worker {
207*f6dc9357SAndroid Build Coastguard Worker // printf(" OK", symbol);
208*f6dc9357SAndroid Build Coastguard Worker return true;
209*f6dc9357SAndroid Build Coastguard Worker }
210*f6dc9357SAndroid Build Coastguard Worker // printf("%3X ", symbol);
211*f6dc9357SAndroid Build Coastguard Worker if (symbol >= head)
212*f6dc9357SAndroid Build Coastguard Worker return false;
213*f6dc9357SAndroid Build Coastguard Worker if (symbol == blockSymbol)
214*f6dc9357SAndroid Build Coastguard Worker {
215*f6dc9357SAndroid Build Coastguard Worker numBufBits = bitPos = 0;
216*f6dc9357SAndroid Build Coastguard Worker numBits = kNumMinBits;
217*f6dc9357SAndroid Build Coastguard Worker head = 257;
218*f6dc9357SAndroid Build Coastguard Worker continue;
219*f6dc9357SAndroid Build Coastguard Worker }
220*f6dc9357SAndroid Build Coastguard Worker if (head < numItems)
221*f6dc9357SAndroid Build Coastguard Worker {
222*f6dc9357SAndroid Build Coastguard Worker head++;
223*f6dc9357SAndroid Build Coastguard Worker if (head > ((UInt32)1 << numBits))
224*f6dc9357SAndroid Build Coastguard Worker {
225*f6dc9357SAndroid Build Coastguard Worker if (numBits < maxbits)
226*f6dc9357SAndroid Build Coastguard Worker {
227*f6dc9357SAndroid Build Coastguard Worker numBufBits = bitPos = 0;
228*f6dc9357SAndroid Build Coastguard Worker numBits++;
229*f6dc9357SAndroid Build Coastguard Worker }
230*f6dc9357SAndroid Build Coastguard Worker }
231*f6dc9357SAndroid Build Coastguard Worker }
232*f6dc9357SAndroid Build Coastguard Worker }
233*f6dc9357SAndroid Build Coastguard Worker }
234*f6dc9357SAndroid Build Coastguard Worker
235*f6dc9357SAndroid Build Coastguard Worker }}
236