Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '7zip/Compress/Deflate/DeflateDecoder.cpp')
-rwxr-xr-x7zip/Compress/Deflate/DeflateDecoder.cpp404
1 files changed, 232 insertions, 172 deletions
diff --git a/7zip/Compress/Deflate/DeflateDecoder.cpp b/7zip/Compress/Deflate/DeflateDecoder.cpp
index 96da47b3..16369326 100755
--- a/7zip/Compress/Deflate/DeflateDecoder.cpp
+++ b/7zip/Compress/Deflate/DeflateDecoder.cpp
@@ -8,7 +8,10 @@ namespace NCompress {
namespace NDeflate {
namespace NDecoder {
-CCoder::CCoder(bool deflate64Mode): _deflate64Mode(deflate64Mode) {}
+const int kLenIdFinished = -1;
+const int kLenIdNeedInit = -2;
+
+CCoder::CCoder(bool deflate64Mode): _deflate64Mode(deflate64Mode), _keepHistory(false) {}
void CCoder::DeCodeLevelTable(Byte *newLevels, int numLevels)
{
@@ -40,211 +43,256 @@ void CCoder::DeCodeLevelTable(Byte *newLevels, int numLevels)
}
}
-void CCoder::ReadTables(void)
-{
- if(m_FinalBlock) // test it
- throw CException(CException::kData);
+#define RIF(x) { if (!(x)) return false; }
+bool CCoder::ReadTables(void)
+{
m_FinalBlock = (m_InBitStream.ReadBits(kFinalBlockFieldSize) == NFinalBlockField::kFinalBlock);
-
int blockType = m_InBitStream.ReadBits(kBlockTypeFieldSize);
+ if (blockType > NBlockType::kDynamicHuffman)
+ return false;
- switch(blockType)
+ if (blockType == NBlockType::kStored)
{
- case NBlockType::kStored:
- {
- m_StoredMode = true;
- UInt32 currentBitPosition = m_InBitStream.GetBitPosition();
- UInt32 numBitsForAlign = currentBitPosition > 0 ? (8 - currentBitPosition): 0;
- if (numBitsForAlign > 0)
- m_InBitStream.ReadBits(numBitsForAlign);
- m_StoredBlockSize = m_InBitStream.ReadBits(kDeflateStoredBlockLengthFieldSizeSize);
- UInt16 onesComplementReverse = ~(UInt16)(m_InBitStream.ReadBits(kDeflateStoredBlockLengthFieldSizeSize));
- if (m_StoredBlockSize != onesComplementReverse)
- throw CException(CException::kData);
- break;
- }
- case NBlockType::kFixedHuffman:
- case NBlockType::kDynamicHuffman:
- {
- m_StoredMode = false;
- Byte litLenLevels[kStaticMainTableSize];
- Byte distLevels[kStaticDistTableSize];
- if (blockType == NBlockType::kFixedHuffman)
- {
- int i;
-
- // Leteral / length levels
- for (i = 0; i < 144; i++)
- litLenLevels[i] = 8;
- for (; i < 256; i++)
- litLenLevels[i] = 9;
- for (; i < 280; i++)
- litLenLevels[i] = 7;
- for (; i < 288; i++) /* make a complete, but wrong code set */
- litLenLevels[i] = 8;
-
- // Distance levels
- for (i = 0; i < kStaticDistTableSize; i++) // test it: infozip only use kDistTableSize
- distLevels[i] = 5;
- }
- else // in case when (blockType == kDeflateBlockTypeFixedHuffman)
- {
- int numLitLenLevels = m_InBitStream.ReadBits(kDeflateNumberOfLengthCodesFieldSize) +
- kDeflateNumberOfLitLenCodesMin;
- int numDistLevels = m_InBitStream.ReadBits(kDeflateNumberOfDistanceCodesFieldSize) +
- kDeflateNumberOfDistanceCodesMin;
- int numLevelCodes = m_InBitStream.ReadBits(kDeflateNumberOfLevelCodesFieldSize) +
- kDeflateNumberOfLevelCodesMin;
-
- int numLevels = _deflate64Mode ? kHeapTablesSizesSum64 :
- kHeapTablesSizesSum32;
-
- Byte levelLevels[kLevelTableSize];
- int i;
- for (i = 0; i < kLevelTableSize; i++)
- {
- int position = kCodeLengthAlphabetOrder[i];
- if(i < numLevelCodes)
- levelLevels[position] = Byte(m_InBitStream.ReadBits(kDeflateLevelCodeFieldSize));
- else
- levelLevels[position] = 0;
- }
-
- try
- {
- m_LevelDecoder.SetCodeLengths(levelLevels);
- }
- catch(...)
- {
- throw CException(CException::kData);
- }
-
- Byte tmpLevels[kStaticMaxTableSize];
- DeCodeLevelTable(tmpLevels, numLitLenLevels + numDistLevels);
-
- memmove(litLenLevels, tmpLevels, numLitLenLevels);
- memset(litLenLevels + numLitLenLevels, 0,
- kStaticMainTableSize - numLitLenLevels);
-
- memmove(distLevels, tmpLevels + numLitLenLevels, numDistLevels);
- memset(distLevels + numDistLevels, 0, kStaticDistTableSize - numDistLevels);
- }
- try
- {
- m_MainDecoder.SetCodeLengths(litLenLevels);
- m_DistDecoder.SetCodeLengths(distLevels);
- }
- catch(...)
- {
- throw CException(CException::kData);
- }
- break;
- }
- default:
- throw CException(CException::kData);
+ m_StoredMode = true;
+ UInt32 currentBitPosition = m_InBitStream.GetBitPosition();
+ UInt32 numBitsForAlign = currentBitPosition > 0 ? (8 - currentBitPosition): 0;
+ if (numBitsForAlign > 0)
+ m_InBitStream.ReadBits(numBitsForAlign);
+ m_StoredBlockSize = m_InBitStream.ReadBits(kDeflateStoredBlockLengthFieldSizeSize);
+ UInt16 onesComplementReverse = ~(UInt16)(m_InBitStream.ReadBits(kDeflateStoredBlockLengthFieldSizeSize));
+ return (m_StoredBlockSize == onesComplementReverse);
}
+
+ m_StoredMode = false;
+ Byte litLenLevels[kStaticMainTableSize];
+ Byte distLevels[kStaticDistTableSize];
+ if (blockType == NBlockType::kFixedHuffman)
+ {
+ int i;
+
+ for (i = 0; i < 144; i++)
+ litLenLevels[i] = 8;
+ for (; i < 256; i++)
+ litLenLevels[i] = 9;
+ for (; i < 280; i++)
+ litLenLevels[i] = 7;
+ for (; i < 288; i++) // make a complete, but wrong code set
+ litLenLevels[i] = 8;
+
+ for (i = 0; i < kStaticDistTableSize; i++) // test it: InfoZip only uses kDistTableSize
+ distLevels[i] = 5;
+ }
+ else // (blockType == kDynamicHuffman)
+ {
+ int numLitLenLevels = m_InBitStream.ReadBits(kDeflateNumberOfLengthCodesFieldSize) +
+ kDeflateNumberOfLitLenCodesMin;
+ int numDistLevels = m_InBitStream.ReadBits(kDeflateNumberOfDistanceCodesFieldSize) +
+ kDeflateNumberOfDistanceCodesMin;
+ int numLevelCodes = m_InBitStream.ReadBits(kDeflateNumberOfLevelCodesFieldSize) +
+ kDeflateNumberOfLevelCodesMin;
+
+ int numLevels = _deflate64Mode ? kHeapTablesSizesSum64 : kHeapTablesSizesSum32;
+
+ Byte levelLevels[kLevelTableSize];
+ for (int i = 0; i < kLevelTableSize; i++)
+ {
+ int position = kCodeLengthAlphabetOrder[i];
+ if(i < numLevelCodes)
+ levelLevels[position] = Byte(m_InBitStream.ReadBits(kDeflateLevelCodeFieldSize));
+ else
+ levelLevels[position] = 0;
+ }
+
+ RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
+
+ Byte tmpLevels[kStaticMaxTableSize];
+ DeCodeLevelTable(tmpLevels, numLitLenLevels + numDistLevels);
+
+ memmove(litLenLevels, tmpLevels, numLitLenLevels);
+ memset(litLenLevels + numLitLenLevels, 0, kStaticMainTableSize - numLitLenLevels);
+
+ memmove(distLevels, tmpLevels + numLitLenLevels, numDistLevels);
+ memset(distLevels + numDistLevels, 0, kStaticDistTableSize - numDistLevels);
+ }
+ RIF(m_MainDecoder.SetCodeLengths(litLenLevels));
+ return m_DistDecoder.SetCodeLengths(distLevels);
}
-HRESULT CCoder::CodeReal(ISequentialInStream *inStream,
- ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
- ICompressProgressInfo *progress)
+HRESULT CCoder::CodeSpec(UInt32 curSize)
{
- if (!m_OutWindowStream.Create(_deflate64Mode ? kHistorySize64: kHistorySize32))
- return E_OUTOFMEMORY;
- if (!m_InBitStream.Create(1 << 17))
- return E_OUTOFMEMORY;
- UInt64 pos = 0;
- m_OutWindowStream.SetStream(outStream);
- m_OutWindowStream.Init(false);
- m_InBitStream.SetStream(inStream);
- m_InBitStream.Init();
- CCoderReleaser coderReleaser(this);
+ if (_remainLen == kLenIdFinished)
+ return S_OK;
+ if (_remainLen == kLenIdNeedInit)
+ {
+ if (!_keepHistory)
+ {
+ if (!m_OutWindowStream.Create(_deflate64Mode ? kHistorySize64: kHistorySize32))
+ return E_OUTOFMEMORY;
+ }
+ if (!m_InBitStream.Create(1 << 17))
+ return E_OUTOFMEMORY;
+ m_OutWindowStream.Init(_keepHistory);
+ m_InBitStream.Init();
+ m_FinalBlock = false;
+ _remainLen = 0;
+ _needReadTable = true;
+ }
- m_FinalBlock = false;
+ if (curSize == 0)
+ return S_OK;
- while(!m_FinalBlock)
+ while(_remainLen > 0 && curSize > 0)
{
- if (progress != NULL)
+ _remainLen--;
+ Byte b = m_OutWindowStream.GetByte(_rep0);
+ m_OutWindowStream.PutByte(b);
+ curSize--;
+ }
+
+ while(curSize > 0)
+ {
+ if (_needReadTable)
{
- UInt64 packSize = m_InBitStream.GetProcessedSize();
- RINOK(progress->SetRatioInfo(&packSize, &pos));
+ if (m_FinalBlock)
+ {
+ _remainLen = kLenIdFinished;
+ break;
+ }
+ if (!ReadTables())
+ return S_FALSE;
+ _needReadTable = false;
}
- ReadTables();
+
if(m_StoredMode)
{
- for (UInt32 i = 0; i < m_StoredBlockSize; i++)
- m_OutWindowStream.PutByte(Byte(m_InBitStream.ReadBits(8)));
- pos += m_StoredBlockSize;
+ for (; m_StoredBlockSize > 0 && curSize > 0; m_StoredBlockSize--, curSize--)
+ m_OutWindowStream.PutByte((Byte)m_InBitStream.ReadBits(8));
+ _needReadTable = (m_StoredBlockSize == 0);
continue;
}
- while(true)
+ while(curSize > 0)
{
if (m_InBitStream.NumExtraBytes > 4)
- throw CException(CException::kData);
+ return S_FALSE;
UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
if (number < 256)
{
- if (outSize != NULL)
- if (pos >= *outSize)
- throw CException(CException::kData);
- m_OutWindowStream.PutByte(Byte(number));
- pos++;
+ m_OutWindowStream.PutByte((Byte)number);
+ curSize--;
continue;
}
else if (number >= kMatchNumber)
{
- if (outSize != NULL)
- if (pos >= *outSize)
- throw CException(CException::kData);
number -= kMatchNumber;
-
- UInt32 length;
- if (_deflate64Mode)
- {
- length = UInt32(kLenStart64[number]) + kMatchMinLen;
- UInt32 numBits = kLenDirectBits64[number];
- if (numBits > 0)
- length += m_InBitStream.ReadBits(numBits);
- }
- else
+ UInt32 len;
{
- length = UInt32(kLenStart32[number]) + kMatchMinLen;
- UInt32 numBits = kLenDirectBits32[number];
- if (numBits > 0)
- length += m_InBitStream.ReadBits(numBits);
+ int numBits;
+ if (_deflate64Mode)
+ {
+ len = kLenStart64[number];
+ numBits = kLenDirectBits64[number];
+ }
+ else
+ {
+ len = kLenStart32[number];
+ numBits = kLenDirectBits32[number];
+ }
+ len += kMatchMinLen + m_InBitStream.ReadBits(numBits);
}
-
-
+ UInt32 locLen = len;
+ if (locLen > curSize)
+ locLen = (UInt32)curSize;
number = m_DistDecoder.DecodeSymbol(&m_InBitStream);
+ if (number >= kStaticDistTableSize)
+ return S_FALSE;
UInt32 distance = kDistStart[number] + m_InBitStream.ReadBits(kDistDirectBits[number]);
- if (distance >= pos)
- throw "data error";
- m_OutWindowStream.CopyBlock(distance, length);
- pos += length;
+ if (!m_OutWindowStream.CopyBlock(distance, locLen))
+ return S_FALSE;
+ curSize -= locLen;
+ len -= locLen;
+ if (len != 0)
+ {
+ _remainLen = (int)len;
+ _rep0 = distance;
+ break;
+ }
}
else if (number == kReadTableNumber)
+ {
+ _needReadTable = true;
break;
+ }
else
- throw CException(CException::kData);
+ return S_FALSE;
}
}
- coderReleaser.NeedFlush = false;
- return m_OutWindowStream.Flush();
+ return S_OK;
}
-HRESULT CCoder::BaseCode(ISequentialInStream *inStream,
- ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+HRESULT CCoder::CodeReal(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream,
+ const UInt64 *, const UInt64 *outSize,
ICompressProgressInfo *progress)
{
- try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
- catch(const CInBufferException &e) { return e.ErrorCode; }
- catch(const CLZOutWindowException &e) { return e.ErrorCode; }
+ SetInStream(inStream);
+ m_OutWindowStream.SetStream(outStream);
+ SetOutStreamSize(outSize);
+ CCoderReleaser flusher(this);
+
+ const UInt64 start = m_OutWindowStream.GetProcessedSize();
+ while(true)
+ {
+ UInt32 curSize = 1 << 18;
+ if (outSize != 0)
+ {
+ const UInt64 rem = *outSize - (m_OutWindowStream.GetProcessedSize() - start);
+ if (curSize > rem)
+ curSize = (UInt32)rem;
+ }
+ if (curSize == 0)
+ break;
+ RINOK(CodeSpec(curSize));
+ if (_remainLen == kLenIdFinished)
+ break;
+ if (progress != NULL)
+ {
+ UInt64 inSize = m_InBitStream.GetProcessedSize();
+ UInt64 nowPos64 = m_OutWindowStream.GetProcessedSize() - start;
+ RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
+ }
+ }
+ flusher.NeedFlush = false;
+ return Flush();
+}
+
+
+#ifdef _NO_EXCEPTIONS
+
+#define DEFLATE_TRY_BEGIN
+#define DEFLATE_TRY_END
+
+#else
+
+#define DEFLATE_TRY_BEGIN try {
+#define DEFLATE_TRY_END } \
+ catch(const CInBufferException &e) { return e.ErrorCode; } \
+ catch(const CLZOutWindowException &e) { return e.ErrorCode; } \
catch(...) { return S_FALSE; }
+
+#endif
+
+HRESULT CCoder::Code(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress)
+{
+ DEFLATE_TRY_BEGIN
+ return CodeReal(inStream, outStream, inSize, outSize, progress);
+ DEFLATE_TRY_END
}
-HRESULT CCoder::BaseGetInStreamProcessedSize(UInt64 *value)
+STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value)
{
if (value == NULL)
return E_INVALIDARG;
@@ -252,29 +300,41 @@ HRESULT CCoder::BaseGetInStreamProcessedSize(UInt64 *value)
return S_OK;
}
-STDMETHODIMP CCOMCoder::GetInStreamProcessedSize(UInt64 *value)
+STDMETHODIMP CCoder::SetInStream(ISequentialInStream *inStream)
{
- return BaseGetInStreamProcessedSize(value);
+ m_InBitStream.SetStream(inStream);
+ return S_OK;
}
-HRESULT CCOMCoder::Code(ISequentialInStream *inStream,
- ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
- ICompressProgressInfo *progress)
+STDMETHODIMP CCoder::ReleaseInStream()
{
- return BaseCode(inStream, outStream, inSize, outSize, progress);
+ m_InBitStream.ReleaseStream();
+ return S_OK;
}
-STDMETHODIMP CCOMCoder64::GetInStreamProcessedSize(UInt64 *value)
+STDMETHODIMP CCoder::SetOutStreamSize(const UInt64 *outSize)
{
- return BaseGetInStreamProcessedSize(value);
+ _remainLen = kLenIdNeedInit;
+ m_OutWindowStream.Init(_keepHistory);
+ return S_OK;
}
-HRESULT CCOMCoder64::Code(ISequentialInStream *inStream,
- ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
- ICompressProgressInfo *progress)
+#ifdef _ST_MODE
+
+STDMETHODIMP CCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
{
- return BaseCode(inStream, outStream, inSize, outSize, progress);
+ DEFLATE_TRY_BEGIN
+ if (processedSize)
+ *processedSize = 0;
+ const UInt64 startPos = m_OutWindowStream.GetProcessedSize();
+ m_OutWindowStream.SetMemStream((Byte *)data);
+ RINOK(CodeSpec(size));
+ if (processedSize)
+ *processedSize = (UInt32)(m_OutWindowStream.GetProcessedSize() - startPos);
+ return Flush();
+ DEFLATE_TRY_END
}
+#endif
}}}