652 lines
19 KiB
C#
652 lines
19 KiB
C#
// 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);
|
|
}
|
|
}
|
|
}
|