From 949e90351f5c8359a25c3d28a50ecea157b648ff Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Sat, 13 Feb 2021 10:45:57 +0000 Subject: [PATCH] More LZMA conversion going, BZip2 not for now --- src/SharpCompress/Common/ArchiveEncoding.cs | 14 +- src/SharpCompress/Common/Zip/ZipFilePart.cs | 6 +- src/SharpCompress/Compressors/LZMA/ICoder.cs | 3 +- .../Compressors/LZMA/LZipStream.cs | 44 +++-- .../Compressors/LZMA/LzmaDecoder.cs | 53 +++--- .../Compressors/LZMA/LzmaEncoder.cs | 161 +++++++++--------- .../Compressors/LZMA/LzmaStream.cs | 126 +++++++------- .../Compressors/LZMA/RangeCoder/RangeCoder.cs | 75 ++++---- .../LZMA/RangeCoder/RangeCoderBit.cs | 5 +- .../LZMA/RangeCoder/RangeCoderBitTree.cs | 13 +- .../Compressors/LZMA/Registry.cs | 11 +- .../Compressors/Xz/Filters/BlockFilter.cs | 3 +- .../Compressors/Xz/Filters/Lzma2Filter.cs | 5 +- src/SharpCompress/Compressors/Xz/XZBlock.cs | 6 +- src/SharpCompress/Readers/ReaderFactory.cs | 8 +- src/SharpCompress/Readers/Tar/TarReader.cs | 14 +- src/SharpCompress/Utility.cs | 5 +- src/SharpCompress/Writers/Tar/TarWriter.cs | 11 +- src/SharpCompress/Writers/Zip/ZipWriter.cs | 5 +- .../Streams/LzmaStreamTests.cs | 5 +- 20 files changed, 301 insertions(+), 272 deletions(-) diff --git a/src/SharpCompress/Common/ArchiveEncoding.cs b/src/SharpCompress/Common/ArchiveEncoding.cs index 691d2080..76053a3f 100644 --- a/src/SharpCompress/Common/ArchiveEncoding.cs +++ b/src/SharpCompress/Common/ArchiveEncoding.cs @@ -24,7 +24,7 @@ namespace SharpCompress.Common /// Set this when you want to use a custom method for all decoding operations. /// /// string Func(bytes, index, length) - public Func? CustomDecoder { get; set; } + //public Func? CustomDecoder { get; set; } public ArchiveEncoding() : this(Encoding.Default, Encoding.Default) @@ -50,7 +50,12 @@ namespace SharpCompress.Common public string Decode(byte[] bytes, int start, int length) { - return GetDecoder().Invoke(bytes, start, length); + return GetEncoding().GetString(bytes, start, length); + } + + public string Decode(ReadOnlySpan span) + { + return GetEncoding().GetString(span); } public string DecodeUTF8(byte[] bytes) @@ -67,10 +72,5 @@ namespace SharpCompress.Common { return Forced ?? Default ?? Encoding.UTF8; } - - public Func GetDecoder() - { - return CustomDecoder ?? ((bytes, index, count) => GetEncoding().GetString(bytes, index, count)); - } } } diff --git a/src/SharpCompress/Common/Zip/ZipFilePart.cs b/src/SharpCompress/Common/Zip/ZipFilePart.cs index bb7aa7dc..c09980db 100644 --- a/src/SharpCompress/Common/Zip/ZipFilePart.cs +++ b/src/SharpCompress/Common/Zip/ZipFilePart.cs @@ -73,10 +73,10 @@ namespace SharpCompress.Common.Zip { return new Deflate64Stream(stream, CompressionMode.Decompress); } - case ZipCompressionMethod.BZip2: + /** case ZipCompressionMethod.BZip2: { return await BZip2Stream.CreateAsync(stream, CompressionMode.Decompress, false, cancellationToken); - } + } */ case ZipCompressionMethod.LZMA: { if (FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted)) @@ -87,7 +87,7 @@ namespace SharpCompress.Common.Zip reader.ReadUInt16(); //LZMA version var props = new byte[reader.ReadUInt16()]; reader.Read(props, 0, props.Length); - return new LzmaStream(props, stream, + return await LzmaStream.CreateAsync(props, stream, Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1, FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1) ? -1 diff --git a/src/SharpCompress/Compressors/LZMA/ICoder.cs b/src/SharpCompress/Compressors/LZMA/ICoder.cs index f5049dd7..01933d02 100644 --- a/src/SharpCompress/Compressors/LZMA/ICoder.cs +++ b/src/SharpCompress/Compressors/LZMA/ICoder.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Threading.Tasks; namespace SharpCompress.Compressors.LZMA { @@ -59,7 +60,7 @@ namespace SharpCompress.Compressors.LZMA /// /// callback progress reference. /// - void Code(Stream inStream, Stream outStream, + ValueTask CodeAsync(Stream inStream, Stream outStream, Int64 inSize, Int64 outSize, ICodeProgress progress); } diff --git a/src/SharpCompress/Compressors/LZMA/LZipStream.cs b/src/SharpCompress/Compressors/LZMA/LZipStream.cs index be7c7d38..42f28664 100644 --- a/src/SharpCompress/Compressors/LZMA/LZipStream.cs +++ b/src/SharpCompress/Compressors/LZMA/LZipStream.cs @@ -1,6 +1,8 @@ using System; +using System.Buffers; using System.Buffers.Binary; using System.IO; +using System.Threading.Tasks; using SharpCompress.Crypto; using SharpCompress.IO; @@ -16,26 +18,34 @@ namespace SharpCompress.Compressors.LZMA /// public sealed class LZipStream : Stream { - private readonly Stream _stream; - private readonly CountingWritableSubStream? _countingWritableSubStream; + #nullable disable + private Stream _stream; +#nullable enable + private CountingWritableSubStream? _countingWritableSubStream; private bool _disposed; private bool _finished; private long _writeCount; - public LZipStream(Stream stream, CompressionMode mode) + private LZipStream() { - Mode = mode; + + } + + public static async ValueTask CreateAsync(Stream stream, CompressionMode mode) + { + var lzip = new LZipStream(); + lzip.Mode = mode; if (mode == CompressionMode.Decompress) { - int dSize = ValidateAndReadSize(stream); + int dSize = await ValidateAndReadSize(stream); if (dSize == 0) { throw new IOException("Not an LZip stream"); } byte[] properties = GetProperties(dSize); - _stream = new LzmaStream(properties, stream); + lzip._stream = await LzmaStream.CreateAsync(properties, stream); } else { @@ -43,9 +53,10 @@ namespace SharpCompress.Compressors.LZMA int dSize = 104 * 1024; WriteHeaderSize(stream); - _countingWritableSubStream = new CountingWritableSubStream(stream); - _stream = new Crc32Stream(new LzmaStream(new LzmaEncoderProperties(true, dSize), false, _countingWritableSubStream)); + lzip._countingWritableSubStream = new CountingWritableSubStream(stream); + lzip._stream = new Crc32Stream(new LzmaStream(new LzmaEncoderProperties(true, dSize), false, lzip._countingWritableSubStream)); } + return lzip; } public void Finish() @@ -90,7 +101,7 @@ namespace SharpCompress.Compressors.LZMA } } - public CompressionMode Mode { get; } + public CompressionMode Mode { get; private set; } public override bool CanRead => Mode == CompressionMode.Decompress; @@ -155,14 +166,14 @@ namespace SharpCompress.Compressors.LZMA /// /// The stream to read from. Must not be null. /// true if the given stream is an LZip file, false otherwise. - public static bool IsLZipFile(Stream stream) => ValidateAndReadSize(stream) != 0; + public static async ValueTask IsLZipFileAsync(Stream stream) => await ValidateAndReadSize(stream) != 0; /// /// Reads the 6-byte header of the stream, and returns 0 if either the header /// couldn't be read or it isn't a validate LZIP header, or the dictionary /// size if it *is* a valid LZIP file. /// - public static int ValidateAndReadSize(Stream stream) + private static async ValueTask ValidateAndReadSize(Stream stream) { if (stream is null) { @@ -170,8 +181,9 @@ namespace SharpCompress.Compressors.LZMA } // Read the header - Span header = stackalloc byte[6]; - int n = stream.Read(header); + using var buffer = MemoryPool.Shared.Rent(6); + var header = buffer.Memory.Slice(0,6); + int n = await stream.ReadAsync(header); // TODO: Handle reading only part of the header? @@ -180,12 +192,12 @@ namespace SharpCompress.Compressors.LZMA return 0; } - if (header[0] != 'L' || header[1] != 'Z' || header[2] != 'I' || header[3] != 'P' || header[4] != 1 /* version 1 */) + if (header.Span[0] != 'L' || header.Span[1] != 'Z' || header.Span[2] != 'I' || header.Span[3] != 'P' || header.Span[4] != 1 /* version 1 */) { return 0; } - int basePower = header[5] & 0x1F; - int subtractionNumerator = (header[5] & 0xE0) >> 5; + int basePower = header.Span[5] & 0x1F; + int subtractionNumerator = (header.Span[5] & 0xE0) >> 5; return (1 << basePower) - subtractionNumerator * (1 << (basePower - 4)); } diff --git a/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs b/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs index 3592cfbf..b20cd6c1 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs @@ -1,7 +1,6 @@ -#nullable disable - using System; using System.IO; +using System.Threading.Tasks; using SharpCompress.Compressors.LZMA.LZ; using SharpCompress.Compressors.LZMA.RangeCoder; @@ -11,11 +10,11 @@ namespace SharpCompress.Compressors.LZMA { private class LenDecoder { - private BitDecoder _choice = new BitDecoder(); - private BitDecoder _choice2 = new BitDecoder(); + private BitDecoder _choice = new(); + private BitDecoder _choice2 = new(); private readonly BitTreeDecoder[] _lowCoder = new BitTreeDecoder[Base.K_NUM_POS_STATES_MAX]; private readonly BitTreeDecoder[] _midCoder = new BitTreeDecoder[Base.K_NUM_POS_STATES_MAX]; - private BitTreeDecoder _highCoder = new BitTreeDecoder(Base.K_NUM_HIGH_LEN_BITS); + private BitTreeDecoder _highCoder = new(Base.K_NUM_HIGH_LEN_BITS); private uint _numPosStates; public void Create(uint numPosStates) @@ -113,12 +112,12 @@ namespace SharpCompress.Compressors.LZMA } } - private Decoder2[] _coders; - private int _numPrevBits; - private int _numPosBits; - private uint _posMask; - - public void Create(int numPosBits, int numPrevBits) + private readonly Decoder2[]_coders; + private readonly int _numPrevBits; + private readonly int _numPosBits; + private readonly uint _posMask; + + public LiteralDecoder(int numPosBits, int numPrevBits) { if (_coders != null && _numPrevBits == numPrevBits && _numPosBits == numPosBits) @@ -161,7 +160,7 @@ namespace SharpCompress.Compressors.LZMA } } - private OutWindow _outWindow; + private OutWindow? _outWindow; private readonly BitDecoder[] _isMatchDecoders = new BitDecoder[Base.K_NUM_STATES << Base.K_NUM_POS_STATES_BITS_MAX]; private readonly BitDecoder[] _isRepDecoders = new BitDecoder[Base.K_NUM_STATES]; @@ -173,18 +172,18 @@ namespace SharpCompress.Compressors.LZMA private readonly BitTreeDecoder[] _posSlotDecoder = new BitTreeDecoder[Base.K_NUM_LEN_TO_POS_STATES]; private readonly BitDecoder[] _posDecoders = new BitDecoder[Base.K_NUM_FULL_DISTANCES - Base.K_END_POS_MODEL_INDEX]; - private BitTreeDecoder _posAlignDecoder = new BitTreeDecoder(Base.K_NUM_ALIGN_BITS); + private BitTreeDecoder _posAlignDecoder = new(Base.K_NUM_ALIGN_BITS); - private readonly LenDecoder _lenDecoder = new LenDecoder(); - private readonly LenDecoder _repLenDecoder = new LenDecoder(); + private readonly LenDecoder _lenDecoder = new(); + private readonly LenDecoder _repLenDecoder = new(); - private readonly LiteralDecoder _literalDecoder = new LiteralDecoder(); + private LiteralDecoder? _literalDecoder; private int _dictionarySize; private uint _posStateMask; - private Base.State _state = new Base.State(); + private Base.State _state = new(); private uint _rep0, _rep1, _rep2, _rep3; public Decoder() @@ -196,15 +195,16 @@ namespace SharpCompress.Compressors.LZMA } } - private void CreateDictionary() + private OutWindow CreateDictionary() { if (_dictionarySize < 0) { throw new InvalidParamException(); } - _outWindow = new OutWindow(); + var outWindow = new OutWindow(); int blockSize = Math.Max(_dictionarySize, (1 << 12)); - _outWindow.Create(blockSize); + outWindow.Create(blockSize); + return outWindow; } private void SetLiteralProperties(int lp, int lc) @@ -217,7 +217,7 @@ namespace SharpCompress.Compressors.LZMA { throw new InvalidParamException(); } - _literalDecoder.Create(lp, lc); + _literalDecoder = new(lp, lc); } private void SetPosBitsProperties(int pb) @@ -249,7 +249,7 @@ namespace SharpCompress.Compressors.LZMA _isRepG2Decoders[i].Init(); } - _literalDecoder.Init(); + _literalDecoder?.Init(); for (i = 0; i < Base.K_NUM_LEN_TO_POS_STATES; i++) { _posSlotDecoder[i].Init(); @@ -272,12 +272,12 @@ namespace SharpCompress.Compressors.LZMA _rep3 = 0; } - public void Code(Stream inStream, Stream outStream, + public async ValueTask CodeAsync(Stream inStream, Stream outStream, Int64 inSize, Int64 outSize, ICodeProgress progress) { if (_outWindow is null) { - CreateDictionary(); + _outWindow = CreateDictionary(); } _outWindow.Init(outStream); if (outSize > 0) @@ -290,7 +290,7 @@ namespace SharpCompress.Compressors.LZMA } RangeCoder.Decoder rangeDecoder = new RangeCoder.Decoder(); - rangeDecoder.Init(inStream); + await rangeDecoder.InitAsync(inStream); Code(_dictionarySize, _outWindow, rangeDecoder); @@ -310,6 +310,7 @@ namespace SharpCompress.Compressors.LZMA internal bool Code(int dictionarySize, OutWindow outWindow, RangeCoder.Decoder rangeDecoder) { + _literalDecoder ??= _literalDecoder.CheckNotNull(nameof(_literalDecoder)); int dictionarySizeCheck = Math.Max(dictionarySize, 1); outWindow.CopyPending(); @@ -450,7 +451,7 @@ namespace SharpCompress.Compressors.LZMA { if (_outWindow is null) { - CreateDictionary(); + _outWindow = CreateDictionary(); } _outWindow.Train(stream); } diff --git a/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs b/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs index e4420f21..9bea4b82 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs @@ -2,6 +2,7 @@ using System; using System.IO; +using System.Threading.Tasks; using SharpCompress.Compressors.LZMA.LZ; using SharpCompress.Compressors.LZMA.RangeCoder; @@ -61,7 +62,7 @@ namespace SharpCompress.Compressors.LZMA return (UInt32)(G_FAST_POS[pos >> 26] + 52); } - private Base.State _state = new Base.State(); + private Base.State _state = new(); private Byte _previousByte; private readonly UInt32[] _repDistances = new UInt32[Base.K_NUM_REP_DISTANCES]; @@ -97,18 +98,18 @@ namespace SharpCompress.Compressors.LZMA } } - public void Encode(RangeCoder.Encoder rangeEncoder, byte symbol) + public async ValueTask EncodeAsync(RangeCoder.Encoder rangeEncoder, byte symbol) { uint context = 1; for (int i = 7; i >= 0; i--) { uint bit = (uint)((symbol >> i) & 1); - _encoders[context].Encode(rangeEncoder, bit); + await _encoders[context].EncodeAsync(rangeEncoder, bit); context = (context << 1) | bit; } } - public void EncodeMatched(RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol) + public async ValueTask EncodeMatchedAsync(RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol) { uint context = 1; bool same = true; @@ -122,7 +123,7 @@ namespace SharpCompress.Compressors.LZMA state += ((1 + matchBit) << 8); same = (matchBit == bit); } - _encoders[state].Encode(rangeEncoder, bit); + await _encoders[state].EncodeAsync(rangeEncoder, bit); context = (context << 1) | bit; } } @@ -196,11 +197,11 @@ namespace SharpCompress.Compressors.LZMA private class LenEncoder { - private BitEncoder _choice = new BitEncoder(); - private BitEncoder _choice2 = new BitEncoder(); + private BitEncoder _choice = new(); + private BitEncoder _choice2 = new(); private readonly BitTreeEncoder[] _lowCoder = new BitTreeEncoder[Base.K_NUM_POS_STATES_ENCODING_MAX]; private readonly BitTreeEncoder[] _midCoder = new BitTreeEncoder[Base.K_NUM_POS_STATES_ENCODING_MAX]; - private BitTreeEncoder _highCoder = new BitTreeEncoder(Base.K_NUM_HIGH_LEN_BITS); + private BitTreeEncoder _highCoder = new(Base.K_NUM_HIGH_LEN_BITS); public LenEncoder() { @@ -223,26 +224,26 @@ namespace SharpCompress.Compressors.LZMA _highCoder.Init(); } - public void Encode(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState) + public virtual async ValueTask EncodeAsync(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState) { if (symbol < Base.K_NUM_LOW_LEN_SYMBOLS) { - _choice.Encode(rangeEncoder, 0); - _lowCoder[posState].Encode(rangeEncoder, symbol); + await _choice.EncodeAsync(rangeEncoder, 0); + await _lowCoder[posState].EncodeAsync(rangeEncoder, symbol); } else { symbol -= Base.K_NUM_LOW_LEN_SYMBOLS; - _choice.Encode(rangeEncoder, 1); + await _choice.EncodeAsync(rangeEncoder, 1); if (symbol < Base.K_NUM_MID_LEN_SYMBOLS) { - _choice2.Encode(rangeEncoder, 0); - _midCoder[posState].Encode(rangeEncoder, symbol); + await _choice2.EncodeAsync(rangeEncoder, 0); + await _midCoder[posState].EncodeAsync(rangeEncoder, symbol); } else { - _choice2.Encode(rangeEncoder, 1); - _highCoder.Encode(rangeEncoder, symbol - Base.K_NUM_MID_LEN_SYMBOLS); + await _choice2.EncodeAsync(rangeEncoder, 1); + await _highCoder.EncodeAsync(rangeEncoder, symbol - Base.K_NUM_MID_LEN_SYMBOLS); } } } @@ -309,9 +310,9 @@ namespace SharpCompress.Compressors.LZMA } } - public new void Encode(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState) + public override async ValueTask EncodeAsync(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState) { - base.Encode(rangeEncoder, symbol, posState); + await base.EncodeAsync(rangeEncoder, symbol, posState); if (--_counters[posState] == 0) { UpdateTable(posState); @@ -361,7 +362,7 @@ namespace SharpCompress.Compressors.LZMA private readonly Optimal[] _optimum = new Optimal[K_NUM_OPTS]; private BinTree _matchFinder; - private readonly RangeCoder.Encoder _rangeEncoder = new RangeCoder.Encoder(); + private readonly RangeCoder.Encoder _rangeEncoder = new(); private readonly BitEncoder[] _isMatch = new BitEncoder[Base.K_NUM_STATES << Base.K_NUM_POS_STATES_BITS_MAX]; @@ -379,12 +380,12 @@ namespace SharpCompress.Compressors.LZMA private readonly BitEncoder[] _posEncoders = new BitEncoder[Base.K_NUM_FULL_DISTANCES - Base.K_END_POS_MODEL_INDEX]; - private BitTreeEncoder _posAlignEncoder = new BitTreeEncoder(Base.K_NUM_ALIGN_BITS); + private BitTreeEncoder _posAlignEncoder = new(Base.K_NUM_ALIGN_BITS); - private readonly LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder(); - private readonly LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder(); + private readonly LenPriceTableEncoder _lenEncoder = new(); + private readonly LenPriceTableEncoder _repMatchLenEncoder = new(); - private readonly LiteralEncoder _literalEncoder = new LiteralEncoder(); + private readonly LiteralEncoder _literalEncoder = new(); private readonly UInt32[] _matchDistances = new UInt32[Base.K_MATCH_MAX_LEN * 2 + 2]; @@ -1189,40 +1190,40 @@ namespace SharpCompress.Compressors.LZMA return (smallDist < ((UInt32)(1) << (32 - kDif)) && bigDist >= (smallDist << kDif)); } - private void WriteEndMarker(UInt32 posState) + private async ValueTask WriteEndMarkerAsync(UInt32 posState) { if (!_writeEndMark) { return; } - _isMatch[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].Encode(_rangeEncoder, 1); - _isRep[_state._index].Encode(_rangeEncoder, 0); + await _isMatch[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].EncodeAsync(_rangeEncoder, 1); + await _isRep[_state._index].EncodeAsync(_rangeEncoder, 0); _state.UpdateMatch(); UInt32 len = Base.K_MATCH_MIN_LEN; - _lenEncoder.Encode(_rangeEncoder, len - Base.K_MATCH_MIN_LEN, posState); + await _lenEncoder.EncodeAsync(_rangeEncoder, len - Base.K_MATCH_MIN_LEN, posState); UInt32 posSlot = (1 << Base.K_NUM_POS_SLOT_BITS) - 1; UInt32 lenToPosState = Base.GetLenToPosState(len); - _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot); + await _posSlotEncoder[lenToPosState].EncodeAsync(_rangeEncoder, posSlot); int footerBits = 30; UInt32 posReduced = (((UInt32)1) << footerBits) - 1; - _rangeEncoder.EncodeDirectBits(posReduced >> Base.K_NUM_ALIGN_BITS, footerBits - Base.K_NUM_ALIGN_BITS); - _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.K_ALIGN_MASK); + await _rangeEncoder.EncodeDirectBits(posReduced >> Base.K_NUM_ALIGN_BITS, footerBits - Base.K_NUM_ALIGN_BITS); + await _posAlignEncoder.ReverseEncodeAsync(_rangeEncoder, posReduced & Base.K_ALIGN_MASK); } - private void Flush(UInt32 nowPos) + private async ValueTask FlushAsync(UInt32 nowPos) { ReleaseMfStream(); - WriteEndMarker(nowPos & _posStateMask); - _rangeEncoder.FlushData(); - _rangeEncoder.FlushStream(); + await WriteEndMarkerAsync(nowPos & _posStateMask); + await _rangeEncoder.FlushData(); + await _rangeEncoder.FlushAsync(); } - public void CodeOneBlock(out Int64 inSize, out Int64 outSize, out bool finished) + public async ValueTask<(Int64, Int64, bool)> CodeOneBlockAsync() { - inSize = 0; - outSize = 0; - finished = true; + long inSize = 0; + long outSize = 0; + var finished = true; if (_inStream != null) { @@ -1233,7 +1234,7 @@ namespace SharpCompress.Compressors.LZMA if (_finished) { - return; + return (inSize, outSize, finished); } _finished = true; @@ -1254,20 +1255,20 @@ namespace SharpCompress.Compressors.LZMA if (_processingMode && _matchFinder.IsDataStarved) { _finished = false; - return; + return (inSize, outSize, finished); } if (_matchFinder.GetNumAvailableBytes() == 0) { - Flush((UInt32)_nowPos64); - return; + await FlushAsync((UInt32)_nowPos64); + return (inSize, outSize, finished); } UInt32 len, numDistancePairs; // it's not used ReadMatchDistances(out len, out numDistancePairs); UInt32 posState = (UInt32)(_nowPos64) & _posStateMask; - _isMatch[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].Encode(_rangeEncoder, 0); + await _isMatch[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].EncodeAsync(_rangeEncoder, 0); _state.UpdateChar(); Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset)); - _literalEncoder.GetSubCoder((UInt32)(_nowPos64), _previousByte).Encode(_rangeEncoder, curByte); + await _literalEncoder.GetSubCoder((UInt32)(_nowPos64), _previousByte).EncodeAsync(_rangeEncoder, curByte); _previousByte = curByte; _additionalOffset--; _nowPos64++; @@ -1275,19 +1276,19 @@ namespace SharpCompress.Compressors.LZMA if (_processingMode && _matchFinder.IsDataStarved) { _finished = false; - return; + return (inSize, outSize, finished); } if (_matchFinder.GetNumAvailableBytes() == 0) { - Flush((UInt32)_nowPos64); - return; + await FlushAsync((UInt32)_nowPos64); + return (inSize, outSize, finished); } while (true) { if (_processingMode && _matchFinder.IsDataStarved) { _finished = false; - return; + return (inSize, outSize, finished); } UInt32 pos; @@ -1297,51 +1298,51 @@ namespace SharpCompress.Compressors.LZMA UInt32 complexState = (_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState; if (len == 1 && pos == 0xFFFFFFFF) { - _isMatch[complexState].Encode(_rangeEncoder, 0); + await _isMatch[complexState].EncodeAsync(_rangeEncoder, 0); Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset)); LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder((UInt32)_nowPos64, _previousByte); if (!_state.IsCharState()) { Byte matchByte = _matchFinder.GetIndexByte((Int32)(0 - _repDistances[0] - 1 - _additionalOffset)); - subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte); + await subCoder.EncodeMatchedAsync(_rangeEncoder, matchByte, curByte); } else { - subCoder.Encode(_rangeEncoder, curByte); + await subCoder.EncodeAsync(_rangeEncoder, curByte); } _previousByte = curByte; _state.UpdateChar(); } else { - _isMatch[complexState].Encode(_rangeEncoder, 1); + await _isMatch[complexState].EncodeAsync(_rangeEncoder, 1); if (pos < Base.K_NUM_REP_DISTANCES) { - _isRep[_state._index].Encode(_rangeEncoder, 1); + await _isRep[_state._index].EncodeAsync(_rangeEncoder, 1); if (pos == 0) { - _isRepG0[_state._index].Encode(_rangeEncoder, 0); + await _isRepG0[_state._index].EncodeAsync(_rangeEncoder, 0); if (len == 1) { - _isRep0Long[complexState].Encode(_rangeEncoder, 0); + await _isRep0Long[complexState].EncodeAsync(_rangeEncoder, 0); } else { - _isRep0Long[complexState].Encode(_rangeEncoder, 1); + await _isRep0Long[complexState].EncodeAsync(_rangeEncoder, 1); } } else { - _isRepG0[_state._index].Encode(_rangeEncoder, 1); + await _isRepG0[_state._index].EncodeAsync(_rangeEncoder, 1); if (pos == 1) { - _isRepG1[_state._index].Encode(_rangeEncoder, 0); + await _isRepG1[_state._index].EncodeAsync(_rangeEncoder, 0); } else { - _isRepG1[_state._index].Encode(_rangeEncoder, 1); - _isRepG2[_state._index].Encode(_rangeEncoder, pos - 2); + await _isRepG1[_state._index].EncodeAsync(_rangeEncoder, 1); + await _isRepG2[_state._index].EncodeAsync(_rangeEncoder, pos - 2); } } if (len == 1) @@ -1350,7 +1351,7 @@ namespace SharpCompress.Compressors.LZMA } else { - _repMatchLenEncoder.Encode(_rangeEncoder, len - Base.K_MATCH_MIN_LEN, posState); + await _repMatchLenEncoder.EncodeAsync(_rangeEncoder, len - Base.K_MATCH_MIN_LEN, posState); _state.UpdateRep(); } UInt32 distance = _repDistances[pos]; @@ -1365,13 +1366,13 @@ namespace SharpCompress.Compressors.LZMA } else { - _isRep[_state._index].Encode(_rangeEncoder, 0); + await _isRep[_state._index].EncodeAsync(_rangeEncoder, 0); _state.UpdateMatch(); - _lenEncoder.Encode(_rangeEncoder, len - Base.K_MATCH_MIN_LEN, posState); + await _lenEncoder.EncodeAsync(_rangeEncoder, len - Base.K_MATCH_MIN_LEN, posState); pos -= Base.K_NUM_REP_DISTANCES; UInt32 posSlot = GetPosSlot(pos); UInt32 lenToPosState = Base.GetLenToPosState(len); - _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot); + await _posSlotEncoder[lenToPosState].EncodeAsync(_rangeEncoder, posSlot); if (posSlot >= Base.K_START_POS_MODEL_INDEX) { @@ -1381,15 +1382,15 @@ namespace SharpCompress.Compressors.LZMA if (posSlot < Base.K_END_POS_MODEL_INDEX) { - BitTreeEncoder.ReverseEncode(_posEncoders, - baseVal - posSlot - 1, _rangeEncoder, footerBits, - posReduced); + await BitTreeEncoder.ReverseEncodeAsync(_posEncoders, + baseVal - posSlot - 1, _rangeEncoder, footerBits, + posReduced); } else { - _rangeEncoder.EncodeDirectBits(posReduced >> Base.K_NUM_ALIGN_BITS, + await _rangeEncoder.EncodeDirectBits(posReduced >> Base.K_NUM_ALIGN_BITS, footerBits - Base.K_NUM_ALIGN_BITS); - _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.K_ALIGN_MASK); + await _posAlignEncoder.ReverseEncodeAsync(_rangeEncoder, posReduced & Base.K_ALIGN_MASK); _alignPriceCount++; } } @@ -1421,19 +1422,19 @@ namespace SharpCompress.Compressors.LZMA if (_processingMode && _matchFinder.IsDataStarved) { _finished = false; - return; + return (inSize, outSize, finished); } if (_matchFinder.GetNumAvailableBytes() == 0) { - Flush((UInt32)_nowPos64); - return; + await FlushAsync((UInt32)_nowPos64); + return (inSize, outSize, finished); } if (_nowPos64 - progressPosValuePrev >= (1 << 12)) { _finished = false; finished = false; - return; + return (inSize, outSize, finished); } } } @@ -1488,7 +1489,7 @@ namespace SharpCompress.Compressors.LZMA _nowPos64 = 0; } - public void Code(Stream inStream, Stream outStream, + public async ValueTask CodeAsync(Stream inStream, Stream outStream, Int64 inSize, Int64 outSize, ICodeProgress progress) { _needReleaseMfStream = false; @@ -1498,10 +1499,7 @@ namespace SharpCompress.Compressors.LZMA SetStreams(inStream, outStream, inSize, outSize); while (true) { - Int64 processedInSize; - Int64 processedOutSize; - bool finished; - CodeOneBlock(out processedInSize, out processedOutSize, out finished); + var (processedInSize, processedOutSize, finished) = await CodeOneBlockAsync(); if (finished) { return; @@ -1518,7 +1516,7 @@ namespace SharpCompress.Compressors.LZMA } } - public long Code(Stream inStream, bool final) + public async ValueTask CodeAsync(Stream inStream, bool final) { _matchFinder.SetStream(inStream); _processingMode = !final; @@ -1526,10 +1524,7 @@ namespace SharpCompress.Compressors.LZMA { while (true) { - Int64 processedInSize; - Int64 processedOutSize; - bool finished; - CodeOneBlock(out processedInSize, out processedOutSize, out finished); + var (processedInSize, processedOutSize, finished) = await CodeOneBlockAsync(); if (finished) { return processedInSize; diff --git a/src/SharpCompress/Compressors/LZMA/LzmaStream.cs b/src/SharpCompress/Compressors/LZMA/LzmaStream.cs index 53c77719..47336c1f 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaStream.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaStream.cs @@ -1,21 +1,24 @@ #nullable disable using System; +using System.Buffers; using System.Buffers.Binary; using System.IO; +using System.Threading; +using System.Threading.Tasks; using SharpCompress.Compressors.LZMA.LZ; namespace SharpCompress.Compressors.LZMA { public class LzmaStream : Stream { - private readonly Stream _inputStream; - private readonly long _inputSize; - private readonly long _outputSize; + private Stream _inputStream; + private long _inputSize; + private long _outputSize; - private readonly int _dictionarySize; - private readonly OutWindow _outWindow = new OutWindow(); - private readonly RangeCoder.Decoder _rangeDecoder = new RangeCoder.Decoder(); + private int _dictionarySize; + private OutWindow _outWindow = new OutWindow(); + private RangeCoder.Decoder _rangeDecoder = new RangeCoder.Decoder(); private Decoder _decoder; private long _position; @@ -25,70 +28,60 @@ namespace SharpCompress.Compressors.LZMA private long _inputPosition; // LZMA2 - private readonly bool _isLzma2; + private bool _isLzma2; private bool _uncompressedChunk; private bool _needDictReset = true; private bool _needProps = true; private readonly Encoder _encoder; private bool _isDisposed; + + private LzmaStream() {} - public LzmaStream(byte[] properties, Stream inputStream) - : this(properties, inputStream, -1, -1, null, properties.Length < 5) + public static async ValueTask CreateAsync(byte[] properties, Stream inputStream, long inputSize = -1, long outputSize = -1, + Stream presetDictionary = null, bool? isLzma2 = null) { - } + var ls = new LzmaStream(); + ls._inputStream = inputStream; + ls._inputSize = inputSize; + ls._outputSize = outputSize; + ls._isLzma2 = isLzma2 ?? properties.Length < 5; - public LzmaStream(byte[] properties, Stream inputStream, long inputSize) - : this(properties, inputStream, inputSize, -1, null, properties.Length < 5) - { - } - - public LzmaStream(byte[] properties, Stream inputStream, long inputSize, long outputSize) - : this(properties, inputStream, inputSize, outputSize, null, properties.Length < 5) - { - } - - public LzmaStream(byte[] properties, Stream inputStream, long inputSize, long outputSize, - Stream presetDictionary, bool isLzma2) - { - _inputStream = inputStream; - _inputSize = inputSize; - _outputSize = outputSize; - _isLzma2 = isLzma2; - - if (!isLzma2) + if (!ls._isLzma2) { - _dictionarySize = BinaryPrimitives.ReadInt32LittleEndian(properties.AsSpan(1)); - _outWindow.Create(_dictionarySize); + ls._dictionarySize = BinaryPrimitives.ReadInt32LittleEndian(properties.AsSpan(1)); + ls._outWindow.Create(ls._dictionarySize); if (presetDictionary != null) { - _outWindow.Train(presetDictionary); + ls._outWindow.Train(presetDictionary); } - _rangeDecoder.Init(inputStream); + await ls._rangeDecoder.InitAsync(inputStream); - _decoder = new Decoder(); - _decoder.SetDecoderProperties(properties); - Properties = properties; + ls._decoder = new Decoder(); + ls._decoder.SetDecoderProperties(properties); + ls.Properties = properties; - _availableBytes = outputSize < 0 ? long.MaxValue : outputSize; - _rangeDecoderLimit = inputSize; + ls._availableBytes = outputSize < 0 ? long.MaxValue : outputSize; + ls._rangeDecoderLimit = inputSize; } else { - _dictionarySize = 2 | (properties[0] & 1); - _dictionarySize <<= (properties[0] >> 1) + 11; + ls. _dictionarySize = 2 | (properties[0] & 1); + ls. _dictionarySize <<= (properties[0] >> 1) + 11; - _outWindow.Create(_dictionarySize); + ls._outWindow.Create(ls._dictionarySize); if (presetDictionary != null) { - _outWindow.Train(presetDictionary); - _needDictReset = false; + ls._outWindow.Train(presetDictionary); + ls._needDictReset = false; } - Properties = new byte[1]; - _availableBytes = 0; + ls. Properties = new byte[1]; + ls._availableBytes = 0; } + + return ls; } public LzmaStream(LzmaEncoderProperties properties, bool isLzma2, Stream outputStream) @@ -128,24 +121,26 @@ namespace SharpCompress.Compressors.LZMA public override void Flush() { + throw new NotSupportedException(); } - protected override void Dispose(bool disposing) + public override async ValueTask DisposeAsync() { if (_isDisposed) { return; } _isDisposed = true; - if (disposing) + if (_encoder != null) { - if (_encoder != null) - { - _position = _encoder.Code(null, true); - } - _inputStream?.Dispose(); + _position = await _encoder.CodeAsync(null, true); } - base.Dispose(disposing); + _inputStream?.DisposeAsync(); + } + + protected override void Dispose(bool disposing) + { + throw new NotSupportedException(); } public override long Length => _position + _availableBytes; @@ -153,6 +148,11 @@ namespace SharpCompress.Compressors.LZMA public override long Position { get => _position; set => throw new NotSupportedException(); } public override int Read(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { if (_endReached) { @@ -166,7 +166,7 @@ namespace SharpCompress.Compressors.LZMA { if (_isLzma2) { - DecodeChunkHeader(); + await DecodeChunkHeader(); } else { @@ -231,7 +231,7 @@ namespace SharpCompress.Compressors.LZMA return total; } - private void DecodeChunkHeader() + private async ValueTask DecodeChunkHeader() { int control = _inputStream.ReadByte(); _inputPosition++; @@ -283,7 +283,7 @@ namespace SharpCompress.Compressors.LZMA _decoder.SetDecoderProperties(Properties); } - _rangeDecoder.Init(_inputStream); + await _rangeDecoder.InitAsync(_inputStream); } else if (control > 0x02) { @@ -307,14 +307,22 @@ namespace SharpCompress.Compressors.LZMA throw new NotSupportedException(); } - public override void Write(byte[] buffer, int offset, int count) + public override async ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = new CancellationToken()) { if (_encoder != null) { - _position = _encoder.Code(new MemoryStream(buffer, offset, count), false); + var m = ArrayPool.Shared.Rent(buffer.Length); + buffer.CopyTo(m.AsMemory()); + _position = await _encoder.CodeAsync(new MemoryStream(m), false); + ArrayPool.Shared.Return(m); } } - public byte[] Properties { get; } = new byte[5]; + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public byte[] Properties { get; private set; } } } diff --git a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs index 9ea026a9..ed2b0f5f 100644 --- a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs +++ b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs @@ -1,11 +1,13 @@ #nullable disable using System; +using System.Buffers; using System.IO; +using System.Threading.Tasks; namespace SharpCompress.Compressors.LZMA.RangeCoder { - internal class Encoder + internal class Encoder : IAsyncDisposable { public const uint K_TOP_VALUE = (1 << 24); @@ -38,43 +40,46 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder _cache = 0; } - public void FlushData() + public async ValueTask FlushData() { for (int i = 0; i < 5; i++) { - ShiftLow(); + await ShiftLowAsync(); } } - public void FlushStream() + public Task FlushAsync() { - _stream.Flush(); + return _stream.FlushAsync(); } - public void CloseStream() + public ValueTask DisposeAsync() { - _stream.Dispose(); + return _stream.DisposeAsync(); } - public void Encode(uint start, uint size, uint total) + public async ValueTask EncodeAsync(uint start, uint size, uint total) { _low += start * (_range /= total); _range *= size; while (_range < K_TOP_VALUE) { _range <<= 8; - ShiftLow(); + await ShiftLowAsync(); } } - public void ShiftLow() + public async ValueTask ShiftLowAsync() { if ((uint)_low < 0xFF000000 || (uint)(_low >> 32) == 1) { + using var buffer = MemoryPool.Shared.Rent(1); + var b = buffer.Memory.Slice(0,1); byte temp = _cache; do { - _stream.WriteByte((byte)(temp + (_low >> 32))); + b.Span[0] = (byte)(temp + (_low >> 32)); + await _stream.WriteAsync(b); temp = 0xFF; } while (--_cacheSize != 0); @@ -84,7 +89,7 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder _low = ((uint)_low) << 8; } - public void EncodeDirectBits(uint v, int numTotalBits) + public async ValueTask EncodeDirectBits(uint v, int numTotalBits) { for (int i = numTotalBits - 1; i >= 0; i--) { @@ -96,12 +101,12 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder if (_range < K_TOP_VALUE) { _range <<= 8; - ShiftLow(); + await ShiftLowAsync(); } } } - public void EncodeBit(uint size0, int numTotalBits, uint symbol) + public async ValueTask EncodeBitAsync(uint size0, int numTotalBits, uint symbol) { uint newBound = (_range >> numTotalBits) * size0; if (symbol == 0) @@ -116,7 +121,7 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder while (_range < K_TOP_VALUE) { _range <<= 8; - ShiftLow(); + await ShiftLowAsync(); } } @@ -129,7 +134,7 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder } } - internal class Decoder + internal class Decoder: IAsyncDisposable { public const uint K_TOP_VALUE = (1 << 24); public uint _range; @@ -139,16 +144,19 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder public Stream _stream; public long _total; - public void Init(Stream stream) + public async ValueTask InitAsync(Stream stream) { // Stream.Init(stream); _stream = stream; _code = 0; _range = 0xFFFFFFFF; + using var buffer = MemoryPool.Shared.Rent(1); + var b = buffer.Memory.Slice(0,1); for (int i = 0; i < 5; i++) { - _code = (_code << 8) | (byte)_stream.ReadByte(); + await _stream.ReadAsync(b); + _code = (_code << 8) | b.Span[0]; } _total = 5; } @@ -159,41 +167,34 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder _stream = null; } - public void CloseStream() + public ValueTask DisposeAsync() { - _stream.Dispose(); + return _stream.DisposeAsync(); } - public void Normalize() + public async ValueTask NormalizeAsync() { + using var buffer = MemoryPool.Shared.Rent(1); + var b = buffer.Memory.Slice(0,1); while (_range < K_TOP_VALUE) { - _code = (_code << 8) | (byte)_stream.ReadByte(); + await _stream.ReadAsync(b); + _code = (_code << 8) | b.Span[0]; _range <<= 8; _total++; } } - - public void Normalize2() - { - if (_range < K_TOP_VALUE) - { - _code = (_code << 8) | (byte)_stream.ReadByte(); - _range <<= 8; - _total++; - } - } - + public uint GetThreshold(uint total) { return _code / (_range /= total); } - public void Decode(uint start, uint size) + public async ValueTask Decode(uint start, uint size) { _code -= start * _range; _range *= size; - Normalize(); + await NormalizeAsync(); } public uint DecodeDirectBits(int numTotalBits) @@ -228,7 +229,7 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder return result; } - public uint DecodeBit(uint size0, int numTotalBits) + public async ValueTask DecodeBitAsync(uint size0, int numTotalBits) { uint newBound = (_range >> numTotalBits) * size0; uint symbol; @@ -243,7 +244,7 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder _code -= newBound; _range -= newBound; } - Normalize(); + await NormalizeAsync(); return symbol; } diff --git a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs index 2ab53aff..12d78691 100644 --- a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs +++ b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; namespace SharpCompress.Compressors.LZMA.RangeCoder { @@ -29,7 +30,7 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder } } - public void Encode(Encoder encoder, uint symbol) + public async ValueTask EncodeAsync(Encoder encoder, uint symbol) { // encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol); // UpdateModel(symbol); @@ -48,7 +49,7 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder if (encoder._range < Encoder.K_TOP_VALUE) { encoder._range <<= 8; - encoder.ShiftLow(); + await encoder.ShiftLowAsync(); } } diff --git a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBitTree.cs b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBitTree.cs index cc511603..73f97a3f 100644 --- a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBitTree.cs +++ b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBitTree.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; namespace SharpCompress.Compressors.LZMA.RangeCoder { @@ -21,25 +22,25 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder } } - public void Encode(Encoder rangeEncoder, UInt32 symbol) + public async ValueTask EncodeAsync(Encoder rangeEncoder, UInt32 symbol) { UInt32 m = 1; for (int bitIndex = _numBitLevels; bitIndex > 0;) { bitIndex--; UInt32 bit = (symbol >> bitIndex) & 1; - _models[m].Encode(rangeEncoder, bit); + await _models[m].EncodeAsync(rangeEncoder, bit); m = (m << 1) | bit; } } - public void ReverseEncode(Encoder rangeEncoder, UInt32 symbol) + public async ValueTask ReverseEncodeAsync(Encoder rangeEncoder, UInt32 symbol) { UInt32 m = 1; for (UInt32 i = 0; i < _numBitLevels; i++) { UInt32 bit = symbol & 1; - _models[m].Encode(rangeEncoder, bit); + await _models[m].EncodeAsync(rangeEncoder, bit); m = (m << 1) | bit; symbol >>= 1; } @@ -88,14 +89,14 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder return price; } - public static void ReverseEncode(BitEncoder[] models, UInt32 startIndex, + public static async ValueTask ReverseEncodeAsync(BitEncoder[] models, UInt32 startIndex, Encoder rangeEncoder, int numBitLevels, UInt32 symbol) { UInt32 m = 1; for (int i = 0; i < numBitLevels; i++) { UInt32 bit = symbol & 1; - models[startIndex + m].Encode(rangeEncoder, bit); + await models[startIndex + m].EncodeAsync(rangeEncoder, bit); m = (m << 1) | bit; symbol >>= 1; } diff --git a/src/SharpCompress/Compressors/LZMA/Registry.cs b/src/SharpCompress/Compressors/LZMA/Registry.cs index 9075647c..687f9cb8 100644 --- a/src/SharpCompress/Compressors/LZMA/Registry.cs +++ b/src/SharpCompress/Compressors/LZMA/Registry.cs @@ -27,6 +27,7 @@ namespace SharpCompress.Compressors.LZMA internal static async ValueTask CreateDecoderStream(CMethodId id, Stream[] inStreams, byte[] info, IPasswordProvider pass, long limit, CancellationToken cancellationToken) { + await Task.CompletedTask; switch (id._id) { case K_COPY: @@ -37,17 +38,17 @@ namespace SharpCompress.Compressors.LZMA return inStreams.Single(); case K_LZMA: case K_LZMA2: - return new LzmaStream(info, inStreams.Single(), -1, limit); + return await LzmaStream.CreateAsync(info, inStreams.Single(), -1, limit); case CMethodId.K_AES_ID: return new AesDecoderStream(inStreams.Single(), info, pass, limit); case K_BCJ: return new BCJFilter(false, inStreams.Single()); case K_BCJ2: return new Bcj2DecoderStream(inStreams, info, limit); - case K_B_ZIP2: - return await BZip2Stream.CreateAsync(inStreams.Single(), CompressionMode.Decompress, true, cancellationToken); - /*case K_PPMD: - return new PpmdStream(new PpmdProperties(info), inStreams.Single(), false);*/ + /* case K_B_ZIP2: + return await BZip2Stream.CreateAsync(inStreams.Single(), CompressionMode.Decompress, true, cancellationToken); + case K_PPMD: + return new PpmdStream(new PpmdProperties(info), inStreams.Single(), false);*/ case K_DEFLATE: return new DeflateStream(inStreams.Single(), CompressionMode.Decompress); default: diff --git a/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs index 875d1b44..684145a5 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Threading.Tasks; namespace SharpCompress.Compressors.Xz.Filters { @@ -52,6 +53,6 @@ namespace SharpCompress.Compressors.Xz.Filters return filter; } - public abstract void SetBaseStream(Stream stream); + public abstract ValueTask SetBaseStreamAsync(Stream stream); } } diff --git a/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs b/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs index 0a842f68..9d926fd0 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Threading.Tasks; using SharpCompress.Compressors.LZMA; namespace SharpCompress.Compressors.Xz.Filters @@ -49,9 +50,9 @@ namespace SharpCompress.Compressors.Xz.Filters { } - public override void SetBaseStream(Stream stream) + public override async ValueTask SetBaseStreamAsync(Stream stream) { - BaseStream = new LzmaStream(new[] { _dictionarySize }, stream); + BaseStream = await LzmaStream.CreateAsync(new[] { _dictionarySize }, stream); } public override int Read(byte[] buffer, int offset, int count) diff --git a/src/SharpCompress/Compressors/Xz/XZBlock.cs b/src/SharpCompress/Compressors/Xz/XZBlock.cs index 14b369fe..da638fc2 100644 --- a/src/SharpCompress/Compressors/Xz/XZBlock.cs +++ b/src/SharpCompress/Compressors/Xz/XZBlock.cs @@ -44,7 +44,7 @@ namespace SharpCompress.Compressors.Xz if (!_streamConnected) { - ConnectStream(); + await ConnectStreamAsync(); } if (!_endOfStream && _decomStream is not null) @@ -95,13 +95,13 @@ namespace SharpCompress.Compressors.Xz _crcChecked = true; } - private void ConnectStream() + private async ValueTask ConnectStreamAsync() { _decomStream = BaseStream; while (Filters.Any()) { BlockFilter filter = Filters.Pop(); - filter.SetBaseStream(_decomStream); + await filter.SetBaseStreamAsync(_decomStream); _decomStream = filter; } _streamConnected = true; diff --git a/src/SharpCompress/Readers/ReaderFactory.cs b/src/SharpCompress/Readers/ReaderFactory.cs index e94c0ecc..f17e749e 100644 --- a/src/SharpCompress/Readers/ReaderFactory.cs +++ b/src/SharpCompress/Readers/ReaderFactory.cs @@ -56,7 +56,7 @@ namespace SharpCompress.Readers return GZipReader.Open(rewindableStream, options); } - rewindableStream.Rewind(false); + /* rewindableStream.Rewind(false); if (await BZip2Stream.IsBZip2Async(rewindableStream, cancellationToken)) { rewindableStream.Rewind(false); @@ -66,13 +66,13 @@ namespace SharpCompress.Readers rewindableStream.Rewind(true); return new TarReader(rewindableStream, options, CompressionType.BZip2); } - } + } */ rewindableStream.Rewind(false); - if (LZipStream.IsLZipFile(rewindableStream)) + if (await LZipStream.IsLZipFileAsync(rewindableStream)) { rewindableStream.Rewind(false); - LZipStream testStream = new(new NonDisposingStream(rewindableStream), CompressionMode.Decompress); + var testStream = await LZipStream.CreateAsync(new NonDisposingStream(rewindableStream), CompressionMode.Decompress); if (await TarArchive.IsTarFileAsync(testStream, cancellationToken)) { rewindableStream.Rewind(true); diff --git a/src/SharpCompress/Readers/Tar/TarReader.cs b/src/SharpCompress/Readers/Tar/TarReader.cs index ae6203ee..7a9db2f9 100644 --- a/src/SharpCompress/Readers/Tar/TarReader.cs +++ b/src/SharpCompress/Readers/Tar/TarReader.cs @@ -34,17 +34,17 @@ namespace SharpCompress.Readers.Tar var stream = await base.RequestInitialStream(cancellationToken); switch (compressionType) { - case CompressionType.BZip2: + /* case CompressionType.BZip2: { return await BZip2Stream.CreateAsync(stream, CompressionMode.Decompress, false, cancellationToken); - } + } */ case CompressionType.GZip: { return new GZipStream(stream, CompressionMode.Decompress); } case CompressionType.LZip: { - return new LZipStream(stream, CompressionMode.Decompress); + return await LZipStream.CreateAsync(stream, CompressionMode.Decompress); } case CompressionType.Xz: { @@ -87,7 +87,7 @@ namespace SharpCompress.Readers.Tar throw new InvalidFormatException("Not a tar file."); } - rewindableStream.Rewind(false); + /*rewindableStream.Rewind(false); if (await BZip2Stream.IsBZip2Async(rewindableStream, cancellationToken)) { rewindableStream.Rewind(false); @@ -98,13 +98,13 @@ namespace SharpCompress.Readers.Tar return new TarReader(rewindableStream, options, CompressionType.BZip2); } throw new InvalidFormatException("Not a tar file."); - } + } */ rewindableStream.Rewind(false); - if (LZipStream.IsLZipFile(rewindableStream)) + if (await LZipStream.IsLZipFileAsync(rewindableStream)) { rewindableStream.Rewind(false); - LZipStream testStream = new(rewindableStream, CompressionMode.Decompress); + var testStream = await LZipStream.CreateAsync(rewindableStream, CompressionMode.Decompress); if (await TarArchive.IsTarFileAsync(testStream, cancellationToken)) { rewindableStream.Rewind(true); diff --git a/src/SharpCompress/Utility.cs b/src/SharpCompress/Utility.cs index 83caec87..c1e318e7 100644 --- a/src/SharpCompress/Utility.cs +++ b/src/SharpCompress/Utility.cs @@ -127,12 +127,15 @@ namespace SharpCompress yield return item; } - public static void CheckNotNull(this object obj, string name) + public static T CheckNotNull(this T? obj, string name) + where T : class { if (obj is null) { throw new ArgumentNullException(name); } + + return obj; } public static void CheckNotNullOrEmpty(this string obj, string name) diff --git a/src/SharpCompress/Writers/Tar/TarWriter.cs b/src/SharpCompress/Writers/Tar/TarWriter.cs index 9d031e73..0cbb26b6 100644 --- a/src/SharpCompress/Writers/Tar/TarWriter.cs +++ b/src/SharpCompress/Writers/Tar/TarWriter.cs @@ -24,6 +24,7 @@ namespace SharpCompress.Writers.Tar public static async ValueTask CreateAsync(Stream destination, TarWriterOptions options, CancellationToken cancellationToken = default) { + await Task.CompletedTask; var tw = new TarWriter(options); tw.finalizeArchiveOnClose = options.FinalizeArchiveOnClose; @@ -39,11 +40,11 @@ namespace SharpCompress.Writers.Tar { case CompressionType.None: break; - case CompressionType.BZip2: + /* case CompressionType.BZip2: { destination = await BZip2Stream.CreateAsync(destination, CompressionMode.Compress, false, cancellationToken); } - break; + break; */ case CompressionType.GZip: { destination = new GZipStream(destination, CompressionMode.Compress); @@ -51,7 +52,7 @@ namespace SharpCompress.Writers.Tar break; case CompressionType.LZip: { - destination = new LZipStream(destination, CompressionMode.Compress); + destination = await LZipStream.CreateAsync(destination, CompressionMode.Compress); } break; default: @@ -122,11 +123,11 @@ namespace SharpCompress.Writers.Tar } switch (OutputStream) { - case BZip2Stream b: + /* case BZip2Stream b: { await b.FinishAsync(CancellationToken.None); break; - } + } */ case LZipStream l: { l.Finish(); diff --git a/src/SharpCompress/Writers/Zip/ZipWriter.cs b/src/SharpCompress/Writers/Zip/ZipWriter.cs index e164f1ab..8f214975 100644 --- a/src/SharpCompress/Writers/Zip/ZipWriter.cs +++ b/src/SharpCompress/Writers/Zip/ZipWriter.cs @@ -379,6 +379,7 @@ namespace SharpCompress.Writers.Zip private async ValueTask GetWriteStream(Stream writeStream, CancellationToken cancellationToken) { + await Task.CompletedTask; counting = new CountingWritableSubStream(writeStream); Stream output = counting; switch (zipCompressionMethod) @@ -391,10 +392,10 @@ namespace SharpCompress.Writers.Zip { return new DeflateStream(counting, CompressionMode.Compress, compressionLevel); } - case ZipCompressionMethod.BZip2: + /*case ZipCompressionMethod.BZip2: { return await BZip2Stream.CreateAsync(counting, CompressionMode.Compress, false, cancellationToken); - } + } */ case ZipCompressionMethod.LZMA: { counting.WriteByte(9); diff --git a/tests/SharpCompress.Test/Streams/LzmaStreamTests.cs b/tests/SharpCompress.Test/Streams/LzmaStreamTests.cs index 3e41ee83..873ed94c 100644 --- a/tests/SharpCompress.Test/Streams/LzmaStreamTests.cs +++ b/tests/SharpCompress.Test/Streams/LzmaStreamTests.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Threading.Tasks; using SharpCompress.Compressors.LZMA; using Xunit; @@ -7,13 +8,13 @@ namespace SharpCompress.Test.Streams public class LzmaStreamTests { [Fact] - public void TestLzma2Decompress1Byte() + public async ValueTask TestLzma2Decompress1Byte() { byte[] properties = new byte[] { 0x01 }; byte[] compressedData = new byte[] { 0x01, 0x00, 0x00, 0x58, 0x00 }; MemoryStream lzma2Stream = new MemoryStream(compressedData); - LzmaStream decompressor = new LzmaStream(properties, lzma2Stream, 5, 1); + LzmaStream decompressor = await LzmaStream.CreateAsync(properties, lzma2Stream, 5, 1); Assert.Equal('X', decompressor.ReadByte()); } }