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