implodedecoder.cpp
来自「由7-zip提供的压缩、解压缩程序」· C++ 代码 · 共 223 行
CPP
223 行
// Implode/Decoder.cpp#include "StdAfx.h"#include "ImplodeDecoder.h"#include "Common/Defs.h"namespace NCompress {namespace NImplode {namespace NDecoder {class CException{public: enum ECauseType { kData } m_Cause; CException(ECauseType cause): m_Cause(cause) {}};static const int kNumDistanceLowDirectBitsForBigDict = 7; static const int kNumDistanceLowDirectBitsForSmallDict = 6; static const int kNumBitsInByte = 8;static const int kLevelStructuresNumberFieldSize = kNumBitsInByte;static const int kLevelStructuresNumberAdditionalValue = 1;static const int kNumLevelStructureLevelBits = 4;static const int kLevelStructureLevelAdditionalValue = 1;static const int kNumLevelStructureRepNumberBits = 4;static const int kLevelStructureRepNumberAdditionalValue = 1;static const int kLiteralTableSize = (1 << kNumBitsInByte);static const int kDistanceTableSize = 64;static const int kLengthTableSize = 64;static const UInt32 kHistorySize = (1 << MyMax(kNumDistanceLowDirectBitsForBigDict, kNumDistanceLowDirectBitsForSmallDict)) * kDistanceTableSize; // = 8 KB;static const int kNumAdditionalLengthBits = 8;static const UInt32 kMatchMinLenWhenLiteralsOn = 3; static const UInt32 kMatchMinLenWhenLiteralsOff = 2;static const UInt32 kMatchMinLenMax = MyMax(kMatchMinLenWhenLiteralsOn, kMatchMinLenWhenLiteralsOff); // 3static const UInt32 kMatchMaxLenMax = kMatchMinLenMax + (kLengthTableSize - 1) + (1 << kNumAdditionalLengthBits) - 1; // or 2enum{ kMatchId = 0, kLiteralId = 1};CCoder::CCoder(): m_LiteralDecoder(kLiteralTableSize), m_LengthDecoder(kLengthTableSize), m_DistanceDecoder(kDistanceTableSize){}void CCoder::ReleaseStreams(){ m_OutWindowStream.ReleaseStream(); m_InBitStream.ReleaseStream();}bool CCoder::ReadLevelItems(NImplode::NHuffman::CDecoder &decoder, Byte *levels, int numLevelItems){ int numCodedStructures = m_InBitStream.ReadBits(kNumBitsInByte) + kLevelStructuresNumberAdditionalValue; int currentIndex = 0; for(int i = 0; i < numCodedStructures; i++) { int level = m_InBitStream.ReadBits(kNumLevelStructureLevelBits) + kLevelStructureLevelAdditionalValue; int rep = m_InBitStream.ReadBits(kNumLevelStructureRepNumberBits) + kLevelStructureRepNumberAdditionalValue; if (currentIndex + rep > numLevelItems) throw CException(CException::kData); for(int j = 0; j < rep; j++) levels[currentIndex++] = level; } if (currentIndex != numLevelItems) return false; return decoder.SetCodeLengths(levels);}bool CCoder::ReadTables(void){ if (m_LiteralsOn) { Byte literalLevels[kLiteralTableSize]; if (!ReadLevelItems(m_LiteralDecoder, literalLevels, kLiteralTableSize)) return false; } Byte lengthLevels[kLengthTableSize]; if (!ReadLevelItems(m_LengthDecoder, lengthLevels, kLengthTableSize)) return false; Byte distanceLevels[kDistanceTableSize]; return ReadLevelItems(m_DistanceDecoder, distanceLevels, kDistanceTableSize);}class CCoderReleaser{ CCoder *m_Coder;public: CCoderReleaser(CCoder *coder): m_Coder(coder) {} ~CCoderReleaser() { m_Coder->ReleaseStreams(); }};STDMETHODIMP CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress){ if (!m_InBitStream.Create(1 << 20)) return E_OUTOFMEMORY; if (!m_OutWindowStream.Create(kHistorySize)) return E_OUTOFMEMORY; if (outSize == NULL) return E_INVALIDARG; UInt64 pos = 0, unPackSize = *outSize; m_OutWindowStream.SetStream(outStream); m_OutWindowStream.Init(false); m_InBitStream.SetStream(inStream); m_InBitStream.Init(); CCoderReleaser coderReleaser(this); if (!ReadTables()) return S_FALSE; while(pos < unPackSize) { if (progress != NULL && pos % (1 << 16) == 0) { UInt64 packSize = m_InBitStream.GetProcessedSize(); RINOK(progress->SetRatioInfo(&packSize, &pos)); } if(m_InBitStream.ReadBits(1) == kMatchId) // match { UInt32 lowDistBits = m_InBitStream.ReadBits(m_NumDistanceLowDirectBits); UInt32 distance = m_DistanceDecoder.DecodeSymbol(&m_InBitStream); if (distance >= kDistanceTableSize) return S_FALSE; distance = (distance << m_NumDistanceLowDirectBits) + lowDistBits; UInt32 lengthSymbol = m_LengthDecoder.DecodeSymbol(&m_InBitStream); if (lengthSymbol >= kLengthTableSize) return S_FALSE; UInt32 length = lengthSymbol + m_MinMatchLength; if (lengthSymbol == kLengthTableSize - 1) // special symbol = 63 length += m_InBitStream.ReadBits(kNumAdditionalLengthBits); while(distance >= pos && length > 0) { m_OutWindowStream.PutByte(0); pos++; length--; } if (length > 0) m_OutWindowStream.CopyBlock(distance, length); pos += length; } else { Byte b; if (m_LiteralsOn) { UInt32 temp = m_LiteralDecoder.DecodeSymbol(&m_InBitStream); if (temp >= kLiteralTableSize) return S_FALSE; b = (Byte)temp; } else b = (Byte)m_InBitStream.ReadBits(kNumBitsInByte); m_OutWindowStream.PutByte(b); pos++; } } if (pos > unPackSize) throw CException(CException::kData); return m_OutWindowStream.Flush();}STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress){ try { return CodeReal(inStream, outStream, inSize, outSize, progress); } catch(const CLZOutWindowException &e) { return e.ErrorCode; } catch(...) { return S_FALSE; }}STDMETHODIMP CCoder::SetDecoderProperties2(const Byte *data, UInt32 size){ if (size < 1) return E_INVALIDARG; Byte flag = data[0]; m_BigDictionaryOn = ((flag & 2) != 0); m_NumDistanceLowDirectBits = m_BigDictionaryOn ? kNumDistanceLowDirectBitsForBigDict: kNumDistanceLowDirectBitsForSmallDict; m_LiteralsOn = ((flag & 4) != 0); m_MinMatchLength = m_LiteralsOn ? kMatchMinLenWhenLiteralsOn : kMatchMinLenWhenLiteralsOff; return S_OK;}}}}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?