bzip2encoder.cpp
来自「由7-zip提供的压缩、解压缩程序」· C++ 代码 · 共 877 行 · 第 1/2 页
CPP
877 行
// BZip2Encoder.cpp#include "StdAfx.h"#include "../../../Common/Alloc.h"#include "BZip2Encoder.h"#include "../BWT/Mtf8.h"#include "BZip2CRC.h"namespace NCompress {namespace NBZip2 {static const UInt32 kBufferSize = (1 << 17);static const int kNumHuffPasses = 4;bool CThreadInfo::Create(){ if (!m_BlockSorter.Create(kBlockSizeMax)) return false; if (m_Block == 0) { m_Block = (Byte *)::BigAlloc(kBlockSizeMax * 5 + kBlockSizeMax / 10 + (20 << 10)); if (m_Block == 0) return false; m_MtfArray = m_Block + kBlockSizeMax; m_TempArray = m_MtfArray + kBlockSizeMax * 2 + 2; } if (m_NeedHuffmanCreate) { for (int i = 0; i < kNumTablesMax; i++) if (!m_HuffEncoders[i].Create(kMaxAlphaSize, 0, 0, kMaxHuffmanLen)) return false; m_NeedHuffmanCreate = false; } return true;}void CThreadInfo::Free(){ m_BlockSorter.Free(); ::BigFree(m_Block); m_Block = 0;}#ifdef COMPRESS_BZIP2_MTvoid CThreadInfo::FinishStream(bool needLeave){ Encoder->StreamWasFinished = true; StreamWasFinishedEvent.Set(); if (needLeave) Encoder->CS.Leave(); Encoder->CanStartWaitingEvent.Lock(); WaitingWasStartedEvent.Set();}DWORD CThreadInfo::ThreadFunc(){ while (true) { Encoder->CS.Enter(); if (Encoder->CloseThreads) { Encoder->CS.Leave(); return 0; } if (Encoder->StreamWasFinished) { FinishStream(true); continue; } HRESULT res = S_OK; bool needLeave = true; try { UInt32 blockSize = Encoder->ReadRleBlock(m_Block); m_PackSize = Encoder->m_InStream.GetProcessedSize(); m_BlockIndex = Encoder->NextBlockIndex; if (++Encoder->NextBlockIndex == Encoder->NumThreads) Encoder->NextBlockIndex = 0; if (blockSize == 0) { FinishStream(true); continue; } Encoder->CS.Leave(); needLeave = false; res = EncodeBlock3(blockSize); } catch(const CInBufferException &e) { res = e.ErrorCode; } catch(const COutBufferException &e) { res = e.ErrorCode; } catch(...) { res = E_FAIL; } if (res != S_OK) { Encoder->Result = res; FinishStream(needLeave); continue; } }}static DWORD WINAPI MFThread(void *threadCoderInfo){ return ((CThreadInfo *)threadCoderInfo)->ThreadFunc();}#endifCEncoder::CEncoder(): NumPasses(1), m_OptimizeNumTables(false), m_BlockSizeMult(kBlockSizeMultMax){ #ifdef COMPRESS_BZIP2_MT ThreadsInfo = 0; m_NumThreadsPrev = 0; NumThreads = 1; CS.Enter(); #endif}#ifdef COMPRESS_BZIP2_MTCEncoder::~CEncoder(){ Free();}bool CEncoder::Create(){ try { if (ThreadsInfo != 0 && m_NumThreadsPrev == NumThreads) return true; Free(); MtMode = (NumThreads > 1); m_NumThreadsPrev = NumThreads; ThreadsInfo = new CThreadInfo[NumThreads]; if (ThreadsInfo == 0) return false; for (UInt32 t = 0; t < NumThreads; t++) { CThreadInfo &ti = ThreadsInfo[t]; ti.Encoder = this; if (MtMode) if (!ti.Thread.Create(MFThread, &ti)) { NumThreads = t; Free(); return false; } } } catch(...) { return false; } return true;}void CEncoder::Free(){ if (!ThreadsInfo) return; CloseThreads = true; CS.Leave(); for (UInt32 t = 0; t < NumThreads; t++) { CThreadInfo &ti = ThreadsInfo[t]; if (MtMode) ti.Thread.Wait(); ti.Free(); } delete []ThreadsInfo; ThreadsInfo = 0;}#endifUInt32 CEncoder::ReadRleBlock(Byte *buffer){ UInt32 i = 0; Byte prevByte; if (m_InStream.ReadByte(prevByte)) { UInt32 blockSize = m_BlockSizeMult * kBlockSizeStep - 1; int numReps = 1; buffer[i++] = prevByte; while (i < blockSize) // "- 1" to support RLE { Byte b; if (!m_InStream.ReadByte(b)) break; if (b != prevByte) { if (numReps >= kRleModeRepSize) buffer[i++] = numReps - kRleModeRepSize; buffer[i++] = b; numReps = 1; prevByte = b; continue; } numReps++; if (numReps <= kRleModeRepSize) buffer[i++] = b; else if (numReps == kRleModeRepSize + 255) { buffer[i++] = numReps - kRleModeRepSize; numReps = 0; } } // it's to support original BZip2 decoder if (numReps >= kRleModeRepSize) buffer[i++] = numReps - kRleModeRepSize; } return i;}void CThreadInfo::WriteBits2(UInt32 value, UInt32 numBits) { m_OutStreamCurrent->WriteBits(value, numBits); }void CThreadInfo::WriteByte2(Byte b) { WriteBits2(b , 8); }void CThreadInfo::WriteBit2(bool v) { WriteBits2((v ? 1 : 0), 1); }void CThreadInfo::WriteCRC2(UInt32 v) { for (int i = 0; i < 4; i++) WriteByte2(((Byte)(v >> (24 - i * 8))));}void CEncoder::WriteBits(UInt32 value, UInt32 numBits) { m_OutStream.WriteBits(value, numBits); }void CEncoder::WriteByte(Byte b) { WriteBits(b , 8); }void CEncoder::WriteBit(bool v) { WriteBits((v ? 1 : 0), 1); }void CEncoder::WriteCRC(UInt32 v) { for (int i = 0; i < 4; i++) WriteByte(((Byte)(v >> (24 - i * 8))));}// blockSize > 0void CThreadInfo::EncodeBlock(Byte *block, UInt32 blockSize){ WriteBit2(false); // Randomised = false { UInt32 origPtr = m_BlockSorter.Sort(block, blockSize); WriteBits2(origPtr, kNumOrigBits); } CMtf8Encoder mtf; int numInUse = 0; { bool inUse[256]; bool inUse16[16]; UInt32 i; for (i = 0; i < 256; i++) inUse[i] = false; for (i = 0; i < 16; i++) inUse16[i] = false; for (i = 0; i < blockSize; i++) inUse[block[i]] = true; for (i = 0; i < 256; i++) if (inUse[i]) { inUse16[i >> 4] = true; mtf.Buffer[numInUse++] = (Byte)i; } for (i = 0; i < 16; i++) WriteBit2(inUse16[i]); for (i = 0; i < 256; i++) if (inUse16[i >> 4]) WriteBit2(inUse[i]); } int alphaSize = numInUse + 2; Byte *mtfs = m_MtfArray; UInt32 mtfArraySize = 0; UInt32 symbolCounts[kMaxAlphaSize]; { for (int i = 0; i < kMaxAlphaSize; i++) symbolCounts[i] = 0; } { UInt32 rleSize = 0; UInt32 i = 0; do { UInt32 index = m_BlockSorter.Indices[i]; if (index == 0) index = blockSize - 1; else index--; int pos = mtf.FindAndMove(block[index]); if (pos == 0) rleSize++; else { while (rleSize != 0) { rleSize--; mtfs[mtfArraySize++] = (rleSize & 1); symbolCounts[rleSize & 1]++; rleSize >>= 1; } if (pos >= 0xFE) { mtfs[mtfArraySize++] = 0xFF; mtfs[mtfArraySize++] = pos - 0xFE; } else mtfs[mtfArraySize++] = pos + 1; symbolCounts[pos + 1]++; } } while (++i < blockSize); while (rleSize != 0) { rleSize--; mtfs[mtfArraySize++] = (rleSize & 1); symbolCounts[rleSize & 1]++; rleSize >>= 1; } if (alphaSize < 256) mtfs[mtfArraySize++] = (Byte)(alphaSize - 1); else { mtfs[mtfArraySize++] = 0xFF; mtfs[mtfArraySize++] = (Byte)(alphaSize - 256); } symbolCounts[alphaSize - 1]++; } UInt32 numSymbols = 0; { for (int i = 0; i < kMaxAlphaSize; i++) numSymbols += symbolCounts[i]; } int bestNumTables = kNumTablesMin; UInt32 bestPrice = 0xFFFFFFFF; UInt32 startPos = m_OutStreamCurrent->GetPos(); UInt32 startCurByte = m_OutStreamCurrent->GetCurByte(); for (int nt = kNumTablesMin; nt <= kNumTablesMax + 1; nt++) { int numTables; if(m_OptimizeNumTables) { m_OutStreamCurrent->SetPos(startPos); m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte); if (nt <= kNumTablesMax) numTables = nt; else numTables = bestNumTables; } else { if (numSymbols < 200) numTables = 2; else if (numSymbols < 600) numTables = 3; else if (numSymbols < 1200) numTables = 4; else if (numSymbols < 2400) numTables = 5; else numTables = 6; } WriteBits2(numTables, kNumTablesBits); UInt32 numSelectors = (numSymbols + kGroupSize - 1) / kGroupSize; WriteBits2(numSelectors, kNumSelectorsBits); { UInt32 remFreq = numSymbols; int gs = 0; int t = numTables; do { UInt32 tFreq = remFreq / t; int ge = gs; UInt32 aFreq = 0; while (aFreq < tFreq) // && ge < alphaSize) aFreq += symbolCounts[ge++]; if (ge - 1 > gs && t != numTables && t != 1 && (((numTables - t) & 1) == 1)) aFreq -= symbolCounts[--ge]; NCompression::NHuffman::CEncoder &huffEncoder = m_HuffEncoders[t - 1]; int i = 0; do huffEncoder.m_Items[i].Len = (i >= gs && i < ge) ? 0 : 1; while (++i < alphaSize); gs = ge; remFreq -= aFreq; } while(--t != 0); } for (int pass = 0; pass < kNumHuffPasses; pass++) { { int t = 0; do m_HuffEncoders[t].StartNewBlock(); while(++t < numTables); } { UInt32 mtfPos = 0; UInt32 g = 0; do { UInt32 symbols[kGroupSize]; int i = 0; do { UInt32 symbol = mtfs[mtfPos++]; if (symbol >= 0xFF) symbol += mtfs[mtfPos++]; symbols[i] = symbol; } while (++i < kGroupSize && mtfPos < mtfArraySize); UInt32 bestPrice = 0xFFFFFFFF; int t = 0; do { NCompression::NHuffman::CItem *items = m_HuffEncoders[t].m_Items; UInt32 price = 0; int j = 0; do price += items[symbols[j]].Len; while (++j < i); if (price < bestPrice) { m_Selectors[g] = (Byte)t; bestPrice = price; } } while(++t < numTables); NCompression::NHuffman::CEncoder &huffEncoder = m_HuffEncoders[m_Selectors[g++]]; int j = 0;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?