VMProtect/runtime/VMProtect.Runtime/LzmaDecoder.cs

652 lines
19 KiB
C#
Raw Normal View History

2023-05-14 16:21:09 +03:00
// LzmaDecoder.cs
using System;
using System.IO;
using SevenZip.Compression.RangeCoder;
#pragma warning disable 414
namespace SevenZip.Compression.LZ
{
public class OutWindow
{
byte[] _buffer;
uint _pos;
uint _windowSize;
uint _streamPos;
Stream _stream;
uint _id = 1;
public uint TrainSize;
public void Create(uint windowSize)
{
if (_windowSize != windowSize)
{
_buffer = new byte[windowSize];
}
_windowSize = windowSize;
_pos = 0;
_streamPos = 0;
}
public void Init(Stream stream, bool solid)
{
ReleaseStream();
_stream = stream;
if (!solid)
{
_streamPos = 0;
_pos = 0;
TrainSize = 0;
}
}
public void ReleaseStream()
{
Flush();
_stream = null;
}
public void Flush()
{
uint size = _pos - _streamPos;
if (size == 0)
return;
_stream.Write(_buffer, (int)_streamPos, (int)size);
if (_pos >= _windowSize)
_pos = 0;
_streamPos = _pos;
}
public void CopyBlock(uint distance, uint len)
{
uint pos = _pos - distance - 1;
if (pos >= _windowSize)
pos += _windowSize;
for (; len > 0; len--)
{
if (pos >= _windowSize)
pos = 0;
_buffer[_pos++] = _buffer[pos++];
if (_pos >= _windowSize)
Flush();
}
}
public void PutByte(byte b)
{
_buffer[_pos++] = b;
if (_pos >= _windowSize)
Flush();
}
public byte GetByte(uint distance)
{
uint pos = _pos - distance - 1;
if (pos >= _windowSize)
pos += _windowSize;
return _buffer[pos];
}
}
}
namespace SevenZip.Compression.RangeCoder
{
class Decoder
{
uint _id = 1;
public const uint KTopValue = (1 << 24);
public uint Range;
public uint Code;
public Stream Stream;
public void Init(Stream stream)
{
Stream = stream;
Code = 0;
Range = 0xFFFFFFFF;
for (int i = 0; i < 5; i++)
Code = (Code << 8) | (byte)Stream.ReadByte();
}
public void ReleaseStream()
{
Stream = null;
}
public uint DecodeDirectBits(int numTotalBits)
{
uint range = Range;
uint code = Code;
uint result = 0;
for (int i = numTotalBits; i > 0; i--)
{
range >>= 1;
uint t = (code - range) >> 31;
code -= range & (t - 1);
result = (result << 1) | (1 - t);
if (range < KTopValue)
{
code = (code << 8) | (byte)Stream.ReadByte();
range <<= 8;
}
}
Range = range;
Code = code;
return result;
}
}
struct BitDecoder
{
private const int KNumBitModelTotalBits = 11;
private const uint KBitModelTotal = (1 << KNumBitModelTotalBits);
const int KNumMoveBits = 5;
uint _prob;
public void Init() { _prob = KBitModelTotal >> 1; }
public uint Decode(Decoder rangeDecoder)
{
uint newBound = (rangeDecoder.Range >> KNumBitModelTotalBits) * _prob;
if (rangeDecoder.Code < newBound)
{
rangeDecoder.Range = newBound;
_prob += (KBitModelTotal - _prob) >> KNumMoveBits;
if (rangeDecoder.Range < Decoder.KTopValue)
{
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
rangeDecoder.Range <<= 8;
}
return 0;
}
else
{
rangeDecoder.Range -= newBound;
rangeDecoder.Code -= newBound;
_prob -= (_prob) >> KNumMoveBits;
if (rangeDecoder.Range < Decoder.KTopValue)
{
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
rangeDecoder.Range <<= 8;
}
return 1;
}
}
}
struct BitTreeDecoder
{
private readonly BitDecoder[] _models;
private readonly int _numBitLevels;
public BitTreeDecoder(int numBitLevels)
{
_numBitLevels = numBitLevels;
_models = new BitDecoder[1 << numBitLevels];
}
public void Init()
{
for (uint i = 1; i < (1 << _numBitLevels); i++)
_models[i].Init();
}
public uint Decode(Decoder rangeDecoder)
{
uint m = 1;
for (int bitIndex = _numBitLevels; bitIndex > 0; bitIndex--)
m = (m << 1) + _models[m].Decode(rangeDecoder);
return m - ((uint)1 << _numBitLevels);
}
public uint ReverseDecode(Decoder rangeDecoder)
{
uint m = 1;
uint symbol = 0;
for (int bitIndex = 0; bitIndex < _numBitLevels; bitIndex++)
{
uint bit = _models[m].Decode(rangeDecoder);
m <<= 1;
m += bit;
symbol |= (bit << bitIndex);
}
return symbol;
}
public static uint ReverseDecode(BitDecoder[] models, UInt32 startIndex,
Decoder rangeDecoder, int numBitLevels)
{
uint m = 1;
uint symbol = 0;
for (int bitIndex = 0; bitIndex < numBitLevels; bitIndex++)
{
uint bit = models[startIndex + m].Decode(rangeDecoder);
m <<= 1;
m += bit;
symbol |= (bit << bitIndex);
}
return symbol;
}
}
}
namespace SevenZip.Compression.LZMA
{
internal abstract class Base
{
public const uint KNumStates = 12;
public struct State
{
public uint Index;
public void Init() { Index = 0; }
public void UpdateChar()
{
if (Index < 4) Index = 0;
else if (Index < 10) Index -= 3;
else Index -= 6;
}
public void UpdateMatch() { Index = (uint)(Index < 7 ? 7 : 10); }
public void UpdateRep() { Index = (uint)(Index < 7 ? 8 : 11); }
public void UpdateShortRep() { Index = (uint)(Index < 7 ? 9 : 11); }
public bool IsCharState() { return Index < 7; }
}
public const int KNumPosSlotBits = 6;
private const int KNumLenToPosStatesBits = 2; // it's for speed optimization
public const uint KNumLenToPosStates = 1 << KNumLenToPosStatesBits;
public const uint KMatchMinLen = 2;
public static uint GetLenToPosState(uint len)
{
len -= KMatchMinLen;
if (len < KNumLenToPosStates)
return len;
return KNumLenToPosStates - 1;
}
public const int KNumAlignBits = 4;
public const uint KStartPosModelIndex = 4;
public const uint KEndPosModelIndex = 14;
public const uint KNumFullDistances = 1 << ((int)KEndPosModelIndex / 2);
public const int KNumPosStatesBitsMax = 4;
public const uint KNumPosStatesMax = (1 << KNumPosStatesBitsMax);
public const int KNumLowLenBits = 3;
public const int KNumMidLenBits = 3;
public const int KNumHighLenBits = 8;
public const uint KNumLowLenSymbols = 1 << KNumLowLenBits;
public const uint KNumMidLenSymbols = 1 << KNumMidLenBits;
}
public class Decoder
{
uint _id = 1;
class LenDecoder
{
BitDecoder _mChoice = new BitDecoder();
BitDecoder _mChoice2 = new BitDecoder();
readonly BitTreeDecoder[] _mLowCoder = new BitTreeDecoder[Base.KNumPosStatesMax];
readonly BitTreeDecoder[] _mMidCoder = new BitTreeDecoder[Base.KNumPosStatesMax];
BitTreeDecoder _mHighCoder = new BitTreeDecoder(Base.KNumHighLenBits);
uint _mNumPosStates;
public void Create(uint numPosStates)
{
for (uint posState = _mNumPosStates; posState < numPosStates; posState++)
{
_mLowCoder[posState] = new BitTreeDecoder(Base.KNumLowLenBits);
_mMidCoder[posState] = new BitTreeDecoder(Base.KNumMidLenBits);
}
_mNumPosStates = numPosStates;
}
public void Init()
{
_mChoice.Init();
for (uint posState = 0; posState < _mNumPosStates; posState++)
{
_mLowCoder[posState].Init();
_mMidCoder[posState].Init();
}
_mChoice2.Init();
_mHighCoder.Init();
}
public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState)
{
if (_mChoice.Decode(rangeDecoder) == 0)
return _mLowCoder[posState].Decode(rangeDecoder);
else
{
uint symbol = Base.KNumLowLenSymbols;
if (_mChoice2.Decode(rangeDecoder) == 0)
symbol += _mMidCoder[posState].Decode(rangeDecoder);
else
{
symbol += Base.KNumMidLenSymbols;
symbol += _mHighCoder.Decode(rangeDecoder);
}
return symbol;
}
}
}
class LiteralDecoder
{
uint _id = 1;
struct Decoder2
{
BitDecoder[] _mDecoders;
public void Create() { _mDecoders = new BitDecoder[0x300]; }
public void Init() { for (int i = 0; i < 0x300; i++) _mDecoders[i].Init(); }
public byte DecodeNormal(RangeCoder.Decoder rangeDecoder)
{
uint symbol = 1;
do
symbol = (symbol << 1) | _mDecoders[symbol].Decode(rangeDecoder);
while (symbol < 0x100);
return (byte)symbol;
}
public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte)
{
uint symbol = 1;
do
{
uint matchBit = (uint)(matchByte >> 7) & 1;
matchByte <<= 1;
uint bit = _mDecoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder);
symbol = (symbol << 1) | bit;
if (matchBit != bit)
{
while (symbol < 0x100)
symbol = (symbol << 1) | _mDecoders[symbol].Decode(rangeDecoder);
break;
}
}
while (symbol < 0x100);
return (byte)symbol;
}
}
Decoder2[] _mCoders;
int _mNumPrevBits;
int _mNumPosBits;
uint _mPosMask;
public void Create(int numPosBits, int numPrevBits)
{
if (_mCoders != null && _mNumPrevBits == numPrevBits &&
_mNumPosBits == numPosBits)
return;
_mNumPosBits = numPosBits;
_mPosMask = ((uint)1 << numPosBits) - 1;
_mNumPrevBits = numPrevBits;
uint numStates = (uint)1 << (_mNumPrevBits + _mNumPosBits);
_mCoders = new Decoder2[numStates];
for (uint i = 0; i < numStates; i++)
_mCoders[i].Create();
}
public void Init()
{
uint numStates = (uint)1 << (_mNumPrevBits + _mNumPosBits);
for (uint i = 0; i < numStates; i++)
_mCoders[i].Init();
}
uint GetState(uint pos, byte prevByte)
{ return ((pos & _mPosMask) << _mNumPrevBits) + (uint)(prevByte >> (8 - _mNumPrevBits)); }
public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte)
{ return _mCoders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); }
public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte)
{ return _mCoders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); }
};
readonly LZ.OutWindow _mOutWindow = new LZ.OutWindow();
readonly RangeCoder.Decoder _mRangeDecoder = new RangeCoder.Decoder();
readonly BitDecoder[] _mIsMatchDecoders = new BitDecoder[Base.KNumStates << Base.KNumPosStatesBitsMax];
readonly BitDecoder[] _mIsRepDecoders = new BitDecoder[Base.KNumStates];
readonly BitDecoder[] _mIsRepG0Decoders = new BitDecoder[Base.KNumStates];
readonly BitDecoder[] _mIsRepG1Decoders = new BitDecoder[Base.KNumStates];
readonly BitDecoder[] _mIsRepG2Decoders = new BitDecoder[Base.KNumStates];
readonly BitDecoder[] _mIsRep0LongDecoders = new BitDecoder[Base.KNumStates << Base.KNumPosStatesBitsMax];
readonly BitTreeDecoder[] _mPosSlotDecoder = new BitTreeDecoder[Base.KNumLenToPosStates];
readonly BitDecoder[] _mPosDecoders = new BitDecoder[Base.KNumFullDistances - Base.KEndPosModelIndex];
BitTreeDecoder _mPosAlignDecoder = new BitTreeDecoder(Base.KNumAlignBits);
readonly LenDecoder _mLenDecoder = new LenDecoder();
readonly LenDecoder _mRepLenDecoder = new LenDecoder();
readonly LiteralDecoder _mLiteralDecoder = new LiteralDecoder();
uint _mDictionarySize;
uint _mDictionarySizeCheck;
uint _mPosStateMask;
public Decoder()
{
_mDictionarySize = 0xFFFFFFFF;
for (int i = 0; i < Base.KNumLenToPosStates; i++)
_mPosSlotDecoder[i] = new BitTreeDecoder(Base.KNumPosSlotBits);
}
void SetDictionarySize(uint dictionarySize)
{
if (_mDictionarySize != dictionarySize)
{
_mDictionarySize = dictionarySize;
_mDictionarySizeCheck = Math.Max(_mDictionarySize, 1);
uint blockSize = Math.Max(_mDictionarySizeCheck, (1 << 12));
_mOutWindow.Create(blockSize);
}
}
void SetLiteralProperties(int lp, int lc)
{
if (lp > 8)
throw new ArgumentException("lp > 8");
if (lc > 8)
throw new ArgumentException("lc > 8");
_mLiteralDecoder.Create(lp, lc);
}
void SetPosBitsProperties(int pb)
{
if (pb > Base.KNumPosStatesBitsMax)
throw new ArgumentException("pb > Base.KNumPosStatesBitsMax");
uint numPosStates = (uint)1 << pb;
_mLenDecoder.Create(numPosStates);
_mRepLenDecoder.Create(numPosStates);
_mPosStateMask = numPosStates - 1;
}
void Init(Stream inStream, Stream outStream)
{
_mRangeDecoder.Init(inStream);
_mOutWindow.Init(outStream, false);
uint i;
for (i = 0; i < Base.KNumStates; i++)
{
for (uint j = 0; j <= _mPosStateMask; j++)
{
uint index = (i << Base.KNumPosStatesBitsMax) + j;
_mIsMatchDecoders[index].Init();
_mIsRep0LongDecoders[index].Init();
}
_mIsRepDecoders[i].Init();
_mIsRepG0Decoders[i].Init();
_mIsRepG1Decoders[i].Init();
_mIsRepG2Decoders[i].Init();
}
_mLiteralDecoder.Init();
for (i = 0; i < Base.KNumLenToPosStates; i++)
_mPosSlotDecoder[i].Init();
for (i = 0; i < Base.KNumFullDistances - Base.KEndPosModelIndex; i++)
_mPosDecoders[i].Init();
_mLenDecoder.Init();
_mRepLenDecoder.Init();
_mPosAlignDecoder.Init();
}
public void Code(Stream inStream, Stream outStream, Int64 outSize)
{
Init(inStream, outStream);
Base.State state = new Base.State();
state.Init();
uint rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;
UInt64 nowPos64 = 0;
UInt64 outSize64 = (UInt64)outSize;
if (nowPos64 < outSize64)
{
if (_mIsMatchDecoders[state.Index << Base.KNumPosStatesBitsMax].Decode(_mRangeDecoder) != 0)
throw new InvalidDataException("IsMatchDecoders");
state.UpdateChar();
byte b = _mLiteralDecoder.DecodeNormal(_mRangeDecoder, 0, 0);
_mOutWindow.PutByte(b);
nowPos64++;
}
while (nowPos64 < outSize64)
{
// UInt64 next = Math.Min(nowPos64 + (1 << 18), outSize64);
// while(nowPos64 < next)
{
uint posState = (uint)nowPos64 & _mPosStateMask;
if (_mIsMatchDecoders[(state.Index << Base.KNumPosStatesBitsMax) + posState].Decode(_mRangeDecoder) == 0)
{
byte b;
byte prevByte = _mOutWindow.GetByte(0);
if (!state.IsCharState())
b = _mLiteralDecoder.DecodeWithMatchByte(_mRangeDecoder,
(uint)nowPos64, prevByte, _mOutWindow.GetByte(rep0));
else
b = _mLiteralDecoder.DecodeNormal(_mRangeDecoder, (uint)nowPos64, prevByte);
_mOutWindow.PutByte(b);
state.UpdateChar();
nowPos64++;
}
else
{
uint len;
if (_mIsRepDecoders[state.Index].Decode(_mRangeDecoder) == 1)
{
if (_mIsRepG0Decoders[state.Index].Decode(_mRangeDecoder) == 0)
{
if (_mIsRep0LongDecoders[(state.Index << Base.KNumPosStatesBitsMax) + posState].Decode(_mRangeDecoder) == 0)
{
state.UpdateShortRep();
_mOutWindow.PutByte(_mOutWindow.GetByte(rep0));
nowPos64++;
continue;
}
}
else
{
UInt32 distance;
if (_mIsRepG1Decoders[state.Index].Decode(_mRangeDecoder) == 0)
{
distance = rep1;
}
else
{
if (_mIsRepG2Decoders[state.Index].Decode(_mRangeDecoder) == 0)
distance = rep2;
else
{
distance = rep3;
rep3 = rep2;
}
rep2 = rep1;
}
rep1 = rep0;
rep0 = distance;
}
len = _mRepLenDecoder.Decode(_mRangeDecoder, posState) + Base.KMatchMinLen;
state.UpdateRep();
}
else
{
rep3 = rep2;
rep2 = rep1;
rep1 = rep0;
len = Base.KMatchMinLen + _mLenDecoder.Decode(_mRangeDecoder, posState);
state.UpdateMatch();
uint posSlot = _mPosSlotDecoder[Base.GetLenToPosState(len)].Decode(_mRangeDecoder);
if (posSlot >= Base.KStartPosModelIndex)
{
int numDirectBits = (int)((posSlot >> 1) - 1);
rep0 = ((2 | (posSlot & 1)) << numDirectBits);
if (posSlot < Base.KEndPosModelIndex)
rep0 += BitTreeDecoder.ReverseDecode(_mPosDecoders,
rep0 - posSlot - 1, _mRangeDecoder, numDirectBits);
else
{
rep0 += (_mRangeDecoder.DecodeDirectBits(
numDirectBits - Base.KNumAlignBits) << Base.KNumAlignBits);
rep0 += _mPosAlignDecoder.ReverseDecode(_mRangeDecoder);
}
}
else
rep0 = posSlot;
}
if (rep0 >= _mOutWindow.TrainSize + nowPos64 || rep0 >= _mDictionarySizeCheck)
{
if (rep0 == 0xFFFFFFFF)
break;
throw new InvalidDataException("rep0");
}
_mOutWindow.CopyBlock(rep0, len);
nowPos64 += len;
}
}
}
_mOutWindow.Flush();
_mOutWindow.ReleaseStream();
_mRangeDecoder.ReleaseStream();
}
public void SetDecoderProperties(byte[] properties)
{
if (properties.Length < 5)
throw new ArgumentException("properties.Length < 5");
int lc = properties[0] % 9;
int remainder = properties[0] / 9;
int lp = remainder % 5;
int pb = remainder / 5;
if (pb > Base.KNumPosStatesBitsMax)
throw new ArgumentException("pb > Base.kNumPosStatesBitsMax");
UInt32 dictionarySize = 0;
for (int i = 0; i < 4; i++)
dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8);
SetDictionarySize(dictionarySize);
SetLiteralProperties(lp, lc);
SetPosBitsProperties(pb);
}
}
}