5 #include "../../Common/Defs.h"
\r
7 #include "LzxDecoder.h"
\r
9 namespace NCompress {
\r
12 const int kLenIdNeedInit = -2;
\r
14 CDecoder::CDecoder(bool wimMode):
\r
15 _keepHistory(false),
\r
19 m_x86ConvertOutStreamSpec = new Cx86ConvertOutStream;
\r
20 m_x86ConvertOutStream = m_x86ConvertOutStreamSpec;
\r
23 void CDecoder::ReleaseStreams()
\r
25 m_OutWindowStream.ReleaseStream();
\r
26 m_InBitStream.ReleaseStream();
\r
27 m_x86ConvertOutStreamSpec->ReleaseStream();
\r
30 STDMETHODIMP CDecoder::Flush()
\r
32 RINOK(m_OutWindowStream.Flush());
\r
33 return m_x86ConvertOutStreamSpec->Flush();
\r
36 UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); }
\r
38 #define RIF(x) { if (!(x)) return false; }
\r
40 bool CDecoder::ReadTable(Byte *lastLevels, Byte *newLevels, UInt32 numSymbols)
\r
42 Byte levelLevels[kLevelTableSize];
\r
44 for (i = 0; i < kLevelTableSize; i++)
\r
45 levelLevels[i] = (Byte)ReadBits(kNumBitsForPreTreeLevel);
\r
46 RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
\r
49 for (i = 0; i < numSymbols;)
\r
53 lastLevels[i] = newLevels[i] = symbol;
\r
58 UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
\r
59 if (number == kLevelSymbolZeros)
\r
61 num = kLevelSymbolZerosStartValue + (unsigned)ReadBits(kLevelSymbolZerosNumBits);
\r
64 else if (number == kLevelSymbolZerosBig)
\r
66 num = kLevelSymbolZerosBigStartValue + (unsigned)ReadBits(kLevelSymbolZerosBigNumBits);
\r
69 else if (number == kLevelSymbolSame || number <= kNumHuffmanBits)
\r
71 if (number <= kNumHuffmanBits)
\r
75 num = kLevelSymbolSameStartValue + (unsigned)ReadBits(kLevelSymbolSameNumBits);
\r
76 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
\r
77 if (number > kNumHuffmanBits)
\r
80 symbol = Byte((17 + lastLevels[i] - number) % (kNumHuffmanBits + 1));
\r
88 bool CDecoder::ReadTables(void)
\r
90 Byte newLevels[kMaxTableSize];
\r
93 m_InBitStream.DirectReadByte();
\r
94 m_InBitStream.Normalize();
\r
96 unsigned blockType = (unsigned)ReadBits(kNumBlockTypeBits);
\r
97 if (blockType > kBlockTypeUncompressed)
\r
100 if (ReadBits(1) == 1)
\r
101 m_UnCompressedBlockSize = (1 << 15);
\r
103 m_UnCompressedBlockSize = ReadBits(16);
\r
105 m_UnCompressedBlockSize = m_InBitStream.ReadBitsBig(kUncompressedBlockSizeNumBits);
\r
107 m_IsUncompressedBlock = (blockType == kBlockTypeUncompressed);
\r
109 _skipByte = (m_IsUncompressedBlock && ((m_UnCompressedBlockSize & 1) != 0));
\r
111 if (m_IsUncompressedBlock)
\r
113 ReadBits(16 - m_InBitStream.GetBitPosition());
\r
114 if (!m_InBitStream.ReadUInt32(m_RepDistances[0]))
\r
116 m_RepDistances[0]--;
\r
117 for (unsigned i = 1; i < kNumRepDistances; i++)
\r
120 for (unsigned j = 0; j < 4; j++)
\r
121 rep |= (UInt32)m_InBitStream.DirectReadByte() << (8 * j);
\r
122 m_RepDistances[i] = rep - 1;
\r
126 m_AlignIsUsed = (blockType == kBlockTypeAligned);
\r
129 for (unsigned i = 0; i < kAlignTableSize; i++)
\r
130 newLevels[i] = (Byte)ReadBits(kNumBitsForAlignLevel);
\r
131 RIF(m_AlignDecoder.SetCodeLengths(newLevels));
\r
135 RIF(ReadTable(m_LastMainLevels, newLevels, 256));
\r
136 RIF(ReadTable(m_LastMainLevels + 256, newLevels + 256, m_NumPosLenSlots));
\r
137 for (UInt32 i = 256 + m_NumPosLenSlots; i < kMainTableSize; i++)
\r
139 RIF(m_MainDecoder.SetCodeLengths(newLevels));
\r
141 RIF(ReadTable(m_LastLenLevels, newLevels, kNumLenSymbols));
\r
142 return m_LenDecoder.SetCodeLengths(newLevels);
\r
145 class CDecoderFlusher
\r
147 CDecoder *m_Decoder;
\r
150 CDecoderFlusher(CDecoder *decoder): m_Decoder(decoder), NeedFlush(true) {}
\r
154 m_Decoder->Flush();
\r
155 m_Decoder->ReleaseStreams();
\r
160 void CDecoder::ClearPrevLevels()
\r
163 for (i = 0; i < kMainTableSize; i++)
\r
164 m_LastMainLevels[i] = 0;
\r
165 for (i = 0; i < kNumLenSymbols; i++)
\r
166 m_LastLenLevels[i] = 0;
\r
170 HRESULT CDecoder::CodeSpec(UInt32 curSize)
\r
172 if (_remainLen == kLenIdNeedInit)
\r
175 m_InBitStream.Init();
\r
176 if (!_keepHistory || !m_IsUncompressedBlock)
\r
177 m_InBitStream.Normalize();
\r
181 m_UnCompressedBlockSize = 0;
\r
183 UInt32 i86TranslationSize = 12000000;
\r
184 bool translationMode = true;
\r
187 translationMode = (ReadBits(1) != 0);
\r
188 if (translationMode)
\r
190 i86TranslationSize = ReadBits(16) << 16;
\r
191 i86TranslationSize |= ReadBits(16);
\r
194 m_x86ConvertOutStreamSpec->Init(translationMode, i86TranslationSize);
\r
196 for (unsigned i = 0 ; i < kNumRepDistances; i++)
\r
197 m_RepDistances[i] = 0;
\r
201 while (_remainLen > 0 && curSize > 0)
\r
203 m_OutWindowStream.PutByte(m_OutWindowStream.GetByte(m_RepDistances[0]));
\r
208 while (curSize > 0)
\r
210 if (m_UnCompressedBlockSize == 0)
\r
213 UInt32 next = (Int32)MyMin(m_UnCompressedBlockSize, curSize);
\r
215 m_UnCompressedBlockSize -= next;
\r
216 if (m_IsUncompressedBlock)
\r
220 m_OutWindowStream.PutByte(m_InBitStream.DirectReadByte());
\r
224 else while (next > 0)
\r
226 UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
\r
229 m_OutWindowStream.PutByte((Byte)number);
\r
234 UInt32 posLenSlot = number - 256;
\r
235 if (posLenSlot >= m_NumPosLenSlots)
\r
237 UInt32 posSlot = posLenSlot / kNumLenSlots;
\r
238 UInt32 lenSlot = posLenSlot % kNumLenSlots;
\r
239 UInt32 len = kMatchMinLen + lenSlot;
\r
240 if (lenSlot == kNumLenSlots - 1)
\r
242 UInt32 lenTemp = m_LenDecoder.DecodeSymbol(&m_InBitStream);
\r
243 if (lenTemp >= kNumLenSymbols)
\r
248 if (posSlot < kNumRepDistances)
\r
250 UInt32 distance = m_RepDistances[posSlot];
\r
251 m_RepDistances[posSlot] = m_RepDistances[0];
\r
252 m_RepDistances[0] = distance;
\r
257 unsigned numDirectBits;
\r
258 if (posSlot < kNumPowerPosSlots)
\r
260 numDirectBits = (unsigned)(posSlot >> 1) - 1;
\r
261 distance = ((2 | (posSlot & 1)) << numDirectBits);
\r
265 numDirectBits = kNumLinearPosSlotBits;
\r
266 distance = ((posSlot - 0x22) << kNumLinearPosSlotBits);
\r
269 if (m_AlignIsUsed && numDirectBits >= kNumAlignBits)
\r
271 distance += (m_InBitStream.ReadBits(numDirectBits - kNumAlignBits) << kNumAlignBits);
\r
272 UInt32 alignTemp = m_AlignDecoder.DecodeSymbol(&m_InBitStream);
\r
273 if (alignTemp >= kAlignTableSize)
\r
275 distance += alignTemp;
\r
278 distance += m_InBitStream.ReadBits(numDirectBits);
\r
279 m_RepDistances[2] = m_RepDistances[1];
\r
280 m_RepDistances[1] = m_RepDistances[0];
\r
281 m_RepDistances[0] = distance - kNumRepDistances;
\r
284 UInt32 locLen = len;
\r
288 if (!m_OutWindowStream.CopyBlock(m_RepDistances[0], locLen))
\r
295 _remainLen = (int)len;
\r
304 HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
\r
305 const UInt64 *, const UInt64 *outSize, ICompressProgressInfo *progress)
\r
307 if (outSize == NULL)
\r
308 return E_INVALIDARG;
\r
309 UInt64 size = *outSize;
\r
311 RINOK(SetInStream(inStream));
\r
312 m_x86ConvertOutStreamSpec->SetStream(outStream);
\r
313 m_OutWindowStream.SetStream(m_x86ConvertOutStream);
\r
314 RINOK(SetOutStreamSize(outSize));
\r
316 CDecoderFlusher flusher(this);
\r
318 const UInt64 start = m_OutWindowStream.GetProcessedSize();
\r
321 UInt32 curSize = 1 << 18;
\r
322 UInt64 rem = size - (m_OutWindowStream.GetProcessedSize() - start);
\r
324 curSize = (UInt32)rem;
\r
327 RINOK(CodeSpec(curSize));
\r
328 if (progress != NULL)
\r
330 UInt64 inSize = m_InBitStream.GetProcessedSize();
\r
331 UInt64 nowPos64 = m_OutWindowStream.GetProcessedSize() - start;
\r
332 RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
\r
335 flusher.NeedFlush = false;
\r
339 HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
\r
340 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
\r
342 try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
\r
343 catch(const CLzOutWindowException &e) { return e.ErrorCode; }
\r
344 catch(...) { return S_FALSE; }
\r
347 STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
\r
349 m_InBitStream.SetStream(inStream);
\r
353 STDMETHODIMP CDecoder::ReleaseInStream()
\r
355 m_InBitStream.ReleaseStream();
\r
359 STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
\r
361 if (outSize == NULL)
\r
363 _remainLen = kLenIdNeedInit;
\r
364 m_OutWindowStream.Init(_keepHistory);
\r
368 HRESULT CDecoder::SetParams(unsigned numDictBits)
\r
370 if (numDictBits < kNumDictionaryBitsMin || numDictBits > kNumDictionaryBitsMax)
\r
371 return E_INVALIDARG;
\r
372 UInt32 numPosSlots;
\r
373 if (numDictBits < 20)
\r
374 numPosSlots = 30 + (numDictBits - 15) * 2;
\r
375 else if (numDictBits == 20)
\r
379 m_NumPosLenSlots = numPosSlots * kNumLenSlots;
\r
380 if (!m_OutWindowStream.Create(kDictionarySizeMax))
\r
381 return E_OUTOFMEMORY;
\r
382 if (!m_InBitStream.Create(1 << 16))
\r
383 return E_OUTOFMEMORY;
\r