1 // LzxDecoder.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../Common/Defs.h"
6
7 #include "LzxDecoder.h"
8
9 namespace NCompress {
10 namespace NLzx {
11
12 const int kLenIdNeedInit = -2;
13
CDecoder(bool wimMode)14 CDecoder::CDecoder(bool wimMode):
15 _keepHistory(false),
16 _skipByte(false),
17 _wimMode(wimMode)
18 {
19 m_x86ConvertOutStreamSpec = new Cx86ConvertOutStream;
20 m_x86ConvertOutStream = m_x86ConvertOutStreamSpec;
21 }
22
ReleaseStreams()23 void CDecoder::ReleaseStreams()
24 {
25 m_OutWindowStream.ReleaseStream();
26 m_InBitStream.ReleaseStream();
27 m_x86ConvertOutStreamSpec->ReleaseStream();
28 }
29
Flush()30 STDMETHODIMP CDecoder::Flush()
31 {
32 RINOK(m_OutWindowStream.Flush());
33 return m_x86ConvertOutStreamSpec->Flush();
34 }
35
ReadBits(int numBits)36 UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); }
37
38 #define RIF(x) { if (!(x)) return false; }
39
ReadTable(Byte * lastLevels,Byte * newLevels,UInt32 numSymbols)40 bool CDecoder::ReadTable(Byte *lastLevels, Byte *newLevels, UInt32 numSymbols)
41 {
42 Byte levelLevels[kLevelTableSize];
43 UInt32 i;
44 for (i = 0; i < kLevelTableSize; i++)
45 levelLevels[i] = (Byte)ReadBits(kNumBitsForPreTreeLevel);
46 RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
47 int num = 0;
48 Byte symbol = 0;
49 for (i = 0; i < numSymbols;)
50 {
51 if (num != 0)
52 {
53 lastLevels[i] = newLevels[i] = symbol;
54 i++;
55 num--;
56 continue;
57 }
58 UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
59 if (number == kLevelSymbolZeros)
60 {
61 num = kLevelSymbolZerosStartValue + (int)ReadBits(kLevelSymbolZerosNumBits);
62 symbol = 0;
63 }
64 else if (number == kLevelSymbolZerosBig)
65 {
66 num = kLevelSymbolZerosBigStartValue + (int)ReadBits(kLevelSymbolZerosBigNumBits);
67 symbol = 0;
68 }
69 else if (number == kLevelSymbolSame || number <= kNumHuffmanBits)
70 {
71 if (number <= kNumHuffmanBits)
72 num = 1;
73 else
74 {
75 num = kLevelSymbolSameStartValue + (int)ReadBits(kLevelSymbolSameNumBits);
76 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
77 if (number > kNumHuffmanBits)
78 return false;
79 }
80 symbol = Byte((17 + lastLevels[i] - number) % (kNumHuffmanBits + 1));
81 }
82 else
83 return false;
84 }
85 return true;
86 }
87
ReadTables(void)88 bool CDecoder::ReadTables(void)
89 {
90 Byte newLevels[kMaxTableSize];
91 {
92 if (_skipByte)
93 m_InBitStream.DirectReadByte();
94 m_InBitStream.Normalize();
95
96 int blockType = (int)ReadBits(kNumBlockTypeBits);
97 if (blockType > kBlockTypeUncompressed)
98 return false;
99 if (_wimMode)
100 if (ReadBits(1) == 1)
101 m_UnCompressedBlockSize = (1 << 15);
102 else
103 m_UnCompressedBlockSize = ReadBits(16);
104 else
105 m_UnCompressedBlockSize = m_InBitStream.ReadBitsBig(kUncompressedBlockSizeNumBits);
106
107 m_IsUncompressedBlock = (blockType == kBlockTypeUncompressed);
108
109 _skipByte = (m_IsUncompressedBlock && ((m_UnCompressedBlockSize & 1) != 0));
110
111 if (m_IsUncompressedBlock)
112 {
113 ReadBits(16 - m_InBitStream.GetBitPosition());
114 if (!m_InBitStream.ReadUInt32(m_RepDistances[0]))
115 return false;
116 m_RepDistances[0]--;
117 for (int i = 1; i < kNumRepDistances; i++)
118 {
119 UInt32 rep = 0;
120 for (int j = 0; j < 4; j++)
121 rep |= (UInt32)m_InBitStream.DirectReadByte() << (8 * j);
122 m_RepDistances[i] = rep - 1;
123 }
124 return true;
125 }
126 m_AlignIsUsed = (blockType == kBlockTypeAligned);
127 if (m_AlignIsUsed)
128 {
129 for(int i = 0; i < kAlignTableSize; i++)
130 newLevels[i] = (Byte)ReadBits(kNumBitsForAlignLevel);
131 RIF(m_AlignDecoder.SetCodeLengths(newLevels));
132 }
133 }
134
135 RIF(ReadTable(m_LastMainLevels, newLevels, 256));
136 RIF(ReadTable(m_LastMainLevels + 256, newLevels + 256, m_NumPosLenSlots));
137 for (UInt32 i = 256 + m_NumPosLenSlots; i < kMainTableSize; i++)
138 newLevels[i] = 0;
139 RIF(m_MainDecoder.SetCodeLengths(newLevels));
140
141 RIF(ReadTable(m_LastLenLevels, newLevels, kNumLenSymbols));
142 return m_LenDecoder.SetCodeLengths(newLevels);
143 }
144
145 class CDecoderFlusher
146 {
147 CDecoder *m_Decoder;
148 public:
149 bool NeedFlush;
CDecoderFlusher(CDecoder * decoder)150 CDecoderFlusher(CDecoder *decoder): m_Decoder(decoder), NeedFlush(true) {}
~CDecoderFlusher()151 ~CDecoderFlusher()
152 {
153 if (NeedFlush)
154 m_Decoder->Flush();
155 m_Decoder->ReleaseStreams();
156 }
157 };
158
159
ClearPrevLevels()160 void CDecoder::ClearPrevLevels()
161 {
162 int i;
163 for (i = 0; i < kMainTableSize; i++)
164 m_LastMainLevels[i] = 0;
165 for (i = 0; i < kNumLenSymbols; i++)
166 m_LastLenLevels[i] = 0;
167 };
168
169
CodeSpec(UInt32 curSize)170 HRESULT CDecoder::CodeSpec(UInt32 curSize)
171 {
172 if (_remainLen == kLenIdNeedInit)
173 {
174 _remainLen = 0;
175 m_InBitStream.Init();
176 if (!_keepHistory || !m_IsUncompressedBlock)
177 m_InBitStream.Normalize();
178 if (!_keepHistory)
179 {
180 _skipByte = false;
181 m_UnCompressedBlockSize = 0;
182 ClearPrevLevels();
183 UInt32 i86TranslationSize = 12000000;
184 bool translationMode = true;
185 if (!_wimMode)
186 {
187 translationMode = (ReadBits(1) != 0);
188 if (translationMode)
189 {
190 i86TranslationSize = ReadBits(16) << 16;
191 i86TranslationSize |= ReadBits(16);
192 }
193 }
194 m_x86ConvertOutStreamSpec->Init(translationMode, i86TranslationSize);
195
196 for(int i = 0 ; i < kNumRepDistances; i++)
197 m_RepDistances[i] = 0;
198 }
199 }
200
201 while(_remainLen > 0 && curSize > 0)
202 {
203 m_OutWindowStream.PutByte(m_OutWindowStream.GetByte(m_RepDistances[0]));
204 _remainLen--;
205 curSize--;
206 }
207
208 while(curSize > 0)
209 {
210 if (m_UnCompressedBlockSize == 0)
211 if (!ReadTables())
212 return S_FALSE;
213 UInt32 next = (Int32)MyMin(m_UnCompressedBlockSize, curSize);
214 curSize -= next;
215 m_UnCompressedBlockSize -= next;
216 if (m_IsUncompressedBlock)
217 {
218 while(next > 0)
219 {
220 m_OutWindowStream.PutByte(m_InBitStream.DirectReadByte());
221 next--;
222 }
223 }
224 else while(next > 0)
225 {
226 UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
227 if (number < 256)
228 {
229 m_OutWindowStream.PutByte((Byte)number);
230 next--;
231 }
232 else
233 {
234 UInt32 posLenSlot = number - 256;
235 if (posLenSlot >= m_NumPosLenSlots)
236 return S_FALSE;
237 UInt32 posSlot = posLenSlot / kNumLenSlots;
238 UInt32 lenSlot = posLenSlot % kNumLenSlots;
239 UInt32 len = kMatchMinLen + lenSlot;
240 if (lenSlot == kNumLenSlots - 1)
241 {
242 UInt32 lenTemp = m_LenDecoder.DecodeSymbol(&m_InBitStream);
243 if (lenTemp >= kNumLenSymbols)
244 return S_FALSE;
245 len += lenTemp;
246 }
247
248 if (posSlot < kNumRepDistances)
249 {
250 UInt32 distance = m_RepDistances[posSlot];
251 m_RepDistances[posSlot] = m_RepDistances[0];
252 m_RepDistances[0] = distance;
253 }
254 else
255 {
256 UInt32 distance;
257 int numDirectBits;
258 if (posSlot < kNumPowerPosSlots)
259 {
260 numDirectBits = (int)(posSlot >> 1) - 1;
261 distance = ((2 | (posSlot & 1)) << numDirectBits);
262 }
263 else
264 {
265 numDirectBits = kNumLinearPosSlotBits;
266 distance = ((posSlot - 0x22) << kNumLinearPosSlotBits);
267 }
268
269 if (m_AlignIsUsed && numDirectBits >= kNumAlignBits)
270 {
271 distance += (m_InBitStream.ReadBits(numDirectBits - kNumAlignBits) << kNumAlignBits);
272 UInt32 alignTemp = m_AlignDecoder.DecodeSymbol(&m_InBitStream);
273 if (alignTemp >= kAlignTableSize)
274 return S_FALSE;
275 distance += alignTemp;
276 }
277 else
278 distance += m_InBitStream.ReadBits(numDirectBits);
279 m_RepDistances[2] = m_RepDistances[1];
280 m_RepDistances[1] = m_RepDistances[0];
281 m_RepDistances[0] = distance - kNumRepDistances;
282 }
283
284 UInt32 locLen = len;
285 if (locLen > next)
286 locLen = next;
287
288 if (!m_OutWindowStream.CopyBlock(m_RepDistances[0], locLen))
289 return S_FALSE;
290
291 len -= locLen;
292 next -= locLen;
293 if (len != 0)
294 {
295 _remainLen = (int)len;
296 return S_OK;
297 }
298 }
299 }
300 }
301 return S_OK;
302 }
303
CodeReal(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 * outSize,ICompressProgressInfo * progress)304 HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
305 const UInt64 *, const UInt64 *outSize, ICompressProgressInfo *progress)
306 {
307 if (outSize == NULL)
308 return E_INVALIDARG;
309 UInt64 size = *outSize;
310
311 RINOK(SetInStream(inStream));
312 m_x86ConvertOutStreamSpec->SetStream(outStream);
313 m_OutWindowStream.SetStream(m_x86ConvertOutStream);
314 RINOK(SetOutStreamSize(outSize));
315
316 CDecoderFlusher flusher(this);
317
318 const UInt64 start = m_OutWindowStream.GetProcessedSize();
319 for (;;)
320 {
321 UInt32 curSize = 1 << 18;
322 UInt64 rem = size - (m_OutWindowStream.GetProcessedSize() - start);
323 if (curSize > rem)
324 curSize = (UInt32)rem;
325 if (curSize == 0)
326 break;
327 RINOK(CodeSpec(curSize));
328 if (progress != NULL)
329 {
330 UInt64 inSize = m_InBitStream.GetProcessedSize();
331 UInt64 nowPos64 = m_OutWindowStream.GetProcessedSize() - start;
332 RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
333 }
334 }
335 flusher.NeedFlush = false;
336 return Flush();
337 }
338
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress)339 HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
340 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
341 {
342 try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
343 catch(const CLzOutWindowException &e) { return e.ErrorCode; }
344 catch(...) { return S_FALSE; }
345 }
346
SetInStream(ISequentialInStream * inStream)347 STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
348 {
349 m_InBitStream.SetStream(inStream);
350 return S_OK;
351 }
352
ReleaseInStream()353 STDMETHODIMP CDecoder::ReleaseInStream()
354 {
355 m_InBitStream.ReleaseStream();
356 return S_OK;
357 }
358
SetOutStreamSize(const UInt64 * outSize)359 STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
360 {
361 if (outSize == NULL)
362 return E_FAIL;
363 _remainLen = kLenIdNeedInit;
364 m_OutWindowStream.Init(_keepHistory);
365 return S_OK;
366 }
367
SetParams(int numDictBits)368 HRESULT CDecoder::SetParams(int numDictBits)
369 {
370 if (numDictBits < kNumDictionaryBitsMin || numDictBits > kNumDictionaryBitsMax)
371 return E_INVALIDARG;
372 UInt32 numPosSlots;
373 if (numDictBits < 20)
374 numPosSlots = 30 + (numDictBits - 15) * 2;
375 else if (numDictBits == 20)
376 numPosSlots = 42;
377 else
378 numPosSlots = 50;
379 m_NumPosLenSlots = numPosSlots * kNumLenSlots;
380 if (!m_OutWindowStream.Create(kDictionarySizeMax))
381 return E_OUTOFMEMORY;
382 if (!m_InBitStream.Create(1 << 16))
383 return E_OUTOFMEMORY;
384 return S_OK;
385 }
386
387 }}
388