using System; | |
namespace SevenZip.Compression.RangeCoder | |
{ | |
class Encoder | |
{ | |
public const uint kTopValue = (1 << 24); | |
System.IO.Stream Stream; | |
public UInt64 Low; | |
public uint Range; | |
uint _cacheSize; | |
byte _cache; | |
long StartPosition; | |
public void SetStream(System.IO.Stream stream) | |
{ | |
Stream = stream; | |
} | |
public void ReleaseStream() | |
{ | |
Stream = null; | |
} | |
public void Init() | |
{ | |
StartPosition = Stream.Position; | |
Low = 0; | |
Range = 0xFFFFFFFF; | |
_cacheSize = 1; | |
_cache = 0; | |
} | |
public void FlushData() | |
{ | |
for (int i = 0; i < 5; i++) | |
ShiftLow(); | |
} | |
public void FlushStream() | |
{ | |
Stream.Flush(); | |
} | |
public void CloseStream() | |
{ | |
Stream.Close(); | |
} | |
public void Encode(uint start, uint size, uint total) | |
{ | |
Low += start * (Range /= total); | |
Range *= size; | |
while (Range < kTopValue) | |
{ | |
Range <<= 8; | |
ShiftLow(); | |
} | |
} | |
public void ShiftLow() | |
{ | |
if ((uint)Low < (uint)0xFF000000 || (uint)(Low >> 32) == 1) | |
{ | |
byte temp = _cache; | |
do | |
{ | |
Stream.WriteByte((byte)(temp + (Low >> 32))); | |
temp = 0xFF; | |
} | |
while (--_cacheSize != 0); | |
_cache = (byte)(((uint)Low) >> 24); | |
} | |
_cacheSize++; | |
Low = ((uint)Low) << 8; | |
} | |
public void EncodeDirectBits(uint v, int numTotalBits) | |
{ | |
for (int i = numTotalBits - 1; i >= 0; i--) | |
{ | |
Range >>= 1; | |
if (((v >> i) & 1) == 1) | |
Low += Range; | |
if (Range < kTopValue) | |
{ | |
Range <<= 8; | |
ShiftLow(); | |
} | |
} | |
} | |
public void EncodeBit(uint size0, int numTotalBits, uint symbol) | |
{ | |
uint newBound = (Range >> numTotalBits) * size0; | |
if (symbol == 0) | |
Range = newBound; | |
else | |
{ | |
Low += newBound; | |
Range -= newBound; | |
} | |
while (Range < kTopValue) | |
{ | |
Range <<= 8; | |
ShiftLow(); | |
} | |
} | |
public long GetProcessedSizeAdd() | |
{ | |
return _cacheSize + | |
Stream.Position - StartPosition + 4; | |
// (long)Stream.GetProcessedSize(); | |
} | |
} | |
class Decoder | |
{ | |
public const uint kTopValue = (1 << 24); | |
public uint Range; | |
public uint Code; | |
// public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16); | |
public System.IO.Stream Stream; | |
public void Init(System.IO.Stream stream) | |
{ | |
// Stream.Init(stream); | |
Stream = stream; | |
Code = 0; | |
Range = 0xFFFFFFFF; | |
for (int i = 0; i < 5; i++) | |
Code = (Code << 8) | (byte)Stream.ReadByte(); | |
} | |
public void ReleaseStream() | |
{ | |
// Stream.ReleaseStream(); | |
Stream = null; | |
} | |
public void CloseStream() | |
{ | |
Stream.Close(); | |
} | |
public void Normalize() | |
{ | |
while (Range < kTopValue) | |
{ | |
Code = (Code << 8) | (byte)Stream.ReadByte(); | |
Range <<= 8; | |
} | |
} | |
public void Normalize2() | |
{ | |
if (Range < kTopValue) | |
{ | |
Code = (Code << 8) | (byte)Stream.ReadByte(); | |
Range <<= 8; | |
} | |
} | |
public uint GetThreshold(uint total) | |
{ | |
return Code / (Range /= total); | |
} | |
public void Decode(uint start, uint size, uint total) | |
{ | |
Code -= start * Range; | |
Range *= size; | |
Normalize(); | |
} | |
public uint DecodeDirectBits(int numTotalBits) | |
{ | |
uint range = Range; | |
uint code = Code; | |
uint result = 0; | |
for (int i = numTotalBits; i > 0; i--) | |
{ | |
range >>= 1; | |
/* | |
result <<= 1; | |
if (code >= range) | |
{ | |
code -= range; | |
result |= 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; | |
} | |
public uint DecodeBit(uint size0, int numTotalBits) | |
{ | |
uint newBound = (Range >> numTotalBits) * size0; | |
uint symbol; | |
if (Code < newBound) | |
{ | |
symbol = 0; | |
Range = newBound; | |
} | |
else | |
{ | |
symbol = 1; | |
Code -= newBound; | |
Range -= newBound; | |
} | |
Normalize(); | |
return symbol; | |
} | |
// ulong GetProcessedSize() {return Stream.GetProcessedSize(); } | |
} | |
} |