diff --git a/src/SharpCompress/Archives/Tar/TarArchive.Factory.cs b/src/SharpCompress/Archives/Tar/TarArchive.Factory.cs index fcd6c3c2..8f9bfd4d 100644 --- a/src/SharpCompress/Archives/Tar/TarArchive.Factory.cs +++ b/src/SharpCompress/Archives/Tar/TarArchive.Factory.cs @@ -6,12 +6,9 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using SharpCompress.Common; -using SharpCompress.Common.Tar; using SharpCompress.Common.Tar.Headers; using SharpCompress.IO; using SharpCompress.Readers; -using SharpCompress.Writers; -using SharpCompress.Writers.Tar; namespace SharpCompress.Archives.Tar; @@ -176,11 +173,11 @@ public partial class TarArchive CancellationToken cancellationToken = default ) { - cancellationToken.ThrowIfCancellationRequested(); try { var tarHeader = new TarHeader(new ArchiveEncoding()); - var readSucceeded = await tarHeader.ReadAsync(stream); + var reader = new AsyncBinaryReader(stream, false); + var readSucceeded = await tarHeader.ReadAsync(reader); var isEmptyArchive = tarHeader.Name?.Length == 0 && tarHeader.Size == 0 diff --git a/src/SharpCompress/Common/Tar/Headers/TarHeader.cs b/src/SharpCompress/Common/Tar/Headers/TarHeader.cs index b86ce809..2823be2d 100644 --- a/src/SharpCompress/Common/Tar/Headers/TarHeader.cs +++ b/src/SharpCompress/Common/Tar/Headers/TarHeader.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.Buffers.Binary; using System.Collections.Generic; using System.IO; @@ -496,7 +497,7 @@ internal sealed class TarHeader return true; } - internal async Task ReadAsync(Stream stream) + internal async Task ReadAsync(AsyncBinaryReader reader) { string? longName = null; string? longLinkName = null; @@ -506,7 +507,7 @@ internal sealed class TarHeader do { - buffer = await ReadBlockAsync(stream); + buffer = await ReadBlockAsync(reader); if (buffer.Length == 0) { @@ -519,12 +520,12 @@ internal sealed class TarHeader // to apply to the header that follows them. if (entryType == EntryType.LongName) { - longName = await ReadLongNameAsync(stream, buffer); + longName = await ReadLongNameAsync(reader, buffer); continue; } else if (entryType == EntryType.LongLink) { - longLinkName = await ReadLongNameAsync(stream, buffer); + longLinkName = await ReadLongNameAsync(reader, buffer); continue; } @@ -616,36 +617,27 @@ internal sealed class TarHeader public string? Magic { get; set; } - private static async Task ReadBlockAsync(Stream stream) + private static async ValueTask ReadBlockAsync(AsyncBinaryReader reader) { - var buffer = new byte[BLOCK_SIZE]; - int bytesRead = 0; - int totalBytesRead = 0; - - while (totalBytesRead < BLOCK_SIZE) + var buffer = ArrayPool.Shared.Rent(BLOCK_SIZE); + try { - bytesRead = await stream.ReadAsync(buffer, totalBytesRead, BLOCK_SIZE - totalBytesRead); - if (bytesRead == 0) + await reader.ReadBytesAsync(buffer, 0, BLOCK_SIZE); + + if (buffer.Length != 0 && buffer.Length < BLOCK_SIZE) { - break; + throw new InvalidFormatException("Buffer is invalid size"); } - totalBytesRead += bytesRead; - } - if (totalBytesRead == 0) + return buffer; + } + finally { - return Array.Empty(); + ArrayPool.Shared.Return(buffer); } - - if (totalBytesRead < BLOCK_SIZE) - { - throw new InvalidFormatException("Buffer is invalid size"); - } - - return buffer; } - private async Task ReadLongNameAsync(Stream stream, byte[] buffer) + private async Task ReadLongNameAsync(AsyncBinaryReader reader, byte[] buffer) { var size = ReadSize(buffer); @@ -658,33 +650,31 @@ internal sealed class TarHeader } var nameLength = (int)size; - var nameBytes = new byte[nameLength]; - int bytesRead = 0; - int totalBytesRead = 0; - - while (totalBytesRead < nameLength) + var nameBytes = ArrayPool.Shared.Rent(nameLength); + try { - bytesRead = await stream.ReadAsync( - nameBytes, - totalBytesRead, - nameLength - totalBytesRead - ); - if (bytesRead == 0) + await reader.ReadBytesAsync(buffer, 0, nameLength); + var remainingBytesToRead = BLOCK_SIZE - (nameLength % BLOCK_SIZE); + + // Read the rest of the block and discard the data + if (remainingBytesToRead < BLOCK_SIZE) { - break; + var remainingBytes = ArrayPool.Shared.Rent(remainingBytesToRead); + try + { + await reader.ReadBytesAsync(remainingBytes, 0, remainingBytesToRead); + } + finally + { + ArrayPool.Shared.Return(nameBytes); + } } - totalBytesRead += bytesRead; + + return ArchiveEncoding.Decode(nameBytes, 0, nameLength).TrimNulls(); } - - var remainingBytesToRead = BLOCK_SIZE - (nameLength % BLOCK_SIZE); - - // Read the rest of the block and discard the data - if (remainingBytesToRead < BLOCK_SIZE) + finally { - var paddingBuffer = new byte[remainingBytesToRead]; - await stream.ReadAsync(paddingBuffer, 0, remainingBytesToRead); + ArrayPool.Shared.Return(nameBytes); } - - return ArchiveEncoding.Decode(nameBytes, 0, nameBytes.Length).TrimNulls(); } } diff --git a/src/SharpCompress/Common/Tar/TarHeaderFactory.cs b/src/SharpCompress/Common/Tar/TarHeaderFactory.cs index ac87eb60..8f155b11 100644 --- a/src/SharpCompress/Common/Tar/TarHeaderFactory.cs +++ b/src/SharpCompress/Common/Tar/TarHeaderFactory.cs @@ -54,7 +54,6 @@ internal static class TarHeaderFactory } } - internal static async IAsyncEnumerable ReadHeaderAsync( StreamingMode mode, Stream stream, @@ -66,26 +65,26 @@ internal static class TarHeaderFactory TarHeader? header = null; try { + var reader = new AsyncBinaryReader(stream, false); header = new TarHeader(archiveEncoding); - - if (!await header.ReadAsync(stream)) + if (!await header.ReadAsync(reader)) { yield break; } switch (mode) { case StreamingMode.Seekable: - { - header.DataStartPosition = stream.Position; + { + header.DataStartPosition = stream.Position; - //skip to nearest 512 - stream.Position += PadTo512(header.Size); - } + //skip to nearest 512 + stream.Position += PadTo512(header.Size); + } break; case StreamingMode.Streaming: - { - header.PackedStream = new TarReadOnlySubStream(stream, header.Size); - } + { + header.PackedStream = new TarReadOnlySubStream(stream, header.Size); + } break; default: { diff --git a/src/SharpCompress/Factories/AceFactory.cs b/src/SharpCompress/Factories/AceFactory.cs index 77fad2d8..29885b16 100644 --- a/src/SharpCompress/Factories/AceFactory.cs +++ b/src/SharpCompress/Factories/AceFactory.cs @@ -39,14 +39,14 @@ namespace SharpCompress.Factories public IReader OpenReader(Stream stream, ReaderOptions? options) => AceReader.OpenReader(stream, options); - public IAsyncReader OpenAsyncReader( + public ValueTask OpenAsyncReader( Stream stream, ReaderOptions? options, CancellationToken cancellationToken = default ) { cancellationToken.ThrowIfCancellationRequested(); - return (IAsyncReader)AceReader.OpenReader(stream, options); + return new((IAsyncReader)AceReader.OpenReader(stream, options)); } } } diff --git a/src/SharpCompress/Factories/ArcFactory.cs b/src/SharpCompress/Factories/ArcFactory.cs index ff402101..7cc84417 100644 --- a/src/SharpCompress/Factories/ArcFactory.cs +++ b/src/SharpCompress/Factories/ArcFactory.cs @@ -52,14 +52,14 @@ namespace SharpCompress.Factories public IReader OpenReader(Stream stream, ReaderOptions? options) => ArcReader.OpenReader(stream, options); - public IAsyncReader OpenAsyncReader( + public ValueTask OpenAsyncReader( Stream stream, ReaderOptions? options, CancellationToken cancellationToken = default ) { cancellationToken.ThrowIfCancellationRequested(); - return (IAsyncReader)ArcReader.OpenReader(stream, options); + return new((IAsyncReader)ArcReader.OpenReader(stream, options)); } public override async ValueTask IsArchiveAsync( diff --git a/src/SharpCompress/Factories/ArjFactory.cs b/src/SharpCompress/Factories/ArjFactory.cs index 623b94e3..fd41e2fd 100644 --- a/src/SharpCompress/Factories/ArjFactory.cs +++ b/src/SharpCompress/Factories/ArjFactory.cs @@ -39,14 +39,14 @@ namespace SharpCompress.Factories public IReader OpenReader(Stream stream, ReaderOptions? options) => ArjReader.OpenReader(stream, options); - public IAsyncReader OpenAsyncReader( + public ValueTask OpenAsyncReader( Stream stream, ReaderOptions? options, CancellationToken cancellationToken = default ) { cancellationToken.ThrowIfCancellationRequested(); - return (IAsyncReader)ArjReader.OpenReader(stream, options); + return new((IAsyncReader)ArjReader.OpenReader(stream, options)); } } } diff --git a/src/SharpCompress/Factories/GZipFactory.cs b/src/SharpCompress/Factories/GZipFactory.cs index f583ad64..7c571038 100644 --- a/src/SharpCompress/Factories/GZipFactory.cs +++ b/src/SharpCompress/Factories/GZipFactory.cs @@ -144,14 +144,14 @@ public class GZipFactory GZipReader.OpenReader(stream, options); /// - public IAsyncReader OpenAsyncReader( + public ValueTask OpenAsyncReader( Stream stream, ReaderOptions? options, CancellationToken cancellationToken = default ) { cancellationToken.ThrowIfCancellationRequested(); - return (IAsyncReader)GZipReader.OpenReader(stream, options); + return new((IAsyncReader)GZipReader.OpenReader(stream, options)); } /// diff --git a/src/SharpCompress/Factories/RarFactory.cs b/src/SharpCompress/Factories/RarFactory.cs index 3bf93622..4142bc0b 100644 --- a/src/SharpCompress/Factories/RarFactory.cs +++ b/src/SharpCompress/Factories/RarFactory.cs @@ -111,14 +111,14 @@ public class RarFactory : Factory, IArchiveFactory, IMultiArchiveFactory, IReade RarReader.OpenReader(stream, options); /// - public IAsyncReader OpenAsyncReader( + public ValueTask OpenAsyncReader( Stream stream, ReaderOptions? options, CancellationToken cancellationToken = default ) { cancellationToken.ThrowIfCancellationRequested(); - return (IAsyncReader)RarReader.OpenReader(stream, options); + return new((IAsyncReader)RarReader.OpenReader(stream, options)); } #endregion diff --git a/src/SharpCompress/Factories/TarFactory.cs b/src/SharpCompress/Factories/TarFactory.cs index 0628a5ad..e9102282 100644 --- a/src/SharpCompress/Factories/TarFactory.cs +++ b/src/SharpCompress/Factories/TarFactory.cs @@ -1,25 +1,15 @@ -using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Threading; using System.Threading.Tasks; using SharpCompress.Archives; using SharpCompress.Archives.Tar; using SharpCompress.Common; -using SharpCompress.Compressors; -using SharpCompress.Compressors.BZip2; -using SharpCompress.Compressors.Deflate; -using SharpCompress.Compressors.LZMA; -using SharpCompress.Compressors.Lzw; -using SharpCompress.Compressors.Xz; -using SharpCompress.Compressors.ZStandard; using SharpCompress.IO; using SharpCompress.Readers; using SharpCompress.Readers.Tar; using SharpCompress.Writers; using SharpCompress.Writers.Tar; -using GZipArchive = SharpCompress.Archives.GZip.GZipArchive; namespace SharpCompress.Factories; @@ -45,7 +35,7 @@ public class TarFactory /// public override IEnumerable GetSupportedExtensions() { - foreach (var testOption in compressionOptions) + foreach (var testOption in TarWrapper.Wrappers) { foreach (var ext in testOption.KnownExtensions) { @@ -59,15 +49,55 @@ public class TarFactory Stream stream, string? password = null, int bufferSize = ReaderOptions.DefaultBufferSize - ) => TarArchive.IsTarFile(stream); + ) + { + var rewindableStream = new SharpCompressStream(stream); + long pos = rewindableStream.GetPosition(); + foreach (var wrapper in TarWrapper.Wrappers) + { + rewindableStream.StackSeek(pos); + if (wrapper.IsMatch(rewindableStream)) + { + rewindableStream.StackSeek(pos); + var decompressedStream = wrapper.CreateStream(rewindableStream); + if (TarArchive.IsTarFile(decompressedStream)) + { + rewindableStream.StackSeek(pos); + return true; + } + } + } + + return false; + } /// - public override ValueTask IsArchiveAsync( + public override async ValueTask IsArchiveAsync( Stream stream, string? password = null, int bufferSize = ReaderOptions.DefaultBufferSize, CancellationToken cancellationToken = default - ) => TarArchive.IsTarFileAsync(stream, cancellationToken); + ) + { + var rewindableStream = new SharpCompressStream(stream); + long pos = rewindableStream.GetPosition(); + foreach (var wrapper in TarWrapper.Wrappers) + { + rewindableStream.StackSeek(pos); + if (await wrapper.IsMatchAsync(rewindableStream, cancellationToken)) + { + rewindableStream.StackSeek(pos); + var decompressedStream = wrapper.CreateStream(rewindableStream); + if (await TarArchive.IsTarFileAsync(decompressedStream, cancellationToken)) + { + rewindableStream.StackSeek(pos); + return true; + } + } + } + + return false; + } #endregion @@ -126,161 +156,54 @@ public class TarFactory #region IReaderFactory - - protected class TestOption - { - public readonly CompressionType Type; - public readonly Func CanHandle; - public readonly bool WrapInSharpCompressStream; - - public readonly Func CreateStream; - - public readonly IEnumerable KnownExtensions; - - public TestOption( - CompressionType Type, - Func CanHandle, - Func CreateStream, - IEnumerable KnownExtensions, - bool WrapInSharpCompressStream = true - ) - { - this.Type = Type; - this.CanHandle = CanHandle; - this.WrapInSharpCompressStream = WrapInSharpCompressStream; - this.CreateStream = CreateStream; - this.KnownExtensions = KnownExtensions; - } - } - - // https://en.wikipedia.org/wiki/Tar_(computing)#Suffixes_for_compressed_files - protected TestOption[] compressionOptions = - [ - new(CompressionType.None, (stream) => true, (stream) => stream, ["tar"], false), // We always do a test for IsTarFile later - new( - CompressionType.BZip2, - BZip2Stream.IsBZip2, - (stream) => new BZip2Stream(stream, CompressionMode.Decompress, false), - ["tar.bz2", "tb2", "tbz", "tbz2", "tz2"] - ), - new( - CompressionType.GZip, - GZipArchive.IsGZipFile, - (stream) => new GZipStream(stream, CompressionMode.Decompress), - ["tar.gz", "taz", "tgz"] - ), - new( - CompressionType.ZStandard, - ZStandardStream.IsZStandard, - (stream) => new ZStandardStream(stream), - ["tar.zst", "tar.zstd", "tzst", "tzstd"] - ), - new( - CompressionType.LZip, - LZipStream.IsLZipFile, - (stream) => new LZipStream(stream, CompressionMode.Decompress), - ["tar.lz"] - ), - new( - CompressionType.Xz, - XZStream.IsXZStream, - (stream) => new XZStream(stream), - ["tar.xz", "txz"], - false - ), - new( - CompressionType.Lzw, - LzwStream.IsLzwStream, - (stream) => new LzwStream(stream), - ["tar.Z", "tZ", "taZ"], - false - ), - ]; - /// - internal override bool TryOpenReader( - SharpCompressStream rewindableStream, - ReaderOptions options, - out IReader? reader - ) + public IReader OpenReader(Stream stream, ReaderOptions? options) { - reader = null; - long pos = ((IStreamStack)rewindableStream).GetPosition(); - TestOption? testedOption = null; - if (!string.IsNullOrWhiteSpace(options.ExtensionHint)) + options ??= new ReaderOptions(); + var rewindableStream = new SharpCompressStream(stream); + long pos = rewindableStream.GetPosition(); + foreach (var wrapper in TarWrapper.Wrappers) { - testedOption = compressionOptions.FirstOrDefault(a => - a.KnownExtensions.Contains( - options.ExtensionHint, - StringComparer.CurrentCultureIgnoreCase - ) - ); - if (testedOption != null) + rewindableStream.StackSeek(pos); + if (wrapper.IsMatch(rewindableStream)) { - reader = TryOption(rewindableStream, options, pos, testedOption); - if (reader != null) + rewindableStream.StackSeek(pos); + var decompressedStream = wrapper.CreateStream(rewindableStream); + if (TarArchive.IsTarFile(decompressedStream)) { - return true; + rewindableStream.StackSeek(pos); + return new TarReader(rewindableStream, options, wrapper.CompressionType); } } } - - foreach (var testOption in compressionOptions) - { - if (testedOption == testOption) - { - continue; // Already tested above - } - ((IStreamStack)rewindableStream).StackSeek(pos); - reader = TryOption(rewindableStream, options, pos, testOption); - if (reader != null) - { - return true; - } - } - - return false; - } - - private static IReader? TryOption( - SharpCompressStream rewindableStream, - ReaderOptions options, - long pos, - TestOption testOption - ) - { - if (testOption.CanHandle(rewindableStream)) - { - ((IStreamStack)rewindableStream).StackSeek(pos); - var inStream = rewindableStream; - if (testOption.WrapInSharpCompressStream) - { - inStream = SharpCompressStream.Create(rewindableStream, leaveOpen: true); - } - var testStream = testOption.CreateStream(rewindableStream); - - if (TarArchive.IsTarFile(testStream)) - { - ((IStreamStack)rewindableStream).StackSeek(pos); - return new TarReader(rewindableStream, options, testOption.Type); - } - } - - return null; + throw new InvalidFormatException("Not a tar file."); } /// - public IReader OpenReader(Stream stream, ReaderOptions? options) => - TarReader.OpenReader(stream, options); - - /// - public IAsyncReader OpenAsyncReader( + public async ValueTask OpenAsyncReader( Stream stream, ReaderOptions? options, CancellationToken cancellationToken = default ) { cancellationToken.ThrowIfCancellationRequested(); + options ??= new ReaderOptions(); + var rewindableStream = new SharpCompressStream(stream); + long pos = rewindableStream.GetPosition(); + foreach (var wrapper in TarWrapper.Wrappers) + { + rewindableStream.StackSeek(pos); + if (await wrapper.IsMatchAsync(rewindableStream, cancellationToken)) + { + rewindableStream.StackSeek(pos); + var decompressedStream = wrapper.CreateStream(rewindableStream); + if (await TarArchive.IsTarFileAsync(decompressedStream, cancellationToken)) + { + rewindableStream.StackSeek(pos); + return new TarReader(rewindableStream, options, wrapper.CompressionType); + } + } + } return (IAsyncReader)TarReader.OpenReader(stream, options); } diff --git a/src/SharpCompress/Factories/TarWrapper.cs b/src/SharpCompress/Factories/TarWrapper.cs new file mode 100644 index 00000000..560a54a4 --- /dev/null +++ b/src/SharpCompress/Factories/TarWrapper.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using SharpCompress.Archives.GZip; +using SharpCompress.Common; +using SharpCompress.Compressors; +using SharpCompress.Compressors.BZip2; +using SharpCompress.Compressors.Deflate; +using SharpCompress.Compressors.LZMA; +using SharpCompress.Compressors.Lzw; +using SharpCompress.Compressors.Xz; +using SharpCompress.Compressors.ZStandard; + +namespace SharpCompress.Factories; + +public class TarWrapper( + CompressionType type, + Func canHandle, + Func> canHandleAsync, + Func createStream, + IEnumerable knownExtensions, + bool wrapInSharpCompressStream = true +) +{ + public CompressionType CompressionType { get; } = type; + public Func IsMatch { get; } = canHandle; + public Func> IsMatchAsync { get; } = canHandleAsync; + public bool WrapInSharpCompressStream { get; } = wrapInSharpCompressStream; + + public Func CreateStream { get; } = createStream; + + public IEnumerable KnownExtensions { get; } = knownExtensions; + + // https://en.wikipedia.org/wiki/Tar_(computing)#Suffixes_for_compressed_files + public static TarWrapper[] Wrappers { get; } = + [ + new( + CompressionType.None, + (_) => true, + (_, _) => new ValueTask(true), + (stream) => stream, + ["tar"], + false + ), // We always do a test for IsTarFile later + new( + CompressionType.BZip2, + BZip2Stream.IsBZip2, + BZip2Stream.IsBZip2Async, + (stream) => new BZip2Stream(stream, CompressionMode.Decompress, false), + ["tar.bz2", "tb2", "tbz", "tbz2", "tz2"] + ), + new( + CompressionType.GZip, + GZipArchive.IsGZipFile, + GZipArchive.IsGZipFileAsync, + (stream) => new GZipStream(stream, CompressionMode.Decompress), + ["tar.gz", "taz", "tgz"] + ), + new( + CompressionType.ZStandard, + ZStandardStream.IsZStandard, + ZStandardStream.IsZStandardAsync, + (stream) => new ZStandardStream(stream), + ["tar.zst", "tar.zstd", "tzst", "tzstd"] + ), + new( + CompressionType.LZip, + LZipStream.IsLZipFile, + LZipStream.IsLZipFileAsync, + (stream) => new LZipStream(stream, CompressionMode.Decompress), + ["tar.lz"] + ), + new( + CompressionType.Xz, + XZStream.IsXZStream, + XZStream.IsXZStreamAsync, + (stream) => new XZStream(stream), + ["tar.xz", "txz"], + false + ), + new( + CompressionType.Lzw, + LzwStream.IsLzwStream, + LzwStream.IsLzwStreamAsync, + (stream) => new LzwStream(stream), + ["tar.Z", "tZ", "taZ"], + false + ), + ]; +} diff --git a/src/SharpCompress/Factories/ZipFactory.cs b/src/SharpCompress/Factories/ZipFactory.cs index 095da20f..9e2a928e 100644 --- a/src/SharpCompress/Factories/ZipFactory.cs +++ b/src/SharpCompress/Factories/ZipFactory.cs @@ -190,14 +190,14 @@ public class ZipFactory ZipReader.OpenReader(stream, options); /// - public IAsyncReader OpenAsyncReader( + public ValueTask OpenAsyncReader( Stream stream, ReaderOptions? options, CancellationToken cancellationToken = default ) { cancellationToken.ThrowIfCancellationRequested(); - return (IAsyncReader)ZipReader.OpenReader(stream, options); + return new((IAsyncReader)ZipReader.OpenReader(stream, options)); } #endregion diff --git a/src/SharpCompress/Readers/IReaderFactory.cs b/src/SharpCompress/Readers/IReaderFactory.cs index 52e7d35e..fb8c2e9f 100644 --- a/src/SharpCompress/Readers/IReaderFactory.cs +++ b/src/SharpCompress/Readers/IReaderFactory.cs @@ -1,5 +1,6 @@ using System.IO; using System.Threading; +using System.Threading.Tasks; namespace SharpCompress.Readers; @@ -20,7 +21,7 @@ public interface IReaderFactory : Factories.IFactory /// /// /// - IAsyncReader OpenAsyncReader( + ValueTask OpenAsyncReader( Stream stream, ReaderOptions? options, CancellationToken cancellationToken diff --git a/src/SharpCompress/Readers/ReaderFactory.cs b/src/SharpCompress/Readers/ReaderFactory.cs index 8230bf32..809714c7 100644 --- a/src/SharpCompress/Readers/ReaderFactory.cs +++ b/src/SharpCompress/Readers/ReaderFactory.cs @@ -70,7 +70,7 @@ public static class ReaderFactory var bStream = new SharpCompressStream(stream, bufferSize: options.BufferSize); - long pos = ((IStreamStack)bStream).GetPosition(); + long pos = bStream.GetPosition(); var factories = Factories.Factory.Factories.OfType(); @@ -89,7 +89,7 @@ public static class ReaderFactory { return reader; } - ((IStreamStack)bStream).StackSeek(pos); + bStream.StackSeek(pos); } foreach (var factory in factories) @@ -98,7 +98,7 @@ public static class ReaderFactory { continue; // Already tested above } - ((IStreamStack)bStream).StackSeek(pos); + bStream.StackSeek(pos); if (factory.TryOpenReader(bStream, options, out var reader) && reader != null) { return reader; @@ -120,13 +120,11 @@ public static class ReaderFactory options ??= new ReaderOptions() { LeaveStreamOpen = false }; var bStream = new SharpCompressStream(stream, bufferSize: options.BufferSize); + long pos = bStream.GetPosition(); - long pos = ((IStreamStack)bStream).GetPosition(); - - var factories = Factories.Factory.Factories.OfType(); + var factories = Factory.Factories.OfType(); Factory? testedFactory = null; - if (!string.IsNullOrWhiteSpace(options.ExtensionHint)) { testedFactory = factories.FirstOrDefault(a => @@ -135,7 +133,7 @@ public static class ReaderFactory ); if (testedFactory is IReaderFactory readerFactory) { - ((IStreamStack)bStream).StackSeek(pos); + bStream.StackSeek(pos); if ( await testedFactory.IsArchiveAsync( bStream, @@ -143,11 +141,11 @@ public static class ReaderFactory ) ) { - ((IStreamStack)bStream).StackSeek(pos); - return readerFactory.OpenAsyncReader(bStream, options, cancellationToken); + bStream.StackSeek(pos); + return await readerFactory.OpenAsyncReader(bStream, options, cancellationToken); } } - ((IStreamStack)bStream).StackSeek(pos); + bStream.StackSeek(pos); } foreach (var factory in factories) @@ -156,14 +154,14 @@ public static class ReaderFactory { continue; // Already tested above } - ((IStreamStack)bStream).StackSeek(pos); + bStream.StackSeek(pos); if ( factory is IReaderFactory readerFactory && await factory.IsArchiveAsync(bStream, cancellationToken: cancellationToken) ) { - ((IStreamStack)bStream).StackSeek(pos); - return readerFactory.OpenAsyncReader(bStream, options, cancellationToken); + bStream.StackSeek(pos); + return await readerFactory.OpenAsyncReader(bStream, options, cancellationToken); } } diff --git a/src/SharpCompress/Readers/Tar/TarReader.Factory.cs b/src/SharpCompress/Readers/Tar/TarReader.Factory.cs index 7d4989c3..801440a7 100644 --- a/src/SharpCompress/Readers/Tar/TarReader.Factory.cs +++ b/src/SharpCompress/Readers/Tar/TarReader.Factory.cs @@ -1,4 +1,3 @@ - using System.IO; using System.Threading; using SharpCompress.Common; @@ -7,7 +6,7 @@ namespace SharpCompress.Readers.Tar; public partial class TarReader #if NET8_0_OR_GREATER -: IReaderOpenable + : IReaderOpenable #endif { public static IAsyncReader OpenAsyncReader( diff --git a/src/SharpCompress/Readers/Tar/TarReader.cs b/src/SharpCompress/Readers/Tar/TarReader.cs index 7f53961f..a0d83a38 100644 --- a/src/SharpCompress/Readers/Tar/TarReader.cs +++ b/src/SharpCompress/Readers/Tar/TarReader.cs @@ -58,9 +58,7 @@ public partial class TarReader : AbstractReader stream.NotNull(nameof(stream)); options = options ?? new ReaderOptions(); var rewindableStream = new SharpCompressStream(stream); - long pos = ((IStreamStack)rewindableStream).GetPosition(); - if (GZipArchive.IsGZipFile(rewindableStream)) { ((IStreamStack)rewindableStream).StackSeek(pos); @@ -72,7 +70,6 @@ public partial class TarReader : AbstractReader } throw new InvalidFormatException("Not a tar file."); } - ((IStreamStack)rewindableStream).StackSeek(pos); if (BZip2Stream.IsBZip2(rewindableStream)) { @@ -85,7 +82,6 @@ public partial class TarReader : AbstractReader } throw new InvalidFormatException("Not a tar file."); } - ((IStreamStack)rewindableStream).StackSeek(pos); if (ZStandardStream.IsZStandard(rewindableStream)) { @@ -110,7 +106,6 @@ public partial class TarReader : AbstractReader } throw new InvalidFormatException("Not a tar file."); } - ((IStreamStack)rewindableStream).StackSeek(pos); return new TarReader(rewindableStream, options, CompressionType.None); } diff --git a/tests/SharpCompress.Test/ReaderTests.cs b/tests/SharpCompress.Test/ReaderTests.cs index fa48e74a..54399ee1 100644 --- a/tests/SharpCompress.Test/ReaderTests.cs +++ b/tests/SharpCompress.Test/ReaderTests.cs @@ -121,8 +121,16 @@ public abstract class ReaderTests : TestBase where T : IFactory { testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); - var factory = await ArchiveFactory.FindFactoryAsync(testArchive, cancellationToken); - (await factory.IsArchiveAsync(new FileInfo(testArchive).OpenRead(), cancellationToken: cancellationToken)).Should().BeTrue(); + var factory = new TarFactory(); + factory.IsArchive(new FileInfo(testArchive).OpenRead()).Should().BeTrue(); + ( + await factory.IsArchiveAsync( + new FileInfo(testArchive).OpenRead(), + cancellationToken: cancellationToken + ) + ) + .Should() + .BeTrue(); } protected async Task ReadAsync( diff --git a/tests/SharpCompress.Test/Tar/TarReaderAsyncTests.cs b/tests/SharpCompress.Test/Tar/TarReaderAsyncTests.cs index 027a8dad..45b80437 100644 --- a/tests/SharpCompress.Test/Tar/TarReaderAsyncTests.cs +++ b/tests/SharpCompress.Test/Tar/TarReaderAsyncTests.cs @@ -46,10 +46,8 @@ public class TarReaderAsyncTests : ReaderTests public async ValueTask Tar_Z_Reader_Async() => await ReadAsync("Tar.tar.Z", CompressionType.Lzw); - [Fact] - public async ValueTask Tar_BZip2_Reader_Async_Assert() => - await AssertArchiveAsync("Tar.tar.bz2", default); + public async ValueTask Tar_Async_Assert() => await AssertArchiveAsync("Tar.tar"); [Fact] public async ValueTask Tar_BZip2_Reader_Async() =>