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