diff --git a/src/SharpCompress/Compressors/LZMA/LZ/LzBinTree.cs b/src/SharpCompress/Compressors/LZMA/LZ/LzBinTree.cs index bc0a8a7a..d09a1e18 100644 --- a/src/SharpCompress/Compressors/LZMA/LZ/LzBinTree.cs +++ b/src/SharpCompress/Compressors/LZMA/LZ/LzBinTree.cs @@ -1,6 +1,7 @@ #nullable disable using System; +using System.Buffers; using System.IO; namespace SharpCompress.Compressors.LZMA.LZ; @@ -108,7 +109,12 @@ internal sealed class BinTree : InWindow var cyclicBufferSize = historySize + 1; if (_cyclicBufferSize != cyclicBufferSize) { - _son = new uint[(_cyclicBufferSize = cyclicBufferSize) * 2]; + if (_son is not null) + { + ArrayPool.Shared.Return(_son); + } + _cyclicBufferSize = cyclicBufferSize; + _son = ArrayPool.Shared.Rent(checked((int)(_cyclicBufferSize * 2))); } var hs = K_BT2_HASH_SIZE; @@ -132,7 +138,27 @@ internal sealed class BinTree : InWindow } if (hs != _hashSizeSum) { - _hash = new uint[_hashSizeSum = hs]; + if (_hash is not null) + { + ArrayPool.Shared.Return(_hash); + } + _hashSizeSum = hs; + _hash = ArrayPool.Shared.Rent(checked((int)_hashSizeSum)); + } + } + + public override void Dispose() + { + base.Dispose(); + if (_son is not null) + { + ArrayPool.Shared.Return(_son); + _son = null; + } + if (_hash is not null) + { + ArrayPool.Shared.Return(_hash); + _hash = null; } } diff --git a/src/SharpCompress/Compressors/LZMA/LZ/LzInWindow.cs b/src/SharpCompress/Compressors/LZMA/LZ/LzInWindow.cs index 9df3c27d..7ee8bc88 100644 --- a/src/SharpCompress/Compressors/LZMA/LZ/LzInWindow.cs +++ b/src/SharpCompress/Compressors/LZMA/LZ/LzInWindow.cs @@ -1,10 +1,12 @@ #nullable disable +using System; +using System.Buffers; using System.IO; namespace SharpCompress.Compressors.LZMA.LZ; -internal class InWindow +internal class InWindow : IDisposable { public byte[] _bufferBase; // pointer to buffer with data private Stream _stream; @@ -78,7 +80,22 @@ internal class InWindow } } - private void Free() => _bufferBase = null; + private void Free() + { + if (_bufferBase is null) + { + return; + } + + ArrayPool.Shared.Return(_bufferBase); + _bufferBase = null; + } + + public virtual void Dispose() + { + ReleaseStream(); + Free(); + } public void Create(uint keepSizeBefore, uint keepSizeAfter, uint keepSizeReserv) { @@ -89,7 +106,7 @@ internal class InWindow { Free(); _blockSize = blockSize; - _bufferBase = new byte[_blockSize]; + _bufferBase = ArrayPool.Shared.Rent(checked((int)_blockSize)); } _pointerToLastSafePosition = _blockSize - keepSizeAfter; _streamEndWasReached = false; diff --git a/src/SharpCompress/Compressors/LZMA/LZipStream.Async.cs b/src/SharpCompress/Compressors/LZMA/LZipStream.Async.cs index ae8e1074..054d5ac7 100644 --- a/src/SharpCompress/Compressors/LZMA/LZipStream.Async.cs +++ b/src/SharpCompress/Compressors/LZMA/LZipStream.Async.cs @@ -126,31 +126,36 @@ public sealed partial class LZipStream ) { // Read the header - byte[] header = new byte[6]; - var n = await stream - .ReadAsync(header, 0, header.Length, cancellationToken) - .ConfigureAwait(false); - - // TODO: Handle reading only part of the header? - - if (n != 6) + var header = ArrayPool.Shared.Rent(6); + try { - return 0; - } + var n = await stream.ReadAsync(header, 0, 6, cancellationToken).ConfigureAwait(false); - if ( - header[0] != 'L' - || header[1] != 'Z' - || header[2] != 'I' - || header[3] != 'P' - || header[4] != 1 /* version 1 */ - ) - { - return 0; + // TODO: Handle reading only part of the header? + + if (n != 6) + { + return 0; + } + + if ( + header[0] != 'L' + || header[1] != 'Z' + || header[2] != 'I' + || header[3] != 'P' + || header[4] != 1 /* version 1 */ + ) + { + return 0; + } + var basePower = header[5] & 0x1F; + var subtractionNumerator = (header[5] & 0xE0) >> 5; + return (1 << basePower) - (subtractionNumerator * (1 << (basePower - 4))); + } + finally + { + ArrayPool.Shared.Return(header); } - var basePower = header[5] & 0x1F; - var subtractionNumerator = (header[5] & 0xE0) >> 5; - return (1 << basePower) - (subtractionNumerator * (1 << (basePower - 4))); } #if !LEGACY_DOTNET diff --git a/src/SharpCompress/Compressors/LZMA/Lzma2EncoderStream.cs b/src/SharpCompress/Compressors/LZMA/Lzma2EncoderStream.cs index f1ed808c..73ce7b64 100644 --- a/src/SharpCompress/Compressors/LZMA/Lzma2EncoderStream.cs +++ b/src/SharpCompress/Compressors/LZMA/Lzma2EncoderStream.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -26,11 +27,12 @@ internal sealed class Lzma2EncoderStream : Stream private readonly int _dictionarySize; private readonly int _numFastBytes; private readonly byte[] _buffer; + private readonly byte[] _properties; + private readonly Encoder _encoder; private int _bufferPosition; private bool _isFirstChunk = true; private bool _isDisposed; private byte _lzmaPropertiesByte; - private bool _lzmaPropertiesKnown; /// /// Creates a new LZMA2 encoder stream. @@ -43,14 +45,23 @@ internal sealed class Lzma2EncoderStream : Stream _output = output; _dictionarySize = dictionarySize; _numFastBytes = numFastBytes; - _buffer = new byte[MAX_UNCOMPRESSED_CHUNK_SIZE]; + _buffer = ArrayPool.Shared.Rent(MAX_UNCOMPRESSED_CHUNK_SIZE); _bufferPosition = 0; + + var encoderProps = new LzmaEncoderProperties(eos: false, _dictionarySize, _numFastBytes); + _encoder = new Encoder(); + _encoder.SetCoderProperties(encoderProps.PropIDs, encoderProps.Properties); + + Span lzmaProperties = stackalloc byte[5]; + _encoder.WriteCoderProperties(lzmaProperties); + _lzmaPropertiesByte = lzmaProperties[0]; + _properties = [EncodeDictionarySize(_dictionarySize)]; } /// /// Gets the 1-byte LZMA2 properties (encoded dictionary size). /// - public byte[] Properties => [EncodeDictionarySize(_dictionarySize)]; + public byte[] Properties => _properties; public override bool CanRead => false; public override bool CanSeek => false; @@ -153,6 +164,8 @@ internal sealed class Lzma2EncoderStream : Stream // Write LZMA2 end marker _output.WriteByte(0x00); + _encoder.Dispose(); + ArrayPool.Shared.Return(_buffer); } base.Dispose(disposing); } @@ -179,6 +192,9 @@ internal sealed class Lzma2EncoderStream : Stream #else await _output.WriteAsync(_endMarker, 0, 1).ConfigureAwait(false); #endif + + _encoder.Dispose(); + ArrayPool.Shared.Return(_buffer); } #if !LEGACY_DOTNET || NETSTANDARD2_1 @@ -193,14 +209,15 @@ internal sealed class Lzma2EncoderStream : Stream return; } - var uncompressedData = _buffer.AsSpan(0, _bufferPosition); + var uncompressedSize = _bufferPosition; + var uncompressedData = _buffer.AsSpan(0, uncompressedSize); _bufferPosition = 0; // Try compressing the data - byte[] compressed; + (byte[] Buffer, int Length) compressed; try { - compressed = CompressBlock(uncompressedData); + compressed = CompressBlock(_buffer, uncompressedSize); } catch (Exception ex) when (ex is not OutOfMemoryException and not StackOverflowException) { @@ -215,7 +232,7 @@ internal sealed class Lzma2EncoderStream : Stream && compressed.Length < uncompressedData.Length ) { - WriteCompressedChunk(uncompressedData.Length, compressed); + WriteCompressedChunk(uncompressedData.Length, compressed.Buffer, compressed.Length); } else { @@ -230,13 +247,14 @@ internal sealed class Lzma2EncoderStream : Stream return; } - var uncompressedData = _buffer.AsMemory(0, _bufferPosition); + var uncompressedSize = _bufferPosition; + var uncompressedData = _buffer.AsMemory(0, uncompressedSize); _bufferPosition = 0; - byte[] compressed; + (byte[] Buffer, int Length) compressed; try { - compressed = CompressBlock(uncompressedData.Span); + compressed = CompressBlock(_buffer, uncompressedSize); } catch (Exception ex) when (ex is not OutOfMemoryException and not StackOverflowException) { @@ -250,7 +268,12 @@ internal sealed class Lzma2EncoderStream : Stream && compressed.Length < uncompressedData.Length ) { - await WriteCompressedChunkAsync(uncompressedData.Length, compressed, cancellationToken) + await WriteCompressedChunkAsync( + uncompressedData.Length, + compressed.Buffer, + compressed.Length, + cancellationToken + ) .ConfigureAwait(false); } else @@ -260,45 +283,26 @@ internal sealed class Lzma2EncoderStream : Stream } } - private byte[] CompressBlock(ReadOnlySpan data) + private (byte[] Buffer, int Length) CompressBlock(byte[] data, int length) { - var encoderProps = new LzmaEncoderProperties(eos: false, _dictionarySize, _numFastBytes); - - var encoder = new Encoder(); - encoder.SetCoderProperties(encoderProps.PropIDs, encoderProps.Properties); - - // Capture the LZMA properties byte (pb/lp/lc encoding) for the chunk header - if (!_lzmaPropertiesKnown) - { - var propBytes = new byte[5]; - encoder.WriteCoderProperties(propBytes); - _lzmaPropertiesByte = propBytes[0]; - _lzmaPropertiesKnown = true; - } - - using var inputMs = new MemoryStream(data.ToArray(), writable: false); + using var inputMs = new MemoryStream(data, 0, length, writable: false); using var outputMs = new PooledMemoryStream(); - encoder.Code(inputMs, outputMs, data.Length, -1, null); + _encoder.Code(inputMs, outputMs, length, -1, null); var fullCompressed = outputMs.ToArray(); // The LZMA range encoder flush writes trailing bytes the decoder doesn't consume. // Trial-decode to find the exact byte count the decoder needs, so the LZMA2 // chunk header reports a compressed size that matches what the decoder reads. - var consumed = FindConsumedBytes(fullCompressed, data.Length); - if (consumed < fullCompressed.Length) - { - return fullCompressed.AsSpan(0, consumed).ToArray(); - } - - return fullCompressed; + var consumed = FindConsumedBytes(fullCompressed, fullCompressed.Length, length); + return (fullCompressed, consumed); } - private int FindConsumedBytes(byte[] compressedData, int uncompressedSize) + private int FindConsumedBytes(byte[] compressedData, int compressedSize, int uncompressedSize) { // Build 5-byte LZMA property header: [pb/lp/lc byte] [dictSize as LE int32] - var props = new byte[5]; + Span props = stackalloc byte[5]; props[0] = _lzmaPropertiesByte; props[1] = (byte)_dictionarySize; props[2] = (byte)(_dictionarySize >> 8); @@ -308,9 +312,8 @@ internal sealed class Lzma2EncoderStream : Stream var decoder = new Decoder(); decoder.SetDecoderProperties(props); - using var input = new MemoryStream(compressedData); - using var output = new PooledMemoryStream(); - decoder.Code(input, output, compressedData.Length, uncompressedSize, null); + using var input = new MemoryStream(compressedData, 0, compressedSize, writable: false); + decoder.Code(input, Stream.Null, compressedSize, uncompressedSize, null); return (int)input.Position; } @@ -319,10 +322,14 @@ internal sealed class Lzma2EncoderStream : Stream /// Writes a compressed LZMA2 chunk. /// Header: [control] [uncompSize_hi] [uncompSize_lo] [compSize_hi] [compSize_lo] [props?] /// - private void WriteCompressedChunk(int uncompressedSize, byte[] compressedData) + private void WriteCompressedChunk( + int uncompressedSize, + byte[] compressedData, + int compressedSize + ) { var uncompSizeMinus1 = uncompressedSize - 1; - var compSizeMinus1 = compressedData.Length - 1; + var compSizeMinus1 = compressedSize - 1; // Each chunk is compressed independently with a fresh LZMA encoder, // so we must use 0xE0 (full reset: dictionary + state + properties) every time. @@ -341,32 +348,38 @@ internal sealed class Lzma2EncoderStream : Stream // 0xE0 (>= 0xC0) requires properties byte _output.WriteByte(_lzmaPropertiesByte); - _output.Write(compressedData, 0, compressedData.Length); + _output.Write(compressedData, 0, compressedSize); } private async ValueTask WriteCompressedChunkAsync( int uncompressedSize, byte[] compressedData, + int compressedSize, CancellationToken cancellationToken = default ) { var uncompSizeMinus1 = uncompressedSize - 1; - var compSizeMinus1 = compressedData.Length - 1; + var compSizeMinus1 = compressedSize - 1; var control = (byte)(0xE0 | ((uncompSizeMinus1 >> 16) & 0x1F)); _isFirstChunk = false; - var header = new[] + var header = ArrayPool.Shared.Rent(6); + try { - control, - (byte)((uncompSizeMinus1 >> 8) & 0xFF), - (byte)(uncompSizeMinus1 & 0xFF), - (byte)((compSizeMinus1 >> 8) & 0xFF), - (byte)(compSizeMinus1 & 0xFF), - _lzmaPropertiesByte, - }; - await _output.WriteAsync(header, 0, header.Length, cancellationToken).ConfigureAwait(false); + header[0] = control; + header[1] = (byte)((uncompSizeMinus1 >> 8) & 0xFF); + header[2] = (byte)(uncompSizeMinus1 & 0xFF); + header[3] = (byte)((compSizeMinus1 >> 8) & 0xFF); + header[4] = (byte)(compSizeMinus1 & 0xFF); + header[5] = _lzmaPropertiesByte; + await _output.WriteAsync(header, 0, 6, cancellationToken).ConfigureAwait(false); + } + finally + { + ArrayPool.Shared.Return(header); + } await _output - .WriteAsync(compressedData, 0, compressedData.Length, cancellationToken) + .WriteAsync(compressedData, 0, compressedSize, cancellationToken) .ConfigureAwait(false); } @@ -426,20 +439,37 @@ internal sealed class Lzma2EncoderStream : Stream control = 0x02; } - var header = new[] + var header = ArrayPool.Shared.Rent(3); + try { - control, - (byte)((sizeMinus1 >> 8) & 0xFF), - (byte)(sizeMinus1 & 0xFF), - }; - await _output - .WriteAsync(header, 0, header.Length, cancellationToken) - .ConfigureAwait(false); + header[0] = control; + header[1] = (byte)((sizeMinus1 >> 8) & 0xFF); + header[2] = (byte)(sizeMinus1 & 0xFF); + await _output.WriteAsync(header, 0, 3, cancellationToken).ConfigureAwait(false); + } + finally + { + ArrayPool.Shared.Return(header); + } - var chunk = data.Slice(offset, chunkSize).ToArray(); +#if !LEGACY_DOTNET || NETSTANDARD2_1 await _output - .WriteAsync(chunk, 0, chunk.Length, cancellationToken) + .WriteAsync(data.Slice(offset, chunkSize), cancellationToken) .ConfigureAwait(false); +#else + var chunk = ArrayPool.Shared.Rent(chunkSize); + try + { + data.Slice(offset, chunkSize).CopyTo(chunk); + await _output + .WriteAsync(chunk, 0, chunkSize, cancellationToken) + .ConfigureAwait(false); + } + finally + { + ArrayPool.Shared.Return(chunk); + } +#endif offset += chunkSize; } } diff --git a/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs b/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs index 49a0e4c2..327aa343 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs @@ -446,7 +446,10 @@ public partial class Decoder : ICoder, ISetDecoderProperties, IDisposable return false; } - public void SetDecoderProperties(byte[] properties) + public void SetDecoderProperties(byte[] properties) => + SetDecoderProperties(properties.AsSpan()); + + internal void SetDecoderProperties(ReadOnlySpan properties) { if (properties.Length < 1) { diff --git a/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs b/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs index 14d94707..d2e3e0d2 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs @@ -10,7 +10,7 @@ using SharpCompress.Compressors.LZMA.RangeCoder; namespace SharpCompress.Compressors.LZMA; -internal partial class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties +internal partial class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties, IDisposable { private enum EMatchFinderType { @@ -574,6 +574,12 @@ internal partial class Encoder : ICoder, ISetCoderProperties, IWriteCoderPropert } } + public void Dispose() + { + _matchFinder?.Dispose(); + _matchFinder = null; + } + private void SetWriteEndMarkerMode(bool writeEndMarker) => _writeEndMark = writeEndMarker; private void Init() diff --git a/src/SharpCompress/Compressors/LZMA/LzmaStream.Async.cs b/src/SharpCompress/Compressors/LZMA/LzmaStream.Async.cs index 3adef73d..4ad30127 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaStream.Async.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaStream.Async.cs @@ -83,11 +83,11 @@ public partial class LzmaStream private async ValueTask DecodeChunkHeaderAsync(CancellationToken cancellationToken = default) { - var controlBuffer = new byte[1]; + var headerBuffer = GetAsyncHeaderBuffer(); await _inputStream! - .ReadExactAsync(controlBuffer, 0, 1, cancellationToken) + .ReadExactAsync(headerBuffer, 0, 1, cancellationToken) .ConfigureAwait(false); - var control = controlBuffer[0]; + var control = headerBuffer[0]; _inputPosition++; if (control == 0x00) @@ -112,26 +112,25 @@ public partial class LzmaStream _uncompressedChunk = false; _availableBytes = (control & 0x1F) << 16; - var buffer = new byte[2]; await _inputStream! - .ReadExactAsync(buffer, 0, 2, cancellationToken) + .ReadExactAsync(headerBuffer, 0, 2, cancellationToken) .ConfigureAwait(false); - _availableBytes += (buffer[0] << 8) + buffer[1] + 1; + _availableBytes += (headerBuffer[0] << 8) + headerBuffer[1] + 1; _inputPosition += 2; await _inputStream! - .ReadExactAsync(buffer, 0, 2, cancellationToken) + .ReadExactAsync(headerBuffer, 0, 2, cancellationToken) .ConfigureAwait(false); - _rangeDecoderLimit = (buffer[0] << 8) + buffer[1] + 1; + _rangeDecoderLimit = (headerBuffer[0] << 8) + headerBuffer[1] + 1; _inputPosition += 2; if (control >= 0xC0) { _needProps = false; await _inputStream! - .ReadExactAsync(controlBuffer, 0, 1, cancellationToken) + .ReadExactAsync(headerBuffer, 0, 1, cancellationToken) .ConfigureAwait(false); - Properties[0] = controlBuffer[0]; + Properties[0] = headerBuffer[0]; _inputPosition++; _decoder = new Decoder(); @@ -156,11 +155,10 @@ public partial class LzmaStream else { _uncompressedChunk = true; - var buffer = new byte[2]; await _inputStream! - .ReadExactAsync(buffer, 0, 2, cancellationToken) + .ReadExactAsync(headerBuffer, 0, 2, cancellationToken) .ConfigureAwait(false); - _availableBytes = (buffer[0] << 8) + buffer[1] + 1; + _availableBytes = (headerBuffer[0] << 8) + headerBuffer[1] + 1; _inputPosition += 2; } } @@ -436,6 +434,7 @@ public partial class LzmaStream if (_encoder != null) { _position = await _encoder.CodeAsync(null, true).ConfigureAwait(false); + _encoder.Dispose(); } if (!_leaveOpen) @@ -450,6 +449,7 @@ public partial class LzmaStream } } await _outWindow.DisposeAsync().ConfigureAwait(false); + ReturnAsyncHeaderBuffer(); #if !LEGACY_DOTNET || NETSTANDARD2_1 await base.DisposeAsync().ConfigureAwait(false); diff --git a/src/SharpCompress/Compressors/LZMA/LzmaStream.cs b/src/SharpCompress/Compressors/LZMA/LzmaStream.cs index 12f6884e..38bb2eca 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaStream.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaStream.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.Buffers.Binary; using System.IO; using System.Threading; @@ -33,6 +34,7 @@ public partial class LzmaStream : Stream, IStreamStack, IAsyncDisposable private bool _needProps = true; private readonly Encoder? _encoder; + private byte[]? _asyncHeaderBuffer; private bool _isDisposed; private LzmaStream( @@ -205,16 +207,31 @@ public partial class LzmaStream : Stream, IStreamStack, IAsyncDisposable if (_encoder != null) { _position = _encoder.Code(null, true); + _encoder.Dispose(); } if (!_leaveOpen) { _inputStream?.Dispose(); } _outWindow.Dispose(); + ReturnAsyncHeaderBuffer(); } base.Dispose(disposing); } + private byte[] GetAsyncHeaderBuffer() => _asyncHeaderBuffer ??= ArrayPool.Shared.Rent(6); + + private void ReturnAsyncHeaderBuffer() + { + if (_asyncHeaderBuffer is null) + { + return; + } + + ArrayPool.Shared.Return(_asyncHeaderBuffer); + _asyncHeaderBuffer = null; + } + public override long Length => _position + _availableBytes; public override long Position diff --git a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.Async.cs b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.Async.cs index cd3fc6a5..61db6eae 100644 --- a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.Async.cs +++ b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.Async.cs @@ -9,6 +9,8 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder; internal partial class Encoder { + private byte[] SingleByteBuffer => _singleByteBuffer ??= new byte[1]; + public async ValueTask ShiftLowAsync(CancellationToken cancellationToken = default) { if ((uint)_low < 0xFF000000 || (uint)(_low >> 32) == 1) @@ -17,7 +19,8 @@ internal partial class Encoder do { var b = (byte)(temp + (_low >> 32)); - var buffer = new[] { b }; + var buffer = SingleByteBuffer; + buffer[0] = b; await _stream.WriteAsync(buffer, 0, 1, cancellationToken).ConfigureAwait(false); temp = 0xFF; } while (--_cacheSize != 0); @@ -78,13 +81,15 @@ internal partial class Encoder internal partial class Decoder { + private byte[] SingleByteBuffer => _singleByteBuffer ??= new byte[1]; + public async ValueTask InitAsync(Stream stream, CancellationToken cancellationToken = default) { _stream = stream; _code = 0; _range = 0xFFFFFFFF; - var buffer = new byte[1]; + var buffer = SingleByteBuffer; for (var i = 0; i < 5; i++) { var read = await _stream @@ -103,7 +108,7 @@ internal partial class Decoder { while (_range < K_TOP_VALUE) { - var buffer = new byte[1]; + var buffer = SingleByteBuffer; var read = await _stream .ReadAsync(buffer, 0, 1, cancellationToken) .ConfigureAwait(false); @@ -121,7 +126,7 @@ internal partial class Decoder { if (_range < K_TOP_VALUE) { - var buffer = new byte[1]; + var buffer = SingleByteBuffer; var read = await _stream .ReadAsync(buffer, 0, 1, cancellationToken) .ConfigureAwait(false); @@ -143,7 +148,7 @@ internal partial class Decoder var range = _range; var code = _code; uint result = 0; - var buffer = new byte[1]; + var buffer = SingleByteBuffer; for (var i = numTotalBits; i > 0; i--) { range >>= 1; diff --git a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs index e29a1c37..518fa88e 100644 --- a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs +++ b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs @@ -15,8 +15,7 @@ internal partial class Encoder public uint _range; private uint _cacheSize; private byte _cache; - - //long StartPosition; + private byte[] _singleByteBuffer; public void SetStream(Stream stream) => _stream = stream; @@ -88,6 +87,7 @@ internal partial class Decoder public Stream _stream; public long _total; + private byte[] _singleByteBuffer; public void Init(Stream stream) { @@ -180,6 +180,4 @@ internal partial class Decoder } public bool IsFinished => _code == 0; - - // ulong GetProcessedSize() {return Stream.GetProcessedSize(); } } diff --git a/src/SharpCompress/packages.lock.json b/src/SharpCompress/packages.lock.json index e1e7afa5..738df599 100644 --- a/src/SharpCompress/packages.lock.json +++ b/src/SharpCompress/packages.lock.json @@ -286,9 +286,9 @@ "net10.0": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[10.0.8, )", - "resolved": "10.0.8", - "contentHash": "dVbSXGIFNR5nZcv2tOLoWI+a9T4jtFd77IYjuND+QVe360qWgAF7H0WtoopYhRw/+SgpGUTyrkrh+65+ClNnfw==" + "requested": "[10.0.6, )", + "resolved": "10.0.6", + "contentHash": "QKuvS0LWX4fjFqeDkyM7Kqt8P3wYTiPD4nwU+9y59n0sCiG714fxDgbbN82vDnzq89AF/PiHl92TP2C4aFDUQA==" }, "Microsoft.NETFramework.ReferenceAssemblies": { "type": "Direct", @@ -388,9 +388,9 @@ "net8.0": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[8.0.27, )", - "resolved": "8.0.27", - "contentHash": "rQi9TxifHRnXP7lVRZH05DxD2/XGbJp12q0ozcbrlBlBnyyzssFTH/2vLhtKWUp2CT1qVscTrcYTFiwTyKPKRg==" + "requested": "[8.0.26, )", + "resolved": "8.0.26", + "contentHash": "o7/yVssM2r9Wyln2s9edBd5ANZXqdSdBI+g7JqXkyJmXrhs2WsJp25K5yPnYrTgdKBCjKB8bg+O2oew4sgzFaA==" }, "Microsoft.NETFramework.ReferenceAssemblies": { "type": "Direct", diff --git a/tests/SharpCompress.Performance/Program.cs b/tests/SharpCompress.Performance/Program.cs index 856a0f9f..ab940ed6 100644 --- a/tests/SharpCompress.Performance/Program.cs +++ b/tests/SharpCompress.Performance/Program.cs @@ -33,7 +33,7 @@ public class Program private static async Task RunWithProfiler(string[] args) { var profileType = "cpu"; // Default to CPU profiling - var outputPath = "./profiler-snapshots";l + var outputPath = "./profiler-snapshots"; // Parse arguments for (int i = 1; i < args.Length; i++)