diff --git a/src/SharpCompress/Archives/ArchiveFactory.Async.cs b/src/SharpCompress/Archives/ArchiveFactory.Async.cs index c6a69d111..b9df44dbb 100644 --- a/src/SharpCompress/Archives/ArchiveFactory.Async.cs +++ b/src/SharpCompress/Archives/ArchiveFactory.Async.cs @@ -69,7 +69,7 @@ public static async ValueTask OpenAsyncArchive( options ??= ReaderOptions.ForOwnedFile; 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 ab6dc7869..1f90de62d 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 static IWritableArchive OpenArchive( 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/IArchiveOpenable.cs b/src/SharpCompress/Archives/IArchiveOpenable.cs index e5ae52b32..e36ea02b9 100644 --- a/src/SharpCompress/Archives/IArchiveOpenable.cs +++ b/src/SharpCompress/Archives/IArchiveOpenable.cs @@ -20,20 +20,17 @@ public static abstract TSync OpenArchive( 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 fc418ad42..936222e6f 100644 --- a/src/SharpCompress/Archives/IMultiArchiveFactory.cs +++ b/src/SharpCompress/Archives/IMultiArchiveFactory.cs @@ -50,10 +50,8 @@ IAsyncArchive OpenAsyncArchive( /// /// /// 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 53f375c09..0fed7adb3 100644 --- a/src/SharpCompress/Archives/IMultiArchiveOpenable.cs +++ b/src/SharpCompress/Archives/IMultiArchiveOpenable.cs @@ -22,14 +22,12 @@ public static abstract TSync OpenArchive( 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 fe1eb5c3d..76154b7f8 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 static IRarArchive OpenArchive( 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 614c44088..2748e07c2 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 static IArchive OpenArchive(Stream stream, ReaderOptions? readerOptions = ); } - 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 f3faac499..3a2ba8f34 100644 --- a/src/SharpCompress/Archives/Tar/TarArchive.Factory.cs +++ b/src/SharpCompress/Archives/Tar/TarArchive.Factory.cs @@ -97,54 +97,28 @@ public static IWritableArchive OpenArchive( 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 56f383cc2..4c2163dc9 100644 --- a/src/SharpCompress/Archives/Zip/ZipArchive.Factory.cs +++ b/src/SharpCompress/Archives/Zip/ZipArchive.Factory.cs @@ -97,53 +97,28 @@ public static IWritableArchive OpenArchive( 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/ArchiveType.cs b/src/SharpCompress/Common/ArchiveType.cs index 5952f6459..ae95af76e 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 000000000..a1982d1b8 --- /dev/null +++ b/src/SharpCompress/Common/Lzw/LzwEntry.Async.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using System.IO; +using System.Runtime.CompilerServices; +using System.Threading; +using SharpCompress.Readers; + +namespace SharpCompress.Common.Lzw; + +public partial class LzwEntry +{ + internal static async IAsyncEnumerable GetEntriesAsync( + Stream stream, + ReaderOptions options, + [EnumeratorCancellation] CancellationToken cancellationToken = default + ) + { + yield return new LzwEntry( + await LzwFilePart.CreateAsync(stream, options.ArchiveEncoding, cancellationToken), + options + ); + } +} diff --git a/src/SharpCompress/Common/Lzw/LzwEntry.cs b/src/SharpCompress/Common/Lzw/LzwEntry.cs new file mode 100644 index 000000000..924904283 --- /dev/null +++ b/src/SharpCompress/Common/Lzw/LzwEntry.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common.Options; +using SharpCompress.Readers; + +namespace SharpCompress.Common.Lzw; + +public partial class LzwEntry : Entry +{ + private readonly LzwFilePart? _filePart; + + internal LzwEntry(LzwFilePart? filePart, IReaderOptions readerOptions) + : base(readerOptions) + { + _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, ReaderOptions options) + { + yield return new LzwEntry(LzwFilePart.Create(stream, options.ArchiveEncoding), options); + } + + // 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 000000000..8b6a5a32d --- /dev/null +++ b/src/SharpCompress/Common/Lzw/LzwFilePart.Async.cs @@ -0,0 +1,23 @@ +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); + + // 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 new file mode 100644 index 000000000..74d682ead --- /dev/null +++ b/src/SharpCompress/Common/Lzw/LzwFilePart.cs @@ -0,0 +1,60 @@ +using System.IO; +using SharpCompress.Compressors.Lzw; + +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); + + // 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; + _name = DeriveFileName(stream); + } + + internal long EntryStartPosition { get; private set; } + + 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) + { + // 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 (unwrappedStream 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/Common/Lzw/LzwVolume.cs b/src/SharpCompress/Common/Lzw/LzwVolume.cs new file mode 100644 index 000000000..7ded1d267 --- /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 with { LeaveStreamOpen = false }) { } + + public override bool IsFirstVolume => true; + + public override bool IsMultiVolume => false; +} diff --git a/src/SharpCompress/Factories/Factory.cs b/src/SharpCompress/Factories/Factory.cs index 7bca8ecb7..69254cad0 100644 --- a/src/SharpCompress/Factories/Factory.cs +++ b/src/SharpCompress/Factories/Factory.cs @@ -18,6 +18,7 @@ static Factory() 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/GZipFactory.cs b/src/SharpCompress/Factories/GZipFactory.cs index 68aa8e783..6d38d4183 100644 --- a/src/SharpCompress/Factories/GZipFactory.cs +++ b/src/SharpCompress/Factories/GZipFactory.cs @@ -95,13 +95,8 @@ public IArchive OpenArchive( /// 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/LzwFactory.cs b/src/SharpCompress/Factories/LzwFactory.cs new file mode 100644 index 000000000..078fad373 --- /dev/null +++ b/src/SharpCompress/Factories/LzwFactory.cs @@ -0,0 +1,94 @@ +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; + +/// +/// 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 + ) => 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(); + using (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); + + /// + public ValueTask OpenAsyncReader( + Stream stream, + ReaderOptions? options, + CancellationToken cancellationToken = default + ) + { + cancellationToken.ThrowIfCancellationRequested(); + return new(LzwReader.OpenAsyncReader(stream, options)); + } + + #endregion +} diff --git a/src/SharpCompress/Factories/RarFactory.cs b/src/SharpCompress/Factories/RarFactory.cs index 11fe6cf81..f3236d2e4 100644 --- a/src/SharpCompress/Factories/RarFactory.cs +++ b/src/SharpCompress/Factories/RarFactory.cs @@ -90,11 +90,9 @@ public IArchive OpenArchive( /// 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 f8f4b7797..0a2762239 100644 --- a/src/SharpCompress/Factories/SevenZipFactory.cs +++ b/src/SharpCompress/Factories/SevenZipFactory.cs @@ -50,7 +50,7 @@ public IArchive OpenArchive(Stream stream, ReaderOptions? readerOptions = null) /// 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 IArchive OpenArchive(FileInfo fileInfo, ReaderOptions? readerOptions = nu /// public IAsyncArchive OpenAsyncArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) => - SevenZipArchive.OpenAsyncArchive(fileInfo, readerOptions, CancellationToken.None); + SevenZipArchive.OpenAsyncArchive(fileInfo, readerOptions); #endregion @@ -74,7 +74,7 @@ public IArchive OpenArchive( 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 IArchive OpenArchive( /// 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 f399b9846..233a51841 100644 --- a/src/SharpCompress/Factories/TarFactory.cs +++ b/src/SharpCompress/Factories/TarFactory.cs @@ -145,13 +145,8 @@ public IArchive OpenArchive( /// 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 f22cdf2e9..6d984259c 100644 --- a/src/SharpCompress/Factories/ZipFactory.cs +++ b/src/SharpCompress/Factories/ZipFactory.cs @@ -155,13 +155,8 @@ public IArchive OpenArchive( /// 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/Readers/Ace/AceReader.Factory.cs b/src/SharpCompress/Readers/Ace/AceReader.Factory.cs index 8daa344e0..9f873d77d 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 static IReader OpenReader(IEnumerable streams, ReaderOptions? opt 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 static IAsyncReader OpenAsyncReader( 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 22ec26664..abfad14af 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 f0f7b01b4..7a84f4c2f 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 3132d139f..55e96e734 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 a421a49e7..ea42b8274 100644 --- a/src/SharpCompress/Readers/IReaderOpenable.cs +++ b/src/SharpCompress/Readers/IReaderOpenable.cs @@ -17,20 +17,17 @@ public static abstract IReader OpenReader( 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.Async.cs b/src/SharpCompress/Readers/Lzw/LzwReader.Async.cs new file mode 100644 index 000000000..6479c9b50 --- /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 000000000..344a95724 --- /dev/null +++ b/src/SharpCompress/Readers/Lzw/LzwReader.Factory.cs @@ -0,0 +1,46 @@ +using System.IO; + +namespace SharpCompress.Readers.Lzw; + +public partial class LzwReader +#if NET8_0_OR_GREATER + : IReaderOpenable +#endif +{ + public static IAsyncReader OpenAsyncReader(string path, ReaderOptions? readerOptions = null) + { + path.NotNullOrEmpty(nameof(path)); + return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions); + } + + public static IAsyncReader OpenAsyncReader(Stream stream, ReaderOptions? readerOptions = null) + { + return (IAsyncReader)OpenReader(stream, readerOptions); + } + + public static IAsyncReader OpenAsyncReader( + FileInfo fileInfo, + ReaderOptions? readerOptions = null + ) + { + 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 000000000..875faf7a0 --- /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/Rar/RarReader.Factory.cs b/src/SharpCompress/Readers/Rar/RarReader.Factory.cs index 775b37644..5fa1cba00 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/ReaderFactory.cs b/src/SharpCompress/Readers/ReaderFactory.cs index 8ecb1b123..0a65c5cf9 100644 --- a/src/SharpCompress/Readers/ReaderFactory.cs +++ b/src/SharpCompress/Readers/ReaderFactory.cs @@ -77,7 +77,7 @@ public static IReader OpenReader(Stream stream, ReaderOptions? options = null) } 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/src/SharpCompress/Readers/Tar/TarReader.Factory.cs b/src/SharpCompress/Readers/Tar/TarReader.Factory.cs index 801440a70..b8f41e60b 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 289059fcb..f03ea4ab9 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 7fd8aec12..715bdc22f 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 static IWriter OpenWriter(Stream stream, GZipWriterOptions writerOptions) 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/IWriterOpenable.cs b/src/SharpCompress/Writers/IWriterOpenable.cs index fe40cda72..828b0b7c9 100644 --- a/src/SharpCompress/Writers/IWriterOpenable.cs +++ b/src/SharpCompress/Writers/IWriterOpenable.cs @@ -19,24 +19,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 c5f9c846b..d70774780 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 static IWriter OpenWriter(Stream stream, TarWriterOptions writerOptions) 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/Zip/ZipWriter.Factory.cs b/src/SharpCompress/Writers/Zip/ZipWriter.Factory.cs index 0df1a81ce..c4083aeae 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 static IWriter OpenWriter(Stream stream, ZipWriterOptions writerOptions) 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/Lzw/LzwReaderAsyncTests.cs b/tests/SharpCompress.Test/Lzw/LzwReaderAsyncTests.cs new file mode 100644 index 000000000..6ecc6047f --- /dev/null +++ b/tests/SharpCompress.Test/Lzw/LzwReaderAsyncTests.cs @@ -0,0 +1,43 @@ +using System.IO; +using SharpCompress.Common; +using SharpCompress.Readers; +using SharpCompress.Readers.Lzw; +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); + } + + [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 new file mode 100644 index 000000000..f75fd6664 --- /dev/null +++ b/tests/SharpCompress.Test/Lzw/LzwReaderTests.cs @@ -0,0 +1,91 @@ +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_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); + } + + [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/SharpCompress.Test/ReaderTests.cs b/tests/SharpCompress.Test/ReaderTests.cs index 6e5b4b9ec..2cc7d86c6 100644 --- a/tests/SharpCompress.Test/ReaderTests.cs +++ b/tests/SharpCompress.Test/ReaderTests.cs @@ -178,8 +178,7 @@ private async ValueTask ReadImplAsync( 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 4b66c0d9c..786cc41dc 100644 --- a/tests/SharpCompress.Test/WriterTests.cs +++ b/tests/SharpCompress.Test/WriterTests.cs @@ -91,8 +91,7 @@ await writer.WriteAllAsync( await using var reader = await ReaderFactory.OpenAsyncReader( new AsyncOnlyStream(SharpCompressStream.CreateNonDisposing(stream)), - readerOptions, - cancellationToken + readerOptions ); await reader.WriteAllToDirectoryAsync(SCRATCH_FILES_PATH, cancellationToken); } diff --git a/tests/TestArchives/Archives/large_test.txt.Z b/tests/TestArchives/Archives/large_test.txt.Z new file mode 100644 index 000000000..64ae2af12 Binary files /dev/null and b/tests/TestArchives/Archives/large_test.txt.Z differ