bzip2encoder.cpp

来自「由7-zip提供的压缩、解压缩程序」· C++ 代码 · 共 877 行 · 第 1/2 页

CPP
877
字号
          do            huffEncoder.AddSymbol(symbols[j]);          while (++j < i);        }        while (mtfPos < mtfArraySize);      }            int t = 0;      do      {        NCompression::NHuffman::CEncoder &huffEncoder = m_HuffEncoders[t];        int i = 0;        do          if (huffEncoder.m_Items[i].Freq == 0)            huffEncoder.m_Items[i].Freq = 1;        while(++i < alphaSize);        Byte levels[kMaxAlphaSize];        huffEncoder.BuildTree(levels);      }      while(++t < numTables);    }        {      Byte mtfSel[kNumTablesMax];      {        int t = 0;        do          mtfSel[t] = (Byte)t;        while(++t < numTables);      }            UInt32 i = 0;      do      {        Byte sel = m_Selectors[i];        int pos;        for (pos = 0; mtfSel[pos] != sel; pos++)          WriteBit2(true);        WriteBit2(false);        for (; pos > 0; pos--)          mtfSel[pos] = mtfSel[pos - 1];        mtfSel[0] = sel;      }      while(++i < numSelectors);    }        {      int t = 0;      do      {        NCompression::NHuffman::CItem *items = m_HuffEncoders[t].m_Items;        UInt32 len = items[0].Len;        WriteBits2(len, kNumLevelsBits);        int i = 0;        do        {          UInt32 level = items[i].Len;          while (len != level)          {            WriteBit2(true);            if (len < level)            {              WriteBit2(false);              len++;            }            else             {              WriteBit2(true);              len--;            }          }          WriteBit2(false);        }        while (++i < alphaSize);      }      while(++t < numTables);    }        {      UInt32 groupSize = 0;      UInt32 groupIndex = 0;      NCompression::NHuffman::CEncoder *huffEncoder = 0;      UInt32 mtfPos = 0;      do      {        UInt32 symbol = mtfs[mtfPos++];        if (symbol >= 0xFF)          symbol += mtfs[mtfPos++];        if (groupSize == 0)         {          groupSize = kGroupSize;          huffEncoder = &m_HuffEncoders[m_Selectors[groupIndex++]];        }        groupSize--;                                    \        huffEncoder->CodeOneValue(m_OutStreamCurrent, symbol);      }      while (mtfPos < mtfArraySize);    }    if (!m_OptimizeNumTables)      break;    UInt32 price = m_OutStreamCurrent->GetPos() - startPos;    if (price <= bestPrice)    {      if (nt == kNumTablesMax)        break;      bestPrice = price;      bestNumTables = nt;    }  }}// blockSize > 0UInt32 CThreadInfo::EncodeBlockWithHeaders(Byte *block, UInt32 blockSize){  WriteByte2(kBlockSig0);  WriteByte2(kBlockSig1);  WriteByte2(kBlockSig2);  WriteByte2(kBlockSig3);  WriteByte2(kBlockSig4);  WriteByte2(kBlockSig5);  CBZip2CRC crc;  int numReps = 0;  Byte prevByte = block[0];  UInt32 i = 0;  do   {    Byte b = block[i];    if (numReps == kRleModeRepSize)    {      for (; b > 0; b--)        crc.UpdateByte(prevByte);      numReps = 0;      continue;    }    if (prevByte == b)      numReps++;    else    {      numReps = 1;      prevByte = b;    }    crc.UpdateByte(b);  }  while (++i < blockSize);  UInt32 crcRes = crc.GetDigest();  WriteCRC2(crcRes);  EncodeBlock(block, blockSize);  return crcRes;}void CThreadInfo::EncodeBlock2(Byte *block, UInt32 blockSize, UInt32 numPasses){  UInt32 numCrcs = m_NumCrcs;  bool needCompare = false;  UInt32 startBytePos = m_OutStreamCurrent->GetBytePos();  UInt32 startPos = m_OutStreamCurrent->GetPos();  UInt32 startCurByte = m_OutStreamCurrent->GetCurByte();  UInt32 endCurByte;  UInt32 endPos;  if (numPasses > 1 && blockSize >= (1 << 10))  {    UInt32 blockSize0 = blockSize / 2;    for (;(block[blockSize0] == block[blockSize0 - 1] ||          block[blockSize0 - 1] == block[blockSize0 - 2]) &&           blockSize0 < blockSize; blockSize0++);    if (blockSize0 < blockSize)    {      EncodeBlock2(block, blockSize0, numPasses - 1);      EncodeBlock2(block + blockSize0, blockSize - blockSize0, numPasses - 1);      endPos = m_OutStreamCurrent->GetPos();      endCurByte = m_OutStreamCurrent->GetCurByte();      if ((endPos & 7) > 0)        WriteBits2(0, 8 - (endPos & 7));      m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte);      needCompare = true;    }  }  UInt32 startBytePos2 = m_OutStreamCurrent->GetBytePos();  UInt32 startPos2 = m_OutStreamCurrent->GetPos();  UInt32 crcVal = EncodeBlockWithHeaders(block, blockSize);  UInt32 endPos2 = m_OutStreamCurrent->GetPos();  if (needCompare)  {    UInt32 size2 = endPos2 - startPos2;    if (size2 < endPos - startPos)    {       UInt32 numBytes = m_OutStreamCurrent->GetBytePos() - startBytePos2;      Byte *buffer = m_OutStreamCurrent->GetStream();      for (UInt32 i = 0; i < numBytes; i++)        buffer[startBytePos + i] = buffer[startBytePos2 + i];      m_OutStreamCurrent->SetPos(startPos + endPos2 - startPos2);      m_NumCrcs = numCrcs;      m_CRCs[m_NumCrcs++] = crcVal;    }    else    {      m_OutStreamCurrent->SetPos(endPos);      m_OutStreamCurrent->SetCurState((endPos & 7), endCurByte);    }  }  else  {    m_NumCrcs = numCrcs;    m_CRCs[m_NumCrcs++] = crcVal;  }}HRESULT CThreadInfo::EncodeBlock3(UInt32 blockSize){  CMsbfEncoderTemp outStreamTemp;  outStreamTemp.SetStream(m_TempArray);  outStreamTemp.Init();  m_OutStreamCurrent = &outStreamTemp;  m_NumCrcs = 0;  EncodeBlock2(m_Block, blockSize, Encoder->NumPasses);  #ifdef COMPRESS_BZIP2_MT  if (Encoder->MtMode)    Encoder->ThreadsInfo[m_BlockIndex].CanWriteEvent.Lock();  #endif  for (UInt32 i = 0; i < m_NumCrcs; i++)    Encoder->CombinedCRC.Update(m_CRCs[i]);  Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetCurByte());  HRESULT res = S_OK;  #ifdef COMPRESS_BZIP2_MT  if (Encoder->MtMode)  {    UInt32 blockIndex = m_BlockIndex + 1;    if (blockIndex == Encoder->NumThreads)      blockIndex = 0;    if (Encoder->Progress)    {      UInt64 unpackSize = Encoder->m_OutStream.GetProcessedSize();      res = Encoder->Progress->SetRatioInfo(&m_PackSize, &unpackSize);    }    Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set();  }  #endif  return res;}void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte){  UInt32 bytesSize = (sizeInBits / 8);  for (UInt32 i = 0; i < bytesSize; i++)    m_OutStream.WriteBits(data[i], 8);  WriteBits(lastByte, (sizeInBits & 7));}HRESULT CEncoder::CodeReal(ISequentialInStream *inStream,    ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,    ICompressProgressInfo *progress){  #ifdef COMPRESS_BZIP2_MT  Progress = progress;  if (!Create())    return E_FAIL;  for (UInt32 t = 0; t < NumThreads; t++)  #endif  {    #ifdef COMPRESS_BZIP2_MT    CThreadInfo &ti = ThreadsInfo[t];    ti.StreamWasFinishedEvent.Reset();    ti.WaitingWasStartedEvent.Reset();    ti.CanWriteEvent.Reset();    #else    CThreadInfo &ti = ThreadsInfo;    ti.Encoder = this;    #endif    ti.m_OptimizeNumTables = m_OptimizeNumTables;    if (!ti.Create())      return E_OUTOFMEMORY;  }  if (!m_InStream.Create(kBufferSize))    return E_OUTOFMEMORY;  if (!m_OutStream.Create(kBufferSize))    return E_OUTOFMEMORY;  m_InStream.SetStream(inStream);  m_InStream.Init();  m_OutStream.SetStream(outStream);  m_OutStream.Init();  CFlusher flusher(this);  CombinedCRC.Init();  #ifdef COMPRESS_BZIP2_MT  NextBlockIndex = 0;  StreamWasFinished = false;  CloseThreads = false;  CanStartWaitingEvent.Reset();  #endif  WriteByte(kArSig0);  WriteByte(kArSig1);  WriteByte(kArSig2);  WriteByte((Byte)(kArSig3 + m_BlockSizeMult));  #ifdef COMPRESS_BZIP2_MT  if (MtMode)  {    ThreadsInfo[0].CanWriteEvent.Set();    Result = S_OK;    CS.Leave();    UInt32 t;    for (t = 0; t < NumThreads; t++)      ThreadsInfo[t].StreamWasFinishedEvent.Lock();    CS.Enter();    CanStartWaitingEvent.Set();    for (t = 0; t < NumThreads; t++)      ThreadsInfo[t].WaitingWasStartedEvent.Lock();    CanStartWaitingEvent.Reset();    RINOK(Result);  }  else  #endif  {    while (true)    {      CThreadInfo &ti =       #ifdef COMPRESS_BZIP2_MT      ThreadsInfo[0];      #else      ThreadsInfo;      #endif      UInt32 blockSize = ReadRleBlock(ti.m_Block);      if (blockSize == 0)        break;      RINOK(ti.EncodeBlock3(blockSize));      if (progress)      {        UInt64 packSize = m_InStream.GetProcessedSize();        UInt64 unpackSize = m_OutStream.GetProcessedSize();        RINOK(progress->SetRatioInfo(&packSize, &unpackSize));      }    }  }  WriteByte(kFinSig0);  WriteByte(kFinSig1);  WriteByte(kFinSig2);  WriteByte(kFinSig3);  WriteByte(kFinSig4);  WriteByte(kFinSig5);  WriteCRC(CombinedCRC.GetDigest());  return S_OK;}STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream,    ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,    ICompressProgressInfo *progress){  try { return CodeReal(inStream, outStream, inSize, outSize, progress); }  catch(const CInBufferException &e) { return e.ErrorCode; }  catch(const COutBufferException &e) { return e.ErrorCode; }  catch(...) { return S_FALSE; }}HRESULT CEncoder::SetCoderProperties(const PROPID *propIDs,     const PROPVARIANT *properties, UInt32 numProperties){  for(UInt32 i = 0; i < numProperties; i++)  {    const PROPVARIANT &property = properties[i];     switch(propIDs[i])    {      case NCoderPropID::kNumPasses:      {        if (property.vt != VT_UI4)          return E_INVALIDARG;        UInt32 numPasses = property.ulVal;        if (numPasses == 0)          numPasses = 1;        if (numPasses > kNumPassesMax)          numPasses = kNumPassesMax;        NumPasses = numPasses;        m_OptimizeNumTables = (NumPasses > 1);        break;      }      case NCoderPropID::kDictionarySize:      {        if (property.vt != VT_UI4)          return E_INVALIDARG;        UInt32 dictionary = property.ulVal / kBlockSizeStep;        if (dictionary < kBlockSizeMultMin)          dictionary = kBlockSizeMultMin;        else if (dictionary > kBlockSizeMultMax)          dictionary = kBlockSizeMultMax;        m_BlockSizeMult = dictionary;        break;      }      case NCoderPropID::kNumThreads:      {        #ifdef COMPRESS_BZIP2_MT        if (property.vt != VT_UI4)          return E_INVALIDARG;        NumThreads = property.ulVal;        if (NumThreads < 1)          NumThreads = 1;        #endif        break;      }      default:        return E_INVALIDARG;    }  }  return S_OK;}#ifdef COMPRESS_BZIP2_MTSTDMETHODIMP CEncoder::SetNumberOfThreads(UInt32 numThreads){  NumThreads = numThreads;  if (NumThreads < 1)    NumThreads = 1;  return S_OK;}#endif}}

⌨️ 快捷键说明

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