rlm@1: // Rar3Decoder.h rlm@1: // According to unRAR license, this code may not be used to develop rlm@1: // a program that creates RAR archives rlm@1: rlm@1: #ifndef __COMPRESS_RAR3_DECODER_H rlm@1: #define __COMPRESS_RAR3_DECODER_H rlm@1: rlm@1: #include "../../Common/MyCom.h" rlm@1: rlm@1: #include "../ICoder.h" rlm@1: rlm@1: #include "../Common/InBuffer.h" rlm@1: rlm@1: #include "BitmDecoder.h" rlm@1: #include "HuffmanDecoder.h" rlm@1: #include "PpmdDecode.h" rlm@1: #include "Rar3Vm.h" rlm@1: rlm@1: namespace NCompress { rlm@1: namespace NRar3 { rlm@1: rlm@1: const UInt32 kWindowSize = 1 << 22; rlm@1: const UInt32 kWindowMask = (kWindowSize - 1); rlm@1: rlm@1: const UInt32 kNumReps = 4; rlm@1: const UInt32 kNumLen2Symbols = 8; rlm@1: const UInt32 kLenTableSize = 28; rlm@1: const UInt32 kMainTableSize = 256 + 1 + 1 + 1 + kNumReps + kNumLen2Symbols + kLenTableSize; rlm@1: const UInt32 kDistTableSize = 60; rlm@1: rlm@1: const int kNumAlignBits = 4; rlm@1: const UInt32 kAlignTableSize = (1 << kNumAlignBits) + 1; rlm@1: rlm@1: const UInt32 kLevelTableSize = 20; rlm@1: rlm@1: const UInt32 kTablesSizesSum = kMainTableSize + kDistTableSize + kAlignTableSize + kLenTableSize; rlm@1: rlm@1: class CBitDecoder rlm@1: { rlm@1: UInt32 m_Value; rlm@1: public: rlm@1: UInt32 m_BitPos; rlm@1: CInBuffer m_Stream; rlm@1: bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); } rlm@1: void SetStream(ISequentialInStream *inStream) { m_Stream.SetStream(inStream);} rlm@1: void ReleaseStream() { m_Stream.ReleaseStream();} rlm@1: rlm@1: void Init() rlm@1: { rlm@1: m_Stream.Init(); rlm@1: m_BitPos = 0; rlm@1: m_Value = 0; rlm@1: // m_BitPos = kNumBigValueBits; rlm@1: // Normalize(); rlm@1: } rlm@1: rlm@1: UInt64 GetProcessedSize() const rlm@1: { return m_Stream.GetProcessedSize() - (m_BitPos) / 8; } rlm@1: UInt32 GetBitPosition() const { return ((8 - m_BitPos) & 7); } rlm@1: rlm@1: /* rlm@1: void Normalize() rlm@1: { rlm@1: for (;m_BitPos >= 8; m_BitPos -= 8) rlm@1: m_Value = (m_Value << 8) | m_Stream.ReadByte(); rlm@1: } rlm@1: */ rlm@1: rlm@1: UInt32 GetValue(UInt32 numBits) rlm@1: { rlm@1: // return (m_Value << m_BitPos) >> (kNumBigValueBits - numBits); rlm@1: // return ((m_Value >> (8 - m_BitPos)) & kMask) >> (kNumValueBits - numBits); rlm@1: if (m_BitPos < numBits) rlm@1: { rlm@1: m_BitPos += 8; rlm@1: m_Value = (m_Value << 8) | m_Stream.ReadByte(); rlm@1: if (m_BitPos < numBits) rlm@1: { rlm@1: m_BitPos += 8; rlm@1: m_Value = (m_Value << 8) | m_Stream.ReadByte(); rlm@1: } rlm@1: } rlm@1: return m_Value >> (m_BitPos - numBits); rlm@1: } rlm@1: rlm@1: void MovePos(UInt32 numBits) rlm@1: { rlm@1: m_BitPos -= numBits; rlm@1: m_Value = m_Value & ((1 << m_BitPos) - 1); rlm@1: } rlm@1: rlm@1: UInt32 ReadBits(UInt32 numBits) rlm@1: { rlm@1: UInt32 res = GetValue(numBits); rlm@1: MovePos(numBits); rlm@1: return res; rlm@1: } rlm@1: }; rlm@1: rlm@1: const int kNumTopBits = 24; rlm@1: const UInt32 kTopValue = (1 << kNumTopBits); rlm@1: const UInt32 kBot = (1 << 15); rlm@1: rlm@1: class CRangeDecoder:public NPpmd::CRangeDecoderVirt, public CBitDecoder rlm@1: { rlm@1: public: rlm@1: UInt32 Range; rlm@1: UInt32 Low; rlm@1: UInt32 Code; rlm@1: rlm@1: void Normalize() rlm@1: { rlm@1: while ((Low ^ (Low + Range)) < kTopValue || rlm@1: Range < kBot && ((Range = (0 - Low) & (kBot - 1)), 1)) rlm@1: { rlm@1: Code = (Code << 8) | m_Stream.ReadByte(); rlm@1: Range <<= 8; rlm@1: Low <<= 8; rlm@1: } rlm@1: } rlm@1: rlm@1: void InitRangeCoder() rlm@1: { rlm@1: Code = 0; rlm@1: Low = 0; rlm@1: Range = 0xFFFFFFFF; rlm@1: for(int i = 0; i < 4; i++) rlm@1: Code = (Code << 8) | ReadBits(8); rlm@1: } rlm@1: rlm@1: virtual UInt32 GetThreshold(UInt32 total) rlm@1: { rlm@1: return (Code - Low) / ( Range /= total); rlm@1: } rlm@1: rlm@1: virtual void Decode(UInt32 start, UInt32 size) rlm@1: { rlm@1: Low += start * Range; rlm@1: Range *= size; rlm@1: Normalize(); rlm@1: } rlm@1: rlm@1: virtual UInt32 DecodeBit(UInt32 size0, UInt32 numTotalBits) rlm@1: { rlm@1: if (((Code - Low) / (Range >>= numTotalBits)) < size0) rlm@1: { rlm@1: Decode(0, size0); rlm@1: return 0; rlm@1: } rlm@1: else rlm@1: { rlm@1: Decode(size0, (1 << numTotalBits) - size0); rlm@1: return 1; rlm@1: } rlm@1: } rlm@1: rlm@1: // UInt64 GetProcessedSizeRangeCoder() {return Stream.GetProcessedSize(); } rlm@1: }; rlm@1: rlm@1: rlm@1: struct CFilter: public NVm::CProgram rlm@1: { rlm@1: CRecordVector GlobalData; rlm@1: UInt32 BlockStart; rlm@1: UInt32 BlockSize; rlm@1: UInt32 ExecCount; rlm@1: CFilter(): BlockStart(0), BlockSize(0), ExecCount(0) {} rlm@1: }; rlm@1: rlm@1: struct CTempFilter: public NVm::CProgramInitState rlm@1: { rlm@1: UInt32 BlockStart; rlm@1: UInt32 BlockSize; rlm@1: UInt32 ExecCount; rlm@1: bool NextWindow; rlm@1: rlm@1: UInt32 FilterIndex; rlm@1: }; rlm@1: rlm@1: const int kNumHuffmanBits = 15; rlm@1: rlm@1: class CDecoder: rlm@1: public ICompressCoder, rlm@1: public ICompressSetDecoderProperties2, rlm@1: public CMyUnknownImp rlm@1: { rlm@1: CRangeDecoder m_InBitStream; rlm@1: Byte *_window; rlm@1: UInt32 _winPos; rlm@1: UInt32 _wrPtr; rlm@1: UInt64 _lzSize; rlm@1: UInt64 _unpackSize; rlm@1: UInt64 _writtenFileSize; // if it's > _unpackSize, then _unpackSize only written rlm@1: CMyComPtr _outStream; rlm@1: NHuffman::CDecoder m_MainDecoder; rlm@1: NHuffman::CDecoder m_DistDecoder; rlm@1: NHuffman::CDecoder m_AlignDecoder; rlm@1: NHuffman::CDecoder m_LenDecoder; rlm@1: NHuffman::CDecoder m_LevelDecoder; rlm@1: rlm@1: UInt32 _reps[kNumReps]; rlm@1: UInt32 _lastLength; rlm@1: rlm@1: Byte m_LastLevels[kTablesSizesSum]; rlm@1: rlm@1: Byte *_vmData; rlm@1: Byte *_vmCode; rlm@1: NVm::CVm _vm; rlm@1: CRecordVector _filters; rlm@1: CRecordVector _tempFilters; rlm@1: UInt32 _lastFilter; rlm@1: rlm@1: bool m_IsSolid; rlm@1: rlm@1: bool _lzMode; rlm@1: rlm@1: UInt32 PrevAlignBits; rlm@1: UInt32 PrevAlignCount; rlm@1: rlm@1: bool TablesRead; rlm@1: rlm@1: NPpmd::CDecodeInfo _ppm; rlm@1: int PpmEscChar; rlm@1: rlm@1: HRESULT WriteDataToStream(const Byte *data, UInt32 size); rlm@1: HRESULT WriteData(const Byte *data, UInt32 size); rlm@1: HRESULT WriteArea(UInt32 startPtr, UInt32 endPtr); rlm@1: void ExecuteFilter(int tempFilterIndex, NVm::CBlockRef &outBlockRef); rlm@1: HRESULT WriteBuf(); rlm@1: rlm@1: void InitFilters(); rlm@1: bool AddVmCode(UInt32 firstByte, UInt32 codeSize); rlm@1: bool ReadVmCodeLZ(); rlm@1: bool ReadVmCodePPM(); rlm@1: rlm@1: UInt32 ReadBits(int numBits); rlm@1: rlm@1: HRESULT InitPPM(); rlm@1: int DecodePpmSymbol(); rlm@1: HRESULT DecodePPM(Int32 num, bool &keepDecompressing); rlm@1: rlm@1: HRESULT ReadTables(bool &keepDecompressing); rlm@1: HRESULT ReadEndOfBlock(bool &keepDecompressing); rlm@1: HRESULT DecodeLZ(bool &keepDecompressing); rlm@1: HRESULT CodeReal(ICompressProgressInfo *progress); rlm@1: public: rlm@1: CDecoder(); rlm@1: ~CDecoder(); rlm@1: rlm@1: MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2) rlm@1: rlm@1: void ReleaseStreams() rlm@1: { rlm@1: _outStream.Release(); rlm@1: m_InBitStream.ReleaseStream(); rlm@1: } rlm@1: rlm@1: STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, rlm@1: const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); rlm@1: rlm@1: STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); rlm@1: rlm@1: void CopyBlock(UInt32 distance, UInt32 len) rlm@1: { rlm@1: _lzSize += len; rlm@1: UInt32 pos = (_winPos - distance - 1) & kWindowMask; rlm@1: Byte *window = _window; rlm@1: UInt32 winPos = _winPos; rlm@1: if (kWindowSize - winPos > len && kWindowSize - pos > len) rlm@1: { rlm@1: const Byte *src = window + pos; rlm@1: Byte *dest = window + winPos; rlm@1: _winPos += len; rlm@1: do rlm@1: *dest++ = *src++; rlm@1: while(--len != 0); rlm@1: return; rlm@1: } rlm@1: do rlm@1: { rlm@1: window[winPos] = window[pos]; rlm@1: winPos = (winPos + 1) & kWindowMask; rlm@1: pos = (pos + 1) & kWindowMask; rlm@1: } rlm@1: while(--len != 0); rlm@1: _winPos = winPos; rlm@1: } rlm@1: rlm@1: void PutByte(Byte b) rlm@1: { rlm@1: _window[_winPos] = b; rlm@1: _winPos = (_winPos + 1) & kWindowMask; rlm@1: _lzSize++; rlm@1: } rlm@1: rlm@1: rlm@1: }; rlm@1: rlm@1: }} rlm@1: rlm@1: #endif