// Rar5Decoder.h // According to unRAR license, this code may not be used to develop // a program that creates RAR archives #ifndef __COMPRESS_RAR5_DECODER_H #define __COMPRESS_RAR5_DECODER_H #include "../../../C/Alloc.h" #include "../../../C/CpuArch.h" #include "../../Common/MyBuffer.h" #include "../../Common/MyCom.h" #include "../../Common/MyException.h" #include "../../Common/MyVector.h" #include "../ICoder.h" #include "HuffmanDecoder.h" namespace NCompress { namespace NRar5 { class CMidBuffer { Byte *_data; size_t _size; CLASS_NO_COPY(CMidBuffer) public: CMidBuffer(): _data(NULL), _size(0) {}; ~CMidBuffer() { ::MidFree(_data); } bool IsAllocated() const { return _data != NULL; } operator Byte *() { return _data; } operator const Byte *() const { return _data; } size_t Size() const { return _size; } void AllocAtLeast(size_t size) { if (size > _size) { const size_t kMinSize = (1 << 16); if (size < kMinSize) size = kMinSize; ::MidFree(_data); _data = (Byte *)::MidAlloc(size); _size = size; } } }; /* struct CInBufferException: public CSystemException { CInBufferException(HRESULT errorCode): CSystemException(errorCode) {} }; */ class CBitDecoder { public: const Byte *_buf; unsigned _bitPos; bool _wasFinished; Byte _blockEndBits7; const Byte *_bufCheck2; const Byte *_bufCheck; Byte *_bufLim; Byte *_bufBase; UInt64 _processedSize; UInt64 _blockEnd; ISequentialInStream *_stream; HRESULT _hres; void SetCheck2() { _bufCheck2 = _bufCheck; if (_bufCheck > _buf) { UInt64 processed = GetProcessedSize_Round(); if (_blockEnd < processed) _bufCheck2 = _buf; else { UInt64 delta = _blockEnd - processed; if ((size_t)(_bufCheck - _buf) > delta) _bufCheck2 = _buf + (size_t)delta; } } } bool IsBlockOverRead() const { UInt64 v = GetProcessedSize_Round(); if (v < _blockEnd) return false; if (v > _blockEnd) return true; return _bitPos > _blockEndBits7; } /* CBitDecoder() throw(): _buf(0), _bufLim(0), _bufBase(0), _stream(0), _processedSize(0), _wasFinished(false) {} */ void Init() throw() { _blockEnd = 0; _blockEndBits7 = 0; _bitPos = 0; _processedSize = 0; _buf = _bufBase; _bufLim = _bufBase; _bufCheck = _buf; _bufCheck2 = _buf; _wasFinished = false; } void Prepare2() throw(); void Prepare() throw() { if (_buf >= _bufCheck) Prepare2(); } bool ExtraBitsWereRead() const { return _buf >= _bufLim && (_buf > _bufLim || _bitPos != 0); } bool InputEofError() const { return ExtraBitsWereRead(); } unsigned GetProcessedBits7() const { return _bitPos; } UInt64 GetProcessedSize_Round() const { return _processedSize + (_buf - _bufBase); } UInt64 GetProcessedSize() const { return _processedSize + (_buf - _bufBase) + ((_bitPos + 7) >> 3); } void AlignToByte() { _buf += (_bitPos + 7) >> 3; _bitPos = 0; } Byte ReadByteInAligned() { return *_buf++; } UInt32 GetValue(unsigned numBits) { UInt32 v = ((UInt32)_buf[0] << 16) | ((UInt32)_buf[1] << 8) | (UInt32)_buf[2]; v >>= (24 - numBits - _bitPos); return v & ((1 << numBits) - 1); } void MovePos(unsigned numBits) { _bitPos += numBits; _buf += (_bitPos >> 3); _bitPos &= 7; } UInt32 ReadBits9(unsigned numBits) { const Byte *buf = _buf; UInt32 v = ((UInt32)buf[0] << 8) | (UInt32)buf[1]; v &= ((UInt32)0xFFFF >> _bitPos); numBits += _bitPos; v >>= (16 - numBits); _buf = buf + (numBits >> 3); _bitPos = numBits & 7; return v; } UInt32 ReadBits9fix(unsigned numBits) { const Byte *buf = _buf; UInt32 v = ((UInt32)buf[0] << 8) | (UInt32)buf[1]; UInt32 mask = ((1 << numBits) - 1); numBits += _bitPos; v >>= (16 - numBits); _buf = buf + (numBits >> 3); _bitPos = numBits & 7; return v & mask; } UInt32 ReadBits32(unsigned numBits) { UInt32 mask = ((1 << numBits) - 1); numBits += _bitPos; const Byte *buf = _buf; UInt32 v = GetBe32(buf); if (numBits > 32) { v <<= (numBits - 32); v |= (UInt32)buf[4] >> (40 - numBits); } else v >>= (32 - numBits); _buf = buf + (numBits >> 3); _bitPos = numBits & 7; return v & mask; } }; struct CFilter { Byte Type; Byte Channels; UInt32 Size; UInt64 Start; }; const unsigned kNumReps = 4; const unsigned kLenTableSize = 11 * 4; const unsigned kMainTableSize = 256 + 1 + 1 + kNumReps + kLenTableSize; const unsigned kDistTableSize = 64; const unsigned kNumAlignBits = 4; const unsigned kAlignTableSize = (1 << kNumAlignBits); const unsigned kLevelTableSize = 20; const unsigned kTablesSizesSum = kMainTableSize + kDistTableSize + kAlignTableSize + kLenTableSize; const unsigned kNumHuffmanBits = 15; class CDecoder: public ICompressCoder, public ICompressSetDecoderProperties2, public CMyUnknownImp { bool _useAlignBits; bool _isLastBlock; bool _unpackSize_Defined; // bool _packSize_Defined; bool _unsupportedFilter; bool _lzError; bool _writeError; // CBitDecoder _bitStream; Byte *_window; size_t _winPos; size_t _winSize; size_t _winMask; UInt64 _lzSize; unsigned _numCorrectDistSymbols; unsigned _numUnusedFilters; UInt64 _lzWritten; UInt64 _lzFileStart; UInt64 _unpackSize; // UInt64 _packSize; UInt64 _lzEnd; UInt64 _writtenFileSize; size_t _winSizeAllocated; Byte _dictSizeLog; bool _tableWasFilled; bool _isSolid; bool _wasInit; UInt32 _reps[kNumReps]; UInt32 _lastLen; UInt64 _filterEnd; CMidBuffer _filterSrc; CMidBuffer _filterDst; CRecordVector _filters; ISequentialInStream *_inStream; ISequentialOutStream *_outStream; ICompressProgressInfo *_progress; Byte *_inputBuf; NHuffman::CDecoder m_MainDecoder; NHuffman::CDecoder m_DistDecoder; NHuffman::CDecoder m_AlignDecoder; NHuffman::CDecoder m_LenDecoder; NHuffman::CDecoder m_LevelDecoder; void InitFilters() { _numUnusedFilters = 0; _filters.Clear(); } void DeleteUnusedFilters() { if (_numUnusedFilters != 0) { _filters.DeleteFrontal(_numUnusedFilters); _numUnusedFilters = 0; } } HRESULT WriteData(const Byte *data, size_t size); HRESULT ExecuteFilter(const CFilter &f); HRESULT WriteBuf(); HRESULT AddFilter(CBitDecoder &_bitStream); HRESULT ReadTables(CBitDecoder &_bitStream); HRESULT DecodeLZ(); HRESULT CodeReal(); public: CDecoder(); ~CDecoder(); MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2) STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); }; }} #endif