xref: /aosp_15_r20/external/lzma/CPP/7zip/Compress/ShrinkDecoder.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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