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