xref: /aosp_15_r20/external/lzma/CPP/7zip/Compress/LzhDecoder.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // LzhDecoder.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "LzhDecoder.h"
6 
7 namespace NCompress{
8 namespace NLzh {
9 namespace NDecoder {
10 
11 static const UInt32 kWindowSizeMin = 1 << 16;
12 
ReadTP(unsigned num,unsigned numBits,int spec)13 bool CCoder::ReadTP(unsigned num, unsigned numBits, int spec)
14 {
15   _symbolT = -1;
16 
17   const unsigned n = (unsigned)_inBitStream.ReadBits(numBits);
18   if (n == 0)
19   {
20     const unsigned s = (unsigned)_inBitStream.ReadBits(numBits);
21     _symbolT = (int)s;
22     return (s < num);
23   }
24   if (n > num)
25     return false;
26 
27   {
28     Byte lens[NPT];
29     unsigned i;
30     for (i = 0; i < NPT; i++)
31       lens[i] = 0;
32     i = 0;
33     do
34     {
35       unsigned val = (unsigned)_inBitStream.GetValue(16);
36       unsigned c = val >> 13;
37       unsigned mov = 3;
38       if (c == 7)
39       {
40         while (val & (1 << 12))
41         {
42           val += val;
43           c++;
44         }
45         if (c > 16)
46           return false;
47         mov = c - 3;
48       }
49       lens[i++] = (Byte)c;
50       _inBitStream.MovePos(mov);
51       if ((int)i == spec)
52         i += _inBitStream.ReadBits(2);
53     }
54     while (i < n);
55 
56     return _decoderT.Build(lens, NHuffman::k_BuildMode_Full);
57   }
58 }
59 
60 static const unsigned NUM_C_BITS = 9;
61 
ReadC()62 bool CCoder::ReadC()
63 {
64   _symbolC = -1;
65 
66   const unsigned n = (unsigned)_inBitStream.ReadBits(NUM_C_BITS);
67   if (n == 0)
68   {
69     const unsigned s = (unsigned)_inBitStream.ReadBits(NUM_C_BITS);
70     _symbolC = (int)s;
71     return (s < NC);
72   }
73   if (n > NC)
74     return false;
75 
76   {
77     Byte lens[NC];
78     unsigned i = 0;
79     do
80     {
81       unsigned c = (unsigned)_symbolT;
82       if (_symbolT < 0)
83         c = _decoderT.DecodeFull(&_inBitStream);
84 
85       if (c <= 2)
86       {
87         if (c == 0)
88           c = 1;
89         else if (c == 1)
90           c = _inBitStream.ReadBits(4) + 3;
91         else
92           c = _inBitStream.ReadBits(NUM_C_BITS) + 20;
93 
94         if (i + c > n)
95           return false;
96 
97         do
98           lens[i++] = 0;
99         while (--c);
100       }
101       else
102         lens[i++] = (Byte)(c - 2);
103     }
104     while (i < n);
105 
106     while (i < NC) lens[i++] = 0;
107     return _decoderC.Build(lens, /* n, */ NHuffman::k_BuildMode_Full);
108   }
109 }
110 
CodeReal(UInt32 rem,ICompressProgressInfo * progress)111 HRESULT CCoder::CodeReal(UInt32 rem, ICompressProgressInfo *progress)
112 {
113   UInt32 blockSize = 0;
114 
115   while (rem != 0)
116   {
117     if (blockSize == 0)
118     {
119       if (_inBitStream.ExtraBitsWereRead())
120         return S_FALSE;
121       if (progress)
122       {
123         const UInt64 packSize = _inBitStream.GetProcessedSize();
124         const UInt64 pos = _outWindow.GetProcessedSize();
125         RINOK(progress->SetRatioInfo(&packSize, &pos))
126       }
127 
128       blockSize = _inBitStream.ReadBits(16);
129       if (blockSize == 0)
130         return S_FALSE;
131 
132       if (!ReadTP(NT, 5, 3))
133         return S_FALSE;
134       if (!ReadC())
135         return S_FALSE;
136       const unsigned pbit = (DictSize <= (1 << 14) ? 4 : 5);
137       if (!ReadTP(NP, pbit, -1))
138         return S_FALSE;
139     }
140 
141     blockSize--;
142 
143     unsigned number = (unsigned)_symbolC;
144     if (_symbolC < 0)
145       number = _decoderC.DecodeFull(&_inBitStream);
146 
147     if (number < 256)
148     {
149       _outWindow.PutByte((Byte)number);
150       rem--;
151     }
152     else
153     {
154       const unsigned len = number - 256 + kMatchMinLen;
155 
156       UInt32 dist = (UInt32)(unsigned)_symbolT;
157       if (_symbolT < 0)
158         dist = (UInt32)_decoderT.DecodeFull(&_inBitStream);
159 
160       if (dist > 1)
161       {
162         dist--;
163         dist = ((UInt32)1 << dist) + _inBitStream.ReadBits((unsigned)dist);
164       }
165 
166       if (dist >= DictSize)
167         return S_FALSE;
168 
169       if (len > rem)
170       {
171         // if (FinishMode)
172         return S_FALSE;
173         // len = (unsigned)rem;
174       }
175 
176       if (!_outWindow.CopyBlock(dist, len))
177         return S_FALSE;
178       rem -= len;
179     }
180   }
181 
182   // if (FinishMode)
183   {
184     if (blockSize != 0)
185       return S_FALSE;
186     if (_inBitStream.ReadAlignBits() != 0)
187       return S_FALSE;
188   }
189   if (_inBitStream.ExtraBitsWereRead())
190     return S_FALSE;
191   return S_OK;
192 }
193 
194 
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt32 outSize,ICompressProgressInfo * progress)195 HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
196     const UInt32 outSize, ICompressProgressInfo *progress)
197 {
198   try
199   {
200     if (!_outWindow.Create(DictSize > kWindowSizeMin ? DictSize : kWindowSizeMin))
201       return E_OUTOFMEMORY;
202     if (!_inBitStream.Create(1 << 17))
203       return E_OUTOFMEMORY;
204     _outWindow.SetStream(outStream);
205     _outWindow.Init(false);
206     _inBitStream.SetStream(inStream);
207     _inBitStream.Init();
208     {
209       CCoderReleaser coderReleaser(this);
210       RINOK(CodeReal(outSize, progress))
211       coderReleaser.Disable();
212     }
213     return _outWindow.Flush();
214   }
215   catch(const CInBufferException &e) { return e.ErrorCode; }
216   catch(const CLzOutWindowException &e) { return e.ErrorCode; }
217   catch(...) { return S_FALSE; }
218 }
219 
220 }}}
221