1 // Compress/BZip2Decoder.h
2 
3 #ifndef __COMPRESS_BZIP2_DECODER_H
4 #define __COMPRESS_BZIP2_DECODER_H
5 
6 #include "../../Common/MyCom.h"
7 
8 // #define NO_READ_FROM_CODER
9 // #define _7ZIP_ST
10 
11 #ifndef _7ZIP_ST
12 #include "../../Windows/Synchronization.h"
13 #include "../../Windows/Thread.h"
14 #endif
15 
16 #include "../ICoder.h"
17 
18 #include "BZip2Const.h"
19 #include "BZip2Crc.h"
20 #include "HuffmanDecoder.h"
21 #include "Mtf8.h"
22 
23 namespace NCompress {
24 namespace NBZip2 {
25 
26 bool IsEndSig(const Byte *p) throw();
27 bool IsBlockSig(const Byte *p) throw();
28 
29 const unsigned kNumTableBits = 9;
30 const unsigned kNumBitsMax = kMaxHuffmanLen;
31 
32 typedef NHuffman::CDecoder<kMaxHuffmanLen, kMaxAlphaSize, kNumTableBits> CHuffmanDecoder;
33 
34 
35 struct CBlockProps
36 {
37   UInt32 blockSize;
38   UInt32 origPtr;
39   unsigned randMode;
40 
CBlockPropsCBlockProps41   CBlockProps(): blockSize(0), origPtr(0), randMode(0) {}
42 };
43 
44 
45 struct CBitDecoder
46 {
47   unsigned _numBits;
48   UInt32 _value;
49   const Byte *_buf;
50   const Byte *_lim;
51 
InitBitDecoderCBitDecoder52   void InitBitDecoder()
53   {
54     _numBits = 0;
55     _value = 0;
56   }
57 
AlignToByteCBitDecoder58   void AlignToByte()
59   {
60     unsigned bits = _numBits & 7;
61     _numBits -= bits;
62     _value <<= bits;
63   }
64 
65   /*
66   bool AreRemainByteBitsEmpty() const
67   {
68     unsigned bits = _numBits & 7;
69     if (bits != 0)
70       return (_value >> (32 - bits)) == 0;
71     return true;
72   }
73   */
74 
75   SRes ReadByte(int &b);
76 };
77 
78 
79 struct CBase: public CBitDecoder
80 {
81   unsigned numInUse;
82   UInt32 groupIndex;
83   UInt32 groupSize;
84   unsigned runPower;
85   UInt32 runCounter;
86   UInt32 blockSize;
87 
88   UInt32 *Counters;
89   UInt32 blockSizeMax;
90 
91   unsigned state;
92   unsigned state2;
93   unsigned state3;
94   unsigned state4;
95   unsigned state5;
96   unsigned numTables;
97   UInt32 numSelectors;
98 
99   CBlockProps Props;
100 
101 private:
102   CMtf8Decoder mtf;
103   Byte selectors[kNumSelectorsMax];
104   CHuffmanDecoder huffs[kNumTablesMax];
105 
106   Byte lens[kMaxAlphaSize];
107 
108   Byte temp[10];
109 
110 public:
111   UInt32 crc;
112   CBZip2CombinedCrc CombinedCrc;
113 
114   bool IsBz;
115   bool StreamCrcError;
116   bool MinorError;
117   bool NeedMoreInput;
118 
119   bool DecodeAllStreams;
120 
121   UInt64 NumStreams;
122   UInt64 NumBlocks;
123   UInt64 FinishedPackSize;
124 
125   ISequentialInStream *InStream;
126 
127   #ifndef NO_READ_FROM_CODER
128   CMyComPtr<ISequentialInStream> InStreamRef;
129   #endif
130 
CBaseCBase131   CBase():
132       StreamCrcError(false),
133       MinorError(false),
134       NeedMoreInput(false),
135 
136       DecodeAllStreams(false),
137 
138       NumStreams(0),
139       NumBlocks(0),
140       FinishedPackSize(0)
141       {}
142 
InitNumStreams2CBase143   void InitNumStreams2()
144   {
145     StreamCrcError = false;
146     MinorError = false;
147     NeedMoreInput = 0;
148     NumStreams = 0;
149     NumBlocks = 0;
150     FinishedPackSize = 0;
151   }
152 
153   SRes ReadStreamSignature2();
154   SRes ReadBlockSignature2();
155 
156   /* ReadBlock2() : Props->randMode:
157        in:  need read randMode bit
158        out: randMode status */
159   SRes ReadBlock2();
160 };
161 
162 
163 class CSpecState
164 {
165   UInt32 _tPos;
166   unsigned _prevByte;
167   int _reps;
168 
169 public:
170   CBZip2Crc _crc;
171   UInt32 _blockSize;
172   UInt32 *_tt;
173 
174   int _randToGo;
175   unsigned _randIndex;
176 
177   void Init(UInt32 origPtr, unsigned randMode) throw();
178 
Finished()179   bool Finished() const { return _reps <= 0 && _blockSize == 0; }
180 
181   Byte *Decode(Byte *data, size_t size) throw();
182 };
183 
184 
185 
186 
187 class CDecoder :
188   public ICompressCoder,
189   public ICompressSetFinishMode,
190   public ICompressGetInStreamProcessedSize,
191 
192   #ifndef NO_READ_FROM_CODER
193   public ICompressSetInStream,
194   public ICompressSetOutStreamSize,
195   public ISequentialInStream,
196   #endif
197 
198   #ifndef _7ZIP_ST
199   public ICompressSetCoderMt,
200   #endif
201 
202   public CMyUnknownImp
203 {
204   Byte *_outBuf;
205   size_t _outPos;
206   UInt64 _outWritten;
207   ISequentialOutStream *_outStream;
208   HRESULT _writeRes;
209 
210 protected:
211   HRESULT ErrorResult; // for ISequentialInStream::Read mode only
212 
213 public:
214 
215   UInt32 _calcedBlockCrc;
216   bool _blockFinished;
217   bool BlockCrcError;
218 
219   bool FinishMode;
220   bool _outSizeDefined;
221   UInt64 _outSize;
222   UInt64 _outPosTotal;
223 
224   CSpecState _spec;
225   UInt32 *_counters;
226 
227   #ifndef _7ZIP_ST
228 
229   struct CBlock
230   {
231     bool StopScout;
232 
233     bool WasFinished;
234     bool Crc_Defined;
235     // bool NextCrc_Defined;
236 
237     UInt32 Crc;
238     UInt32 NextCrc;
239     HRESULT Res;
240     UInt64 PackPos;
241 
242     CBlockProps Props;
243   };
244 
245   CBlock _block;
246 
247   bool NeedWaitScout;
248   bool MtMode;
249 
250   NWindows::CThread Thread;
251   NWindows::NSynchronization::CAutoResetEvent DecoderEvent;
252   NWindows::NSynchronization::CAutoResetEvent ScoutEvent;
253   // HRESULT ScoutRes;
254 
255   Byte MtPad[1 << 7]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
256 
257 
258   void RunScout();
259 
WaitScout()260   void WaitScout()
261   {
262     if (NeedWaitScout)
263     {
264       DecoderEvent.Lock();
265       NeedWaitScout = false;
266     }
267   }
268 
269   class CWaitScout_Releaser
270   {
271     CDecoder *_decoder;
272   public:
CWaitScout_Releaser(CDecoder * decoder)273     CWaitScout_Releaser(CDecoder *decoder): _decoder(decoder) {}
~CWaitScout_Releaser()274     ~CWaitScout_Releaser() { _decoder->WaitScout(); }
275   };
276 
277   HRESULT CreateThread();
278 
279   #endif
280 
281   Byte *_inBuf;
282   UInt64 _inProcessed;
283   bool _inputFinished;
284   HRESULT _inputRes;
285 
286   CBase Base;
287 
GetCrcError()288   bool GetCrcError() const { return BlockCrcError || Base.StreamCrcError; }
289 
290   void InitOutSize(const UInt64 *outSize);
291 
292   bool CreateInputBufer();
293 
InitInputBuffer()294   void InitInputBuffer()
295   {
296     _inProcessed = 0;
297     Base._buf = _inBuf;
298     Base._lim = _inBuf;
299     Base.InitBitDecoder();
300   }
301 
GetInputProcessedSize()302   UInt64 GetInputProcessedSize() const
303   {
304     // for NSIS case : we need also look the number of bits in bitDecoder
305     return _inProcessed + (Base._buf - _inBuf);
306   }
307 
GetOutProcessedSize()308   UInt64 GetOutProcessedSize() const { return _outWritten + _outPos; }
309 
310   HRESULT ReadInput();
311 
312   void StartNewStream();
313 
314   HRESULT ReadStreamSignature();
315   HRESULT StartRead();
316 
317   HRESULT ReadBlockSignature();
318   HRESULT ReadBlock();
319 
320   HRESULT Flush();
321   HRESULT DecodeBlock(const CBlockProps &props);
322   HRESULT DecodeStreams(ICompressProgressInfo *progress);
323 
324   MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
325   MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)
326   MY_QUERYINTERFACE_ENTRY(ICompressGetInStreamProcessedSize)
327 
328   #ifndef NO_READ_FROM_CODER
329   MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
330   MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)
331   MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
332   #endif
333 
334   #ifndef _7ZIP_ST
335   MY_QUERYINTERFACE_ENTRY(ICompressSetCoderMt)
336   #endif
337 
338   MY_QUERYINTERFACE_END
339   MY_ADDREF_RELEASE
340 
341 
342   STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
343       const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
344 
345   STDMETHOD(SetFinishMode)(UInt32 finishMode);
346   STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
347 
GetNumStreams()348   UInt64 GetNumStreams() const { return Base.NumStreams; }
GetNumBlocks()349   UInt64 GetNumBlocks() const { return Base.NumBlocks; }
350 
351   #ifndef NO_READ_FROM_CODER
352 
353   STDMETHOD(SetInStream)(ISequentialInStream *inStream);
354   STDMETHOD(ReleaseInStream)();
355   STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
356   STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
357 
358   #endif
359 
360   #ifndef _7ZIP_ST
361   STDMETHOD(SetNumberOfThreads)(UInt32 numThreads);
362   #endif
363 
364   CDecoder();
365   ~CDecoder();
366 };
367 
368 
369 
370 #ifndef NO_READ_FROM_CODER
371 
372 class CNsisDecoder : public CDecoder
373 {
374 public:
375   STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
376 };
377 
378 #endif
379 
380 }}
381 
382 #endif
383