lzxdecoder.cpp

来自「由7-zip提供的压缩、解压缩程序」· C++ 代码 · 共 383 行

CPP
383
字号
// LzxDecoder.cpp#include "StdAfx.h"#include "LzxDecoder.h"#include "Common/Defs.h"#include "Common/Alloc.h"#include "Windows/Defs.h"namespace NCompress {namespace NLzx {const int kLenIdNeedInit = -2;CDecoder::CDecoder():  _keepHistory(false),  m_AlignPos(0){  m_x86ConvertOutStreamSpec = new Cx86ConvertOutStream;  m_x86ConvertOutStream = m_x86ConvertOutStreamSpec;}void CDecoder::ReleaseStreams(){  m_OutWindowStream.ReleaseStream();  m_InBitStream.ReleaseStream();  m_x86ConvertOutStreamSpec->ReleaseStream();}STDMETHODIMP CDecoder::Flush(){  RINOK(m_OutWindowStream.Flush());  return m_x86ConvertOutStreamSpec->Flush();}UInt32 CDecoder::ReadBits(UInt32 numBits) { return m_InBitStream.ReadBits(numBits); }#define RIF(x) { if (!(x)) return false; }bool CDecoder::ReadTable(Byte *lastLevels, Byte *newLevels, UInt32 numSymbols){  Byte levelLevels[kLevelTableSize];  UInt32 i;  for (i = 0; i < kLevelTableSize; i++)    levelLevels[i] = (Byte)ReadBits(kNumBitsForPreTreeLevel);  RIF(m_LevelDecoder.SetCodeLengths(levelLevels));  int num = 0;  Byte symbol = 0;  for (i = 0; i < numSymbols;)  {    if (num != 0)    {      lastLevels[i] = newLevels[i] = symbol;      i++;      num--;      continue;    }    UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);    if (number == kLevelSymbolZeros)    {      num = kLevelSymbolZerosStartValue + ReadBits(kLevelSymbolZerosNumBits);      symbol = 0;    }    else if (number == kLevelSymbolZerosBig)    {      num = kLevelSymbolZerosBigStartValue + ReadBits(kLevelSymbolZerosBigNumBits);      symbol = 0;    }    else if (number == kLevelSymbolSame || number <= kNumHuffmanBits)    {      if (number <= kNumHuffmanBits)        num = 1;      else      {        num = kLevelSymbolSameStartValue + ReadBits(kLevelSymbolSameNumBits);        number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);        if (number > kNumHuffmanBits)          return false;      }      symbol = Byte((17 + lastLevels[i] - number) % (kNumHuffmanBits + 1));    }    else      return false;  }  return true;}bool CDecoder::ReadTables(void){  Byte newLevels[kMaxTableSize];  {    int blockType = (int)ReadBits(kNumBlockTypeBits);    if (blockType > kBlockTypeUncompressed)      return false;    m_UnCompressedBlockSize = m_InBitStream.ReadBitsBig(kUncompressedBlockSizeNumBits);        if (m_IsUncompressedBlock = (blockType == kBlockTypeUncompressed))    {      m_InBitStream.ReadBits(16 - m_InBitStream.GetBitPosition());      if (!m_InBitStream.ReadUInt32(m_RepDistances[0]))        return false;      m_RepDistances[0]--;      for (int i = 1; i < kNumRepDistances; i++)      {        UInt32 rep = 0;        for (int j = 0; j < 4; j++)          rep |= (UInt32)m_InBitStream.DirectReadByte() << (8 * j);        m_RepDistances[i] = rep - 1;      }      return true;    }    if (m_AlignIsUsed = (blockType == kBlockTypeAligned))    {      for(int i = 0; i < kAlignTableSize; i++)        newLevels[i] = ReadBits(kNumBitsForAlignLevel);      RIF(m_AlignDecoder.SetCodeLengths(newLevels));    }  }  RIF(ReadTable(m_LastMainLevels, newLevels, 256));  RIF(ReadTable(m_LastMainLevels + 256, newLevels + 256, m_NumPosLenSlots));  for (UInt32 i = 256 + m_NumPosLenSlots; i < kMainTableSize; i++)    newLevels[i] = 0;  RIF(m_MainDecoder.SetCodeLengths(newLevels));  RIF(ReadTable(m_LastLenLevels, newLevels, kNumLenSymbols));  return m_LenDecoder.SetCodeLengths(newLevels);}class CDecoderFlusher{  CDecoder *m_Decoder;public:  bool NeedFlush;  CDecoderFlusher(CDecoder *decoder): m_Decoder(decoder), NeedFlush(true) {}  ~CDecoderFlusher()  {    if (NeedFlush)      m_Decoder->Flush();    m_Decoder->ReleaseStreams();  }};void CDecoder::ClearPrevLevels(){  int i;  for (i = 0; i < kMainTableSize; i++)    m_LastMainLevels[i] = 0;  for (i = 0; i < kNumLenSymbols; i++)    m_LastLenLevels[i] = 0;};HRESULT CDecoder::CodeSpec(UInt32 curSize){  if (_remainLen == kLenIdNeedInit)  {    _remainLen = 0;    if (_keepHistory && m_IsUncompressedBlock && m_UnCompressedBlockSize > 0)      m_InBitStream.InitDirect();    else      m_InBitStream.InitNormal();    if (!_keepHistory)    {      m_UnCompressedBlockSize = 0;      ClearPrevLevels();      UInt32 i86TranslationSize = 0;      bool translationMode = (ReadBits(1) != 0);      if (translationMode)      {        i86TranslationSize = ReadBits(16) << 16;        i86TranslationSize |= ReadBits(16);      }      m_x86ConvertOutStreamSpec->Init(translationMode, i86TranslationSize);            for(int i = 0 ; i < kNumRepDistances; i++)        m_RepDistances[i] = 0;    }  }  if (curSize == 0)    return S_OK;  while(_remainLen > 0 && curSize > 0)  {    m_OutWindowStream.PutByte(m_OutWindowStream.GetByte(m_RepDistances[0]));    _remainLen--;    curSize--;  }  while(curSize > 0)  {    if (m_UnCompressedBlockSize == 0)     if (!ReadTables())       return S_FALSE;    UInt32 nowPos = 0;    UInt32 next = (Int32)MyMin(m_UnCompressedBlockSize, curSize);    curSize -= next;    m_UnCompressedBlockSize -= next;    if (m_IsUncompressedBlock)    {      while(next > 0)      {        m_OutWindowStream.PutByte(m_InBitStream.DirectReadByte());        next--;      }      if (m_UnCompressedBlockSize == 0)      {        m_InBitStream.Align(m_AlignPos);        // m_AlignPos = 0;      }    }    else while(next > 0)    {      UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);      if (number < 256)      {        m_OutWindowStream.PutByte((Byte)number);        next--;      }      else      {        UInt32 posLenSlot = number - 256;        if (posLenSlot >= m_NumPosLenSlots)          return S_FALSE;        UInt32 posSlot = posLenSlot / kNumLenSlots;        UInt32 lenSlot = posLenSlot % kNumLenSlots;        UInt32 len = kMatchMinLen + lenSlot;        if (lenSlot == kNumLenSlots - 1)        {          UInt32 lenTemp = m_LenDecoder.DecodeSymbol(&m_InBitStream);          if (lenTemp >= kNumLenSymbols)            return S_FALSE;          len += lenTemp;        }                if (posSlot < kNumRepDistances)        {          UInt32 distance = m_RepDistances[posSlot];          m_RepDistances[posSlot] = m_RepDistances[0];          m_RepDistances[0] = distance;        }        else        {          UInt32 distance;          int numDirectBits;          if (posSlot < kNumPowerPosSlots)          {            numDirectBits = (posSlot >> 1) - 1;            distance = ((2 | (posSlot & 1)) << numDirectBits);          }          else          {            numDirectBits = kNumLinearPosSlotBits;            distance = ((posSlot - 0x22) << kNumLinearPosSlotBits);          }          if (m_AlignIsUsed && numDirectBits >= kNumAlignBits)          {            distance += (m_InBitStream.ReadBits(numDirectBits - kNumAlignBits) << kNumAlignBits);            UInt32 alignTemp = m_AlignDecoder.DecodeSymbol(&m_InBitStream);            if (alignTemp >= kAlignTableSize)              return S_FALSE;            distance += alignTemp;          }          else            distance += m_InBitStream.ReadBits(numDirectBits);          m_RepDistances[2] = m_RepDistances[1];          m_RepDistances[1] = m_RepDistances[0];          m_RepDistances[0] = distance - kNumRepDistances;        }        UInt32 locLen = len;        if (locLen > next)          locLen = next;        if (!m_OutWindowStream.CopyBlock(m_RepDistances[0], locLen))          return S_FALSE;        len -= locLen;        next -= locLen;        if (len != 0)        {          _remainLen = len;          return S_OK;        }      }    }  }  return S_OK;}HRESULT CDecoder::CodeReal(ISequentialInStream *inStream,    ISequentialOutStream *outStream,     const UInt64 *, const UInt64 *outSize,    ICompressProgressInfo *progress){  if (outSize == NULL)    return E_INVALIDARG;  UInt64 size = *outSize;  const UInt64 startSize = size;  RINOK(SetInStream(inStream));  m_x86ConvertOutStreamSpec->SetStream(outStream);  m_OutWindowStream.SetStream(m_x86ConvertOutStream);  RINOK(SetOutStreamSize(outSize));  CDecoderFlusher flusher(this);  const UInt64 start = m_OutWindowStream.GetProcessedSize();  while(true)  {    UInt32 curSize = 1 << 18;    UInt64 rem = size - (m_OutWindowStream.GetProcessedSize() - start);    if (curSize > rem)      curSize = (UInt32)rem;    if (curSize == 0)      break;    RINOK(CodeSpec(curSize));    if (progress != NULL)    {      UInt64 inSize = m_InBitStream.GetProcessedSize();      UInt64 nowPos64 = m_OutWindowStream.GetProcessedSize() - start;      RINOK(progress->SetRatioInfo(&inSize, &nowPos64));    }  }   flusher.NeedFlush = false;  return Flush();}HRESULT CDecoder::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 CDecoder::SetInStream(ISequentialInStream *inStream){  m_InBitStream.SetStream(inStream);  return S_OK;}STDMETHODIMP CDecoder::ReleaseInStream(){  m_InBitStream.ReleaseStream();  return S_OK;}STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize){  if (outSize == NULL)    return E_FAIL;  _remainLen = kLenIdNeedInit;  m_OutWindowStream.Init(_keepHistory);  return S_OK;}HRESULT CDecoder::SetParams(int numDictBits){   if (numDictBits < kNumDictionaryBitsMin || numDictBits > kNumDictionaryBitsMax)    return E_INVALIDARG;  UInt32 numPosSlots;  if (numDictBits < 20)    numPosSlots = 30 + (numDictBits - 15) * 2;  else if (numDictBits == 20)    numPosSlots = 42;  else    numPosSlots = 50;  m_NumPosLenSlots = numPosSlots * kNumLenSlots;  if (!m_OutWindowStream.Create(kDictionarySizeMax))    return E_OUTOFMEMORY;  if (!m_InBitStream.Create(1 << 16))    return E_OUTOFMEMORY;  return S_OK;}}}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?