mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-11 21:22:10 +00:00
140 lines
4.4 KiB
C#
140 lines
4.4 KiB
C#
using System;
|
|
|
|
namespace SharpCompress.Compressors.LZMA.RangeCoder
|
|
{
|
|
internal struct BitEncoder
|
|
{
|
|
public const int K_NUM_BIT_MODEL_TOTAL_BITS = 11;
|
|
public const uint K_BIT_MODEL_TOTAL = (1 << K_NUM_BIT_MODEL_TOTAL_BITS);
|
|
private const int K_NUM_MOVE_BITS = 5;
|
|
private const int K_NUM_MOVE_REDUCING_BITS = 2;
|
|
public const int K_NUM_BIT_PRICE_SHIFT_BITS = 6;
|
|
|
|
private uint _prob;
|
|
|
|
public void Init()
|
|
{
|
|
_prob = K_BIT_MODEL_TOTAL >> 1;
|
|
}
|
|
|
|
public void UpdateModel(uint symbol)
|
|
{
|
|
if (symbol == 0)
|
|
{
|
|
_prob += (K_BIT_MODEL_TOTAL - _prob) >> K_NUM_MOVE_BITS;
|
|
}
|
|
else
|
|
{
|
|
_prob -= (_prob) >> K_NUM_MOVE_BITS;
|
|
}
|
|
}
|
|
|
|
public void Encode(Encoder encoder, uint symbol)
|
|
{
|
|
// encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol);
|
|
// UpdateModel(symbol);
|
|
uint newBound = (encoder._range >> K_NUM_BIT_MODEL_TOTAL_BITS) * _prob;
|
|
if (symbol == 0)
|
|
{
|
|
encoder._range = newBound;
|
|
_prob += (K_BIT_MODEL_TOTAL - _prob) >> K_NUM_MOVE_BITS;
|
|
}
|
|
else
|
|
{
|
|
encoder._low += newBound;
|
|
encoder._range -= newBound;
|
|
_prob -= (_prob) >> K_NUM_MOVE_BITS;
|
|
}
|
|
if (encoder._range < Encoder.K_TOP_VALUE)
|
|
{
|
|
encoder._range <<= 8;
|
|
encoder.ShiftLow();
|
|
}
|
|
}
|
|
|
|
private static readonly UInt32[] PROB_PRICES = new UInt32[K_BIT_MODEL_TOTAL >> K_NUM_MOVE_REDUCING_BITS];
|
|
|
|
static BitEncoder()
|
|
{
|
|
const int kNumBits = (K_NUM_BIT_MODEL_TOTAL_BITS - K_NUM_MOVE_REDUCING_BITS);
|
|
for (int i = kNumBits - 1; i >= 0; i--)
|
|
{
|
|
UInt32 start = (UInt32)1 << (kNumBits - i - 1);
|
|
UInt32 end = (UInt32)1 << (kNumBits - i);
|
|
for (UInt32 j = start; j < end; j++)
|
|
{
|
|
PROB_PRICES[j] = ((UInt32)i << K_NUM_BIT_PRICE_SHIFT_BITS) +
|
|
(((end - j) << K_NUM_BIT_PRICE_SHIFT_BITS) >> (kNumBits - i - 1));
|
|
}
|
|
}
|
|
}
|
|
|
|
public uint GetPrice(uint symbol)
|
|
{
|
|
return PROB_PRICES[(((_prob - symbol) ^ ((-(int)symbol))) & (K_BIT_MODEL_TOTAL - 1)) >> K_NUM_MOVE_REDUCING_BITS];
|
|
}
|
|
|
|
public uint GetPrice0()
|
|
{
|
|
return PROB_PRICES[_prob >> K_NUM_MOVE_REDUCING_BITS];
|
|
}
|
|
|
|
public uint GetPrice1()
|
|
{
|
|
return PROB_PRICES[(K_BIT_MODEL_TOTAL - _prob) >> K_NUM_MOVE_REDUCING_BITS];
|
|
}
|
|
}
|
|
|
|
internal struct BitDecoder
|
|
{
|
|
public const int K_NUM_BIT_MODEL_TOTAL_BITS = 11;
|
|
public const uint K_BIT_MODEL_TOTAL = (1 << K_NUM_BIT_MODEL_TOTAL_BITS);
|
|
private const int K_NUM_MOVE_BITS = 5;
|
|
|
|
private uint _prob;
|
|
|
|
public void UpdateModel(int numMoveBits, uint symbol)
|
|
{
|
|
if (symbol == 0)
|
|
{
|
|
_prob += (K_BIT_MODEL_TOTAL - _prob) >> numMoveBits;
|
|
}
|
|
else
|
|
{
|
|
_prob -= (_prob) >> numMoveBits;
|
|
}
|
|
}
|
|
|
|
public void Init()
|
|
{
|
|
_prob = K_BIT_MODEL_TOTAL >> 1;
|
|
}
|
|
|
|
public uint Decode(Decoder rangeDecoder)
|
|
{
|
|
uint newBound = (rangeDecoder._range >> K_NUM_BIT_MODEL_TOTAL_BITS) * _prob;
|
|
if (rangeDecoder._code < newBound)
|
|
{
|
|
rangeDecoder._range = newBound;
|
|
_prob += (K_BIT_MODEL_TOTAL - _prob) >> K_NUM_MOVE_BITS;
|
|
if (rangeDecoder._range < Decoder.K_TOP_VALUE)
|
|
{
|
|
rangeDecoder._code = (rangeDecoder._code << 8) | (byte)rangeDecoder._stream.ReadByte();
|
|
rangeDecoder._range <<= 8;
|
|
rangeDecoder._total++;
|
|
}
|
|
return 0;
|
|
}
|
|
rangeDecoder._range -= newBound;
|
|
rangeDecoder._code -= newBound;
|
|
_prob -= (_prob) >> K_NUM_MOVE_BITS;
|
|
if (rangeDecoder._range < Decoder.K_TOP_VALUE)
|
|
{
|
|
rangeDecoder._code = (rangeDecoder._code << 8) | (byte)rangeDecoder._stream.ReadByte();
|
|
rangeDecoder._range <<= 8;
|
|
rangeDecoder._total++;
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
} |