⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rar3decoder.cpp

📁 7-Zip 是一款号称有着现今最高压缩比的压缩软件
💻 CPP
📖 第 1 页 / 共 2 页
字号:
    if (c == PpmEscChar)
    {
      int nextCh = DecodePpmSymbol();
      if (nextCh == 0)
        return ReadTables(keepDecompressing);
      if (nextCh == 2 || nextCh == -1)
        return S_OK;
      if (nextCh == 3)
      {
        if (!ReadVmCodePPM())
          return S_FALSE;
        continue;
      }
      if (nextCh == 4 || nextCh == 5)
      {
        UInt32 distance = 0;
        UInt32 length = 4;
        if (nextCh == 4)
        {
          for (int i = 0; i < 3; i++)
          {
            int c = DecodePpmSymbol();
            if (c == -1)
              return S_OK;
            distance = (distance << 8) + (Byte)c;
          }
          distance++;
          length += 28;
        }
        int c = DecodePpmSymbol();
        if (c == -1)
          return S_OK;
        length += c;
        if (distance >= _lzSize)
          return S_FALSE;
        CopyBlock(distance, length);
        num -= (Int32)length;
        continue;
      }
    }
    PutByte((Byte)c);
    num--;
  }
  while (num >= 0);
  keepDecompressing = true;
  return S_OK;
}

/////////////////////////////////////////////////
// LZ

HRESULT CDecoder::ReadTables(bool &keepDecompressing)
{
  keepDecompressing = true;
  ReadBits((8 - m_InBitStream.GetBitPosition()) & 7);
  if (ReadBits(1) != 0)
  {
    _lzMode = false;
    return InitPPM();
  }

  _lzMode = true;
  PrevAlignBits = 0;
  PrevAlignCount = 0;

  Byte levelLevels[kLevelTableSize];
  Byte newLevels[kTablesSizesSum];

  if (ReadBits(1) == 0)
    memset(m_LastLevels, 0, kTablesSizesSum);

  int i;
  for (i = 0; i < kLevelTableSize; i++)
  {
    UInt32 length = ReadBits(4);
    if (length == 15)
    {
      UInt32 zeroCount = ReadBits(4);
      if (zeroCount != 0)
      {
        zeroCount += 2;
        while (zeroCount-- > 0 && i < kLevelTableSize)
          levelLevels[i++]=0;
        i--;
        continue;
      }
    }
    levelLevels[i] = (Byte)length;
  }
  RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
  i = 0;
  while (i < kTablesSizesSum)
  {
    UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
    if (number < 16)
    {
      newLevels[i] = Byte((number + m_LastLevels[i]) & 15);
      i++;
    }
    else if (number > kLevelTableSize)
      return S_FALSE;
    else
    {
      int num;
      if (((number - 16) & 1) == 0)
        num = ReadBits(3) + 3;
      else
        num = ReadBits(7) + 11;
      if (number < 18)
      {
        if (i == 0)
          return S_FALSE;
        for (; num > 0 && i < kTablesSizesSum; num--, i++)
          newLevels[i] = newLevels[i - 1];
      }
      else
      {
        for (; num > 0 && i < kTablesSizesSum; num--)
          newLevels[i++] = 0;
      }
    }
  }
  TablesRead = true;

  // original code has check here:
  /*
  if (InAddr > ReadTop)
  {
    keepDecompressing = false;
    return true;
  }
  */

  RIF(m_MainDecoder.SetCodeLengths(&newLevels[0]));
  RIF(m_DistDecoder.SetCodeLengths(&newLevels[kMainTableSize]));
  RIF(m_AlignDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize]));
  RIF(m_LenDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize + kAlignTableSize]));

  memcpy(m_LastLevels, newLevels, kTablesSizesSum);
  return S_OK;
}

class CCoderReleaser
{
  CDecoder *m_Coder;
public:
  CCoderReleaser(CDecoder *coder): m_Coder(coder) {}
  ~CCoderReleaser()
  {
    // m_Coder->m_OutWindowStream.Flush();
    m_Coder->ReleaseStreams();
  }
};

HRESULT CDecoder::ReadEndOfBlock(bool &keepDecompressing)
{
  if (ReadBits(1) != 0)
  {
    // old file
    TablesRead = false;
    return ReadTables(keepDecompressing);
  }
  // new file
  keepDecompressing = false;
  TablesRead = (ReadBits(1) == 0);
  return S_OK;
}

UInt32 kDistStart[kDistTableSize];

class CDistInit
{
public:
  CDistInit() { Init(); }
  void Init()
  {
    UInt32 start = 0;
    for (UInt32 i = 0; i < kDistTableSize; i++)
    {
      kDistStart[i] = start;
      start += (1 << kDistDirectBits[i]);
    }
  }
} g_DistInit;

HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
{
  UInt32 rep0 = _reps[0];
  UInt32 rep1 = _reps[1];
  UInt32 rep2 = _reps[2];
  UInt32 rep3 = _reps[3];
  UInt32 length = _lastLength;
  for (;;)
  {
    if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos)
    {
      RINOK(WriteBuf());
      if (_writtenFileSize > _unpackSize)
      {
        keepDecompressing = false;
        return S_OK;
      }
    }
    UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
    if (number < 256)
    {
      PutByte(Byte(number));

      continue;
    }
    else if (number == kSymbolReadTable)
    {
      RINOK(ReadEndOfBlock(keepDecompressing));
      break;
    }
    else if (number == 257)
    {
      if (!ReadVmCodeLZ())
        return S_FALSE;
      continue;
    }
    else if (number == 258)
    {
    }
    else if (number < kSymbolRep + 4)
    {
      if (number != kSymbolRep)
      {
        UInt32 distance;
        if (number == kSymbolRep + 1)
          distance = rep1;
        else
        {
          if (number == kSymbolRep + 2)
            distance = rep2;
          else
          {
            distance = rep3;
            rep3 = rep2;
          }
          rep2 = rep1;
        }
        rep1 = rep0;
        rep0 = distance;
      }

      UInt32 number = m_LenDecoder.DecodeSymbol(&m_InBitStream);
      if (number >= kLenTableSize)
        return S_FALSE;
      length = 2 + kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]);
    }
    else
    {
      rep3 = rep2;
      rep2 = rep1;
      rep1 = rep0;
      if (number < 271)
      {
        number -= 263;
        rep0 = kLen2DistStarts[number] + m_InBitStream.ReadBits(kLen2DistDirectBits[number]);
        length = 2;
      }
      else if (number < 299)
      {
        number -= 271;
        length = kNormalMatchMinLen + (UInt32)kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]);
        UInt32 number = m_DistDecoder.DecodeSymbol(&m_InBitStream);
        if (number >= kDistTableSize)
          return S_FALSE;
        rep0 = kDistStart[number];
        int numBits = kDistDirectBits[number];
        if (number >= (kNumAlignBits * 2) + 2)
        {
          if (numBits > kNumAlignBits)
            rep0 += (m_InBitStream.ReadBits(numBits - kNumAlignBits) << kNumAlignBits);
          if (PrevAlignCount > 0)
          {
            PrevAlignCount--;
            rep0 += PrevAlignBits;
          }
          else
          {
            UInt32 number = m_AlignDecoder.DecodeSymbol(&m_InBitStream);
            if (number < (1 << kNumAlignBits))
            {
              rep0 += number;
              PrevAlignBits = number;
            }
            else if (number  == (1 << kNumAlignBits))
            {
              PrevAlignCount = kNumAlignReps;
              rep0 += PrevAlignBits;
            }
            else
              return S_FALSE;
          }
        }
        else
          rep0 += m_InBitStream.ReadBits(numBits);
        length += ((kDistLimit4 - rep0) >> 31) + ((kDistLimit3 - rep0) >> 31);
      }
      else
        return S_FALSE;
    }
    if (rep0 >= _lzSize)
      return S_FALSE;
    CopyBlock(rep0, length);
  }
  _reps[0] = rep0;
  _reps[1] = rep1;
  _reps[2] = rep2;
  _reps[3] = rep3;
  _lastLength = length;

  return S_OK;
}

HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress)
{
  _writtenFileSize = 0;
  if (!m_IsSolid)
  {
    _lzSize = 0;
    _winPos = 0;
    _wrPtr = 0;
    for (int i = 0; i < kNumReps; i++)
      _reps[i] = 0;
    _lastLength = 0;
    memset(m_LastLevels, 0, kTablesSizesSum);
    TablesRead = false;
    PpmEscChar = 2;
    InitFilters();
  }
  if (!m_IsSolid || !TablesRead)
  {
    bool keepDecompressing;
    RINOK(ReadTables(keepDecompressing));
    if (!keepDecompressing)
      return S_OK;
  }

  for(;;)
  {
    bool keepDecompressing;
    if (_lzMode)
    {
      RINOK(DecodeLZ(keepDecompressing))
    }
    else
    {
      RINOK(DecodePPM(1 << 18, keepDecompressing))
    }
    UInt64 packSize = m_InBitStream.GetProcessedSize();
    RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize));
    if (!keepDecompressing)
      break;
  }
  RINOK(WriteBuf());
  if (_writtenFileSize < _unpackSize)
    return S_FALSE;
  // return m_OutWindowStream.Flush();
  return S_OK;
}

STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream,
    ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
    ICompressProgressInfo *progress)
{
  try
  {
    if (inSize == NULL || outSize == NULL)
      return E_INVALIDARG;

    if (_vmData == 0)
    {
      _vmData = (Byte *)::MidAlloc(kVmDataSizeMax + kVmCodeSizeMax);
      if (_vmData == 0)
        return E_OUTOFMEMORY;
      _vmCode = _vmData + kVmDataSizeMax;
    }
    
    if (_window == 0)
    {
      _window = (Byte *)::MidAlloc(kWindowSize);
      if (_window == 0)
        return E_OUTOFMEMORY;
    }
    if (!m_InBitStream.Create(1 << 20))
      return E_OUTOFMEMORY;
    if (!_vm.Create())
      return E_OUTOFMEMORY;

    
    m_InBitStream.SetStream(inStream);
    m_InBitStream.Init();
    _outStream = outStream;
   
    CCoderReleaser coderReleaser(this);
    _unpackSize = *outSize;
    return CodeReal(progress);
  }
  catch(const CInBufferException &e)  { return e.ErrorCode; }
  catch(...) { return S_FALSE; }
  // CNewException is possible here. But probably CNewException is caused
  // by error in data stream.
}

STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
{
  if (size < 1)
    return E_INVALIDARG;
  m_IsSolid = (data[0] != 0);
  return S_OK;
}

}}

⌨️ 快捷键说明

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