diff --git a/src/SharpCompress/Algorithms/Adler32.cs b/src/SharpCompress/Algorithms/Adler32.cs index f7ea0eb3..d7645327 100644 --- a/src/SharpCompress/Algorithms/Adler32.cs +++ b/src/SharpCompress/Algorithms/Adler32.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -#if !NETSTANDARD2_0 && !NETSTANDARD2_1 && !NETFRAMEWORK +#if !LEGACY_DOTNET #define SUPPORTS_RUNTIME_INTRINSICS #define SUPPORTS_HOTPATH #endif diff --git a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs index b4956592..60c843d6 100644 --- a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs +++ b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs @@ -253,7 +253,7 @@ public partial class SevenZipArchive : AbstractArchive ReadAsync( Memory buffer, CancellationToken cancellationToken = default diff --git a/src/SharpCompress/Common/AsyncBinaryReader.cs b/src/SharpCompress/Common/AsyncBinaryReader.cs index 99a29786..39e1b719 100644 --- a/src/SharpCompress/Common/AsyncBinaryReader.cs +++ b/src/SharpCompress/Common/AsyncBinaryReader.cs @@ -87,7 +87,7 @@ namespace SharpCompress.Common } } -#if NET6_0_OR_GREATER +#if NET8_0_OR_GREATER public async ValueTask DisposeAsync() { if (_disposed) diff --git a/src/SharpCompress/Common/EntryStream.cs b/src/SharpCompress/Common/EntryStream.cs index 11d0e898..e4de4ca9 100644 --- a/src/SharpCompress/Common/EntryStream.cs +++ b/src/SharpCompress/Common/EntryStream.cs @@ -93,7 +93,7 @@ public class EntryStream : Stream, IStreamStack _stream.Dispose(); } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async ValueTask DisposeAsync() { if (_isDisposed) @@ -171,7 +171,7 @@ public class EntryStream : Stream, IStreamStack return read; } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async ValueTask ReadAsync( Memory buffer, CancellationToken cancellationToken = default diff --git a/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs b/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs index 4e6ddb70..9a91ba9c 100644 --- a/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs +++ b/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs @@ -66,7 +66,7 @@ internal class TarReadOnlySubStream : SharpCompressStream, IStreamStack base.Dispose(disposing); } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async System.Threading.Tasks.ValueTask DisposeAsync() { if (_isDisposed) @@ -170,7 +170,7 @@ internal class TarReadOnlySubStream : SharpCompressStream, IStreamStack return read; } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async System.Threading.Tasks.ValueTask ReadAsync( System.Memory buffer, System.Threading.CancellationToken cancellationToken = default diff --git a/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs b/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs index da37501b..9925c593 100644 --- a/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs +++ b/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs @@ -20,7 +20,7 @@ internal class WinzipAesEncryptionData { _keySize = keySize; -#if NETFRAMEWORK || NETSTANDARD2_0 +#if LEGACY_DOTNET var rfc2898 = new Rfc2898DeriveBytes(password, salt, RFC2898_ITERATIONS); KeyBytes = rfc2898.GetBytes(KeySizeInBytes); IvBytes = rfc2898.GetBytes(KeySizeInBytes); diff --git a/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs b/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs index 24547875..519e8db1 100644 --- a/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs +++ b/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs @@ -30,6 +30,7 @@ public sealed class BZip2Stream : Stream, IStreamStack private Stream stream = default!; private bool isDisposed; + private bool leaveOpen; private BZip2Stream() { } @@ -42,10 +43,12 @@ public sealed class BZip2Stream : Stream, IStreamStack public static BZip2Stream Create( Stream stream, CompressionMode compressionMode, - bool decompressConcatenated + bool decompressConcatenated, + bool leaveOpen = false ) { var bZip2Stream = new BZip2Stream(); + bZip2Stream.leaveOpen = leaveOpen; #if DEBUG_STREAMS bZip2Stream.DebugConstruct(typeof(BZip2Stream)); #endif @@ -73,10 +76,12 @@ public sealed class BZip2Stream : Stream, IStreamStack Stream stream, CompressionMode compressionMode, bool decompressConcatenated, + bool leaveOpen = false, CancellationToken cancellationToken = default ) { var bZip2Stream = new BZip2Stream(); + bZip2Stream.leaveOpen = leaveOpen; #if DEBUG_STREAMS bZip2Stream.DebugConstruct(typeof(BZip2Stream)); #endif @@ -101,7 +106,7 @@ public sealed class BZip2Stream : Stream, IStreamStack protected override void Dispose(bool disposing) { - if (isDisposed) + if (isDisposed || leaveOpen) { return; } @@ -142,7 +147,7 @@ public sealed class BZip2Stream : Stream, IStreamStack public override void SetLength(long value) => stream.SetLength(value); -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override int Read(Span buffer) => stream.Read(buffer); diff --git a/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs b/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs index e304ff7f..adbb17f0 100644 --- a/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs +++ b/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs @@ -168,7 +168,8 @@ internal class CBZip2InputStream : Stream, IStreamStack storedCombinedCRC; private int computedBlockCRC, computedCombinedCRC; - private bool decompressConcatenated; + private bool decompressConcatenated; + private bool leaveOpen; private int i2, count, @@ -184,10 +185,12 @@ internal class CBZip2InputStream : Stream, IStreamStack private CBZip2InputStream() { } - public static CBZip2InputStream Create(Stream zStream, bool decompressConcatenated) + public static CBZip2InputStream Create(Stream zStream, bool decompressConcatenated, + bool leaveOpen = false) { var cbZip2InputStream = new CBZip2InputStream(); cbZip2InputStream.decompressConcatenated = decompressConcatenated; + cbZip2InputStream.leaveOpen = leaveOpen; cbZip2InputStream.ll8 = null; cbZip2InputStream.tt = null; cbZip2InputStream.BsSetStream(zStream); @@ -215,7 +218,7 @@ internal class CBZip2InputStream : Stream, IStreamStack protected override void Dispose(bool disposing) { - if (isDisposed) + if (isDisposed || leaveOpen) { return; } @@ -224,7 +227,7 @@ internal class CBZip2InputStream : Stream, IStreamStack this.DebugDispose(typeof(CBZip2InputStream)); #endif base.Dispose(disposing); - bsStream?.Dispose(); + bsStream?.Dispose(); } internal static int[][] InitIntArray(int n1, int n2) @@ -580,7 +583,10 @@ internal class CBZip2InputStream : Stream, IStreamStack private void BsFinishedWithStream() { - bsStream?.Dispose(); + if (!leaveOpen) + { + bsStream?.Dispose(); + } bsStream = null; } diff --git a/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs b/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs index 7ee38b81..e0500adc 100644 --- a/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs +++ b/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs @@ -341,12 +341,14 @@ internal sealed class CBZip2OutputStream : Stream, IStreamStack private int currentChar = -1; private int runLength; + private readonly bool leaveOpen; - public CBZip2OutputStream(Stream inStream) - : this(inStream, 9) { } + public CBZip2OutputStream(Stream inStream, bool leaveOpen = false) + : this(inStream, 9, leaveOpen) { } - public CBZip2OutputStream(Stream inStream, int inBlockSize) + public CBZip2OutputStream(Stream inStream, int inBlockSize, bool leaveOpen = false) { + this.leaveOpen = leaveOpen; block = null; quadrant = null; zptr = null; @@ -481,7 +483,10 @@ internal sealed class CBZip2OutputStream : Stream, IStreamStack this.DebugDispose(typeof(CBZip2OutputStream)); #endif Dispose(); - bsStream?.Dispose(); + if (!leaveOpen) + { + bsStream?.Dispose(); + } bsStream = null; } } diff --git a/src/SharpCompress/Compressors/Deflate/DeflateStream.cs b/src/SharpCompress/Compressors/Deflate/DeflateStream.cs index c045c396..1f41a240 100644 --- a/src/SharpCompress/Compressors/Deflate/DeflateStream.cs +++ b/src/SharpCompress/Compressors/Deflate/DeflateStream.cs @@ -366,7 +366,7 @@ public class DeflateStream : Stream, IStreamStack .ConfigureAwait(false); } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async ValueTask ReadAsync( Memory buffer, CancellationToken cancellationToken = default @@ -457,7 +457,7 @@ public class DeflateStream : Stream, IStreamStack .ConfigureAwait(false); } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async ValueTask WriteAsync( ReadOnlyMemory buffer, CancellationToken cancellationToken = default diff --git a/src/SharpCompress/Compressors/Deflate/GZipStream.cs b/src/SharpCompress/Compressors/Deflate/GZipStream.cs index d9af4284..aceacb28 100644 --- a/src/SharpCompress/Compressors/Deflate/GZipStream.cs +++ b/src/SharpCompress/Compressors/Deflate/GZipStream.cs @@ -345,7 +345,7 @@ public class GZipStream : Stream, IStreamStack return n; } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async ValueTask ReadAsync( Memory buffer, CancellationToken cancellationToken = default @@ -454,7 +454,7 @@ public class GZipStream : Stream, IStreamStack await BaseStream.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async ValueTask WriteAsync( ReadOnlyMemory buffer, CancellationToken cancellationToken = default diff --git a/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs b/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs index d3c10f9b..dd6590b7 100644 --- a/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs +++ b/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs @@ -552,7 +552,7 @@ internal class ZlibBaseStream : Stream, IStreamStack } } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async ValueTask DisposeAsync() { if (isDisposed) @@ -1171,7 +1171,7 @@ internal class ZlibBaseStream : Stream, IStreamStack return rc; } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async ValueTask ReadAsync( Memory buffer, CancellationToken cancellationToken = default diff --git a/src/SharpCompress/Compressors/Deflate/ZlibConstants.cs b/src/SharpCompress/Compressors/Deflate/ZlibConstants.cs index ec415d9c..7bf8a3f6 100644 --- a/src/SharpCompress/Compressors/Deflate/ZlibConstants.cs +++ b/src/SharpCompress/Compressors/Deflate/ZlibConstants.cs @@ -108,13 +108,9 @@ internal static class ZlibConstants public const int Z_BUF_ERROR = -5; /// - /// The size of the working buffer used in the ZlibCodec class. Defaults to 8192 bytes. + /// The size of the working buffer used in the ZlibCodec class. Defaults to 16384 bytes. /// -#if NETCF - public const int WorkingBufferSizeDefault = 8192; -#else public const int WorkingBufferSizeDefault = 16384; -#endif /// /// The minimum size of the working buffer used in the ZlibCodec class. Currently it is 128 bytes. diff --git a/src/SharpCompress/Compressors/Deflate/ZlibStream.cs b/src/SharpCompress/Compressors/Deflate/ZlibStream.cs index 3365832c..d94ca210 100644 --- a/src/SharpCompress/Compressors/Deflate/ZlibStream.cs +++ b/src/SharpCompress/Compressors/Deflate/ZlibStream.cs @@ -277,7 +277,7 @@ public class ZlibStream : Stream, IStreamStack await _baseStream.FlushAsync(cancellationToken).ConfigureAwait(false); } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async ValueTask DisposeAsync() { if (_disposed) @@ -347,7 +347,7 @@ public class ZlibStream : Stream, IStreamStack .ConfigureAwait(false); } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async ValueTask ReadAsync( Memory buffer, CancellationToken cancellationToken = default @@ -431,7 +431,7 @@ public class ZlibStream : Stream, IStreamStack .ConfigureAwait(false); } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async ValueTask WriteAsync( ReadOnlyMemory buffer, CancellationToken cancellationToken = default diff --git a/src/SharpCompress/Compressors/Deflate64/Deflate64Stream.cs b/src/SharpCompress/Compressors/Deflate64/Deflate64Stream.cs index 3ba9e618..083f0380 100644 --- a/src/SharpCompress/Compressors/Deflate64/Deflate64Stream.cs +++ b/src/SharpCompress/Compressors/Deflate64/Deflate64Stream.cs @@ -200,7 +200,7 @@ public sealed class Deflate64Stream : Stream, IStreamStack return count - remainingCount; } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async ValueTask ReadAsync( Memory buffer, CancellationToken cancellationToken = default diff --git a/src/SharpCompress/Compressors/LZMA/LZipStream.cs b/src/SharpCompress/Compressors/LZMA/LZipStream.cs index eb7fd29b..a7e2d572 100644 --- a/src/SharpCompress/Compressors/LZMA/LZipStream.cs +++ b/src/SharpCompress/Compressors/LZMA/LZipStream.cs @@ -46,11 +46,13 @@ public sealed class LZipStream : Stream, IStreamStack private long _writeCount; private readonly Stream? _originalStream; + private readonly bool _leaveOpen; - public LZipStream(Stream stream, CompressionMode mode) + public LZipStream(Stream stream, CompressionMode mode, bool leaveOpen = false) { Mode = mode; _originalStream = stream; + _leaveOpen = leaveOpen; if (mode == CompressionMode.Decompress) { @@ -60,7 +62,7 @@ public sealed class LZipStream : Stream, IStreamStack throw new InvalidFormatException("Not an LZip stream"); } var properties = GetProperties(dSize); - _stream = new LzmaStream(properties, stream); + _stream = new LzmaStream(properties, stream, leaveOpen: leaveOpen); } else { @@ -127,7 +129,7 @@ public sealed class LZipStream : Stream, IStreamStack { Finish(); _stream.Dispose(); - if (Mode == CompressionMode.Compress) + if (Mode == CompressionMode.Compress && !_leaveOpen) { _originalStream?.Dispose(); } @@ -163,7 +165,7 @@ public sealed class LZipStream : Stream, IStreamStack public override void SetLength(long value) => throw new NotImplementedException(); -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override ValueTask ReadAsync( Memory buffer, diff --git a/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs b/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs index 95d3d027..0fb39626 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs @@ -201,7 +201,7 @@ public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream } } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET [MemberNotNull(nameof(_outWindow))] #endif private void CreateDictionary() diff --git a/src/SharpCompress/Compressors/LZMA/LzmaStream.cs b/src/SharpCompress/Compressors/LZMA/LzmaStream.cs index 26079966..2ddfdd8c 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaStream.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaStream.cs @@ -35,6 +35,7 @@ public class LzmaStream : Stream, IStreamStack private readonly Stream _inputStream; private readonly long _inputSize; private readonly long _outputSize; + private readonly bool _leaveOpen; private readonly int _dictionarySize; private readonly OutWindow _outWindow = new(); @@ -56,14 +57,28 @@ public class LzmaStream : Stream, IStreamStack private readonly Encoder _encoder; private bool _isDisposed; - public LzmaStream(byte[] properties, Stream inputStream) - : this(properties, inputStream, -1, -1, null, properties.Length < 5) { } + public LzmaStream(byte[] properties, Stream inputStream, bool leaveOpen = false) + : this(properties, inputStream, -1, -1, null, properties.Length < 5, leaveOpen) { } - 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, bool leaveOpen = false) + : this(properties, inputStream, inputSize, -1, null, properties.Length < 5, leaveOpen) { } - 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, + bool leaveOpen = false + ) + : this( + properties, + inputStream, + inputSize, + outputSize, + null, + properties.Length < 5, + leaveOpen + ) { } public LzmaStream( byte[] properties, @@ -71,13 +86,15 @@ public class LzmaStream : Stream, IStreamStack long inputSize, long outputSize, Stream presetDictionary, - bool isLzma2 + bool isLzma2, + bool leaveOpen = false ) { _inputStream = inputStream; _inputSize = inputSize; _outputSize = outputSize; _isLzma2 = isLzma2; + _leaveOpen = leaveOpen; #if DEBUG_STREAMS this.DebugConstruct(typeof(LzmaStream)); @@ -179,7 +196,10 @@ public class LzmaStream : Stream, IStreamStack { _position = _encoder.Code(null, true); } - _inputStream?.Dispose(); + if (!_leaveOpen) + { + _inputStream?.Dispose(); + } _outWindow.Dispose(); } base.Dispose(disposing); @@ -632,7 +652,7 @@ public class LzmaStream : Stream, IStreamStack return total; } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async ValueTask ReadAsync( Memory buffer, CancellationToken cancellationToken = default diff --git a/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs b/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs index 8d1a0a5e..ebf9202c 100644 --- a/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs +++ b/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs @@ -188,7 +188,7 @@ internal sealed class MultiVolumeReadOnlyStream : MultiVolumeReadOnlyStreamBase, return totalRead; } -#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER +#if !LEGACY_DOTNET public override async System.Threading.Tasks.ValueTask ReadAsync( Memory buffer, System.Threading.CancellationToken cancellationToken = default diff --git a/src/SharpCompress/Compressors/Rar/RarBLAKE2spStream.cs b/src/SharpCompress/Compressors/Rar/RarBLAKE2spStream.cs index adc1c6f3..57be3533 100644 --- a/src/SharpCompress/Compressors/Rar/RarBLAKE2spStream.cs +++ b/src/SharpCompress/Compressors/Rar/RarBLAKE2spStream.cs @@ -385,7 +385,7 @@ internal class RarBLAKE2spStream : RarStream, IStreamStack return result; } -#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER +#if !LEGACY_DOTNET public override async System.Threading.Tasks.ValueTask ReadAsync( Memory buffer, System.Threading.CancellationToken cancellationToken = default diff --git a/src/SharpCompress/Compressors/Rar/RarCrcStream.cs b/src/SharpCompress/Compressors/Rar/RarCrcStream.cs index 75a1381e..00753d05 100644 --- a/src/SharpCompress/Compressors/Rar/RarCrcStream.cs +++ b/src/SharpCompress/Compressors/Rar/RarCrcStream.cs @@ -129,7 +129,7 @@ internal class RarCrcStream : RarStream, IStreamStack return result; } -#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER +#if !LEGACY_DOTNET public override async System.Threading.Tasks.ValueTask ReadAsync( Memory buffer, System.Threading.CancellationToken cancellationToken = default diff --git a/src/SharpCompress/Compressors/Rar/RarStream.cs b/src/SharpCompress/Compressors/Rar/RarStream.cs index 21c225c3..34700edf 100644 --- a/src/SharpCompress/Compressors/Rar/RarStream.cs +++ b/src/SharpCompress/Compressors/Rar/RarStream.cs @@ -189,7 +189,7 @@ internal class RarStream : Stream, IStreamStack return outTotal; } -#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER +#if !LEGACY_DOTNET public override async System.Threading.Tasks.ValueTask ReadAsync( Memory buffer, System.Threading.CancellationToken cancellationToken = default diff --git a/src/SharpCompress/Compressors/ZStandard/CompressionStream.cs b/src/SharpCompress/Compressors/ZStandard/CompressionStream.cs index af8865b4..df4b4d68 100644 --- a/src/SharpCompress/Compressors/ZStandard/CompressionStream.cs +++ b/src/SharpCompress/Compressors/ZStandard/CompressionStream.cs @@ -74,7 +74,7 @@ public class CompressionStream : Stream ~CompressionStream() => Dispose(false); -#if !NETSTANDARD2_0 && !NETFRAMEWORK +#if !LEGACY_DOTNET public override async ValueTask DisposeAsync() #else public async ValueTask DisposeAsync() @@ -145,7 +145,7 @@ public class CompressionStream : Stream public override void Write(byte[] buffer, int offset, int count) => Write(new ReadOnlySpan(buffer, offset, count)); -#if !NETSTANDARD2_0 && !NETFRAMEWORK +#if !LEGACY_DOTNET public override void Write(ReadOnlySpan buffer) => WriteInternal(buffer, ZSTD_EndDirective.ZSTD_e_continue); #else @@ -176,7 +176,7 @@ public class CompressionStream : Stream ); } -#if !NETSTANDARD2_0 && !NETFRAMEWORK +#if !LEGACY_DOTNET private async ValueTask WriteInternalAsync( ReadOnlyMemory? buffer, ZSTD_EndDirective directive, @@ -218,7 +218,7 @@ public class CompressionStream : Stream ); } -#if !NETSTANDARD2_0 && !NETFRAMEWORK +#if !LEGACY_DOTNET public override Task WriteAsync( byte[] buffer, diff --git a/src/SharpCompress/Compressors/ZStandard/DecompressionStream.cs b/src/SharpCompress/Compressors/ZStandard/DecompressionStream.cs index 78af4351..c1aed766 100644 --- a/src/SharpCompress/Compressors/ZStandard/DecompressionStream.cs +++ b/src/SharpCompress/Compressors/ZStandard/DecompressionStream.cs @@ -105,7 +105,7 @@ public class DecompressionStream : Stream public override int Read(byte[] buffer, int offset, int count) => Read(new Span(buffer, offset, count)); -#if !NETSTANDARD2_0 && !NETFRAMEWORK +#if !LEGACY_DOTNET public override int Read(Span buffer) #else public int Read(Span buffer) @@ -158,7 +158,7 @@ public class DecompressionStream : Stream } } -#if !NETSTANDARD2_0 && !NETFRAMEWORK +#if !LEGACY_DOTNET public override Task ReadAsync( byte[] buffer, int offset, @@ -276,7 +276,7 @@ public class DecompressionStream : Stream throw new ObjectDisposedException(nameof(DecompressionStream)); } -#if NETSTANDARD2_0 || NETFRAMEWORK +#if LEGACY_DOTNET public virtual Task DisposeAsync() { try diff --git a/src/SharpCompress/Compressors/ZStandard/UnsafeHelper.cs b/src/SharpCompress/Compressors/ZStandard/UnsafeHelper.cs index b145099b..a73023c4 100644 --- a/src/SharpCompress/Compressors/ZStandard/UnsafeHelper.cs +++ b/src/SharpCompress/Compressors/ZStandard/UnsafeHelper.cs @@ -16,7 +16,7 @@ public static unsafe class UnsafeHelper [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void* malloc(ulong size) { -#if NET6_0_OR_GREATER +#if NET8_0_OR_GREATER var ptr = NativeMemory.Alloc((nuint)size); #else var ptr = (void*)Marshal.AllocHGlobal((nint)size); @@ -31,7 +31,7 @@ public static unsafe class UnsafeHelper [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void* calloc(ulong num, ulong size) { -#if NET6_0_OR_GREATER +#if NET8_0_OR_GREATER return NativeMemory.AllocZeroed((nuint)num, (nuint)size); #else var total = num * size; @@ -53,7 +53,7 @@ public static unsafe class UnsafeHelper [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void free(void* ptr) { -#if NET6_0_OR_GREATER +#if NET8_0_OR_GREATER NativeMemory.Free(ptr); #else Marshal.FreeHGlobal((IntPtr)ptr); diff --git a/src/SharpCompress/Crypto/Crc32Stream.cs b/src/SharpCompress/Crypto/Crc32Stream.cs index dfbcfac8..0dbcce8c 100644 --- a/src/SharpCompress/Crypto/Crc32Stream.cs +++ b/src/SharpCompress/Crypto/Crc32Stream.cs @@ -70,7 +70,7 @@ public sealed class Crc32Stream : Stream, IStreamStack public override void SetLength(long value) => throw new NotSupportedException(); -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override void Write(ReadOnlySpan buffer) { diff --git a/src/SharpCompress/IO/BufferedSubStream.cs b/src/SharpCompress/IO/BufferedSubStream.cs index 747c9776..7a51bb0f 100755 --- a/src/SharpCompress/IO/BufferedSubStream.cs +++ b/src/SharpCompress/IO/BufferedSubStream.cs @@ -154,7 +154,7 @@ internal class BufferedSubStream : SharpCompressStream, IStreamStack return count; } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async ValueTask ReadAsync( Memory buffer, CancellationToken cancellationToken = default diff --git a/src/SharpCompress/IO/ProgressReportingStream.cs b/src/SharpCompress/IO/ProgressReportingStream.cs index 5ed02835..efadba41 100644 --- a/src/SharpCompress/IO/ProgressReportingStream.cs +++ b/src/SharpCompress/IO/ProgressReportingStream.cs @@ -64,7 +64,7 @@ internal sealed class ProgressReportingStream : Stream return bytesRead; } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override int Read(Span buffer) { var bytesRead = _baseStream.Read(buffer); @@ -95,7 +95,7 @@ internal sealed class ProgressReportingStream : Stream return bytesRead; } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async ValueTask ReadAsync( Memory buffer, CancellationToken cancellationToken = default @@ -147,7 +147,7 @@ internal sealed class ProgressReportingStream : Stream base.Dispose(disposing); } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async ValueTask DisposeAsync() { if (!_leaveOpen) diff --git a/src/SharpCompress/IO/ReadOnlySubStream.cs b/src/SharpCompress/IO/ReadOnlySubStream.cs index 86ef1645..c9d7d830 100644 --- a/src/SharpCompress/IO/ReadOnlySubStream.cs +++ b/src/SharpCompress/IO/ReadOnlySubStream.cs @@ -81,7 +81,7 @@ internal class ReadOnlySubStream : SharpCompressStream, IStreamStack return value; } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override int Read(Span buffer) { var sliceLen = BytesLeftToRead < buffer.Length ? BytesLeftToRead : buffer.Length; @@ -117,7 +117,7 @@ internal class ReadOnlySubStream : SharpCompressStream, IStreamStack return read; } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async ValueTask ReadAsync( Memory buffer, CancellationToken cancellationToken = default diff --git a/src/SharpCompress/IO/SharpCompressStream.cs b/src/SharpCompress/IO/SharpCompressStream.cs index 8da633d1..bc4cad50 100644 --- a/src/SharpCompress/IO/SharpCompressStream.cs +++ b/src/SharpCompress/IO/SharpCompressStream.cs @@ -384,7 +384,7 @@ public class SharpCompressStream : Stream, IStreamStack await Stream.FlushAsync(cancellationToken).ConfigureAwait(false); } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async ValueTask ReadAsync( Memory buffer, diff --git a/src/SharpCompress/IO/SourceStream.cs b/src/SharpCompress/IO/SourceStream.cs index 0712d915..e9cc74a6 100644 --- a/src/SharpCompress/IO/SourceStream.cs +++ b/src/SharpCompress/IO/SourceStream.cs @@ -289,7 +289,7 @@ public class SourceStream : Stream, IStreamStack return total - count; } -#if !NETFRAMEWORK && !NETSTANDARD2_0 +#if !LEGACY_DOTNET public override async ValueTask ReadAsync( Memory buffer, diff --git a/src/SharpCompress/NotNullExtensions.cs b/src/SharpCompress/NotNullExtensions.cs index 4fdd355c..0f5ba99c 100644 --- a/src/SharpCompress/NotNullExtensions.cs +++ b/src/SharpCompress/NotNullExtensions.cs @@ -21,7 +21,7 @@ internal static class NotNullExtensions return source.AsEnumerable(); } -#if NETFRAMEWORK || NETSTANDARD +#if LEGACY_DOTNET [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T NotNull(this T? obj, string? message = null) where T : class diff --git a/src/SharpCompress/Polyfills/StringExtensions.cs b/src/SharpCompress/Polyfills/StringExtensions.cs index 57d1e1bc..c83dee70 100644 --- a/src/SharpCompress/Polyfills/StringExtensions.cs +++ b/src/SharpCompress/Polyfills/StringExtensions.cs @@ -1,4 +1,4 @@ -#if NETFRAMEWORK || NETSTANDARD2_0 +#if LEGACY_DOTNET namespace SharpCompress; diff --git a/src/SharpCompress/Readers/AbstractReader.cs b/src/SharpCompress/Readers/AbstractReader.cs index bed01bd5..31423765 100644 --- a/src/SharpCompress/Readers/AbstractReader.cs +++ b/src/SharpCompress/Readers/AbstractReader.cs @@ -279,7 +279,7 @@ public abstract class AbstractReader : IReader, IAsyncReader } } //don't know the size so we have to try to decompress to skip -#if NETFRAMEWORK || NETSTANDARD2_0 +#if LEGACY_DOTNET using var s = await OpenEntryStreamAsync(cancellationToken).ConfigureAwait(false); await s.SkipEntryAsync(cancellationToken).ConfigureAwait(false); #else @@ -346,7 +346,7 @@ public abstract class AbstractReader : IReader, IAsyncReader internal async ValueTask WriteAsync(Stream writeStream, CancellationToken cancellationToken) { -#if NETFRAMEWORK || NETSTANDARD2_0 +#if LEGACY_DOTNET using Stream s = await OpenEntryStreamAsync(cancellationToken).ConfigureAwait(false); var sourceStream = WrapWithProgress(s, Entry); await sourceStream.CopyToAsync(writeStream, 81920, cancellationToken).ConfigureAwait(false); diff --git a/src/SharpCompress/SharpCompress.csproj b/src/SharpCompress/SharpCompress.csproj index a48b0b7a..2e9f4056 100644 --- a/src/SharpCompress/SharpCompress.csproj +++ b/src/SharpCompress/SharpCompress.csproj @@ -28,6 +28,9 @@ true $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + + $(DefineConstants);LEGACY_DOTNET + true diff --git a/src/SharpCompress/Utility.cs b/src/SharpCompress/Utility.cs index 5fd18e6b..5b3ed2dd 100644 --- a/src/SharpCompress/Utility.cs +++ b/src/SharpCompress/Utility.cs @@ -189,7 +189,7 @@ internal static class Utility } } -#if NET60_OR_GREATER +#if NET8_0_OR_GREATER public bool ReadFully(byte[] buffer) { try diff --git a/tests/SharpCompress.Test/Streams/DisposalTests.cs b/tests/SharpCompress.Test/Streams/DisposalTests.cs index 9d30ab76..08995892 100644 --- a/tests/SharpCompress.Test/Streams/DisposalTests.cs +++ b/tests/SharpCompress.Test/Streams/DisposalTests.cs @@ -2,6 +2,7 @@ using System; using System.IO; using SharpCompress.Common; using SharpCompress.Compressors; +using SharpCompress.Compressors.BZip2; using SharpCompress.Compressors.Deflate; using SharpCompress.Compressors.LZMA; using SharpCompress.Compressors.Lzw; @@ -152,9 +153,21 @@ public class DisposalTests [Fact] public void LZipStream_Disposal() { - // LZipStream always disposes inner stream + // LZipStream now supports leaveOpen parameter // Use Compress mode to avoid need for valid input header - VerifyAlwaysDispose(stream => new LZipStream(stream, CompressionMode.Compress)); + VerifyStreamDisposal( + (stream, leaveOpen) => new LZipStream(stream, CompressionMode.Compress, leaveOpen) + ); + } + + [Fact] + public void BZip2Stream_Disposal() + { + // BZip2Stream now supports leaveOpen parameter + VerifyStreamDisposal( + (stream, leaveOpen) => + new BZip2Stream(stream, CompressionMode.Compress, false, leaveOpen) + ); } [Fact] diff --git a/tests/SharpCompress.Test/Streams/LeaveOpenBehaviorTests.cs b/tests/SharpCompress.Test/Streams/LeaveOpenBehaviorTests.cs new file mode 100644 index 00000000..76e0565e --- /dev/null +++ b/tests/SharpCompress.Test/Streams/LeaveOpenBehaviorTests.cs @@ -0,0 +1,226 @@ +using System; +using System.IO; +using System.Text; +using SharpCompress.Compressors; +using SharpCompress.Compressors.BZip2; +using SharpCompress.Compressors.LZMA; +using SharpCompress.Test.Mocks; +using Xunit; + +namespace SharpCompress.Test.Streams; + +public class LeaveOpenBehaviorTests +{ + private static byte[] CreateTestData() => + Encoding.UTF8.GetBytes("The quick brown fox jumps over the lazy dog"); + + [Fact] + public void BZip2Stream_Compress_LeaveOpen_False() + { + using var innerStream = new TestStream(new MemoryStream()); + using ( + var bzip2 = new BZip2Stream( + innerStream, + CompressionMode.Compress, + false, + leaveOpen: false + ) + ) + { + bzip2.Write(CreateTestData(), 0, CreateTestData().Length); + bzip2.Finish(); + } + + Assert.True(innerStream.IsDisposed, "Inner stream should be disposed when leaveOpen=false"); + } + + [Fact] + public void BZip2Stream_Compress_LeaveOpen_True() + { + using var innerStream = new TestStream(new MemoryStream()); + byte[] compressed; + using ( + var bzip2 = new BZip2Stream( + innerStream, + CompressionMode.Compress, + false, + leaveOpen: true + ) + ) + { + bzip2.Write(CreateTestData(), 0, CreateTestData().Length); + bzip2.Finish(); + } + + Assert.False( + innerStream.IsDisposed, + "Inner stream should NOT be disposed when leaveOpen=true" + ); + + // Should be able to read the compressed data + innerStream.Position = 0; + compressed = new byte[innerStream.Length]; + innerStream.Read(compressed, 0, compressed.Length); + Assert.True(compressed.Length > 0); + } + + [Fact] + public void BZip2Stream_Decompress_LeaveOpen_False() + { + // First compress some data + var memStream = new MemoryStream(); + using (var bzip2 = new BZip2Stream(memStream, CompressionMode.Compress, false, true)) + { + bzip2.Write(CreateTestData(), 0, CreateTestData().Length); + bzip2.Finish(); + } + + memStream.Position = 0; + using var innerStream = new TestStream(memStream); + var decompressed = new byte[CreateTestData().Length]; + + using ( + var bzip2 = new BZip2Stream( + innerStream, + CompressionMode.Decompress, + false, + leaveOpen: false + ) + ) + { + bzip2.Read(decompressed, 0, decompressed.Length); + } + + Assert.True(innerStream.IsDisposed, "Inner stream should be disposed when leaveOpen=false"); + Assert.Equal(CreateTestData(), decompressed); + } + + [Fact] + public void BZip2Stream_Decompress_LeaveOpen_True() + { + // First compress some data + var memStream = new MemoryStream(); + using (var bzip2 = new BZip2Stream(memStream, CompressionMode.Compress, false, true)) + { + bzip2.Write(CreateTestData(), 0, CreateTestData().Length); + bzip2.Finish(); + } + + memStream.Position = 0; + using var innerStream = new TestStream(memStream); + var decompressed = new byte[CreateTestData().Length]; + + using ( + var bzip2 = new BZip2Stream( + innerStream, + CompressionMode.Decompress, + false, + leaveOpen: true + ) + ) + { + bzip2.Read(decompressed, 0, decompressed.Length); + } + + Assert.False( + innerStream.IsDisposed, + "Inner stream should NOT be disposed when leaveOpen=true" + ); + Assert.Equal(CreateTestData(), decompressed); + + // Should still be able to use the stream + innerStream.Position = 0; + Assert.True(innerStream.CanRead); + } + + [Fact] + public void LZipStream_Compress_LeaveOpen_False() + { + using var innerStream = new TestStream(new MemoryStream()); + using (var lzip = new LZipStream(innerStream, CompressionMode.Compress, leaveOpen: false)) + { + lzip.Write(CreateTestData(), 0, CreateTestData().Length); + lzip.Finish(); + } + + Assert.True(innerStream.IsDisposed, "Inner stream should be disposed when leaveOpen=false"); + } + + [Fact] + public void LZipStream_Compress_LeaveOpen_True() + { + using var innerStream = new TestStream(new MemoryStream()); + byte[] compressed; + using (var lzip = new LZipStream(innerStream, CompressionMode.Compress, leaveOpen: true)) + { + lzip.Write(CreateTestData(), 0, CreateTestData().Length); + lzip.Finish(); + } + + Assert.False( + innerStream.IsDisposed, + "Inner stream should NOT be disposed when leaveOpen=true" + ); + + // Should be able to read the compressed data + innerStream.Position = 0; + compressed = new byte[innerStream.Length]; + innerStream.Read(compressed, 0, compressed.Length); + Assert.True(compressed.Length > 0); + } + + [Fact] + public void LZipStream_Decompress_LeaveOpen_False() + { + // First compress some data + var memStream = new MemoryStream(); + using (var lzip = new LZipStream(memStream, CompressionMode.Compress, true)) + { + lzip.Write(CreateTestData(), 0, CreateTestData().Length); + lzip.Finish(); + } + + memStream.Position = 0; + using var innerStream = new TestStream(memStream); + var decompressed = new byte[CreateTestData().Length]; + + using (var lzip = new LZipStream(innerStream, CompressionMode.Decompress, leaveOpen: false)) + { + lzip.Read(decompressed, 0, decompressed.Length); + } + + Assert.True(innerStream.IsDisposed, "Inner stream should be disposed when leaveOpen=false"); + Assert.Equal(CreateTestData(), decompressed); + } + + [Fact] + public void LZipStream_Decompress_LeaveOpen_True() + { + // First compress some data + var memStream = new MemoryStream(); + using (var lzip = new LZipStream(memStream, CompressionMode.Compress, true)) + { + lzip.Write(CreateTestData(), 0, CreateTestData().Length); + lzip.Finish(); + } + + memStream.Position = 0; + using var innerStream = new TestStream(memStream); + var decompressed = new byte[CreateTestData().Length]; + + using (var lzip = new LZipStream(innerStream, CompressionMode.Decompress, leaveOpen: true)) + { + lzip.Read(decompressed, 0, decompressed.Length); + } + + Assert.False( + innerStream.IsDisposed, + "Inner stream should NOT be disposed when leaveOpen=true" + ); + Assert.Equal(CreateTestData(), decompressed); + + // Should still be able to use the stream + innerStream.Position = 0; + Assert.True(innerStream.CanRead); + } +}