Files
sharpcompress/SharpCompress/Compressor/LZMA/RangeCoder/RangeCoder.cs

243 lines
6.1 KiB
C#
Raw Normal View History

2013-04-07 10:58:58 +01:00
using System;
namespace SharpCompress.Compressor.LZMA.RangeCoder
{
internal class Encoder
{
public const uint kTopValue = (1 << 24);
2013-04-28 12:32:55 +01:00
private System.IO.Stream Stream;
2013-04-07 10:58:58 +01:00
public UInt64 Low;
public uint Range;
2013-04-28 12:32:55 +01:00
private uint _cacheSize;
private byte _cache;
2013-04-07 10:58:58 +01:00
//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.Dispose();
}
public void Encode(uint start, uint size, uint total)
{
2013-04-28 12:32:55 +01:00
Low += start*(Range /= total);
2013-04-07 10:58:58 +01:00
Range *= size;
while (Range < kTopValue)
{
Range <<= 8;
ShiftLow();
}
}
public void ShiftLow()
{
2013-04-28 12:32:55 +01:00
if ((uint) Low < (uint) 0xFF000000 || (uint) (Low >> 32) == 1)
2013-04-07 10:58:58 +01:00
{
byte temp = _cache;
do
{
2013-04-28 12:32:55 +01:00
Stream.WriteByte((byte) (temp + (Low >> 32)));
2013-04-07 10:58:58 +01:00
temp = 0xFF;
2013-04-28 12:32:55 +01:00
} while (--_cacheSize != 0);
_cache = (byte) (((uint) Low) >> 24);
2013-04-07 10:58:58 +01:00
}
_cacheSize++;
2013-04-28 12:32:55 +01:00
Low = ((uint) Low) << 8;
2013-04-07 10:58:58 +01:00
}
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)
{
2013-04-28 12:32:55 +01:00
uint newBound = (Range >> numTotalBits)*size0;
2013-04-07 10:58:58 +01:00
if (symbol == 0)
Range = newBound;
else
{
Low += newBound;
Range -= newBound;
}
while (Range < kTopValue)
{
Range <<= 8;
ShiftLow();
}
}
public long GetProcessedSizeAdd()
{
return -1;
//return _cacheSize + Stream.Position - StartPosition + 4;
// (long)Stream.GetProcessedSize();
}
}
internal class Decoder
{
public const uint kTopValue = (1 << 24);
public uint Range;
public uint Code = 0;
// public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16);
public System.IO.Stream Stream;
public long Total;
public void Init(System.IO.Stream stream)
{
// Stream.Init(stream);
Stream = stream;
Code = 0;
Range = 0xFFFFFFFF;
for (int i = 0; i < 5; i++)
2013-04-28 12:32:55 +01:00
Code = (Code << 8) | (byte) Stream.ReadByte();
2013-04-07 10:58:58 +01:00
Total = 5;
}
public void ReleaseStream()
{
// Stream.ReleaseStream();
Stream = null;
}
public void CloseStream()
{
Stream.Dispose();
}
public void Normalize()
{
while (Range < kTopValue)
{
2013-04-28 12:32:55 +01:00
Code = (Code << 8) | (byte) Stream.ReadByte();
2013-04-07 10:58:58 +01:00
Range <<= 8;
Total++;
}
}
public void Normalize2()
{
if (Range < kTopValue)
{
2013-04-28 12:32:55 +01:00
Code = (Code << 8) | (byte) Stream.ReadByte();
2013-04-07 10:58:58 +01:00
Range <<= 8;
Total++;
}
}
public uint GetThreshold(uint total)
{
2013-04-28 12:32:55 +01:00
return Code/(Range /= total);
2013-04-07 10:58:58 +01:00
}
public void Decode(uint start, uint size)
{
2013-04-28 12:32:55 +01:00
Code -= start*Range;
2013-04-07 10:58:58 +01:00
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)
{
2013-04-28 12:32:55 +01:00
code = (code << 8) | (byte) Stream.ReadByte();
2013-04-07 10:58:58 +01:00
range <<= 8;
Total++;
}
}
Range = range;
Code = code;
return result;
}
public uint DecodeBit(uint size0, int numTotalBits)
{
2013-04-28 12:32:55 +01:00
uint newBound = (Range >> numTotalBits)*size0;
2013-04-07 10:58:58 +01:00
uint symbol;
if (Code < newBound)
{
symbol = 0;
Range = newBound;
}
else
{
symbol = 1;
Code -= newBound;
Range -= newBound;
}
Normalize();
return symbol;
}
public bool IsFinished
{
2013-04-28 12:32:55 +01:00
get { return Code == 0; }
2013-04-07 10:58:58 +01:00
}
// ulong GetProcessedSize() {return Stream.GetProcessedSize(); }
}
2013-04-28 12:32:55 +01:00
}