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