// BZip2Encoder.h #ifndef __COMPRESS_BZIP2_ENCODER_H #define __COMPRESS_BZIP2_ENCODER_H #include "../../Common/Defs.h" #include "../../Common/MyCom.h" #ifndef _7ZIP_ST #include "../../Windows/Synchronization.h" #include "../../Windows/Thread.h" #endif #include "../ICoder.h" #include "../Common/InBuffer.h" #include "../Common/OutBuffer.h" #include "BitmEncoder.h" #include "BZip2Const.h" #include "BZip2Crc.h" namespace NCompress { namespace NBZip2 { class CMsbfEncoderTemp { UInt32 m_Pos; int m_BitPos; Byte m_CurByte; Byte *Buffer; public: void SetStream(Byte *buffer) { Buffer = buffer; } Byte *GetStream() const { return Buffer; } void Init() { m_Pos = 0; m_BitPos = 8; m_CurByte = 0; } void Flush() { if (m_BitPos < 8) WriteBits(0, m_BitPos); } void WriteBits(UInt32 value, int numBits) { while (numBits > 0) { int numNewBits = MyMin(numBits, m_BitPos); numBits -= numNewBits; m_CurByte <<= numNewBits; UInt32 newBits = value >> numBits; m_CurByte |= Byte(newBits); value -= (newBits << numBits); m_BitPos -= numNewBits; if (m_BitPos == 0) { Buffer[m_Pos++] = m_CurByte; m_BitPos = 8; } } } UInt32 GetBytePos() const { return m_Pos ; } UInt32 GetPos() const { return m_Pos * 8 + (8 - m_BitPos); } Byte GetCurByte() const { return m_CurByte; } void SetPos(UInt32 bitPos) { m_Pos = bitPos / 8; m_BitPos = 8 - ((int)bitPos & 7); } void SetCurState(int bitPos, Byte curByte) { m_BitPos = 8 - bitPos; m_CurByte = curByte; } }; class CEncoder; const int kNumPassesMax = 10; class CThreadInfo { public: Byte *m_Block; private: Byte *m_MtfArray; Byte *m_TempArray; UInt32 *m_BlockSorterIndex; CMsbfEncoderTemp *m_OutStreamCurrent; Byte Lens[kNumTablesMax][kMaxAlphaSize]; UInt32 Freqs[kNumTablesMax][kMaxAlphaSize]; UInt32 Codes[kNumTablesMax][kMaxAlphaSize]; Byte m_Selectors[kNumSelectorsMax]; UInt32 m_CRCs[1 << kNumPassesMax]; UInt32 m_NumCrcs; UInt32 m_BlockIndex; void WriteBits2(UInt32 value, UInt32 numBits); void WriteByte2(Byte b); void WriteBit2(bool v); void WriteCrc2(UInt32 v); void EncodeBlock(const Byte *block, UInt32 blockSize); UInt32 EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize); void EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses); public: bool m_OptimizeNumTables; CEncoder *Encoder; #ifndef _7ZIP_ST NWindows::CThread Thread; NWindows::NSynchronization::CAutoResetEvent StreamWasFinishedEvent; NWindows::NSynchronization::CAutoResetEvent WaitingWasStartedEvent; // it's not member of this thread. We just need one event per thread NWindows::NSynchronization::CAutoResetEvent CanWriteEvent; UInt64 m_PackSize; Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size. HRESULT Create(); void FinishStream(bool needLeave); DWORD ThreadFunc(); #endif CThreadInfo(): m_BlockSorterIndex(0), m_Block(0) {} ~CThreadInfo() { Free(); } bool Alloc(); void Free(); HRESULT EncodeBlock3(UInt32 blockSize); }; class CEncoder : public ICompressCoder, public ICompressSetCoderProperties, #ifndef _7ZIP_ST public ICompressSetCoderMt, #endif public CMyUnknownImp { UInt32 m_BlockSizeMult; bool m_OptimizeNumTables; UInt32 m_NumPassesPrev; UInt32 m_NumThreadsPrev; public: CInBuffer m_InStream; Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size. CBitmEncoder m_OutStream; UInt32 NumPasses; CBZip2CombinedCrc CombinedCrc; #ifndef _7ZIP_ST CThreadInfo *ThreadsInfo; NWindows::NSynchronization::CManualResetEvent CanProcessEvent; NWindows::NSynchronization::CCriticalSection CS; UInt32 NumThreads; bool MtMode; UInt32 NextBlockIndex; bool CloseThreads; bool StreamWasFinished; NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent; HRESULT Result; ICompressProgressInfo *Progress; #else CThreadInfo ThreadsInfo; #endif UInt32 ReadRleBlock(Byte *buffer); void WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte); void WriteBits(UInt32 value, UInt32 numBits); void WriteByte(Byte b); void WriteBit(bool v); void WriteCrc(UInt32 v); #ifndef _7ZIP_ST HRESULT Create(); void Free(); #endif public: CEncoder(); #ifndef _7ZIP_ST ~CEncoder(); #endif HRESULT Flush() { return m_OutStream.Flush(); } void ReleaseStreams() { m_InStream.ReleaseStream(); m_OutStream.ReleaseStream(); } class CFlusher { CEncoder *_coder; public: CFlusher(CEncoder *coder): _coder(coder) {} ~CFlusher() { _coder->ReleaseStreams(); } }; #ifndef _7ZIP_ST MY_UNKNOWN_IMP2(ICompressSetCoderMt, ICompressSetCoderProperties) #else MY_UNKNOWN_IMP1(ICompressSetCoderProperties) #endif HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); #ifndef _7ZIP_ST STDMETHOD(SetNumberOfThreads)(UInt32 numThreads); #endif }; }} #endif