1 // BZip2Encoder.h
2 
3 #ifndef __COMPRESS_BZIP2_ENCODER_H
4 #define __COMPRESS_BZIP2_ENCODER_H
5 
6 #include "../../Common/Defs.h"
7 #include "../../Common/MyCom.h"
8 
9 #ifdef COMPRESS_BZIP2_MT
10 #include "../../Windows/Synchronization.h"
11 #include "../../Windows/Thread.h"
12 #endif
13 
14 #include "../ICoder.h"
15 
16 #include "../Common/InBuffer.h"
17 #include "../Common/OutBuffer.h"
18 
19 #include "BitmEncoder.h"
20 #include "BZip2Const.h"
21 #include "BZip2Crc.h"
22 
23 namespace NCompress {
24 namespace NBZip2 {
25 
26 class CMsbfEncoderTemp
27 {
28   UInt32 m_Pos;
29   int m_BitPos;
30   Byte m_CurByte;
31   Byte *Buffer;
32 public:
SetStream(Byte * buffer)33   void SetStream(Byte *buffer) { Buffer = buffer;  }
GetStream()34   Byte *GetStream() const { return Buffer; }
35 
Init()36   void Init()
37   {
38     m_Pos = 0;
39     m_BitPos = 8;
40     m_CurByte = 0;
41   }
42 
Flush()43   void Flush()
44   {
45     if (m_BitPos < 8)
46       WriteBits(0, m_BitPos);
47   }
48 
WriteBits(UInt32 value,int numBits)49   void WriteBits(UInt32 value, int numBits)
50   {
51     while (numBits > 0)
52     {
53       int numNewBits = MyMin(numBits, m_BitPos);
54       numBits -= numNewBits;
55 
56       m_CurByte <<= numNewBits;
57       UInt32 newBits = value >> numBits;
58       m_CurByte |= Byte(newBits);
59       value -= (newBits << numBits);
60 
61       m_BitPos -= numNewBits;
62 
63       if (m_BitPos == 0)
64       {
65        Buffer[m_Pos++] = m_CurByte;
66         m_BitPos = 8;
67       }
68     }
69   }
70 
GetBytePos()71   UInt32 GetBytePos() const { return m_Pos ; }
GetPos()72   UInt32 GetPos() const { return m_Pos * 8 + (8 - m_BitPos); }
GetCurByte()73   Byte GetCurByte() const { return m_CurByte; }
SetPos(UInt32 bitPos)74   void SetPos(UInt32 bitPos)
75   {
76     m_Pos = bitPos / 8;
77     m_BitPos = 8 - ((int)bitPos & 7);
78   }
SetCurState(int bitPos,Byte curByte)79   void SetCurState(int bitPos, Byte curByte)
80   {
81     m_BitPos = 8 - bitPos;
82     m_CurByte = curByte;
83   }
84 };
85 
86 class CEncoder;
87 
88 const int kNumPassesMax = 10;
89 
90 class CThreadInfo
91 {
92 public:
93   Byte *m_Block;
94 private:
95   Byte *m_MtfArray;
96   Byte *m_TempArray;
97   UInt32 *m_BlockSorterIndex;
98 
99   CMsbfEncoderTemp *m_OutStreamCurrent;
100 
101   Byte Lens[kNumTablesMax][kMaxAlphaSize];
102   UInt32 Freqs[kNumTablesMax][kMaxAlphaSize];
103   UInt32 Codes[kNumTablesMax][kMaxAlphaSize];
104 
105   Byte m_Selectors[kNumSelectorsMax];
106 
107   UInt32 m_CRCs[1 << kNumPassesMax];
108   UInt32 m_NumCrcs;
109 
110   UInt32 m_BlockIndex;
111 
112   void WriteBits2(UInt32 value, UInt32 numBits);
113   void WriteByte2(Byte b);
114   void WriteBit2(bool v);
115   void WriteCrc2(UInt32 v);
116 
117   void EncodeBlock(const Byte *block, UInt32 blockSize);
118   UInt32 EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize);
119   void EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses);
120 public:
121   bool m_OptimizeNumTables;
122   CEncoder *Encoder;
123   #ifdef COMPRESS_BZIP2_MT
124   NWindows::CThread Thread;
125 
126   NWindows::NSynchronization::CAutoResetEvent StreamWasFinishedEvent;
127   NWindows::NSynchronization::CAutoResetEvent WaitingWasStartedEvent;
128 
129   // it's not member of this thread. We just need one event per thread
130   NWindows::NSynchronization::CAutoResetEvent CanWriteEvent;
131 
132   UInt64 m_PackSize;
133 
134   Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
135   HRESULT Create();
136   void FinishStream(bool needLeave);
137   DWORD ThreadFunc();
138   #endif
139 
CThreadInfo()140   CThreadInfo(): m_BlockSorterIndex(0), m_Block(0) {}
~CThreadInfo()141   ~CThreadInfo() { Free(); }
142   bool Alloc();
143   void Free();
144 
145   HRESULT EncodeBlock3(UInt32 blockSize);
146 };
147 
148 class CEncoder :
149   public ICompressCoder,
150   public ICompressSetCoderProperties,
151   #ifdef COMPRESS_BZIP2_MT
152   public ICompressSetCoderMt,
153   #endif
154   public CMyUnknownImp
155 {
156   UInt32 m_BlockSizeMult;
157   bool m_OptimizeNumTables;
158 
159   UInt32 m_NumPassesPrev;
160 
161   UInt32 m_NumThreadsPrev;
162 public:
163   CInBuffer m_InStream;
164   Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
165   CBitmEncoder<COutBuffer> m_OutStream;
166   UInt32 NumPasses;
167   CBZip2CombinedCrc CombinedCrc;
168 
169   #ifdef COMPRESS_BZIP2_MT
170   CThreadInfo *ThreadsInfo;
171   NWindows::NSynchronization::CManualResetEvent CanProcessEvent;
172   NWindows::NSynchronization::CCriticalSection CS;
173   UInt32 NumThreads;
174   bool MtMode;
175   UInt32 NextBlockIndex;
176 
177   bool CloseThreads;
178   bool StreamWasFinished;
179   NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent;
180 
181   HRESULT Result;
182   ICompressProgressInfo *Progress;
183   #else
184   CThreadInfo ThreadsInfo;
185   #endif
186 
187   UInt32 ReadRleBlock(Byte *buffer);
188   void WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte);
189 
190   void WriteBits(UInt32 value, UInt32 numBits);
191   void WriteByte(Byte b);
192   void WriteBit(bool v);
193   void WriteCrc(UInt32 v);
194 
195   #ifdef COMPRESS_BZIP2_MT
196   HRESULT Create();
197   void Free();
198   #endif
199 
200 public:
201   CEncoder();
202   #ifdef COMPRESS_BZIP2_MT
203   ~CEncoder();
204   #endif
205 
Flush()206   HRESULT Flush() { return m_OutStream.Flush(); }
207 
ReleaseStreams()208   void ReleaseStreams()
209   {
210     m_InStream.ReleaseStream();
211     m_OutStream.ReleaseStream();
212   }
213 
214   class CFlusher
215   {
216     CEncoder *_coder;
217   public:
CFlusher(CEncoder * coder)218     CFlusher(CEncoder *coder): _coder(coder) {}
~CFlusher()219     ~CFlusher()
220     {
221       _coder->ReleaseStreams();
222     }
223   };
224 
225   #ifdef COMPRESS_BZIP2_MT
226   MY_UNKNOWN_IMP2(ICompressSetCoderMt, ICompressSetCoderProperties)
227   #else
228   MY_UNKNOWN_IMP1(ICompressSetCoderProperties)
229   #endif
230 
231   HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
232       const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
233 
234   STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
235       const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
236   STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
237 
238   #ifdef COMPRESS_BZIP2_MT
239   STDMETHOD(SetNumberOfThreads)(UInt32 numThreads);
240   #endif
241 };
242 
243 }}
244 
245 #endif
246