1 // DeflateDecoder.cpp
\r
5 #include "DeflateDecoder.h"
\r
7 namespace NCompress {
\r
11 static const int kLenIdFinished = -1;
\r
12 static const int kLenIdNeedInit = -2;
\r
14 CCoder::CCoder(bool deflate64Mode, bool deflateNSIS):
\r
15 _deflate64Mode(deflate64Mode),
\r
16 _deflateNSIS(deflateNSIS),
\r
17 _keepHistory(false),
\r
18 _needInitInStream(true),
\r
21 UInt32 CCoder::ReadBits(int numBits)
\r
23 return m_InBitStream.ReadBits(numBits);
\r
26 bool CCoder::DeCodeLevelTable(Byte *values, int numSymbols)
\r
31 UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
\r
32 if (number < kTableDirectLevels)
\r
33 values[i++] = (Byte)number;
\r
34 else if (number < kLevelTableSize)
\r
36 if (number == kTableLevelRepNumber)
\r
40 int num = ReadBits(2) + 3;
\r
41 for (; num > 0 && i < numSymbols; num--, i++)
\r
42 values[i] = values[i - 1];
\r
47 if (number == kTableLevel0Number)
\r
48 num = ReadBits(3) + 3;
\r
50 num = ReadBits(7) + 11;
\r
51 for (;num > 0 && i < numSymbols; num--)
\r
58 while(i < numSymbols);
\r
62 #define RIF(x) { if (!(x)) return false; }
\r
64 bool CCoder::ReadTables(void)
\r
66 m_FinalBlock = (ReadBits(kFinalBlockFieldSize) == NFinalBlockField::kFinalBlock);
\r
67 UInt32 blockType = ReadBits(kBlockTypeFieldSize);
\r
68 if (blockType > NBlockType::kDynamicHuffman)
\r
71 if (blockType == NBlockType::kStored)
\r
73 m_StoredMode = true;
\r
74 m_InBitStream.AlignToByte();
\r
75 m_StoredBlockSize = ReadBits(kStoredBlockLengthFieldSize);
\r
78 return (m_StoredBlockSize == (UInt16)~ReadBits(kStoredBlockLengthFieldSize));
\r
81 m_StoredMode = false;
\r
84 if (blockType == NBlockType::kFixedHuffman)
\r
86 levels.SetFixedLevels();
\r
87 _numDistLevels = _deflate64Mode ? kDistTableSize64 : kDistTableSize32;
\r
91 int numLitLenLevels = ReadBits(kNumLenCodesFieldSize) + kNumLitLenCodesMin;
\r
92 _numDistLevels = ReadBits(kNumDistCodesFieldSize) + kNumDistCodesMin;
\r
93 int numLevelCodes = ReadBits(kNumLevelCodesFieldSize) + kNumLevelCodesMin;
\r
95 if (!_deflate64Mode)
\r
96 if (_numDistLevels > kDistTableSize32)
\r
99 Byte levelLevels[kLevelTableSize];
\r
100 for (int i = 0; i < kLevelTableSize; i++)
\r
102 int position = kCodeLengthAlphabetOrder[i];
\r
103 if(i < numLevelCodes)
\r
104 levelLevels[position] = (Byte)ReadBits(kLevelFieldSize);
\r
106 levelLevels[position] = 0;
\r
109 RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
\r
111 Byte tmpLevels[kFixedMainTableSize + kFixedDistTableSize];
\r
112 if (!DeCodeLevelTable(tmpLevels, numLitLenLevels + _numDistLevels))
\r
116 memcpy(levels.litLenLevels, tmpLevels, numLitLenLevels);
\r
117 memcpy(levels.distLevels, tmpLevels + numLitLenLevels, _numDistLevels);
\r
119 RIF(m_MainDecoder.SetCodeLengths(levels.litLenLevels));
\r
120 return m_DistDecoder.SetCodeLengths(levels.distLevels);
\r
123 HRESULT CCoder::CodeSpec(UInt32 curSize)
\r
125 if (_remainLen == kLenIdFinished)
\r
127 if (_remainLen == kLenIdNeedInit)
\r
130 if (!m_OutWindowStream.Create(_deflate64Mode ? kHistorySize64: kHistorySize32))
\r
131 return E_OUTOFMEMORY;
\r
132 RINOK(InitInStream(_needInitInStream));
\r
133 m_OutWindowStream.Init(_keepHistory);
\r
134 m_FinalBlock = false;
\r
136 _needReadTable = true;
\r
142 while(_remainLen > 0 && curSize > 0)
\r
145 Byte b = m_OutWindowStream.GetByte(_rep0);
\r
146 m_OutWindowStream.PutByte(b);
\r
152 if (_needReadTable)
\r
156 _remainLen = kLenIdFinished;
\r
161 _needReadTable = false;
\r
166 for (; m_StoredBlockSize > 0 && curSize > 0; m_StoredBlockSize--, curSize--)
\r
167 m_OutWindowStream.PutByte(m_InBitStream.ReadByte());
\r
168 _needReadTable = (m_StoredBlockSize == 0);
\r
173 if (m_InBitStream.NumExtraBytes > 4)
\r
176 UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
\r
177 if (number < 0x100)
\r
179 m_OutWindowStream.PutByte((Byte)number);
\r
183 else if (number == kSymbolEndOfBlock)
\r
185 _needReadTable = true;
\r
188 else if (number < kMainTableSize)
\r
190 number -= kSymbolMatch;
\r
194 if (_deflate64Mode)
\r
196 len = kLenStart64[number];
\r
197 numBits = kLenDirectBits64[number];
\r
201 len = kLenStart32[number];
\r
202 numBits = kLenDirectBits32[number];
\r
204 len += kMatchMinLen + m_InBitStream.ReadBits(numBits);
\r
206 UInt32 locLen = len;
\r
207 if (locLen > curSize)
\r
208 locLen = (UInt32)curSize;
\r
209 number = m_DistDecoder.DecodeSymbol(&m_InBitStream);
\r
210 if (number >= _numDistLevels)
\r
212 UInt32 distance = kDistStart[number] + m_InBitStream.ReadBits(kDistDirectBits[number]);
\r
213 if (!m_OutWindowStream.CopyBlock(distance, locLen))
\r
219 _remainLen = (Int32)len;
\r
231 #ifdef _NO_EXCEPTIONS
\r
233 #define DEFLATE_TRY_BEGIN
\r
234 #define DEFLATE_TRY_END
\r
238 #define DEFLATE_TRY_BEGIN try {
\r
239 #define DEFLATE_TRY_END } \
\r
240 catch(const CInBufferException &e) { return e.ErrorCode; } \
\r
241 catch(const CLzOutWindowException &e) { return e.ErrorCode; } \
\r
242 catch(...) { return S_FALSE; }
\r
246 HRESULT CCoder::CodeReal(ISequentialOutStream *outStream,
\r
247 const UInt64 *outSize, ICompressProgressInfo *progress)
\r
250 m_OutWindowStream.SetStream(outStream);
\r
251 CCoderReleaser flusher(this);
\r
253 const UInt64 inStart = _needInitInStream ? 0 : m_InBitStream.GetProcessedSize();
\r
254 const UInt64 start = m_OutWindowStream.GetProcessedSize();
\r
257 UInt32 curSize = 1 << 18;
\r
260 const UInt64 rem = *outSize - (m_OutWindowStream.GetProcessedSize() - start);
\r
262 curSize = (UInt32)rem;
\r
266 RINOK(CodeSpec(curSize));
\r
267 if (_remainLen == kLenIdFinished)
\r
269 if (progress != NULL)
\r
271 const UInt64 inSize = m_InBitStream.GetProcessedSize() - inStart;
\r
272 const UInt64 nowPos64 = m_OutWindowStream.GetProcessedSize() - start;
\r
273 RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
\r
276 if (_remainLen == kLenIdFinished && ZlibMode)
\r
278 m_InBitStream.AlignToByte();
\r
279 for (int i = 0; i < 4; i++)
\r
280 ZlibFooter[i] = m_InBitStream.ReadByte();
\r
282 flusher.NeedFlush = false;
\r
283 HRESULT res = Flush();
\r
284 if (res == S_OK && InputEofError())
\r
290 HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
\r
291 const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
\r
293 SetInStream(inStream);
\r
294 SetOutStreamSize(outSize);
\r
295 HRESULT res = CodeReal(outStream, outSize, progress);
\r
300 STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value)
\r
303 return E_INVALIDARG;
\r
304 *value = m_InBitStream.GetProcessedSize();
\r
308 STDMETHODIMP CCoder::SetInStream(ISequentialInStream *inStream)
\r
310 m_InBitStream.SetStream(inStream);
\r
314 STDMETHODIMP CCoder::ReleaseInStream()
\r
316 m_InBitStream.ReleaseStream();
\r
320 STDMETHODIMP CCoder::SetOutStreamSize(const UInt64 * /* outSize */)
\r
322 _remainLen = kLenIdNeedInit;
\r
323 _needInitInStream = true;
\r
324 m_OutWindowStream.Init(_keepHistory);
\r
328 #ifndef NO_READ_FROM_CODER
\r
330 STDMETHODIMP CCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
\r
334 *processedSize = 0;
\r
335 const UInt64 startPos = m_OutWindowStream.GetProcessedSize();
\r
336 m_OutWindowStream.SetMemStream((Byte *)data);
\r
337 RINOK(CodeSpec(size));
\r
339 *processedSize = (UInt32)(m_OutWindowStream.GetProcessedSize() - startPos);
\r
346 STDMETHODIMP CCoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)
\r
348 _remainLen = kLenIdNeedInit;
\r
349 m_OutWindowStream.Init(_keepHistory);
\r
350 return CodeReal(outStream, outSize, progress);
\r