From 38d295b089370c1cc1dadf2a30c27a16f1c8a8f3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Feb 2026 10:23:41 +0000 Subject: [PATCH 01/12] Initial plan From 2b74807f5eb9cb9098dda456005107d61fc043b6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Feb 2026 10:29:18 +0000 Subject: [PATCH 02/12] Implement LzwReader support for .Z archives - Add Lzw to ArchiveType enum - Create Common/Lzw classes (LzwEntry, LzwVolume, LzwFilePart) - Create Readers/Lzw/LzwReader with factory methods - Create LzwFactory for integration with ReaderFactory - Add comprehensive tests in Lzw test directory - Update ReaderFactory error message to include Lzw format Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- src/SharpCompress/Common/ArchiveType.cs | 1 + .../Common/Lzw/LzwEntry.Async.cs | 20 ++++++ src/SharpCompress/Common/Lzw/LzwEntry.cs | 47 +++++++++++++ .../Common/Lzw/LzwFilePart.Async.cs | 30 +++++++++ src/SharpCompress/Common/Lzw/LzwFilePart.cs | 38 +++++++++++ src/SharpCompress/Common/Lzw/LzwVolume.cs | 17 +++++ src/SharpCompress/Factories/Factory.cs | 1 + src/SharpCompress/Factories/LzwFactory.cs | 67 +++++++++++++++++++ .../Readers/Lzw/LzwReader.Async.cs | 15 +++++ .../Readers/Lzw/LzwReader.Factory.cs | 59 ++++++++++++++++ src/SharpCompress/Readers/Lzw/LzwReader.cs | 19 ++++++ src/SharpCompress/Readers/ReaderFactory.cs | 2 +- .../Lzw/LzwReaderAsyncTests.cs | 15 +++++ .../SharpCompress.Test/Lzw/LzwReaderTests.cs | 38 +++++++++++ 14 files changed, 368 insertions(+), 1 deletion(-) create mode 100644 src/SharpCompress/Common/Lzw/LzwEntry.Async.cs create mode 100644 src/SharpCompress/Common/Lzw/LzwEntry.cs create mode 100644 src/SharpCompress/Common/Lzw/LzwFilePart.Async.cs create mode 100644 src/SharpCompress/Common/Lzw/LzwFilePart.cs create mode 100644 src/SharpCompress/Common/Lzw/LzwVolume.cs create mode 100644 src/SharpCompress/Factories/LzwFactory.cs create mode 100644 src/SharpCompress/Readers/Lzw/LzwReader.Async.cs create mode 100644 src/SharpCompress/Readers/Lzw/LzwReader.Factory.cs create mode 100644 src/SharpCompress/Readers/Lzw/LzwReader.cs create mode 100644 tests/SharpCompress.Test/Lzw/LzwReaderAsyncTests.cs create mode 100644 tests/SharpCompress.Test/Lzw/LzwReaderTests.cs diff --git a/src/SharpCompress/Common/ArchiveType.cs b/src/SharpCompress/Common/ArchiveType.cs index 5952f645..ae95af76 100644 --- a/src/SharpCompress/Common/ArchiveType.cs +++ b/src/SharpCompress/Common/ArchiveType.cs @@ -10,4 +10,5 @@ public enum ArchiveType Arc, Arj, Ace, + Lzw, } diff --git a/src/SharpCompress/Common/Lzw/LzwEntry.Async.cs b/src/SharpCompress/Common/Lzw/LzwEntry.Async.cs new file mode 100644 index 00000000..9ea826b5 --- /dev/null +++ b/src/SharpCompress/Common/Lzw/LzwEntry.Async.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using System.IO; +using System.Runtime.CompilerServices; +using System.Threading; + +namespace SharpCompress.Common.Lzw; + +public partial class LzwEntry +{ + internal static async IAsyncEnumerable GetEntriesAsync( + Stream stream, + OptionsBase options, + [EnumeratorCancellation] CancellationToken cancellationToken = default + ) + { + yield return new LzwEntry( + await LzwFilePart.CreateAsync(stream, options.ArchiveEncoding, cancellationToken) + ); + } +} diff --git a/src/SharpCompress/Common/Lzw/LzwEntry.cs b/src/SharpCompress/Common/Lzw/LzwEntry.cs new file mode 100644 index 00000000..ab74910a --- /dev/null +++ b/src/SharpCompress/Common/Lzw/LzwEntry.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace SharpCompress.Common.Lzw; + +public partial class LzwEntry : Entry +{ + private readonly LzwFilePart? _filePart; + + internal LzwEntry(LzwFilePart? filePart) => _filePart = filePart; + + public override CompressionType CompressionType => CompressionType.Lzw; + + public override long Crc => 0; + + public override string? Key => _filePart?.FilePartName; + + public override string? LinkTarget => null; + + public override long CompressedSize => 0; + + public override long Size => 0; + + public override DateTime? LastModifiedTime => null; + + public override DateTime? CreatedTime => null; + + public override DateTime? LastAccessedTime => null; + + public override DateTime? ArchivedTime => null; + + public override bool IsEncrypted => false; + + public override bool IsDirectory => false; + + public override bool IsSplitAfter => false; + + internal override IEnumerable Parts => _filePart.Empty(); + + internal static IEnumerable GetEntries(Stream stream, OptionsBase options) + { + yield return new LzwEntry(LzwFilePart.Create(stream, options.ArchiveEncoding)); + } + + // Async methods moved to LzwEntry.Async.cs +} diff --git a/src/SharpCompress/Common/Lzw/LzwFilePart.Async.cs b/src/SharpCompress/Common/Lzw/LzwFilePart.Async.cs new file mode 100644 index 00000000..c26f33bf --- /dev/null +++ b/src/SharpCompress/Common/Lzw/LzwFilePart.Async.cs @@ -0,0 +1,30 @@ +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace SharpCompress.Common.Lzw; + +internal sealed partial class LzwFilePart +{ + internal static async ValueTask CreateAsync( + Stream stream, + IArchiveEncoding archiveEncoding, + CancellationToken cancellationToken = default + ) + { + cancellationToken.ThrowIfCancellationRequested(); + var part = new LzwFilePart(stream, archiveEncoding); + + if (stream.CanSeek) + { + part.EntryStartPosition = stream.Position; + } + else + { + // For non-seekable streams, we can't track position. + // Set to 0 since the stream will be read sequentially from its current position. + part.EntryStartPosition = 0; + } + return part; + } +} diff --git a/src/SharpCompress/Common/Lzw/LzwFilePart.cs b/src/SharpCompress/Common/Lzw/LzwFilePart.cs new file mode 100644 index 00000000..dcf2946d --- /dev/null +++ b/src/SharpCompress/Common/Lzw/LzwFilePart.cs @@ -0,0 +1,38 @@ +using System.IO; +using SharpCompress.Compressors.Lzw; + +namespace SharpCompress.Common.Lzw; + +internal sealed partial class LzwFilePart : FilePart +{ + private readonly Stream _stream; + + internal static LzwFilePart Create(Stream stream, IArchiveEncoding archiveEncoding) + { + var part = new LzwFilePart(stream, archiveEncoding); + + if (stream.CanSeek) + { + part.EntryStartPosition = stream.Position; + } + else + { + // For non-seekable streams, we can't track position. + // Set to 0 since the stream will be read sequentially from its current position. + part.EntryStartPosition = 0; + } + return part; + } + + private LzwFilePart(Stream stream, IArchiveEncoding archiveEncoding) + : base(archiveEncoding) => _stream = stream; + + internal long EntryStartPosition { get; private set; } + + internal override string? FilePartName => null; + + internal override Stream GetCompressedStream() => + new LzwStream(_stream) { IsStreamOwner = false }; + + internal override Stream GetRawStream() => _stream; +} diff --git a/src/SharpCompress/Common/Lzw/LzwVolume.cs b/src/SharpCompress/Common/Lzw/LzwVolume.cs new file mode 100644 index 00000000..83060cf5 --- /dev/null +++ b/src/SharpCompress/Common/Lzw/LzwVolume.cs @@ -0,0 +1,17 @@ +using System.IO; +using SharpCompress.Readers; + +namespace SharpCompress.Common.Lzw; + +public class LzwVolume : Volume +{ + public LzwVolume(Stream stream, ReaderOptions? options, int index) + : base(stream, options, index) { } + + public LzwVolume(FileInfo fileInfo, ReaderOptions options) + : base(fileInfo.OpenRead(), options) => options.LeaveStreamOpen = false; + + public override bool IsFirstVolume => true; + + public override bool IsMultiVolume => true; +} diff --git a/src/SharpCompress/Factories/Factory.cs b/src/SharpCompress/Factories/Factory.cs index 7bca8ecb..69254cad 100644 --- a/src/SharpCompress/Factories/Factory.cs +++ b/src/SharpCompress/Factories/Factory.cs @@ -18,6 +18,7 @@ public abstract class Factory : IFactory RegisterFactory(new RarFactory()); RegisterFactory(new TarFactory()); //put tar before most RegisterFactory(new GZipFactory()); + RegisterFactory(new LzwFactory()); RegisterFactory(new ArcFactory()); RegisterFactory(new ArjFactory()); RegisterFactory(new AceFactory()); diff --git a/src/SharpCompress/Factories/LzwFactory.cs b/src/SharpCompress/Factories/LzwFactory.cs new file mode 100644 index 00000000..e60451ac --- /dev/null +++ b/src/SharpCompress/Factories/LzwFactory.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using SharpCompress.Common; +using SharpCompress.Compressors.Lzw; +using SharpCompress.IO; +using SharpCompress.Readers; +using SharpCompress.Readers.Lzw; + +namespace SharpCompress.Factories; + +/// +/// Represents the foundation factory of LZW archive. +/// +public class LzwFactory : Factory, IReaderFactory +{ + #region IFactory + + /// + public override string Name => "Lzw"; + + /// + public override ArchiveType? KnownArchiveType => ArchiveType.Lzw; + + /// + public override IEnumerable GetSupportedExtensions() + { + yield return "Z"; + } + + /// + public override bool IsArchive(Stream stream, string? password = null) => + LzwStream.IsLzwStream(stream); + + /// + public override ValueTask IsArchiveAsync( + Stream stream, + string? password = null, + CancellationToken cancellationToken = default + ) + { + cancellationToken.ThrowIfCancellationRequested(); + return new(IsArchive(stream, password)); + } + + #endregion + + #region IReaderFactory + + /// + public IReader OpenReader(Stream stream, ReaderOptions? options) => + LzwReader.OpenReader(stream, options); + + /// + public ValueTask OpenAsyncReader( + Stream stream, + ReaderOptions? options, + CancellationToken cancellationToken = default + ) + { + cancellationToken.ThrowIfCancellationRequested(); + return new((IAsyncReader)LzwReader.OpenReader(stream, options)); + } + + #endregion +} diff --git a/src/SharpCompress/Readers/Lzw/LzwReader.Async.cs b/src/SharpCompress/Readers/Lzw/LzwReader.Async.cs new file mode 100644 index 00000000..6479c9b5 --- /dev/null +++ b/src/SharpCompress/Readers/Lzw/LzwReader.Async.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common; +using SharpCompress.Common.Lzw; + +namespace SharpCompress.Readers.Lzw; + +public partial class LzwReader +{ + /// + /// Returns entries asynchronously for streams that only support async reads. + /// + protected override IAsyncEnumerable GetEntriesAsync(Stream stream) => + LzwEntry.GetEntriesAsync(stream, Options); +} diff --git a/src/SharpCompress/Readers/Lzw/LzwReader.Factory.cs b/src/SharpCompress/Readers/Lzw/LzwReader.Factory.cs new file mode 100644 index 00000000..59448f14 --- /dev/null +++ b/src/SharpCompress/Readers/Lzw/LzwReader.Factory.cs @@ -0,0 +1,59 @@ +using System.IO; +using System.Threading; + +namespace SharpCompress.Readers.Lzw; + +public partial class LzwReader +#if NET8_0_OR_GREATER + : IReaderOpenable +#endif +{ + public static IAsyncReader OpenAsyncReader( + string path, + ReaderOptions? readerOptions = null, + CancellationToken cancellationToken = default + ) + { + cancellationToken.ThrowIfCancellationRequested(); + path.NotNullOrEmpty(nameof(path)); + return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions); + } + + public static IAsyncReader OpenAsyncReader( + Stream stream, + ReaderOptions? readerOptions = null, + CancellationToken cancellationToken = default + ) + { + cancellationToken.ThrowIfCancellationRequested(); + return (IAsyncReader)OpenReader(stream, readerOptions); + } + + public static IAsyncReader OpenAsyncReader( + FileInfo fileInfo, + ReaderOptions? readerOptions = null, + CancellationToken cancellationToken = default + ) + { + cancellationToken.ThrowIfCancellationRequested(); + return (IAsyncReader)OpenReader(fileInfo, readerOptions); + } + + public static IReader OpenReader(string filePath, ReaderOptions? readerOptions = null) + { + filePath.NotNullOrEmpty(nameof(filePath)); + return OpenReader(new FileInfo(filePath), readerOptions); + } + + public static IReader OpenReader(FileInfo fileInfo, ReaderOptions? readerOptions = null) + { + fileInfo.NotNull(nameof(fileInfo)); + return OpenReader(fileInfo.OpenRead(), readerOptions); + } + + public static IReader OpenReader(Stream stream, ReaderOptions? options = null) + { + stream.NotNull(nameof(stream)); + return new LzwReader(stream, options ?? new ReaderOptions()); + } +} diff --git a/src/SharpCompress/Readers/Lzw/LzwReader.cs b/src/SharpCompress/Readers/Lzw/LzwReader.cs new file mode 100644 index 00000000..875faf7a --- /dev/null +++ b/src/SharpCompress/Readers/Lzw/LzwReader.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common; +using SharpCompress.Common.Lzw; + +namespace SharpCompress.Readers.Lzw; + +public partial class LzwReader : AbstractReader +{ + private LzwReader(Stream stream, ReaderOptions options) + : base(options, ArchiveType.Lzw) => Volume = new LzwVolume(stream, options, 0); + + public override LzwVolume Volume { get; } + + protected override IEnumerable GetEntries(Stream stream) => + LzwEntry.GetEntries(stream, Options); + + // GetEntriesAsync moved to LzwReader.Async.cs +} diff --git a/src/SharpCompress/Readers/ReaderFactory.cs b/src/SharpCompress/Readers/ReaderFactory.cs index 186efb64..5cdc403a 100644 --- a/src/SharpCompress/Readers/ReaderFactory.cs +++ b/src/SharpCompress/Readers/ReaderFactory.cs @@ -77,7 +77,7 @@ public static partial class ReaderFactory } throw new InvalidFormatException( - "Cannot determine compressed stream type. Supported Reader Formats: Ace, Arc, Arj, Zip, GZip, BZip2, Tar, Rar, LZip, XZ, ZStandard" + "Cannot determine compressed stream type. Supported Reader Formats: Ace, Arc, Arj, Zip, GZip, BZip2, Tar, Rar, LZip, Lzw, XZ, ZStandard" ); } } diff --git a/tests/SharpCompress.Test/Lzw/LzwReaderAsyncTests.cs b/tests/SharpCompress.Test/Lzw/LzwReaderAsyncTests.cs new file mode 100644 index 00000000..b9083138 --- /dev/null +++ b/tests/SharpCompress.Test/Lzw/LzwReaderAsyncTests.cs @@ -0,0 +1,15 @@ +using SharpCompress.Common; +using Xunit; + +namespace SharpCompress.Test.Lzw; + +public class LzwReaderAsyncTests : ReaderTests +{ + public LzwReaderAsyncTests() => UseExtensionInsteadOfNameToVerify = true; + + [Fact] + public async System.Threading.Tasks.Task Lzw_Reader_Async() + { + await ReadAsync("Tar.tar.Z", CompressionType.Lzw); + } +} diff --git a/tests/SharpCompress.Test/Lzw/LzwReaderTests.cs b/tests/SharpCompress.Test/Lzw/LzwReaderTests.cs new file mode 100644 index 00000000..4653a993 --- /dev/null +++ b/tests/SharpCompress.Test/Lzw/LzwReaderTests.cs @@ -0,0 +1,38 @@ +using System.IO; +using SharpCompress.Common; +using SharpCompress.IO; +using SharpCompress.Readers; +using SharpCompress.Readers.Lzw; +using Xunit; + +namespace SharpCompress.Test.Lzw; + +public class LzwReaderTests : ReaderTests +{ + public LzwReaderTests() => UseExtensionInsteadOfNameToVerify = true; + + [Fact] + public void Lzw_Reader_Generic() => Read("Tar.tar.Z", CompressionType.Lzw); + + [Fact] + public void Lzw_Reader_Generic2() + { + //read only as Lzw item + using Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.Z")); + using var reader = LzwReader.OpenReader(SharpCompressStream.CreateNonDisposing(stream)); + while (reader.MoveToNextEntry()) + { + // LZW doesn't have CRC or Size in header like GZip, so we just check the entry exists + Assert.NotNull(reader.Entry); + } + } + + [Fact] + public void Lzw_Reader_Factory_Detects_Format() + { + using Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.Z")); + using var reader = ReaderFactory.OpenReader(stream, new ReaderOptions { LeaveStreamOpen = false }); + Assert.True(reader.MoveToNextEntry()); + Assert.NotNull(reader.Entry); + } +} From 1da178a4be0705437a700baaf68cfdb7a135cd66 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Feb 2026 10:30:00 +0000 Subject: [PATCH 03/12] Run code formatter on LzwReader implementation Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- tests/SharpCompress.Test/Lzw/LzwReaderTests.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/SharpCompress.Test/Lzw/LzwReaderTests.cs b/tests/SharpCompress.Test/Lzw/LzwReaderTests.cs index 4653a993..7802a6ed 100644 --- a/tests/SharpCompress.Test/Lzw/LzwReaderTests.cs +++ b/tests/SharpCompress.Test/Lzw/LzwReaderTests.cs @@ -31,7 +31,10 @@ public class LzwReaderTests : ReaderTests public void Lzw_Reader_Factory_Detects_Format() { using Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.Z")); - using var reader = ReaderFactory.OpenReader(stream, new ReaderOptions { LeaveStreamOpen = false }); + using var reader = ReaderFactory.OpenReader( + stream, + new ReaderOptions { LeaveStreamOpen = false } + ); Assert.True(reader.MoveToNextEntry()); Assert.NotNull(reader.Entry); } From 7b746c49cfbbd0ad7ae4b3cabcfcebf5a4af8e28 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Feb 2026 10:30:56 +0000 Subject: [PATCH 04/12] Fix code review issues: LzwVolume multi-volume flag and extension case Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- src/SharpCompress/Common/Lzw/LzwVolume.cs | 2 +- src/SharpCompress/Factories/LzwFactory.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SharpCompress/Common/Lzw/LzwVolume.cs b/src/SharpCompress/Common/Lzw/LzwVolume.cs index 83060cf5..46cd8d25 100644 --- a/src/SharpCompress/Common/Lzw/LzwVolume.cs +++ b/src/SharpCompress/Common/Lzw/LzwVolume.cs @@ -13,5 +13,5 @@ public class LzwVolume : Volume public override bool IsFirstVolume => true; - public override bool IsMultiVolume => true; + public override bool IsMultiVolume => false; } diff --git a/src/SharpCompress/Factories/LzwFactory.cs b/src/SharpCompress/Factories/LzwFactory.cs index e60451ac..00083c3d 100644 --- a/src/SharpCompress/Factories/LzwFactory.cs +++ b/src/SharpCompress/Factories/LzwFactory.cs @@ -26,7 +26,7 @@ public class LzwFactory : Factory, IReaderFactory /// public override IEnumerable GetSupportedExtensions() { - yield return "Z"; + yield return "z"; } /// From 0048452efa02aeecbf7df49b08fd6612bd733881 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Mon, 9 Feb 2026 09:59:49 +0000 Subject: [PATCH 05/12] Remove cancellation tokens for factory methods that aren't async --- .../Archives/ArchiveFactory.Async.cs | 2 +- .../Archives/GZip/GZipArchive.Factory.cs | 20 ++++---------- .../Archives/IArchiveOpenable.cs | 9 +++---- .../Archives/IMultiArchiveFactory.cs | 4 +-- .../Archives/IMultiArchiveOpenable.cs | 6 ++--- .../Archives/Rar/RarArchive.Factory.cs | 20 ++++---------- .../SevenZip/SevenZipArchive.Factory.cs | 26 ++++--------------- .../Archives/Tar/TarArchive.Factory.cs | 20 ++++---------- .../Archives/Zip/ZipArchive.Factory.cs | 20 ++++---------- src/SharpCompress/Factories/GZipFactory.cs | 11 ++------ src/SharpCompress/Factories/LzwFactory.cs | 2 +- src/SharpCompress/Factories/RarFactory.cs | 4 +-- .../Factories/SevenZipFactory.cs | 11 ++++---- src/SharpCompress/Factories/TarFactory.cs | 11 ++------ src/SharpCompress/Factories/ZipFactory.cs | 11 ++------ .../Readers/Ace/AceReader.Factory.cs | 19 +++----------- .../Readers/Arc/ArcReader.Factory.cs | 19 +++----------- .../Readers/Arj/ArjReader.Factory.cs | 19 +++----------- .../Readers/GZip/GZipReader.Factory.cs | 19 +++----------- src/SharpCompress/Readers/IReaderOpenable.cs | 9 +++---- .../Readers/Lzw/LzwReader.Factory.cs | 19 +++----------- .../Readers/Rar/RarReader.Factory.cs | 19 +++----------- .../Readers/Tar/TarReader.Factory.cs | 19 +++----------- .../Readers/Zip/ZipReader.Factory.cs | 19 +++----------- .../Writers/GZip/GZipWriter.Factory.cs | 22 +++------------- src/SharpCompress/Writers/IWriterFactory.cs | 7 +---- src/SharpCompress/Writers/IWriterOpenable.cs | 10 +++---- .../Writers/Tar/TarWriter.Factory.cs | 22 +++------------- src/SharpCompress/Writers/WriterFactory.cs | 23 +++++----------- .../Writers/Zip/ZipWriter.Factory.cs | 22 +++------------- tests/SharpCompress.Test/ReaderTests.cs | 3 +-- tests/SharpCompress.Test/WriterTests.cs | 3 +-- 32 files changed, 93 insertions(+), 357 deletions(-) diff --git a/src/SharpCompress/Archives/ArchiveFactory.Async.cs b/src/SharpCompress/Archives/ArchiveFactory.Async.cs index 59e16c31..8339171c 100644 --- a/src/SharpCompress/Archives/ArchiveFactory.Async.cs +++ b/src/SharpCompress/Archives/ArchiveFactory.Async.cs @@ -69,7 +69,7 @@ public static partial class ArchiveFactory options ??= new ReaderOptions { LeaveStreamOpen = false }; var factory = await FindFactoryAsync(fileInfo, cancellationToken); - return factory.OpenAsyncArchive(filesArray, options, cancellationToken); + return factory.OpenAsyncArchive(filesArray, options); } public static async ValueTask OpenAsyncArchive( diff --git a/src/SharpCompress/Archives/GZip/GZipArchive.Factory.cs b/src/SharpCompress/Archives/GZip/GZipArchive.Factory.cs index e793cd9b..56d4c541 100644 --- a/src/SharpCompress/Archives/GZip/GZipArchive.Factory.cs +++ b/src/SharpCompress/Archives/GZip/GZipArchive.Factory.cs @@ -23,11 +23,9 @@ public partial class GZipArchive { public static IWritableAsyncArchive OpenAsyncArchive( string path, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); path.NotNullOrEmpty(nameof(path)); return (IWritableAsyncArchive)OpenArchive( new FileInfo(path), @@ -104,41 +102,33 @@ public partial class GZipArchive public static IWritableAsyncArchive OpenAsyncArchive( Stream stream, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IWritableAsyncArchive)OpenArchive(stream, readerOptions); } public static IWritableAsyncArchive OpenAsyncArchive( FileInfo fileInfo, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IWritableAsyncArchive)OpenArchive(fileInfo, readerOptions); } public static IWritableAsyncArchive OpenAsyncArchive( IReadOnlyList streams, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IWritableAsyncArchive)OpenArchive(streams, readerOptions); } public static IWritableAsyncArchive OpenAsyncArchive( IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IWritableAsyncArchive)OpenArchive(fileInfos, readerOptions); } diff --git a/src/SharpCompress/Archives/IArchiveOpenable.cs b/src/SharpCompress/Archives/IArchiveOpenable.cs index e5ae52b3..e36ea02b 100644 --- a/src/SharpCompress/Archives/IArchiveOpenable.cs +++ b/src/SharpCompress/Archives/IArchiveOpenable.cs @@ -20,20 +20,17 @@ public interface IArchiveOpenable public static abstract TASync OpenAsyncArchive( string path, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ); public static abstract TASync OpenAsyncArchive( Stream stream, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ); public static abstract TASync OpenAsyncArchive( FileInfo fileInfo, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ); } diff --git a/src/SharpCompress/Archives/IMultiArchiveFactory.cs b/src/SharpCompress/Archives/IMultiArchiveFactory.cs index fc418ad4..936222e6 100644 --- a/src/SharpCompress/Archives/IMultiArchiveFactory.cs +++ b/src/SharpCompress/Archives/IMultiArchiveFactory.cs @@ -50,10 +50,8 @@ public interface IMultiArchiveFactory : IFactory /// /// /// reading options. - /// Cancellation token. IAsyncArchive OpenAsyncArchive( IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ); } diff --git a/src/SharpCompress/Archives/IMultiArchiveOpenable.cs b/src/SharpCompress/Archives/IMultiArchiveOpenable.cs index 53f375c0..0fed7adb 100644 --- a/src/SharpCompress/Archives/IMultiArchiveOpenable.cs +++ b/src/SharpCompress/Archives/IMultiArchiveOpenable.cs @@ -22,14 +22,12 @@ public interface IMultiArchiveOpenable public static abstract TASync OpenAsyncArchive( IReadOnlyList streams, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ); public static abstract TASync OpenAsyncArchive( IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ); } #endif diff --git a/src/SharpCompress/Archives/Rar/RarArchive.Factory.cs b/src/SharpCompress/Archives/Rar/RarArchive.Factory.cs index fe1eb5c3..76154b7f 100644 --- a/src/SharpCompress/Archives/Rar/RarArchive.Factory.cs +++ b/src/SharpCompress/Archives/Rar/RarArchive.Factory.cs @@ -22,11 +22,9 @@ public partial class RarArchive { public static IRarAsyncArchive OpenAsyncArchive( string path, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); path.NotNullOrEmpty(nameof(path)); return (IRarAsyncArchive)OpenArchive(new FileInfo(path), readerOptions); } @@ -102,41 +100,33 @@ public partial class RarArchive public static IRarAsyncArchive OpenAsyncArchive( Stream stream, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IRarAsyncArchive)OpenArchive(stream, readerOptions); } public static IRarAsyncArchive OpenAsyncArchive( FileInfo fileInfo, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IRarAsyncArchive)OpenArchive(fileInfo, readerOptions); } public static IRarAsyncArchive OpenAsyncArchive( IReadOnlyList streams, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IRarAsyncArchive)OpenArchive(streams, readerOptions); } public static IRarAsyncArchive OpenAsyncArchive( IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IRarAsyncArchive)OpenArchive(fileInfos, readerOptions); } diff --git a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.Factory.cs b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.Factory.cs index 614c4408..2748e07c 100644 --- a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.Factory.cs +++ b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.Factory.cs @@ -16,13 +16,8 @@ public partial class SevenZipArchive IMultiArchiveOpenable #endif { - public static IAsyncArchive OpenAsyncArchive( - string path, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) + public static IAsyncArchive OpenAsyncArchive(string path, ReaderOptions? readerOptions = null) { - cancellationToken.ThrowIfCancellationRequested(); path.NotNullOrEmpty("path"); return (IAsyncArchive)OpenArchive(new FileInfo(path), readerOptions ?? new ReaderOptions()); } @@ -91,43 +86,32 @@ public partial class SevenZipArchive ); } - public static IAsyncArchive OpenAsyncArchive( - Stream stream, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) + public static IAsyncArchive OpenAsyncArchive(Stream stream, ReaderOptions? readerOptions = null) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncArchive)OpenArchive(stream, readerOptions); } public static IAsyncArchive OpenAsyncArchive( FileInfo fileInfo, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncArchive)OpenArchive(fileInfo, readerOptions); } public static IAsyncArchive OpenAsyncArchive( IReadOnlyList streams, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncArchive)OpenArchive(streams, readerOptions); } public static IAsyncArchive OpenAsyncArchive( IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncArchive)OpenArchive(fileInfos, readerOptions); } diff --git a/src/SharpCompress/Archives/Tar/TarArchive.Factory.cs b/src/SharpCompress/Archives/Tar/TarArchive.Factory.cs index 959b4ab4..ad8bd8ab 100644 --- a/src/SharpCompress/Archives/Tar/TarArchive.Factory.cs +++ b/src/SharpCompress/Archives/Tar/TarArchive.Factory.cs @@ -87,51 +87,41 @@ public partial class TarArchive public static IWritableAsyncArchive OpenAsyncArchive( Stream stream, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IWritableAsyncArchive)OpenArchive(stream, readerOptions); } public static IWritableAsyncArchive OpenAsyncArchive( string path, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IWritableAsyncArchive)OpenArchive(new FileInfo(path), readerOptions); } public static IWritableAsyncArchive OpenAsyncArchive( FileInfo fileInfo, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IWritableAsyncArchive)OpenArchive(fileInfo, readerOptions); } public static IWritableAsyncArchive OpenAsyncArchive( IReadOnlyList streams, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IWritableAsyncArchive)OpenArchive(streams, readerOptions); } public static IWritableAsyncArchive OpenAsyncArchive( IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IWritableAsyncArchive)OpenArchive(fileInfos, readerOptions); } diff --git a/src/SharpCompress/Archives/Zip/ZipArchive.Factory.cs b/src/SharpCompress/Archives/Zip/ZipArchive.Factory.cs index 4904decb..c4ddc86a 100644 --- a/src/SharpCompress/Archives/Zip/ZipArchive.Factory.cs +++ b/src/SharpCompress/Archives/Zip/ZipArchive.Factory.cs @@ -87,51 +87,41 @@ public partial class ZipArchive public static IWritableAsyncArchive OpenAsyncArchive( string path, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IWritableAsyncArchive)OpenArchive(path, readerOptions); } public static IWritableAsyncArchive OpenAsyncArchive( Stream stream, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IWritableAsyncArchive)OpenArchive(stream, readerOptions); } public static IWritableAsyncArchive OpenAsyncArchive( FileInfo fileInfo, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IWritableAsyncArchive)OpenArchive(fileInfo, readerOptions); } public static IWritableAsyncArchive OpenAsyncArchive( IReadOnlyList streams, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IWritableAsyncArchive)OpenArchive(streams, readerOptions); } public static IWritableAsyncArchive OpenAsyncArchive( IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IWritableAsyncArchive)OpenArchive(fileInfos, readerOptions); } diff --git a/src/SharpCompress/Factories/GZipFactory.cs b/src/SharpCompress/Factories/GZipFactory.cs index ae4ac8b8..1030c63a 100644 --- a/src/SharpCompress/Factories/GZipFactory.cs +++ b/src/SharpCompress/Factories/GZipFactory.cs @@ -93,11 +93,9 @@ public class GZipFactory /// public IAsyncArchive OpenAsyncArchive( IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncArchive)OpenArchive(fileInfos, readerOptions); } @@ -166,13 +164,8 @@ public class GZipFactory } /// - public IAsyncWriter OpenAsyncWriter( - Stream stream, - WriterOptions writerOptions, - CancellationToken cancellationToken = default - ) + public IAsyncWriter OpenAsyncWriter(Stream stream, WriterOptions writerOptions) { - cancellationToken.ThrowIfCancellationRequested(); if (writerOptions.CompressionType != CompressionType.GZip) { throw new InvalidFormatException("GZip archives only support GZip compression type."); diff --git a/src/SharpCompress/Factories/LzwFactory.cs b/src/SharpCompress/Factories/LzwFactory.cs index 00083c3d..b9767064 100644 --- a/src/SharpCompress/Factories/LzwFactory.cs +++ b/src/SharpCompress/Factories/LzwFactory.cs @@ -60,7 +60,7 @@ public class LzwFactory : Factory, IReaderFactory ) { cancellationToken.ThrowIfCancellationRequested(); - return new((IAsyncReader)LzwReader.OpenReader(stream, options)); + return new(LzwReader.OpenAsyncReader(stream, options)); } #endregion diff --git a/src/SharpCompress/Factories/RarFactory.cs b/src/SharpCompress/Factories/RarFactory.cs index 11fe6cf8..f3236d2e 100644 --- a/src/SharpCompress/Factories/RarFactory.cs +++ b/src/SharpCompress/Factories/RarFactory.cs @@ -90,11 +90,9 @@ public class RarFactory : Factory, IArchiveFactory, IMultiArchiveFactory, IReade /// public IAsyncArchive OpenAsyncArchive( IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncArchive)OpenArchive(fileInfos, readerOptions); } diff --git a/src/SharpCompress/Factories/SevenZipFactory.cs b/src/SharpCompress/Factories/SevenZipFactory.cs index f8f4b779..0a276223 100644 --- a/src/SharpCompress/Factories/SevenZipFactory.cs +++ b/src/SharpCompress/Factories/SevenZipFactory.cs @@ -50,7 +50,7 @@ public class SevenZipFactory : Factory, IArchiveFactory, IMultiArchiveFactory /// public IAsyncArchive OpenAsyncArchive(Stream stream, ReaderOptions? readerOptions = null) => - SevenZipArchive.OpenAsyncArchive(stream, readerOptions, CancellationToken.None); + SevenZipArchive.OpenAsyncArchive(stream, readerOptions); /// public IArchive OpenArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) => @@ -58,7 +58,7 @@ public class SevenZipFactory : Factory, IArchiveFactory, IMultiArchiveFactory /// public IAsyncArchive OpenAsyncArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) => - SevenZipArchive.OpenAsyncArchive(fileInfo, readerOptions, CancellationToken.None); + SevenZipArchive.OpenAsyncArchive(fileInfo, readerOptions); #endregion @@ -74,7 +74,7 @@ public class SevenZipFactory : Factory, IArchiveFactory, IMultiArchiveFactory public IAsyncArchive OpenAsyncArchive( IReadOnlyList streams, ReaderOptions? readerOptions = null - ) => SevenZipArchive.OpenAsyncArchive(streams, readerOptions, CancellationToken.None); + ) => SevenZipArchive.OpenAsyncArchive(streams, readerOptions); /// public IArchive OpenArchive( @@ -85,9 +85,8 @@ public class SevenZipFactory : Factory, IArchiveFactory, IMultiArchiveFactory /// public IAsyncArchive OpenAsyncArchive( IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) => SevenZipArchive.OpenAsyncArchive(fileInfos, readerOptions, cancellationToken); + ReaderOptions? readerOptions = null + ) => SevenZipArchive.OpenAsyncArchive(fileInfos, readerOptions); #endregion diff --git a/src/SharpCompress/Factories/TarFactory.cs b/src/SharpCompress/Factories/TarFactory.cs index 8857cca7..19836cd6 100644 --- a/src/SharpCompress/Factories/TarFactory.cs +++ b/src/SharpCompress/Factories/TarFactory.cs @@ -144,11 +144,9 @@ public class TarFactory /// public IAsyncArchive OpenAsyncArchive( IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncArchive)OpenArchive(fileInfos, readerOptions); } @@ -220,13 +218,8 @@ public class TarFactory new TarWriter(stream, new TarWriterOptions(writerOptions)); /// - public IAsyncWriter OpenAsyncWriter( - Stream stream, - WriterOptions writerOptions, - CancellationToken cancellationToken = default - ) + public IAsyncWriter OpenAsyncWriter(Stream stream, WriterOptions writerOptions) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncWriter)OpenWriter(stream, writerOptions); } diff --git a/src/SharpCompress/Factories/ZipFactory.cs b/src/SharpCompress/Factories/ZipFactory.cs index 573c95bf..3108c3d2 100644 --- a/src/SharpCompress/Factories/ZipFactory.cs +++ b/src/SharpCompress/Factories/ZipFactory.cs @@ -153,11 +153,9 @@ public class ZipFactory /// public IAsyncArchive OpenAsyncArchive( IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncArchive)OpenArchive(fileInfos, readerOptions); } @@ -189,13 +187,8 @@ public class ZipFactory new ZipWriter(stream, new ZipWriterOptions(writerOptions)); /// - public IAsyncWriter OpenAsyncWriter( - Stream stream, - WriterOptions writerOptions, - CancellationToken cancellationToken = default - ) + public IAsyncWriter OpenAsyncWriter(Stream stream, WriterOptions writerOptions) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncWriter)OpenWriter(stream, writerOptions); } diff --git a/src/SharpCompress/Readers/Ace/AceReader.Factory.cs b/src/SharpCompress/Readers/Ace/AceReader.Factory.cs index 8daa344e..9f873d77 100644 --- a/src/SharpCompress/Readers/Ace/AceReader.Factory.cs +++ b/src/SharpCompress/Readers/Ace/AceReader.Factory.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.IO; -using System.Threading; using SharpCompress.Common; namespace SharpCompress.Readers.Ace; @@ -34,24 +33,14 @@ public partial class AceReader return new MultiVolumeAceReader(streams, options ?? new ReaderOptions()); } - public static IAsyncReader OpenAsyncReader( - string path, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) + public static IAsyncReader OpenAsyncReader(string path, ReaderOptions? readerOptions = null) { - cancellationToken.ThrowIfCancellationRequested(); path.NotNullOrEmpty(nameof(path)); return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions); } - public static IAsyncReader OpenAsyncReader( - Stream stream, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) + public static IAsyncReader OpenAsyncReader(Stream stream, ReaderOptions? readerOptions = null) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncReader)OpenReader(stream, readerOptions); } @@ -66,11 +55,9 @@ public partial class AceReader public static IAsyncReader OpenAsyncReader( FileInfo fileInfo, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncReader)OpenReader(fileInfo, readerOptions); } diff --git a/src/SharpCompress/Readers/Arc/ArcReader.Factory.cs b/src/SharpCompress/Readers/Arc/ArcReader.Factory.cs index 22ec2666..abfad14a 100644 --- a/src/SharpCompress/Readers/Arc/ArcReader.Factory.cs +++ b/src/SharpCompress/Readers/Arc/ArcReader.Factory.cs @@ -1,40 +1,27 @@ #if NET8_0_OR_GREATER using System.IO; -using System.Threading; using SharpCompress.Common; namespace SharpCompress.Readers.Arc; public partial class ArcReader : IReaderOpenable { - public static IAsyncReader OpenAsyncReader( - string path, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) + public static IAsyncReader OpenAsyncReader(string path, ReaderOptions? readerOptions = null) { - cancellationToken.ThrowIfCancellationRequested(); path.NotNullOrEmpty(nameof(path)); return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions); } - public static IAsyncReader OpenAsyncReader( - Stream stream, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) + public static IAsyncReader OpenAsyncReader(Stream stream, ReaderOptions? readerOptions = null) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncReader)OpenReader(stream, readerOptions); } public static IAsyncReader OpenAsyncReader( FileInfo fileInfo, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncReader)OpenReader(fileInfo, readerOptions); } diff --git a/src/SharpCompress/Readers/Arj/ArjReader.Factory.cs b/src/SharpCompress/Readers/Arj/ArjReader.Factory.cs index f0f7b01b..7a84f4c2 100644 --- a/src/SharpCompress/Readers/Arj/ArjReader.Factory.cs +++ b/src/SharpCompress/Readers/Arj/ArjReader.Factory.cs @@ -1,40 +1,27 @@ #if NET8_0_OR_GREATER using System.IO; -using System.Threading; using SharpCompress.Common; namespace SharpCompress.Readers.Arj; public partial class ArjReader : IReaderOpenable { - public static IAsyncReader OpenAsyncReader( - string path, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) + public static IAsyncReader OpenAsyncReader(string path, ReaderOptions? readerOptions = null) { - cancellationToken.ThrowIfCancellationRequested(); path.NotNullOrEmpty(nameof(path)); return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions); } - public static IAsyncReader OpenAsyncReader( - Stream stream, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) + public static IAsyncReader OpenAsyncReader(Stream stream, ReaderOptions? readerOptions = null) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncReader)OpenReader(stream, readerOptions); } public static IAsyncReader OpenAsyncReader( FileInfo fileInfo, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncReader)OpenReader(fileInfo, readerOptions); } diff --git a/src/SharpCompress/Readers/GZip/GZipReader.Factory.cs b/src/SharpCompress/Readers/GZip/GZipReader.Factory.cs index 3132d139..55e96e73 100644 --- a/src/SharpCompress/Readers/GZip/GZipReader.Factory.cs +++ b/src/SharpCompress/Readers/GZip/GZipReader.Factory.cs @@ -1,5 +1,4 @@ using System.IO; -using System.Threading; namespace SharpCompress.Readers.GZip; @@ -8,34 +7,22 @@ public partial class GZipReader : IReaderOpenable #endif { - public static IAsyncReader OpenAsyncReader( - string path, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) + public static IAsyncReader OpenAsyncReader(string path, ReaderOptions? readerOptions = null) { - cancellationToken.ThrowIfCancellationRequested(); path.NotNullOrEmpty(nameof(path)); return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions); } - public static IAsyncReader OpenAsyncReader( - Stream stream, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) + public static IAsyncReader OpenAsyncReader(Stream stream, ReaderOptions? readerOptions = null) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncReader)OpenReader(stream, readerOptions); } public static IAsyncReader OpenAsyncReader( FileInfo fileInfo, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncReader)OpenReader(fileInfo, readerOptions); } diff --git a/src/SharpCompress/Readers/IReaderOpenable.cs b/src/SharpCompress/Readers/IReaderOpenable.cs index a421a49e..ea42b827 100644 --- a/src/SharpCompress/Readers/IReaderOpenable.cs +++ b/src/SharpCompress/Readers/IReaderOpenable.cs @@ -17,20 +17,17 @@ public interface IReaderOpenable public static abstract IAsyncReader OpenAsyncReader( string path, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ); public static abstract IAsyncReader OpenAsyncReader( Stream stream, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ); public static abstract IAsyncReader OpenAsyncReader( FileInfo fileInfo, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ); } #endif diff --git a/src/SharpCompress/Readers/Lzw/LzwReader.Factory.cs b/src/SharpCompress/Readers/Lzw/LzwReader.Factory.cs index 59448f14..344a9572 100644 --- a/src/SharpCompress/Readers/Lzw/LzwReader.Factory.cs +++ b/src/SharpCompress/Readers/Lzw/LzwReader.Factory.cs @@ -1,5 +1,4 @@ using System.IO; -using System.Threading; namespace SharpCompress.Readers.Lzw; @@ -8,34 +7,22 @@ public partial class LzwReader : IReaderOpenable #endif { - public static IAsyncReader OpenAsyncReader( - string path, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) + public static IAsyncReader OpenAsyncReader(string path, ReaderOptions? readerOptions = null) { - cancellationToken.ThrowIfCancellationRequested(); path.NotNullOrEmpty(nameof(path)); return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions); } - public static IAsyncReader OpenAsyncReader( - Stream stream, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) + public static IAsyncReader OpenAsyncReader(Stream stream, ReaderOptions? readerOptions = null) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncReader)OpenReader(stream, readerOptions); } public static IAsyncReader OpenAsyncReader( FileInfo fileInfo, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncReader)OpenReader(fileInfo, readerOptions); } diff --git a/src/SharpCompress/Readers/Rar/RarReader.Factory.cs b/src/SharpCompress/Readers/Rar/RarReader.Factory.cs index 775b3764..5fa1cba0 100644 --- a/src/SharpCompress/Readers/Rar/RarReader.Factory.cs +++ b/src/SharpCompress/Readers/Rar/RarReader.Factory.cs @@ -1,40 +1,27 @@ #if NET8_0_OR_GREATER using System.IO; -using System.Threading; using SharpCompress.Common; namespace SharpCompress.Readers.Rar; public partial class RarReader : IReaderOpenable { - public static IAsyncReader OpenAsyncReader( - string path, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) + public static IAsyncReader OpenAsyncReader(string path, ReaderOptions? readerOptions = null) { - cancellationToken.ThrowIfCancellationRequested(); path.NotNullOrEmpty(nameof(path)); return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions); } - public static IAsyncReader OpenAsyncReader( - Stream stream, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) + public static IAsyncReader OpenAsyncReader(Stream stream, ReaderOptions? readerOptions = null) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncReader)OpenReader(stream, readerOptions); } public static IAsyncReader OpenAsyncReader( FileInfo fileInfo, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncReader)OpenReader(fileInfo, readerOptions); } } diff --git a/src/SharpCompress/Readers/Tar/TarReader.Factory.cs b/src/SharpCompress/Readers/Tar/TarReader.Factory.cs index 801440a7..b8f41e60 100644 --- a/src/SharpCompress/Readers/Tar/TarReader.Factory.cs +++ b/src/SharpCompress/Readers/Tar/TarReader.Factory.cs @@ -1,5 +1,4 @@ using System.IO; -using System.Threading; using SharpCompress.Common; namespace SharpCompress.Readers.Tar; @@ -9,34 +8,22 @@ public partial class TarReader : IReaderOpenable #endif { - public static IAsyncReader OpenAsyncReader( - string path, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) + public static IAsyncReader OpenAsyncReader(string path, ReaderOptions? readerOptions = null) { - cancellationToken.ThrowIfCancellationRequested(); path.NotNullOrEmpty(nameof(path)); return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions); } - public static IAsyncReader OpenAsyncReader( - Stream stream, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) + public static IAsyncReader OpenAsyncReader(Stream stream, ReaderOptions? readerOptions = null) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncReader)OpenReader(stream, readerOptions); } public static IAsyncReader OpenAsyncReader( FileInfo fileInfo, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncReader)OpenReader(fileInfo, readerOptions); } diff --git a/src/SharpCompress/Readers/Zip/ZipReader.Factory.cs b/src/SharpCompress/Readers/Zip/ZipReader.Factory.cs index 289059fc..f03ea4ab 100644 --- a/src/SharpCompress/Readers/Zip/ZipReader.Factory.cs +++ b/src/SharpCompress/Readers/Zip/ZipReader.Factory.cs @@ -1,40 +1,27 @@ #if NET8_0_OR_GREATER using System.IO; -using System.Threading; using SharpCompress.Common; namespace SharpCompress.Readers.Zip; public partial class ZipReader : IReaderOpenable { - public static IAsyncReader OpenAsyncReader( - string path, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) + public static IAsyncReader OpenAsyncReader(string path, ReaderOptions? readerOptions = null) { - cancellationToken.ThrowIfCancellationRequested(); path.NotNullOrEmpty(nameof(path)); return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions); } - public static IAsyncReader OpenAsyncReader( - Stream stream, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) + public static IAsyncReader OpenAsyncReader(Stream stream, ReaderOptions? readerOptions = null) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncReader)OpenReader(stream, readerOptions); } public static IAsyncReader OpenAsyncReader( FileInfo fileInfo, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncReader)OpenReader(fileInfo, readerOptions); } diff --git a/src/SharpCompress/Writers/GZip/GZipWriter.Factory.cs b/src/SharpCompress/Writers/GZip/GZipWriter.Factory.cs index 7fd8aec1..715bdc22 100644 --- a/src/SharpCompress/Writers/GZip/GZipWriter.Factory.cs +++ b/src/SharpCompress/Writers/GZip/GZipWriter.Factory.cs @@ -1,6 +1,5 @@ #if NET8_0_OR_GREATER using System.IO; -using System.Threading; using SharpCompress.Common; namespace SharpCompress.Writers.GZip; @@ -25,33 +24,18 @@ public partial class GZipWriter : IWriterOpenable return new GZipWriter(stream, writerOptions); } - public static IAsyncWriter OpenAsyncWriter( - string path, - GZipWriterOptions writerOptions, - CancellationToken cancellationToken = default - ) + public static IAsyncWriter OpenAsyncWriter(string path, GZipWriterOptions writerOptions) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncWriter)OpenWriter(path, writerOptions); } - public static IAsyncWriter OpenAsyncWriter( - Stream stream, - GZipWriterOptions writerOptions, - CancellationToken cancellationToken = default - ) + public static IAsyncWriter OpenAsyncWriter(Stream stream, GZipWriterOptions writerOptions) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncWriter)OpenWriter(stream, writerOptions); } - public static IAsyncWriter OpenAsyncWriter( - FileInfo fileInfo, - GZipWriterOptions writerOptions, - CancellationToken cancellationToken = default - ) + public static IAsyncWriter OpenAsyncWriter(FileInfo fileInfo, GZipWriterOptions writerOptions) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncWriter)OpenWriter(fileInfo, writerOptions); } } diff --git a/src/SharpCompress/Writers/IWriterFactory.cs b/src/SharpCompress/Writers/IWriterFactory.cs index f8bd8bde..9095231a 100644 --- a/src/SharpCompress/Writers/IWriterFactory.cs +++ b/src/SharpCompress/Writers/IWriterFactory.cs @@ -1,5 +1,4 @@ using System.IO; -using System.Threading; using SharpCompress.Factories; namespace SharpCompress.Writers; @@ -8,9 +7,5 @@ public interface IWriterFactory : IFactory { IWriter OpenWriter(Stream stream, WriterOptions writerOptions); - IAsyncWriter OpenAsyncWriter( - Stream stream, - WriterOptions writerOptions, - CancellationToken cancellationToken = default - ); + IAsyncWriter OpenAsyncWriter(Stream stream, WriterOptions writerOptions); } diff --git a/src/SharpCompress/Writers/IWriterOpenable.cs b/src/SharpCompress/Writers/IWriterOpenable.cs index 14b98f71..d3102a02 100644 --- a/src/SharpCompress/Writers/IWriterOpenable.cs +++ b/src/SharpCompress/Writers/IWriterOpenable.cs @@ -18,24 +18,20 @@ public interface IWriterOpenable /// The stream to write to. /// The archive type. /// Writer options. - /// Cancellation token. /// A task that returns an IWriter. public static abstract IAsyncWriter OpenAsyncWriter( Stream stream, - TWriterOptions writerOptions, - CancellationToken cancellationToken = default + TWriterOptions writerOptions ); public static abstract IAsyncWriter OpenAsyncWriter( string filePath, - TWriterOptions writerOptions, - CancellationToken cancellationToken = default + TWriterOptions writerOptions ); public static abstract IAsyncWriter OpenAsyncWriter( FileInfo fileInfo, - TWriterOptions writerOptions, - CancellationToken cancellationToken = default + TWriterOptions writerOptions ); } #endif diff --git a/src/SharpCompress/Writers/Tar/TarWriter.Factory.cs b/src/SharpCompress/Writers/Tar/TarWriter.Factory.cs index c5f9c846..d7077478 100644 --- a/src/SharpCompress/Writers/Tar/TarWriter.Factory.cs +++ b/src/SharpCompress/Writers/Tar/TarWriter.Factory.cs @@ -1,6 +1,5 @@ #if NET8_0_OR_GREATER using System.IO; -using System.Threading; using SharpCompress.Common; namespace SharpCompress.Writers.Tar; @@ -25,33 +24,18 @@ public partial class TarWriter : IWriterOpenable return new TarWriter(stream, writerOptions); } - public static IAsyncWriter OpenAsyncWriter( - string path, - TarWriterOptions writerOptions, - CancellationToken cancellationToken = default - ) + public static IAsyncWriter OpenAsyncWriter(string path, TarWriterOptions writerOptions) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncWriter)OpenWriter(path, writerOptions); } - public static IAsyncWriter OpenAsyncWriter( - Stream stream, - TarWriterOptions writerOptions, - CancellationToken cancellationToken = default - ) + public static IAsyncWriter OpenAsyncWriter(Stream stream, TarWriterOptions writerOptions) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncWriter)OpenWriter(stream, writerOptions); } - public static IAsyncWriter OpenAsyncWriter( - FileInfo fileInfo, - TarWriterOptions writerOptions, - CancellationToken cancellationToken = default - ) + public static IAsyncWriter OpenAsyncWriter(FileInfo fileInfo, TarWriterOptions writerOptions) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncWriter)OpenWriter(fileInfo, writerOptions); } } diff --git a/src/SharpCompress/Writers/WriterFactory.cs b/src/SharpCompress/Writers/WriterFactory.cs index 3d482541..ebf18625 100644 --- a/src/SharpCompress/Writers/WriterFactory.cs +++ b/src/SharpCompress/Writers/WriterFactory.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Linq; -using System.Threading; using SharpCompress.Common; namespace SharpCompress.Writers; @@ -31,32 +30,24 @@ public static class WriterFactory public static IAsyncWriter OpenAsyncWriter( string filePath, ArchiveType archiveType, - WriterOptions writerOptions, - CancellationToken cancellationToken = default + WriterOptions writerOptions ) { filePath.NotNullOrEmpty(nameof(filePath)); - return OpenAsyncWriter( - new FileInfo(filePath), - archiveType, - writerOptions, - cancellationToken - ); + return OpenAsyncWriter(new FileInfo(filePath), archiveType, writerOptions); } public static IAsyncWriter OpenAsyncWriter( FileInfo fileInfo, ArchiveType archiveType, - WriterOptions writerOptions, - CancellationToken cancellationToken = default + WriterOptions writerOptions ) { fileInfo.NotNull(nameof(fileInfo)); return OpenAsyncWriter( fileInfo.Open(FileMode.Create, FileAccess.Write), archiveType, - writerOptions, - cancellationToken + writerOptions ); } @@ -84,13 +75,11 @@ public static class WriterFactory /// The stream to write to. /// The archive type. /// Writer options. - /// Cancellation token. /// A task that returns an IWriter. public static IAsyncWriter OpenAsyncWriter( Stream stream, ArchiveType archiveType, - WriterOptions writerOptions, - CancellationToken cancellationToken = default + WriterOptions writerOptions ) { var factory = Factories @@ -99,7 +88,7 @@ public static class WriterFactory if (factory != null) { - return factory.OpenAsyncWriter(stream, writerOptions, cancellationToken); + return factory.OpenAsyncWriter(stream, writerOptions); } throw new NotSupportedException("Archive Type does not have a Writer: " + archiveType); diff --git a/src/SharpCompress/Writers/Zip/ZipWriter.Factory.cs b/src/SharpCompress/Writers/Zip/ZipWriter.Factory.cs index 0df1a81c..c4083aea 100644 --- a/src/SharpCompress/Writers/Zip/ZipWriter.Factory.cs +++ b/src/SharpCompress/Writers/Zip/ZipWriter.Factory.cs @@ -1,6 +1,5 @@ #if NET8_0_OR_GREATER using System.IO; -using System.Threading; using SharpCompress.Common; namespace SharpCompress.Writers.Zip; @@ -25,33 +24,18 @@ public partial class ZipWriter : IWriterOpenable return new ZipWriter(stream, writerOptions); } - public static IAsyncWriter OpenAsyncWriter( - string path, - ZipWriterOptions writerOptions, - CancellationToken cancellationToken = default - ) + public static IAsyncWriter OpenAsyncWriter(string path, ZipWriterOptions writerOptions) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncWriter)OpenWriter(path, writerOptions); } - public static IAsyncWriter OpenAsyncWriter( - Stream stream, - ZipWriterOptions writerOptions, - CancellationToken cancellationToken = default - ) + public static IAsyncWriter OpenAsyncWriter(Stream stream, ZipWriterOptions writerOptions) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncWriter)OpenWriter(stream, writerOptions); } - public static IAsyncWriter OpenAsyncWriter( - FileInfo fileInfo, - ZipWriterOptions writerOptions, - CancellationToken cancellationToken = default - ) + public static IAsyncWriter OpenAsyncWriter(FileInfo fileInfo, ZipWriterOptions writerOptions) { - cancellationToken.ThrowIfCancellationRequested(); return (IAsyncWriter)OpenWriter(fileInfo, writerOptions); } } diff --git a/tests/SharpCompress.Test/ReaderTests.cs b/tests/SharpCompress.Test/ReaderTests.cs index a6e1c25b..bab9d9f5 100644 --- a/tests/SharpCompress.Test/ReaderTests.cs +++ b/tests/SharpCompress.Test/ReaderTests.cs @@ -174,8 +174,7 @@ public abstract class ReaderTests : TestBase await using ( var reader = await ReaderFactory.OpenAsyncReader( new AsyncOnlyStream(testStream), - options, - cancellationToken + options ) ) { diff --git a/tests/SharpCompress.Test/WriterTests.cs b/tests/SharpCompress.Test/WriterTests.cs index f02b65d7..a04e92cc 100644 --- a/tests/SharpCompress.Test/WriterTests.cs +++ b/tests/SharpCompress.Test/WriterTests.cs @@ -94,8 +94,7 @@ public class WriterTests : TestBase await using var reader = await ReaderFactory.OpenAsyncReader( new AsyncOnlyStream(SharpCompressStream.CreateNonDisposing(stream)), - readerOptions, - cancellationToken + readerOptions ); await reader.WriteAllToDirectoryAsync( SCRATCH_FILES_PATH, From ed6c774f08941c749c5b62870ff7c678e07c3c57 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Feb 2026 10:50:48 +0000 Subject: [PATCH 06/12] Address PR review feedback: async IsArchive, tar detection, filename derivation, and code style - Use LzwStream.IsLzwStreamAsync for async archive detection - Add TryOpenReader override to detect tar.Z files and return TarReader - Derive filename from FileStream (strip .Z extension) or use "data" as fallback - Simplify if-else statements to use ternary operators Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- .../Common/Lzw/LzwFilePart.Async.cs | 13 ++----- src/SharpCompress/Common/Lzw/LzwFilePart.cs | 39 +++++++++++++------ src/SharpCompress/Factories/LzwFactory.cs | 35 ++++++++++++++--- 3 files changed, 60 insertions(+), 27 deletions(-) diff --git a/src/SharpCompress/Common/Lzw/LzwFilePart.Async.cs b/src/SharpCompress/Common/Lzw/LzwFilePart.Async.cs index c26f33bf..8b6a5a32 100644 --- a/src/SharpCompress/Common/Lzw/LzwFilePart.Async.cs +++ b/src/SharpCompress/Common/Lzw/LzwFilePart.Async.cs @@ -15,16 +15,9 @@ internal sealed partial class LzwFilePart cancellationToken.ThrowIfCancellationRequested(); var part = new LzwFilePart(stream, archiveEncoding); - if (stream.CanSeek) - { - part.EntryStartPosition = stream.Position; - } - else - { - // For non-seekable streams, we can't track position. - // Set to 0 since the stream will be read sequentially from its current position. - part.EntryStartPosition = 0; - } + // For non-seekable streams, we can't track position, so use 0 since the stream will be + // read sequentially from its current position. + part.EntryStartPosition = stream.CanSeek ? stream.Position : 0; return part; } } diff --git a/src/SharpCompress/Common/Lzw/LzwFilePart.cs b/src/SharpCompress/Common/Lzw/LzwFilePart.cs index dcf2946d..6afc0943 100644 --- a/src/SharpCompress/Common/Lzw/LzwFilePart.cs +++ b/src/SharpCompress/Common/Lzw/LzwFilePart.cs @@ -6,33 +6,48 @@ namespace SharpCompress.Common.Lzw; internal sealed partial class LzwFilePart : FilePart { private readonly Stream _stream; + private readonly string? _name; internal static LzwFilePart Create(Stream stream, IArchiveEncoding archiveEncoding) { var part = new LzwFilePart(stream, archiveEncoding); - if (stream.CanSeek) - { - part.EntryStartPosition = stream.Position; - } - else - { - // For non-seekable streams, we can't track position. - // Set to 0 since the stream will be read sequentially from its current position. - part.EntryStartPosition = 0; - } + // For non-seekable streams, we can't track position, so use 0 since the stream will be + // read sequentially from its current position. + part.EntryStartPosition = stream.CanSeek ? stream.Position : 0; return part; } private LzwFilePart(Stream stream, IArchiveEncoding archiveEncoding) - : base(archiveEncoding) => _stream = stream; + : base(archiveEncoding) + { + _stream = stream; + _name = DeriveFileName(stream); + } internal long EntryStartPosition { get; private set; } - internal override string? FilePartName => null; + internal override string? FilePartName => _name; internal override Stream GetCompressedStream() => new LzwStream(_stream) { IsStreamOwner = false }; internal override Stream GetRawStream() => _stream; + + private static string? DeriveFileName(Stream stream) + { + // Try to derive filename from FileStream + if (stream is FileStream fileStream && !string.IsNullOrEmpty(fileStream.Name)) + { + var fileName = Path.GetFileName(fileStream.Name); + // Strip .Z extension if present + if (fileName.EndsWith(".Z", System.StringComparison.OrdinalIgnoreCase)) + { + return fileName.Substring(0, fileName.Length - 2); + } + return fileName; + } + // Default name for non-file streams + return "data"; + } } diff --git a/src/SharpCompress/Factories/LzwFactory.cs b/src/SharpCompress/Factories/LzwFactory.cs index b9767064..9b50874e 100644 --- a/src/SharpCompress/Factories/LzwFactory.cs +++ b/src/SharpCompress/Factories/LzwFactory.cs @@ -2,11 +2,13 @@ using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; +using SharpCompress.Archives.Tar; using SharpCompress.Common; using SharpCompress.Compressors.Lzw; using SharpCompress.IO; using SharpCompress.Readers; using SharpCompress.Readers.Lzw; +using SharpCompress.Readers.Tar; namespace SharpCompress.Factories; @@ -38,16 +40,39 @@ public class LzwFactory : Factory, IReaderFactory Stream stream, string? password = null, CancellationToken cancellationToken = default - ) - { - cancellationToken.ThrowIfCancellationRequested(); - return new(IsArchive(stream, password)); - } + ) => LzwStream.IsLzwStreamAsync(stream, cancellationToken); #endregion #region IReaderFactory + /// + internal override bool TryOpenReader( + SharpCompressStream sharpCompressStream, + ReaderOptions options, + out IReader? reader + ) + { + reader = null; + + if (LzwStream.IsLzwStream(sharpCompressStream)) + { + sharpCompressStream.Rewind(); + var testStream = new LzwStream(sharpCompressStream) { IsStreamOwner = false }; + if (TarArchive.IsTarFile(testStream)) + { + sharpCompressStream.StopRecording(); + reader = new TarReader(sharpCompressStream, options, CompressionType.Lzw); + return true; + } + sharpCompressStream.StopRecording(); + reader = OpenReader(sharpCompressStream, options); + return true; + } + sharpCompressStream.Rewind(); + return false; + } + /// public IReader OpenReader(Stream stream, ReaderOptions? options) => LzwReader.OpenReader(stream, options); From b3038010d94ea1305987d6da775da27021c9a903 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Feb 2026 10:52:13 +0000 Subject: [PATCH 07/12] Improve test documentation for tar.Z wrapper detection - Rename test to clarify it tests tar wrapper detection - Add detailed comment explaining why we use Tar.tar.Z (LzwStream compression not supported) - Add assertions to verify ArchiveType.Tar and CompressionType.Lzw are correctly detected Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- tests/SharpCompress.Test/Lzw/LzwReaderTests.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/SharpCompress.Test/Lzw/LzwReaderTests.cs b/tests/SharpCompress.Test/Lzw/LzwReaderTests.cs index 7802a6ed..4c7f2d6d 100644 --- a/tests/SharpCompress.Test/Lzw/LzwReaderTests.cs +++ b/tests/SharpCompress.Test/Lzw/LzwReaderTests.cs @@ -28,14 +28,22 @@ public class LzwReaderTests : ReaderTests } [Fact] - public void Lzw_Reader_Factory_Detects_Format() + public void Lzw_Reader_Factory_Detects_Tar_Wrapper() { + // Note: Testing with Tar.tar.Z because: + // 1. LzwStream only supports decompression, not compression + // 2. This tests the important tar wrapper detection code path in LzwFactory.TryOpenReader + // 3. Verifies that tar.Z files correctly return TarReader with CompressionType.Lzw using Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.Z")); using var reader = ReaderFactory.OpenReader( stream, new ReaderOptions { LeaveStreamOpen = false } ); + + // Should detect as Tar archive with Lzw compression + Assert.Equal(ArchiveType.Tar, reader.ArchiveType); Assert.True(reader.MoveToNextEntry()); Assert.NotNull(reader.Entry); + Assert.Equal(CompressionType.Lzw, reader.Entry.CompressionType); } } From a8c06386a3be8f59d05b85c69df8046957fc3be3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Feb 2026 10:56:11 +0000 Subject: [PATCH 08/12] Address code review feedback: use range syntax and dispose testStream - Use C# range syntax [..^2] instead of Substring for better readability - Wrap testStream in using statement for proper resource cleanup Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- src/SharpCompress/Common/Lzw/LzwFilePart.cs | 2 +- src/SharpCompress/Factories/LzwFactory.cs | 12 +++++++----- src/SharpCompress/packages.lock.json | 12 ++++++------ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/SharpCompress/Common/Lzw/LzwFilePart.cs b/src/SharpCompress/Common/Lzw/LzwFilePart.cs index 6afc0943..707d16cd 100644 --- a/src/SharpCompress/Common/Lzw/LzwFilePart.cs +++ b/src/SharpCompress/Common/Lzw/LzwFilePart.cs @@ -43,7 +43,7 @@ internal sealed partial class LzwFilePart : FilePart // Strip .Z extension if present if (fileName.EndsWith(".Z", System.StringComparison.OrdinalIgnoreCase)) { - return fileName.Substring(0, fileName.Length - 2); + return fileName[..^2]; } return fileName; } diff --git a/src/SharpCompress/Factories/LzwFactory.cs b/src/SharpCompress/Factories/LzwFactory.cs index 9b50874e..078fad37 100644 --- a/src/SharpCompress/Factories/LzwFactory.cs +++ b/src/SharpCompress/Factories/LzwFactory.cs @@ -58,12 +58,14 @@ public class LzwFactory : Factory, IReaderFactory if (LzwStream.IsLzwStream(sharpCompressStream)) { sharpCompressStream.Rewind(); - var testStream = new LzwStream(sharpCompressStream) { IsStreamOwner = false }; - if (TarArchive.IsTarFile(testStream)) + using (var testStream = new LzwStream(sharpCompressStream) { IsStreamOwner = false }) { - sharpCompressStream.StopRecording(); - reader = new TarReader(sharpCompressStream, options, CompressionType.Lzw); - return true; + if (TarArchive.IsTarFile(testStream)) + { + sharpCompressStream.StopRecording(); + reader = new TarReader(sharpCompressStream, options, CompressionType.Lzw); + return true; + } } sharpCompressStream.StopRecording(); reader = OpenReader(sharpCompressStream, options); diff --git a/src/SharpCompress/packages.lock.json b/src/SharpCompress/packages.lock.json index 27e9e496..29e7a1bd 100644 --- a/src/SharpCompress/packages.lock.json +++ b/src/SharpCompress/packages.lock.json @@ -216,9 +216,9 @@ "net10.0": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[10.0.2, )", - "resolved": "10.0.2", - "contentHash": "sXdDtMf2qcnbygw9OdE535c2lxSxrZP8gO4UhDJ0xiJbl1wIqXS1OTcTDFTIJPOFd6Mhcm8gPEthqWGUxBsTqw==" + "requested": "[10.0.0, )", + "resolved": "10.0.0", + "contentHash": "kICGrGYEzCNI3wPzfEXcwNHgTvlvVn9yJDhSdRK+oZQy4jvYH529u7O0xf5ocQKzOMjfS07+3z9PKRIjrFMJDA==" }, "Microsoft.NETFramework.ReferenceAssemblies": { "type": "Direct", @@ -264,9 +264,9 @@ "net8.0": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[8.0.23, )", - "resolved": "8.0.23", - "contentHash": "GqHiB1HbbODWPbY/lc5xLQH8siEEhNA0ptpJCC6X6adtAYNEzu5ZlqV3YHA3Gh7fuEwgA8XqVwMtH2KNtuQM1Q==" + "requested": "[8.0.22, )", + "resolved": "8.0.22", + "contentHash": "MhcMithKEiyyNkD2ZfbDZPmcOdi0GheGfg8saEIIEfD/fol3iHmcV8TsZkD4ZYz5gdUuoX4YtlVySUU7Sxl9SQ==" }, "Microsoft.NETFramework.ReferenceAssemblies": { "type": "Direct", From 1ba438d4c77130f148dadf1fe3b62eba8a85873f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Feb 2026 14:56:54 +0000 Subject: [PATCH 09/12] Add tests for plain .Z files (not tar-wrapped) - Create test .Z file (large_test.txt.Z) using compress tool - Add tests for direct LzwReader usage with plain .Z files - Add tests for ReaderFactory detection of plain .Z files - Improve filename derivation to unwrap SharpCompressStream - Verify decompression works correctly for non-tar .Z files - All 15 tests now passing Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- src/SharpCompress/Common/Lzw/LzwFilePart.cs | 9 +++- src/SharpCompress/packages.lock.json | 12 ++--- .../Lzw/LzwReaderAsyncTests.cs | 28 ++++++++++++ .../SharpCompress.Test/Lzw/LzwReaderTests.cs | 42 ++++++++++++++++++ tests/TestArchives/Archives/large_test.txt.Z | Bin 0 -> 5348 bytes 5 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 tests/TestArchives/Archives/large_test.txt.Z diff --git a/src/SharpCompress/Common/Lzw/LzwFilePart.cs b/src/SharpCompress/Common/Lzw/LzwFilePart.cs index 707d16cd..087ab3aa 100644 --- a/src/SharpCompress/Common/Lzw/LzwFilePart.cs +++ b/src/SharpCompress/Common/Lzw/LzwFilePart.cs @@ -36,8 +36,15 @@ internal sealed partial class LzwFilePart : FilePart private static string? DeriveFileName(Stream stream) { + // Unwrap SharpCompressStream to get to the underlying FileStream + var unwrappedStream = stream; + if (stream is SharpCompress.IO.IStreamStack streamStack) + { + unwrappedStream = streamStack.BaseStream(); + } + // Try to derive filename from FileStream - if (stream is FileStream fileStream && !string.IsNullOrEmpty(fileStream.Name)) + if (unwrappedStream is FileStream fileStream && !string.IsNullOrEmpty(fileStream.Name)) { var fileName = Path.GetFileName(fileStream.Name); // Strip .Z extension if present diff --git a/src/SharpCompress/packages.lock.json b/src/SharpCompress/packages.lock.json index 29e7a1bd..27e9e496 100644 --- a/src/SharpCompress/packages.lock.json +++ b/src/SharpCompress/packages.lock.json @@ -216,9 +216,9 @@ "net10.0": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[10.0.0, )", - "resolved": "10.0.0", - "contentHash": "kICGrGYEzCNI3wPzfEXcwNHgTvlvVn9yJDhSdRK+oZQy4jvYH529u7O0xf5ocQKzOMjfS07+3z9PKRIjrFMJDA==" + "requested": "[10.0.2, )", + "resolved": "10.0.2", + "contentHash": "sXdDtMf2qcnbygw9OdE535c2lxSxrZP8gO4UhDJ0xiJbl1wIqXS1OTcTDFTIJPOFd6Mhcm8gPEthqWGUxBsTqw==" }, "Microsoft.NETFramework.ReferenceAssemblies": { "type": "Direct", @@ -264,9 +264,9 @@ "net8.0": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[8.0.22, )", - "resolved": "8.0.22", - "contentHash": "MhcMithKEiyyNkD2ZfbDZPmcOdi0GheGfg8saEIIEfD/fol3iHmcV8TsZkD4ZYz5gdUuoX4YtlVySUU7Sxl9SQ==" + "requested": "[8.0.23, )", + "resolved": "8.0.23", + "contentHash": "GqHiB1HbbODWPbY/lc5xLQH8siEEhNA0ptpJCC6X6adtAYNEzu5ZlqV3YHA3Gh7fuEwgA8XqVwMtH2KNtuQM1Q==" }, "Microsoft.NETFramework.ReferenceAssemblies": { "type": "Direct", diff --git a/tests/SharpCompress.Test/Lzw/LzwReaderAsyncTests.cs b/tests/SharpCompress.Test/Lzw/LzwReaderAsyncTests.cs index b9083138..6ecc6047 100644 --- a/tests/SharpCompress.Test/Lzw/LzwReaderAsyncTests.cs +++ b/tests/SharpCompress.Test/Lzw/LzwReaderAsyncTests.cs @@ -1,4 +1,7 @@ +using System.IO; using SharpCompress.Common; +using SharpCompress.Readers; +using SharpCompress.Readers.Lzw; using Xunit; namespace SharpCompress.Test.Lzw; @@ -12,4 +15,29 @@ public class LzwReaderAsyncTests : ReaderTests { await ReadAsync("Tar.tar.Z", CompressionType.Lzw); } + + [Fact] + public async System.Threading.Tasks.Task Lzw_Reader_Plain_Z_File_Async() + { + // Test async reading of a plain .Z file (not tar-wrapped) using LzwReader directly + using Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "large_test.txt.Z")); + using var reader = LzwReader.OpenReader(stream); + + Assert.Equal(ArchiveType.Lzw, reader.ArchiveType); + Assert.True(reader.MoveToNextEntry()); + + var entry = reader.Entry; + Assert.NotNull(entry); + Assert.Equal(CompressionType.Lzw, entry.CompressionType); + + // When opened as FileStream, key should be derived from filename + Assert.Equal("large_test.txt", entry.Key); + + // Decompress asynchronously + using var entryStream = reader.OpenEntryStream(); + using var ms = new MemoryStream(); + await entryStream.CopyToAsync(ms); + + Assert.Equal(22300, ms.Length); + } } diff --git a/tests/SharpCompress.Test/Lzw/LzwReaderTests.cs b/tests/SharpCompress.Test/Lzw/LzwReaderTests.cs index 4c7f2d6d..f75fd666 100644 --- a/tests/SharpCompress.Test/Lzw/LzwReaderTests.cs +++ b/tests/SharpCompress.Test/Lzw/LzwReaderTests.cs @@ -46,4 +46,46 @@ public class LzwReaderTests : ReaderTests Assert.NotNull(reader.Entry); Assert.Equal(CompressionType.Lzw, reader.Entry.CompressionType); } + + [Fact] + public void Lzw_Reader_Plain_Z_File() + { + // Test with a plain .Z file (not tar-wrapped) using LzwReader directly + using Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "large_test.txt.Z")); + using var reader = LzwReader.OpenReader(stream); + + Assert.True(reader.MoveToNextEntry()); + var entry = reader.Entry; + Assert.NotNull(entry); + Assert.Equal(CompressionType.Lzw, entry.CompressionType); + + // Entry key should be "large_test.txt" (stripped .Z extension) when opened via FileStream + Assert.Equal("large_test.txt", entry.Key); + + // Decompress and verify content + using var entryStream = reader.OpenEntryStream(); + using var ms = new MemoryStream(); + entryStream.CopyTo(ms); + var decompressed = System.Text.Encoding.UTF8.GetString(ms.ToArray()); + + Assert.Equal(22300, ms.Length); + Assert.Contains("This is a test file for LZW compression testing", decompressed); + } + + [Fact] + public void Lzw_Reader_Factory_Detects_Plain_Z_File() + { + // Test that ReaderFactory correctly identifies a plain .Z file (not tar-wrapped) + using Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "large_test.txt.Z")); + using var reader = ReaderFactory.OpenReader(stream); + + // Should detect as Lzw archive (not Tar) + Assert.Equal(ArchiveType.Lzw, reader.ArchiveType); + Assert.True(reader.MoveToNextEntry()); + Assert.NotNull(reader.Entry); + Assert.Equal(CompressionType.Lzw, reader.Entry.CompressionType); + + // When opened via ReaderFactory with a non-FileStream, key defaults to "data" + Assert.NotNull(reader.Entry.Key); + } } diff --git a/tests/TestArchives/Archives/large_test.txt.Z b/tests/TestArchives/Archives/large_test.txt.Z new file mode 100644 index 0000000000000000000000000000000000000000..64ae2af12404f804db4d2da8bbaf7be327311dd5 GIT binary patch literal 5348 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 B?C$^o literal 0 HcmV?d00001 From b67b4fd57f462f20d88c64dee4986961de81b180 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:01:25 +0000 Subject: [PATCH 10/12] Add LzwReader support for .Z compressed archives Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- src/SharpCompress/packages.lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/SharpCompress/packages.lock.json b/src/SharpCompress/packages.lock.json index 27e9e496..29e7a1bd 100644 --- a/src/SharpCompress/packages.lock.json +++ b/src/SharpCompress/packages.lock.json @@ -216,9 +216,9 @@ "net10.0": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[10.0.2, )", - "resolved": "10.0.2", - "contentHash": "sXdDtMf2qcnbygw9OdE535c2lxSxrZP8gO4UhDJ0xiJbl1wIqXS1OTcTDFTIJPOFd6Mhcm8gPEthqWGUxBsTqw==" + "requested": "[10.0.0, )", + "resolved": "10.0.0", + "contentHash": "kICGrGYEzCNI3wPzfEXcwNHgTvlvVn9yJDhSdRK+oZQy4jvYH529u7O0xf5ocQKzOMjfS07+3z9PKRIjrFMJDA==" }, "Microsoft.NETFramework.ReferenceAssemblies": { "type": "Direct", @@ -264,9 +264,9 @@ "net8.0": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[8.0.23, )", - "resolved": "8.0.23", - "contentHash": "GqHiB1HbbODWPbY/lc5xLQH8siEEhNA0ptpJCC6X6adtAYNEzu5ZlqV3YHA3Gh7fuEwgA8XqVwMtH2KNtuQM1Q==" + "requested": "[8.0.22, )", + "resolved": "8.0.22", + "contentHash": "MhcMithKEiyyNkD2ZfbDZPmcOdi0GheGfg8saEIIEfD/fol3iHmcV8TsZkD4ZYz5gdUuoX4YtlVySUU7Sxl9SQ==" }, "Microsoft.NETFramework.ReferenceAssemblies": { "type": "Direct", From 4475c2af736cc41695e1ceffbd394b029d37ca81 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Mon, 9 Feb 2026 16:16:32 +0000 Subject: [PATCH 11/12] add back substring usage --- src/SharpCompress/Common/Lzw/LzwFilePart.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SharpCompress/Common/Lzw/LzwFilePart.cs b/src/SharpCompress/Common/Lzw/LzwFilePart.cs index 087ab3aa..74d682ea 100644 --- a/src/SharpCompress/Common/Lzw/LzwFilePart.cs +++ b/src/SharpCompress/Common/Lzw/LzwFilePart.cs @@ -50,7 +50,7 @@ internal sealed partial class LzwFilePart : FilePart // Strip .Z extension if present if (fileName.EndsWith(".Z", System.StringComparison.OrdinalIgnoreCase)) { - return fileName[..^2]; + return fileName.Substring(0, fileName.Length - 2); } return fileName; } From a0a7da9254331159c690ccdda6e4b02a89fbe039 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 10 Feb 2026 11:36:35 +0000 Subject: [PATCH 12/12] merge fixes --- .../Archives/GZip/GZipArchive.Factory.cs | 40 ++++------------ .../Archives/Tar/TarArchive.Factory.cs | 46 ++++--------------- .../Archives/Zip/ZipArchive.Factory.cs | 45 ++++-------------- .../Common/Lzw/LzwEntry.Async.cs | 6 ++- src/SharpCompress/Common/Lzw/LzwEntry.cs | 12 +++-- src/SharpCompress/Common/Lzw/LzwVolume.cs | 2 +- src/SharpCompress/Factories/GZipFactory.cs | 9 +--- src/SharpCompress/Factories/TarFactory.cs | 9 +--- src/SharpCompress/Factories/ZipFactory.cs | 9 +--- 9 files changed, 49 insertions(+), 129 deletions(-) diff --git a/src/SharpCompress/Archives/GZip/GZipArchive.Factory.cs b/src/SharpCompress/Archives/GZip/GZipArchive.Factory.cs index ab6dc786..1f90de62 100644 --- a/src/SharpCompress/Archives/GZip/GZipArchive.Factory.cs +++ b/src/SharpCompress/Archives/GZip/GZipArchive.Factory.cs @@ -22,11 +22,9 @@ public partial class GZipArchive { public static IWritableAsyncArchive OpenAsyncArchive( string path, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default + ReaderOptions? readerOptions = null ) { - cancellationToken.ThrowIfCancellationRequested(); path.NotNullOrEmpty(nameof(path)); return (IWritableAsyncArchive) OpenArchive(new FileInfo(path), readerOptions ?? new ReaderOptions()); @@ -107,43 +105,23 @@ public partial class GZipArchive public static IWritableAsyncArchive OpenAsyncArchive( Stream stream, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) - { - cancellationToken.ThrowIfCancellationRequested(); - return (IWritableAsyncArchive)OpenArchive(stream, readerOptions); - } + ReaderOptions? readerOptions = null + ) => (IWritableAsyncArchive)OpenArchive(stream, readerOptions); public static IWritableAsyncArchive OpenAsyncArchive( FileInfo fileInfo, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) - { - cancellationToken.ThrowIfCancellationRequested(); - return (IWritableAsyncArchive)OpenArchive(fileInfo, readerOptions); - } + ReaderOptions? readerOptions = null + ) => (IWritableAsyncArchive)OpenArchive(fileInfo, readerOptions); public static IWritableAsyncArchive OpenAsyncArchive( IReadOnlyList streams, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) - { - cancellationToken.ThrowIfCancellationRequested(); - return (IWritableAsyncArchive)OpenArchive(streams, readerOptions); - } + ReaderOptions? readerOptions = null + ) => (IWritableAsyncArchive)OpenArchive(streams, readerOptions); public static IWritableAsyncArchive OpenAsyncArchive( IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) - { - cancellationToken.ThrowIfCancellationRequested(); - return (IWritableAsyncArchive)OpenArchive(fileInfos, readerOptions); - } + ReaderOptions? readerOptions = null + ) => (IWritableAsyncArchive)OpenArchive(fileInfos, readerOptions); public static IWritableArchive CreateArchive() => new GZipArchive(); diff --git a/src/SharpCompress/Archives/Tar/TarArchive.Factory.cs b/src/SharpCompress/Archives/Tar/TarArchive.Factory.cs index f3faac49..3a2ba8f3 100644 --- a/src/SharpCompress/Archives/Tar/TarArchive.Factory.cs +++ b/src/SharpCompress/Archives/Tar/TarArchive.Factory.cs @@ -97,54 +97,28 @@ public partial class TarArchive public static IWritableAsyncArchive OpenAsyncArchive( Stream stream, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) - { - cancellationToken.ThrowIfCancellationRequested(); - return (IWritableAsyncArchive)OpenArchive(stream, readerOptions); - } + ReaderOptions? readerOptions = null + ) => (IWritableAsyncArchive)OpenArchive(stream, readerOptions); public static IWritableAsyncArchive OpenAsyncArchive( string path, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) - { - cancellationToken.ThrowIfCancellationRequested(); - return (IWritableAsyncArchive) - OpenArchive(new FileInfo(path), readerOptions); - } + ReaderOptions? readerOptions = null + ) => (IWritableAsyncArchive)OpenArchive(new FileInfo(path), readerOptions); public static IWritableAsyncArchive OpenAsyncArchive( FileInfo fileInfo, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) - { - cancellationToken.ThrowIfCancellationRequested(); - return (IWritableAsyncArchive)OpenArchive(fileInfo, readerOptions); - } + ReaderOptions? readerOptions = null + ) => (IWritableAsyncArchive)OpenArchive(fileInfo, readerOptions); public static IWritableAsyncArchive OpenAsyncArchive( IReadOnlyList streams, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) - { - cancellationToken.ThrowIfCancellationRequested(); - return (IWritableAsyncArchive)OpenArchive(streams, readerOptions); - } + ReaderOptions? readerOptions = null + ) => (IWritableAsyncArchive)OpenArchive(streams, readerOptions); public static IWritableAsyncArchive OpenAsyncArchive( IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) - { - cancellationToken.ThrowIfCancellationRequested(); - return (IWritableAsyncArchive)OpenArchive(fileInfos, readerOptions); - } + ReaderOptions? readerOptions = null + ) => (IWritableAsyncArchive)OpenArchive(fileInfos, readerOptions); public static bool IsTarFile(string filePath) => IsTarFile(new FileInfo(filePath)); diff --git a/src/SharpCompress/Archives/Zip/ZipArchive.Factory.cs b/src/SharpCompress/Archives/Zip/ZipArchive.Factory.cs index 56f383cc..4c2163dc 100644 --- a/src/SharpCompress/Archives/Zip/ZipArchive.Factory.cs +++ b/src/SharpCompress/Archives/Zip/ZipArchive.Factory.cs @@ -97,53 +97,28 @@ public partial class ZipArchive public static IWritableAsyncArchive OpenAsyncArchive( string path, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) - { - cancellationToken.ThrowIfCancellationRequested(); - return (IWritableAsyncArchive)OpenArchive(path, readerOptions); - } + ReaderOptions? readerOptions = null + ) => (IWritableAsyncArchive)OpenArchive(path, readerOptions); public static IWritableAsyncArchive OpenAsyncArchive( Stream stream, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) - { - cancellationToken.ThrowIfCancellationRequested(); - return (IWritableAsyncArchive)OpenArchive(stream, readerOptions); - } + ReaderOptions? readerOptions = null + ) => (IWritableAsyncArchive)OpenArchive(stream, readerOptions); public static IWritableAsyncArchive OpenAsyncArchive( FileInfo fileInfo, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) - { - cancellationToken.ThrowIfCancellationRequested(); - return (IWritableAsyncArchive)OpenArchive(fileInfo, readerOptions); - } + ReaderOptions? readerOptions = null + ) => (IWritableAsyncArchive)OpenArchive(fileInfo, readerOptions); public static IWritableAsyncArchive OpenAsyncArchive( IReadOnlyList streams, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) - { - cancellationToken.ThrowIfCancellationRequested(); - return (IWritableAsyncArchive)OpenArchive(streams, readerOptions); - } + ReaderOptions? readerOptions = null + ) => (IWritableAsyncArchive)OpenArchive(streams, readerOptions); public static IWritableAsyncArchive OpenAsyncArchive( IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) - { - cancellationToken.ThrowIfCancellationRequested(); - return (IWritableAsyncArchive)OpenArchive(fileInfos, readerOptions); - } + ReaderOptions? readerOptions = null + ) => (IWritableAsyncArchive)OpenArchive(fileInfos, readerOptions); public static bool IsZipFile(string filePath, string? password = null) => IsZipFile(new FileInfo(filePath), password); diff --git a/src/SharpCompress/Common/Lzw/LzwEntry.Async.cs b/src/SharpCompress/Common/Lzw/LzwEntry.Async.cs index 9ea826b5..a1982d1b 100644 --- a/src/SharpCompress/Common/Lzw/LzwEntry.Async.cs +++ b/src/SharpCompress/Common/Lzw/LzwEntry.Async.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; using System.Threading; +using SharpCompress.Readers; namespace SharpCompress.Common.Lzw; @@ -9,12 +10,13 @@ public partial class LzwEntry { internal static async IAsyncEnumerable GetEntriesAsync( Stream stream, - OptionsBase options, + ReaderOptions options, [EnumeratorCancellation] CancellationToken cancellationToken = default ) { yield return new LzwEntry( - await LzwFilePart.CreateAsync(stream, options.ArchiveEncoding, cancellationToken) + await LzwFilePart.CreateAsync(stream, options.ArchiveEncoding, cancellationToken), + options ); } } diff --git a/src/SharpCompress/Common/Lzw/LzwEntry.cs b/src/SharpCompress/Common/Lzw/LzwEntry.cs index ab74910a..92490428 100644 --- a/src/SharpCompress/Common/Lzw/LzwEntry.cs +++ b/src/SharpCompress/Common/Lzw/LzwEntry.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.IO; +using SharpCompress.Common.Options; +using SharpCompress.Readers; namespace SharpCompress.Common.Lzw; @@ -8,7 +10,11 @@ public partial class LzwEntry : Entry { private readonly LzwFilePart? _filePart; - internal LzwEntry(LzwFilePart? filePart) => _filePart = filePart; + internal LzwEntry(LzwFilePart? filePart, IReaderOptions readerOptions) + : base(readerOptions) + { + _filePart = filePart; + } public override CompressionType CompressionType => CompressionType.Lzw; @@ -38,9 +44,9 @@ public partial class LzwEntry : Entry internal override IEnumerable Parts => _filePart.Empty(); - internal static IEnumerable GetEntries(Stream stream, OptionsBase options) + internal static IEnumerable GetEntries(Stream stream, ReaderOptions options) { - yield return new LzwEntry(LzwFilePart.Create(stream, options.ArchiveEncoding)); + yield return new LzwEntry(LzwFilePart.Create(stream, options.ArchiveEncoding), options); } // Async methods moved to LzwEntry.Async.cs diff --git a/src/SharpCompress/Common/Lzw/LzwVolume.cs b/src/SharpCompress/Common/Lzw/LzwVolume.cs index 46cd8d25..7ded1d26 100644 --- a/src/SharpCompress/Common/Lzw/LzwVolume.cs +++ b/src/SharpCompress/Common/Lzw/LzwVolume.cs @@ -9,7 +9,7 @@ public class LzwVolume : Volume : base(stream, options, index) { } public LzwVolume(FileInfo fileInfo, ReaderOptions options) - : base(fileInfo.OpenRead(), options) => options.LeaveStreamOpen = false; + : base(fileInfo.OpenRead(), options with { LeaveStreamOpen = false }) { } public override bool IsFirstVolume => true; diff --git a/src/SharpCompress/Factories/GZipFactory.cs b/src/SharpCompress/Factories/GZipFactory.cs index 68aa8e78..6d38d418 100644 --- a/src/SharpCompress/Factories/GZipFactory.cs +++ b/src/SharpCompress/Factories/GZipFactory.cs @@ -95,13 +95,8 @@ public class GZipFactory /// public IAsyncArchive OpenAsyncArchive( IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) - { - cancellationToken.ThrowIfCancellationRequested(); - return (IAsyncArchive)OpenArchive(fileInfos, readerOptions); - } + ReaderOptions? readerOptions = null + ) => (IAsyncArchive)OpenArchive(fileInfos, readerOptions); #endregion diff --git a/src/SharpCompress/Factories/TarFactory.cs b/src/SharpCompress/Factories/TarFactory.cs index f399b984..233a5184 100644 --- a/src/SharpCompress/Factories/TarFactory.cs +++ b/src/SharpCompress/Factories/TarFactory.cs @@ -145,13 +145,8 @@ public class TarFactory /// public IAsyncArchive OpenAsyncArchive( IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) - { - cancellationToken.ThrowIfCancellationRequested(); - return (IAsyncArchive)OpenArchive(fileInfos, readerOptions); - } + ReaderOptions? readerOptions = null + ) => (IAsyncArchive)OpenArchive(fileInfos, readerOptions); #endregion diff --git a/src/SharpCompress/Factories/ZipFactory.cs b/src/SharpCompress/Factories/ZipFactory.cs index f22cdf2e..6d984259 100644 --- a/src/SharpCompress/Factories/ZipFactory.cs +++ b/src/SharpCompress/Factories/ZipFactory.cs @@ -155,13 +155,8 @@ public class ZipFactory /// public IAsyncArchive OpenAsyncArchive( IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null, - CancellationToken cancellationToken = default - ) - { - cancellationToken.ThrowIfCancellationRequested(); - return (IAsyncArchive)OpenArchive(fileInfos, readerOptions); - } + ReaderOptions? readerOptions = null + ) => (IAsyncArchive)OpenArchive(fileInfos, readerOptions); #endregion