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