Files
sharpcompress/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs

258 lines
6.7 KiB
C#
Raw Normal View History

2020-05-23 16:27:55 -07:00
#nullable disable
2015-12-30 11:19:42 +00:00
using System;
using System.Buffers;
using System.IO;
using System.Threading.Tasks;
2015-12-30 11:19:42 +00:00
2016-09-26 11:49:49 +01:00
namespace SharpCompress.Compressors.LZMA.RangeCoder
2015-12-30 11:19:42 +00:00
{
internal class Encoder : IAsyncDisposable
2015-12-30 11:19:42 +00:00
{
2018-05-06 08:49:32 +01:00
public const uint K_TOP_VALUE = (1 << 24);
2015-12-30 11:19:42 +00:00
2018-05-06 08:49:32 +01:00
private Stream _stream;
2015-12-30 11:19:42 +00:00
2018-05-06 08:49:32 +01:00
public UInt64 _low;
public uint _range;
2015-12-30 11:19:42 +00:00
private uint _cacheSize;
private byte _cache;
//long StartPosition;
public void SetStream(Stream stream)
2015-12-30 11:19:42 +00:00
{
2018-05-06 08:49:32 +01:00
_stream = stream;
2015-12-30 11:19:42 +00:00
}
public void ReleaseStream()
{
2018-05-06 08:49:32 +01:00
_stream = null;
2015-12-30 11:19:42 +00:00
}
public void Init()
{
//StartPosition = Stream.Position;
2018-05-06 08:49:32 +01:00
_low = 0;
_range = 0xFFFFFFFF;
2015-12-30 11:19:42 +00:00
_cacheSize = 1;
_cache = 0;
}
public async ValueTask FlushData()
2015-12-30 11:19:42 +00:00
{
for (int i = 0; i < 5; i++)
{
await ShiftLowAsync();
}
2015-12-30 11:19:42 +00:00
}
public Task FlushAsync()
2015-12-30 11:19:42 +00:00
{
return _stream.FlushAsync();
2015-12-30 11:19:42 +00:00
}
public ValueTask DisposeAsync()
2015-12-30 11:19:42 +00:00
{
return _stream.DisposeAsync();
2015-12-30 11:19:42 +00:00
}
public async ValueTask EncodeAsync(uint start, uint size, uint total)
2015-12-30 11:19:42 +00:00
{
2018-05-06 08:49:32 +01:00
_low += start * (_range /= total);
_range *= size;
while (_range < K_TOP_VALUE)
2015-12-30 11:19:42 +00:00
{
2018-05-06 08:49:32 +01:00
_range <<= 8;
await ShiftLowAsync();
2015-12-30 11:19:42 +00:00
}
}
public async ValueTask ShiftLowAsync()
2015-12-30 11:19:42 +00:00
{
2018-05-06 08:49:32 +01:00
if ((uint)_low < 0xFF000000 || (uint)(_low >> 32) == 1)
2015-12-30 11:19:42 +00:00
{
using var buffer = MemoryPool<byte>.Shared.Rent(1);
var b = buffer.Memory.Slice(0,1);
2015-12-30 11:19:42 +00:00
byte temp = _cache;
do
{
b.Span[0] = (byte)(temp + (_low >> 32));
await _stream.WriteAsync(b);
2015-12-30 11:19:42 +00:00
temp = 0xFF;
}
while (--_cacheSize != 0);
2018-05-06 08:49:32 +01:00
_cache = (byte)(((uint)_low) >> 24);
2015-12-30 11:19:42 +00:00
}
_cacheSize++;
2018-05-06 08:49:32 +01:00
_low = ((uint)_low) << 8;
2015-12-30 11:19:42 +00:00
}
public async ValueTask EncodeDirectBits(uint v, int numTotalBits)
2015-12-30 11:19:42 +00:00
{
for (int i = numTotalBits - 1; i >= 0; i--)
{
2018-05-06 08:49:32 +01:00
_range >>= 1;
2015-12-30 11:19:42 +00:00
if (((v >> i) & 1) == 1)
{
2018-05-06 08:49:32 +01:00
_low += _range;
}
2018-05-06 08:49:32 +01:00
if (_range < K_TOP_VALUE)
2015-12-30 11:19:42 +00:00
{
2018-05-06 08:49:32 +01:00
_range <<= 8;
await ShiftLowAsync();
2015-12-30 11:19:42 +00:00
}
}
}
public async ValueTask EncodeBitAsync(uint size0, int numTotalBits, uint symbol)
2015-12-30 11:19:42 +00:00
{
2018-05-06 08:49:32 +01:00
uint newBound = (_range >> numTotalBits) * size0;
2015-12-30 11:19:42 +00:00
if (symbol == 0)
{
2018-05-06 08:49:32 +01:00
_range = newBound;
}
2015-12-30 11:19:42 +00:00
else
{
2018-05-06 08:49:32 +01:00
_low += newBound;
_range -= newBound;
2015-12-30 11:19:42 +00:00
}
2018-05-06 08:49:32 +01:00
while (_range < K_TOP_VALUE)
2015-12-30 11:19:42 +00:00
{
2018-05-06 08:49:32 +01:00
_range <<= 8;
await ShiftLowAsync();
2015-12-30 11:19:42 +00:00
}
}
public long GetProcessedSizeAdd()
{
return -1;
2015-12-30 11:19:42 +00:00
//return _cacheSize + Stream.Position - StartPosition + 4;
// (long)Stream.GetProcessedSize();
}
}
internal class Decoder: IAsyncDisposable
2015-12-30 11:19:42 +00:00
{
2018-05-06 08:49:32 +01:00
public const uint K_TOP_VALUE = (1 << 24);
public uint _range;
public uint _code;
2015-12-30 11:19:42 +00:00
// public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16);
2018-05-06 08:49:32 +01:00
public Stream _stream;
public long _total;
2015-12-30 11:19:42 +00:00
public async ValueTask InitAsync(Stream stream)
2015-12-30 11:19:42 +00:00
{
// Stream.Init(stream);
2018-05-06 08:49:32 +01:00
_stream = stream;
2015-12-30 11:19:42 +00:00
2018-05-06 08:49:32 +01:00
_code = 0;
_range = 0xFFFFFFFF;
using var buffer = MemoryPool<byte>.Shared.Rent(1);
var b = buffer.Memory.Slice(0,1);
2015-12-30 11:19:42 +00:00
for (int i = 0; i < 5; i++)
{
await _stream.ReadAsync(b);
_code = (_code << 8) | b.Span[0];
}
2018-05-06 08:49:32 +01:00
_total = 5;
2015-12-30 11:19:42 +00:00
}
public void ReleaseStream()
{
// Stream.ReleaseStream();
2018-05-06 08:49:32 +01:00
_stream = null;
2015-12-30 11:19:42 +00:00
}
public ValueTask DisposeAsync()
2015-12-30 11:19:42 +00:00
{
return _stream.DisposeAsync();
2015-12-30 11:19:42 +00:00
}
public async ValueTask NormalizeAsync()
2015-12-30 11:19:42 +00:00
{
using var buffer = MemoryPool<byte>.Shared.Rent(1);
var b = buffer.Memory.Slice(0,1);
2018-05-06 08:49:32 +01:00
while (_range < K_TOP_VALUE)
2015-12-30 11:19:42 +00:00
{
await _stream.ReadAsync(b);
_code = (_code << 8) | b.Span[0];
2018-05-06 08:49:32 +01:00
_range <<= 8;
_total++;
2015-12-30 11:19:42 +00:00
}
}
2015-12-30 11:19:42 +00:00
public uint GetThreshold(uint total)
{
2018-05-06 08:49:32 +01:00
return _code / (_range /= total);
2015-12-30 11:19:42 +00:00
}
2021-02-13 16:44:53 +00:00
public async ValueTask DecodeAsync(uint start, uint size)
2015-12-30 11:19:42 +00:00
{
2018-05-06 08:49:32 +01:00
_code -= start * _range;
_range *= size;
await NormalizeAsync();
2015-12-30 11:19:42 +00:00
}
2021-02-13 16:44:53 +00:00
public async ValueTask<uint> DecodeDirectBitsAsync(int numTotalBits)
2015-12-30 11:19:42 +00:00
{
2018-05-06 08:49:32 +01:00
uint range = _range;
uint code = _code;
2015-12-30 11:19:42 +00:00
uint result = 0;
2021-02-13 16:44:53 +00:00
using var byteBuffer = MemoryPool<byte>.Shared.Rent(1);
var bite = byteBuffer.Memory.Slice(0, 1);
2015-12-30 11:19:42 +00:00
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);
2018-05-06 08:49:32 +01:00
if (range < K_TOP_VALUE)
2015-12-30 11:19:42 +00:00
{
2021-02-13 16:44:53 +00:00
await _stream.ReadAsync(bite);
code = (code << 8) | bite.Span[0];
2015-12-30 11:19:42 +00:00
range <<= 8;
2018-05-06 08:49:32 +01:00
_total++;
2015-12-30 11:19:42 +00:00
}
}
2018-05-06 08:49:32 +01:00
_range = range;
_code = code;
2015-12-30 11:19:42 +00:00
return result;
}
public async ValueTask<uint> DecodeBitAsync(uint size0, int numTotalBits)
2015-12-30 11:19:42 +00:00
{
2018-05-06 08:49:32 +01:00
uint newBound = (_range >> numTotalBits) * size0;
2015-12-30 11:19:42 +00:00
uint symbol;
2018-05-06 08:49:32 +01:00
if (_code < newBound)
2015-12-30 11:19:42 +00:00
{
symbol = 0;
2018-05-06 08:49:32 +01:00
_range = newBound;
2015-12-30 11:19:42 +00:00
}
else
{
symbol = 1;
2018-05-06 08:49:32 +01:00
_code -= newBound;
_range -= newBound;
2015-12-30 11:19:42 +00:00
}
await NormalizeAsync();
2015-12-30 11:19:42 +00:00
return symbol;
}
2018-05-06 08:49:32 +01:00
public bool IsFinished => _code == 0;
2015-12-30 11:19:42 +00:00
// ulong GetProcessedSize() {return Stream.GetProcessedSize(); }
}
2013-04-28 12:32:55 +01:00
}