more lzma porting

This commit is contained in:
Adam Hathcock
2026-01-26 18:09:44 +00:00
parent 27cf2795ef
commit 27fe2d807e
8 changed files with 115 additions and 100 deletions

View File

@@ -1,20 +1,38 @@
#nullable disable #nullable disable
using System; using System;
using System.Buffers;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace SharpCompress.Compressors.LZMA.LZ; namespace SharpCompress.Compressors.LZMA.LZ;
internal partial class OutWindow : IDisposable internal partial class OutWindow : IAsyncDisposable
{ {
public async ValueTask InitAsync(Stream stream)
{
await ReleaseStreamAsync();
_stream = stream;
}
public async ValueTask ReleaseStreamAsync(CancellationToken cancellationToken = default) public async ValueTask ReleaseStreamAsync(CancellationToken cancellationToken = default)
{ {
await FlushAsync(cancellationToken).ConfigureAwait(false); await FlushAsync(cancellationToken).ConfigureAwait(false);
_stream = null; _stream = null;
} }
public async ValueTask DisposeAsync()
{
await ReleaseStreamAsync();
if (_buffer is null)
{
return;
}
ArrayPool<byte>.Shared.Return(_buffer);
_buffer = null;
}
private async ValueTask FlushAsync(CancellationToken cancellationToken = default) private async ValueTask FlushAsync(CancellationToken cancellationToken = default)
{ {
if (_stream is null) if (_stream is null)
@@ -140,4 +158,20 @@ internal partial class OutWindow : IDisposable
} }
return len - size; return len - size;
} }
public async ValueTask TrainAsync(Stream stream)
{
var len = stream.Length;
var size = (len < _windowSize) ? (int)len : _windowSize;
stream.Position = len - size;
_total = 0;
_limit = size;
_pos = _windowSize - size;
await CopyStreamAsync(stream, size);
if (_pos == _windowSize)
{
_pos = 0;
}
_streamPos = _pos;
}
} }

View File

@@ -137,7 +137,7 @@ public partial class Decoder : ICoder, ISetDecoderProperties
{ {
CreateDictionary(); CreateDictionary();
} }
_outWindow.Init(outStream); await _outWindow.InitAsync(outStream);
if (outSize > 0) if (outSize > 0)
{ {
_outWindow.SetLimit(outSize); _outWindow.SetLimit(outSize);
@@ -156,7 +156,7 @@ public partial class Decoder : ICoder, ISetDecoderProperties
await _outWindow.ReleaseStreamAsync(cancellationToken).ConfigureAwait(false); await _outWindow.ReleaseStreamAsync(cancellationToken).ConfigureAwait(false);
rangeDecoder.ReleaseStream(); rangeDecoder.ReleaseStream();
_outWindow.Dispose(); await _outWindow.DisposeAsync().ConfigureAwait(false);
_outWindow = null; _outWindow = null;
} }
@@ -332,4 +332,13 @@ public partial class Decoder : ICoder, ISetDecoderProperties
} }
return false; return false;
} }
public async ValueTask TrainAsync(Stream stream)
{
if (_outWindow is null)
{
CreateDictionary();
}
await _outWindow.TrainAsync(stream);
}
} }

View File

@@ -1,5 +1,3 @@
#nullable disable
using System; using System;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
@@ -10,10 +8,66 @@ namespace SharpCompress.Compressors.LZMA;
public partial class LzmaStream public partial class LzmaStream
{ {
public static async ValueTask<LzmaStream> CreateAsync(
byte[] properties,
Stream inputStream,
long inputSize,
long outputSize,
Stream? presetDictionary,
bool isLzma2,
bool leaveOpen = false
)
{
var lzma = new LzmaStream(
properties,
inputStream,
inputSize,
outputSize,
isLzma2,
leaveOpen
);
if (!isLzma2)
{
if (presetDictionary != null)
{
await lzma._outWindow.TrainAsync(presetDictionary);
}
await lzma._rangeDecoder.InitAsync(inputStream);
}
else
{
if (presetDictionary != null)
{
await lzma._outWindow.TrainAsync(presetDictionary);
lzma._needDictReset = false;
}
}
return lzma;
}
/*public static async ValueTask<LzmaStream> CreateAsync(
LzmaEncoderProperties properties,
bool isLzma2,
Stream? presetDictionary,
Stream outputStream
)
{
var lzma = new LzmaStream(properties, isLzma2, presetDictionary);
lzma._encoder!.SetStreams(null, outputStream, -1, -1);
if (presetDictionary != null)
{
lzma._encoder.Train(presetDictionary);
}
return lzma;
}*/
private async ValueTask DecodeChunkHeaderAsync(CancellationToken cancellationToken = default) private async ValueTask DecodeChunkHeaderAsync(CancellationToken cancellationToken = default)
{ {
var controlBuffer = new byte[1]; var controlBuffer = new byte[1];
await _inputStream await _inputStream!
.ReadExactAsync(controlBuffer, 0, 1, cancellationToken) .ReadExactAsync(controlBuffer, 0, 1, cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);
var control = controlBuffer[0]; var control = controlBuffer[0];
@@ -42,13 +96,13 @@ public partial class LzmaStream
_availableBytes = (control & 0x1F) << 16; _availableBytes = (control & 0x1F) << 16;
var buffer = new byte[2]; var buffer = new byte[2];
await _inputStream await _inputStream!
.ReadExactAsync(buffer, 0, 2, cancellationToken) .ReadExactAsync(buffer, 0, 2, cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);
_availableBytes += (buffer[0] << 8) + buffer[1] + 1; _availableBytes += (buffer[0] << 8) + buffer[1] + 1;
_inputPosition += 2; _inputPosition += 2;
await _inputStream await _inputStream!
.ReadExactAsync(buffer, 0, 2, cancellationToken) .ReadExactAsync(buffer, 0, 2, cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);
_rangeDecoderLimit = (buffer[0] << 8) + buffer[1] + 1; _rangeDecoderLimit = (buffer[0] << 8) + buffer[1] + 1;
@@ -57,7 +111,7 @@ public partial class LzmaStream
if (control >= 0xC0) if (control >= 0xC0)
{ {
_needProps = false; _needProps = false;
await _inputStream await _inputStream!
.ReadExactAsync(controlBuffer, 0, 1, cancellationToken) .ReadExactAsync(controlBuffer, 0, 1, cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);
Properties[0] = controlBuffer[0]; Properties[0] = controlBuffer[0];
@@ -86,7 +140,7 @@ public partial class LzmaStream
{ {
_uncompressedChunk = true; _uncompressedChunk = true;
var buffer = new byte[2]; var buffer = new byte[2];
await _inputStream await _inputStream!
.ReadExactAsync(buffer, 0, 2, cancellationToken) .ReadExactAsync(buffer, 0, 2, cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);
_availableBytes = (buffer[0] << 8) + buffer[1] + 1; _availableBytes = (buffer[0] << 8) + buffer[1] + 1;
@@ -141,7 +195,7 @@ public partial class LzmaStream
.ConfigureAwait(false); .ConfigureAwait(false);
} }
else if ( else if (
await _decoder await _decoder!
.CodeAsync(_dictionarySize, _outWindow, _rangeDecoder, cancellationToken) .CodeAsync(_dictionarySize, _outWindow, _rangeDecoder, cancellationToken)
.ConfigureAwait(false) .ConfigureAwait(false)
&& _outputSize < 0 && _outputSize < 0
@@ -165,7 +219,7 @@ public partial class LzmaStream
{ {
_outWindow.SetLimit(toProcess + 1); _outWindow.SetLimit(toProcess + 1);
if ( if (
!await _decoder !await _decoder!
.CodeAsync( .CodeAsync(
_dictionarySize, _dictionarySize,
_outWindow, _outWindow,
@@ -253,7 +307,7 @@ public partial class LzmaStream
.ConfigureAwait(false); .ConfigureAwait(false);
} }
else if ( else if (
await _decoder await _decoder!
.CodeAsync(_dictionarySize, _outWindow, _rangeDecoder, cancellationToken) .CodeAsync(_dictionarySize, _outWindow, _rangeDecoder, cancellationToken)
.ConfigureAwait(false) .ConfigureAwait(false)
&& _outputSize < 0 && _outputSize < 0
@@ -277,7 +331,7 @@ public partial class LzmaStream
{ {
_outWindow.SetLimit(toProcess + 1); _outWindow.SetLimit(toProcess + 1);
if ( if (
!await _decoder !await _decoder!
.CodeAsync( .CodeAsync(
_dictionarySize, _dictionarySize,
_outWindow, _outWindow,

View File

@@ -161,7 +161,7 @@ public partial class LzmaStream : Stream, IStreamStack
return lzma; return lzma;
} }
private LzmaStream(LzmaEncoderProperties properties, bool isLzma2, Stream? presetDictionary) private LzmaStream(LzmaEncoderProperties properties, bool isLzma2)
{ {
_isLzma2 = isLzma2; _isLzma2 = isLzma2;
_availableBytes = 0; _availableBytes = 0;
@@ -177,11 +177,6 @@ public partial class LzmaStream : Stream, IStreamStack
var prop = new byte[5]; var prop = new byte[5];
_encoder.WriteCoderProperties(prop); _encoder.WriteCoderProperties(prop);
Properties = prop; Properties = prop;
if (presetDictionary != null)
{
_encoder.Train(presetDictionary);
}
} }
public static LzmaStream Create( public static LzmaStream Create(
@@ -197,7 +192,7 @@ public partial class LzmaStream : Stream, IStreamStack
Stream outputStream Stream outputStream
) )
{ {
var lzma = new LzmaStream(properties, isLzma2, presetDictionary); var lzma = new LzmaStream(properties, isLzma2);
lzma._encoder!.SetStreams(null, outputStream, -1, -1); lzma._encoder!.SetStreams(null, outputStream, -1, -1);

View File

@@ -15,7 +15,7 @@ internal partial class Encoder
var temp = _cache; var temp = _cache;
do do
{ {
var b = (byte)(temp + (uint)(_low >> 32)); var b = (byte)(temp + (_low >> 32));
var buffer = new[] { b }; var buffer = new[] { b };
await _stream.WriteAsync(buffer, 0, 1, cancellationToken).ConfigureAwait(false); await _stream.WriteAsync(buffer, 0, 1, cancellationToken).ConfigureAwait(false);
temp = 0xFF; temp = 0xFF;
@@ -26,22 +26,6 @@ internal partial class Encoder
_low = ((uint)_low) << 8; _low = ((uint)_low) << 8;
} }
public async ValueTask EncodeAsync(
uint start,
uint size,
uint total,
CancellationToken cancellationToken = default
)
{
_low += start * (_range /= total);
_range *= size;
while (_range < K_TOP_VALUE)
{
_range <<= 8;
await ShiftLowAsync(cancellationToken).ConfigureAwait(false);
}
}
public async ValueTask EncodeBitAsync( public async ValueTask EncodeBitAsync(
uint size0, uint size0,
int numTotalBits, int numTotalBits,
@@ -114,8 +98,6 @@ internal partial class Decoder
_total = 5; _total = 5;
} }
public void ReleaseStream() => _stream = null;
public async ValueTask NormalizeAsync(CancellationToken cancellationToken = default) public async ValueTask NormalizeAsync(CancellationToken cancellationToken = default)
{ {
while (_range < K_TOP_VALUE) while (_range < K_TOP_VALUE)

View File

@@ -44,17 +44,6 @@ internal partial class Encoder
public void CloseStream() => _stream.Dispose(); public void CloseStream() => _stream.Dispose();
public void Encode(uint start, uint size, uint total)
{
_low += start * (_range /= total);
_range *= size;
while (_range < K_TOP_VALUE)
{
_range <<= 8;
ShiftLow();
}
}
public void ShiftLow() public void ShiftLow()
{ {
if ((uint)_low < 0xFF000000 || (uint)(_low >> 32) == 1) if ((uint)_low < 0xFF000000 || (uint)(_low >> 32) == 1)
@@ -88,29 +77,7 @@ internal partial class Encoder
} }
} }
public void EncodeBit(uint size0, int numTotalBits, uint symbol)
{
var newBound = (_range >> numTotalBits) * size0;
if (symbol == 0)
{
_range = newBound;
}
else
{
_low += newBound;
_range -= newBound;
}
while (_range < K_TOP_VALUE)
{
_range <<= 8;
ShiftLow();
}
}
public long GetProcessedSizeAdd() => -1; public long GetProcessedSizeAdd() => -1;
//return _cacheSize + Stream.Position - StartPosition + 4;
// (long)Stream.GetProcessedSize();
} }
internal partial class Decoder internal partial class Decoder
@@ -119,13 +86,11 @@ internal partial class Decoder
public uint _range; public uint _range;
public uint _code; public uint _code;
// public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16);
public Stream _stream; public Stream _stream;
public long _total; public long _total;
public void Init(Stream stream) public void Init(Stream stream)
{ {
// Stream.Init(stream);
_stream = stream; _stream = stream;
_code = 0; _code = 0;
@@ -141,8 +106,6 @@ internal partial class Decoder
// Stream.ReleaseStream(); // Stream.ReleaseStream();
_stream = null; _stream = null;
public void CloseStream() => _stream.Dispose();
public void Normalize() public void Normalize()
{ {
while (_range < K_TOP_VALUE) while (_range < K_TOP_VALUE)
@@ -181,14 +144,6 @@ internal partial class Decoder
for (var i = numTotalBits; i > 0; i--) for (var i = numTotalBits; i > 0; i--)
{ {
range >>= 1; range >>= 1;
/*
result <<= 1;
if (code >= range)
{
code -= range;
result |= 1;
}
*/
var t = (code - range) >> 31; var t = (code - range) >> 31;
code -= range & (t - 1); code -= range & (t - 1);
result = (result << 1) | (1 - t); result = (result << 1) | (1 - t);

View File

@@ -26,8 +26,6 @@ internal partial struct BitEncoder
public void Encode(Encoder encoder, uint symbol) public void Encode(Encoder encoder, uint symbol)
{ {
// encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol);
// UpdateModel(symbol);
var newBound = (encoder._range >> K_NUM_BIT_MODEL_TOTAL_BITS) * _prob; var newBound = (encoder._range >> K_NUM_BIT_MODEL_TOTAL_BITS) * _prob;
if (symbol == 0) if (symbol == 0)
{ {
@@ -86,18 +84,6 @@ internal partial struct BitDecoder
private uint _prob; 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 void Init() => _prob = K_BIT_MODEL_TOTAL >> 1;
public uint Decode(Decoder rangeDecoder) public uint Decode(Decoder rangeDecoder)

View File

@@ -585,7 +585,7 @@ public class LzmaStreamAsyncTests
long decompressedSize long decompressedSize
) )
{ {
var lzmaStream = LzmaStream.Create( var lzmaStream = await LzmaStream.CreateAsync(
properties, properties,
compressedStream, compressedStream,
compressedSize, compressedSize,