1*f6dc9357SAndroid Build Coastguard Worker // ShrinkDecoder.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 "../../../C/Alloc.h"
6*f6dc9357SAndroid Build Coastguard Worker
7*f6dc9357SAndroid Build Coastguard Worker #include "../Common/InBuffer.h"
8*f6dc9357SAndroid Build Coastguard Worker #include "../Common/OutBuffer.h"
9*f6dc9357SAndroid Build Coastguard Worker
10*f6dc9357SAndroid Build Coastguard Worker #include "BitlDecoder.h"
11*f6dc9357SAndroid Build Coastguard Worker #include "ShrinkDecoder.h"
12*f6dc9357SAndroid Build Coastguard Worker
13*f6dc9357SAndroid Build Coastguard Worker namespace NCompress {
14*f6dc9357SAndroid Build Coastguard Worker namespace NShrink {
15*f6dc9357SAndroid Build Coastguard Worker
16*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kEmpty = 256; // kNumItems;
17*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kBufferSize = (1 << 18);
18*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumMinBits = 9;
19*f6dc9357SAndroid Build Coastguard Worker
CodeReal(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress)20*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
21*f6dc9357SAndroid Build Coastguard Worker const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
22*f6dc9357SAndroid Build Coastguard Worker {
23*f6dc9357SAndroid Build Coastguard Worker NBitl::CBaseDecoder<CInBuffer> inBuffer;
24*f6dc9357SAndroid Build Coastguard Worker COutBuffer outBuffer;
25*f6dc9357SAndroid Build Coastguard Worker
26*f6dc9357SAndroid Build Coastguard Worker if (!inBuffer.Create(kBufferSize))
27*f6dc9357SAndroid Build Coastguard Worker return E_OUTOFMEMORY;
28*f6dc9357SAndroid Build Coastguard Worker if (!outBuffer.Create(kBufferSize))
29*f6dc9357SAndroid Build Coastguard Worker return E_OUTOFMEMORY;
30*f6dc9357SAndroid Build Coastguard Worker
31*f6dc9357SAndroid Build Coastguard Worker inBuffer.SetStream(inStream);
32*f6dc9357SAndroid Build Coastguard Worker inBuffer.Init();
33*f6dc9357SAndroid Build Coastguard Worker
34*f6dc9357SAndroid Build Coastguard Worker outBuffer.SetStream(outStream);
35*f6dc9357SAndroid Build Coastguard Worker outBuffer.Init();
36*f6dc9357SAndroid Build Coastguard Worker
37*f6dc9357SAndroid Build Coastguard Worker {
38*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < kNumItems; i++)
39*f6dc9357SAndroid Build Coastguard Worker _parents[i] = kEmpty;
40*f6dc9357SAndroid Build Coastguard Worker }
41*f6dc9357SAndroid Build Coastguard Worker
42*f6dc9357SAndroid Build Coastguard Worker UInt64 outPrev = 0, inPrev = 0;
43*f6dc9357SAndroid Build Coastguard Worker unsigned numBits = kNumMinBits;
44*f6dc9357SAndroid Build Coastguard Worker unsigned head = 257;
45*f6dc9357SAndroid Build Coastguard Worker int lastSym = -1;
46*f6dc9357SAndroid Build Coastguard Worker Byte lastChar = 0;
47*f6dc9357SAndroid Build Coastguard Worker bool moreOut = false;
48*f6dc9357SAndroid Build Coastguard Worker
49*f6dc9357SAndroid Build Coastguard Worker HRESULT res = S_FALSE;
50*f6dc9357SAndroid Build Coastguard Worker
51*f6dc9357SAndroid Build Coastguard Worker for (;;)
52*f6dc9357SAndroid Build Coastguard Worker {
53*f6dc9357SAndroid Build Coastguard Worker _inProcessed = inBuffer.GetProcessedSize();
54*f6dc9357SAndroid Build Coastguard Worker const UInt64 nowPos = outBuffer.GetProcessedSize();
55*f6dc9357SAndroid Build Coastguard Worker
56*f6dc9357SAndroid Build Coastguard Worker bool eofCheck = false;
57*f6dc9357SAndroid Build Coastguard Worker
58*f6dc9357SAndroid Build Coastguard Worker if (outSize && nowPos >= *outSize)
59*f6dc9357SAndroid Build Coastguard Worker {
60*f6dc9357SAndroid Build Coastguard Worker if (!_fullStreamMode || moreOut)
61*f6dc9357SAndroid Build Coastguard Worker {
62*f6dc9357SAndroid Build Coastguard Worker res = S_OK;
63*f6dc9357SAndroid Build Coastguard Worker break;
64*f6dc9357SAndroid Build Coastguard Worker }
65*f6dc9357SAndroid Build Coastguard Worker eofCheck = true;
66*f6dc9357SAndroid Build Coastguard Worker // Is specSym(=256) allowed after end of stream ?
67*f6dc9357SAndroid Build Coastguard Worker // Do we need to read it here ?
68*f6dc9357SAndroid Build Coastguard Worker }
69*f6dc9357SAndroid Build Coastguard Worker
70*f6dc9357SAndroid Build Coastguard Worker if (progress)
71*f6dc9357SAndroid Build Coastguard Worker {
72*f6dc9357SAndroid Build Coastguard Worker if (nowPos - outPrev >= (1 << 20) || _inProcessed - inPrev >= (1 << 20))
73*f6dc9357SAndroid Build Coastguard Worker {
74*f6dc9357SAndroid Build Coastguard Worker outPrev = nowPos;
75*f6dc9357SAndroid Build Coastguard Worker inPrev = _inProcessed;
76*f6dc9357SAndroid Build Coastguard Worker res = progress->SetRatioInfo(&_inProcessed, &nowPos);
77*f6dc9357SAndroid Build Coastguard Worker if (res != SZ_OK)
78*f6dc9357SAndroid Build Coastguard Worker {
79*f6dc9357SAndroid Build Coastguard Worker // break;
80*f6dc9357SAndroid Build Coastguard Worker return res;
81*f6dc9357SAndroid Build Coastguard Worker }
82*f6dc9357SAndroid Build Coastguard Worker }
83*f6dc9357SAndroid Build Coastguard Worker }
84*f6dc9357SAndroid Build Coastguard Worker
85*f6dc9357SAndroid Build Coastguard Worker UInt32 sym = inBuffer.ReadBits(numBits);
86*f6dc9357SAndroid Build Coastguard Worker
87*f6dc9357SAndroid Build Coastguard Worker if (inBuffer.ExtraBitsWereRead())
88*f6dc9357SAndroid Build Coastguard Worker {
89*f6dc9357SAndroid Build Coastguard Worker res = S_OK;
90*f6dc9357SAndroid Build Coastguard Worker break;
91*f6dc9357SAndroid Build Coastguard Worker }
92*f6dc9357SAndroid Build Coastguard Worker
93*f6dc9357SAndroid Build Coastguard Worker if (sym == 256)
94*f6dc9357SAndroid Build Coastguard Worker {
95*f6dc9357SAndroid Build Coastguard Worker sym = inBuffer.ReadBits(numBits);
96*f6dc9357SAndroid Build Coastguard Worker
97*f6dc9357SAndroid Build Coastguard Worker if (inBuffer.ExtraBitsWereRead())
98*f6dc9357SAndroid Build Coastguard Worker break;
99*f6dc9357SAndroid Build Coastguard Worker
100*f6dc9357SAndroid Build Coastguard Worker if (sym == 1)
101*f6dc9357SAndroid Build Coastguard Worker {
102*f6dc9357SAndroid Build Coastguard Worker if (numBits >= kNumMaxBits)
103*f6dc9357SAndroid Build Coastguard Worker break;
104*f6dc9357SAndroid Build Coastguard Worker numBits++;
105*f6dc9357SAndroid Build Coastguard Worker continue;
106*f6dc9357SAndroid Build Coastguard Worker }
107*f6dc9357SAndroid Build Coastguard Worker if (sym != 2)
108*f6dc9357SAndroid Build Coastguard Worker {
109*f6dc9357SAndroid Build Coastguard Worker break;
110*f6dc9357SAndroid Build Coastguard Worker // continue; // info-zip just ignores such code
111*f6dc9357SAndroid Build Coastguard Worker }
112*f6dc9357SAndroid Build Coastguard Worker {
113*f6dc9357SAndroid Build Coastguard Worker /*
114*f6dc9357SAndroid Build Coastguard Worker ---------- Free leaf nodes ----------
115*f6dc9357SAndroid Build Coastguard Worker Note : that code can mark _parents[lastSym] as free, and next
116*f6dc9357SAndroid Build Coastguard Worker inserted node will be Orphan in that case.
117*f6dc9357SAndroid Build Coastguard Worker */
118*f6dc9357SAndroid Build Coastguard Worker
119*f6dc9357SAndroid Build Coastguard Worker unsigned i;
120*f6dc9357SAndroid Build Coastguard Worker for (i = 256; i < kNumItems; i++)
121*f6dc9357SAndroid Build Coastguard Worker _stack[i] = 0;
122*f6dc9357SAndroid Build Coastguard Worker for (i = 257; i < kNumItems; i++)
123*f6dc9357SAndroid Build Coastguard Worker {
124*f6dc9357SAndroid Build Coastguard Worker unsigned par = _parents[i];
125*f6dc9357SAndroid Build Coastguard Worker if (par != kEmpty)
126*f6dc9357SAndroid Build Coastguard Worker _stack[par] = 1;
127*f6dc9357SAndroid Build Coastguard Worker }
128*f6dc9357SAndroid Build Coastguard Worker for (i = 257; i < kNumItems; i++)
129*f6dc9357SAndroid Build Coastguard Worker if (_stack[i] == 0)
130*f6dc9357SAndroid Build Coastguard Worker _parents[i] = kEmpty;
131*f6dc9357SAndroid Build Coastguard Worker head = 257;
132*f6dc9357SAndroid Build Coastguard Worker continue;
133*f6dc9357SAndroid Build Coastguard Worker }
134*f6dc9357SAndroid Build Coastguard Worker }
135*f6dc9357SAndroid Build Coastguard Worker
136*f6dc9357SAndroid Build Coastguard Worker if (eofCheck)
137*f6dc9357SAndroid Build Coastguard Worker {
138*f6dc9357SAndroid Build Coastguard Worker // It's can be error case.
139*f6dc9357SAndroid Build Coastguard Worker // That error can be detected later in (*inSize != _inProcessed) check.
140*f6dc9357SAndroid Build Coastguard Worker res = S_OK;
141*f6dc9357SAndroid Build Coastguard Worker break;
142*f6dc9357SAndroid Build Coastguard Worker }
143*f6dc9357SAndroid Build Coastguard Worker
144*f6dc9357SAndroid Build Coastguard Worker bool needPrev = false;
145*f6dc9357SAndroid Build Coastguard Worker if (head < kNumItems && lastSym >= 0)
146*f6dc9357SAndroid Build Coastguard Worker {
147*f6dc9357SAndroid Build Coastguard Worker while (head < kNumItems && _parents[head] != kEmpty)
148*f6dc9357SAndroid Build Coastguard Worker head++;
149*f6dc9357SAndroid Build Coastguard Worker if (head < kNumItems)
150*f6dc9357SAndroid Build Coastguard Worker {
151*f6dc9357SAndroid Build Coastguard Worker /*
152*f6dc9357SAndroid Build Coastguard Worker if (head == lastSym), it updates Orphan to self-linked Orphan and creates two problems:
153*f6dc9357SAndroid Build Coastguard Worker 1) we must check _stack[i++] overflow in code that walks tree nodes.
154*f6dc9357SAndroid Build Coastguard Worker 2) self-linked node can not be removed. So such self-linked nodes can occupy all _parents items.
155*f6dc9357SAndroid Build Coastguard Worker */
156*f6dc9357SAndroid Build Coastguard Worker needPrev = true;
157*f6dc9357SAndroid Build Coastguard Worker _parents[head] = (UInt16)lastSym;
158*f6dc9357SAndroid Build Coastguard Worker _suffixes[head] = (Byte)lastChar;
159*f6dc9357SAndroid Build Coastguard Worker head++;
160*f6dc9357SAndroid Build Coastguard Worker }
161*f6dc9357SAndroid Build Coastguard Worker }
162*f6dc9357SAndroid Build Coastguard Worker
163*f6dc9357SAndroid Build Coastguard Worker lastSym = (int)sym;
164*f6dc9357SAndroid Build Coastguard Worker unsigned cur = sym;
165*f6dc9357SAndroid Build Coastguard Worker unsigned i = 0;
166*f6dc9357SAndroid Build Coastguard Worker
167*f6dc9357SAndroid Build Coastguard Worker while (cur >= 256)
168*f6dc9357SAndroid Build Coastguard Worker {
169*f6dc9357SAndroid Build Coastguard Worker _stack[i++] = _suffixes[cur];
170*f6dc9357SAndroid Build Coastguard Worker cur = _parents[cur];
171*f6dc9357SAndroid Build Coastguard Worker // don't change that code:
172*f6dc9357SAndroid Build Coastguard Worker // Orphan Check and self-linked Orphan check (_stack overflow check);
173*f6dc9357SAndroid Build Coastguard Worker if (cur == kEmpty || i >= kNumItems)
174*f6dc9357SAndroid Build Coastguard Worker break;
175*f6dc9357SAndroid Build Coastguard Worker }
176*f6dc9357SAndroid Build Coastguard Worker
177*f6dc9357SAndroid Build Coastguard Worker if (cur == kEmpty || i >= kNumItems)
178*f6dc9357SAndroid Build Coastguard Worker break;
179*f6dc9357SAndroid Build Coastguard Worker
180*f6dc9357SAndroid Build Coastguard Worker _stack[i++] = (Byte)cur;
181*f6dc9357SAndroid Build Coastguard Worker lastChar = (Byte)cur;
182*f6dc9357SAndroid Build Coastguard Worker
183*f6dc9357SAndroid Build Coastguard Worker if (needPrev)
184*f6dc9357SAndroid Build Coastguard Worker _suffixes[(size_t)head - 1] = (Byte)cur;
185*f6dc9357SAndroid Build Coastguard Worker
186*f6dc9357SAndroid Build Coastguard Worker if (outSize)
187*f6dc9357SAndroid Build Coastguard Worker {
188*f6dc9357SAndroid Build Coastguard Worker const UInt64 limit = *outSize - nowPos;
189*f6dc9357SAndroid Build Coastguard Worker if (i > limit)
190*f6dc9357SAndroid Build Coastguard Worker {
191*f6dc9357SAndroid Build Coastguard Worker moreOut = true;
192*f6dc9357SAndroid Build Coastguard Worker i = (unsigned)limit;
193*f6dc9357SAndroid Build Coastguard Worker }
194*f6dc9357SAndroid Build Coastguard Worker }
195*f6dc9357SAndroid Build Coastguard Worker
196*f6dc9357SAndroid Build Coastguard Worker do
197*f6dc9357SAndroid Build Coastguard Worker outBuffer.WriteByte(_stack[--i]);
198*f6dc9357SAndroid Build Coastguard Worker while (i);
199*f6dc9357SAndroid Build Coastguard Worker }
200*f6dc9357SAndroid Build Coastguard Worker
201*f6dc9357SAndroid Build Coastguard Worker RINOK(outBuffer.Flush())
202*f6dc9357SAndroid Build Coastguard Worker
203*f6dc9357SAndroid Build Coastguard Worker if (res == S_OK)
204*f6dc9357SAndroid Build Coastguard Worker if (_fullStreamMode)
205*f6dc9357SAndroid Build Coastguard Worker {
206*f6dc9357SAndroid Build Coastguard Worker if (moreOut)
207*f6dc9357SAndroid Build Coastguard Worker res = S_FALSE;
208*f6dc9357SAndroid Build Coastguard Worker const UInt64 nowPos = outBuffer.GetProcessedSize();
209*f6dc9357SAndroid Build Coastguard Worker if (outSize && *outSize != nowPos)
210*f6dc9357SAndroid Build Coastguard Worker res = S_FALSE;
211*f6dc9357SAndroid Build Coastguard Worker if (inSize && *inSize != _inProcessed)
212*f6dc9357SAndroid Build Coastguard Worker res = S_FALSE;
213*f6dc9357SAndroid Build Coastguard Worker }
214*f6dc9357SAndroid Build Coastguard Worker
215*f6dc9357SAndroid Build Coastguard Worker return res;
216*f6dc9357SAndroid Build Coastguard Worker }
217*f6dc9357SAndroid Build Coastguard Worker
218*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CDecoder::Code (ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress))219*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
220*f6dc9357SAndroid Build Coastguard Worker const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
221*f6dc9357SAndroid Build Coastguard Worker {
222*f6dc9357SAndroid Build Coastguard Worker try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
223*f6dc9357SAndroid Build Coastguard Worker // catch(const CInBufferException &e) { return e.ErrorCode; }
224*f6dc9357SAndroid Build Coastguard Worker // catch(const COutBufferException &e) { return e.ErrorCode; }
225*f6dc9357SAndroid Build Coastguard Worker catch(const CSystemException &e) { return e.ErrorCode; }
226*f6dc9357SAndroid Build Coastguard Worker catch(...) { return S_FALSE; }
227*f6dc9357SAndroid Build Coastguard Worker }
228*f6dc9357SAndroid Build Coastguard Worker
229*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CDecoder::SetFinishMode (UInt32 finishMode))230*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
231*f6dc9357SAndroid Build Coastguard Worker {
232*f6dc9357SAndroid Build Coastguard Worker _fullStreamMode = (finishMode != 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(CDecoder::GetInStreamProcessedSize (UInt64 * value))237*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value))
238*f6dc9357SAndroid Build Coastguard Worker {
239*f6dc9357SAndroid Build Coastguard Worker *value = _inProcessed;
240*f6dc9357SAndroid Build Coastguard Worker return S_OK;
241*f6dc9357SAndroid Build Coastguard Worker }
242*f6dc9357SAndroid Build Coastguard Worker
243*f6dc9357SAndroid Build Coastguard Worker
244*f6dc9357SAndroid Build Coastguard Worker }}
245