Files
sharpcompress/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs
2018-05-06 08:49:32 +01:00

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;
}
}
}