diff --git a/src/SharpCompress/Archives/ArchiveFactory.cs b/src/SharpCompress/Archives/ArchiveFactory.cs index 2a901900..06bc7434 100644 --- a/src/SharpCompress/Archives/ArchiveFactory.cs +++ b/src/SharpCompress/Archives/ArchiveFactory.cs @@ -41,7 +41,7 @@ public static class ArchiveFactory { readerOptions ??= new ReaderOptions(); stream = SharpCompressStream.Create(stream, bufferSize: readerOptions.BufferSize); - var factory = FindFactory(stream); + var factory = await FindFactoryAsync(stream, cancellationToken).ConfigureAwait(false); return await factory .OpenAsync(stream, readerOptions, cancellationToken) .ConfigureAwait(false); @@ -114,7 +114,7 @@ public static class ArchiveFactory { options ??= new ReaderOptions { LeaveStreamOpen = false }; - var factory = FindFactory(fileInfo); + var factory = await FindFactoryAsync(fileInfo, cancellationToken).ConfigureAwait(false); return await factory.OpenAsync(fileInfo, options, cancellationToken).ConfigureAwait(false); } @@ -292,6 +292,46 @@ public static class ArchiveFactory ); } + private static ValueTask FindFactoryAsync(FileInfo finfo, CancellationToken cancellationToken ) + where T : IFactory + { + finfo.NotNull(nameof(finfo)); + using Stream stream = finfo.OpenRead(); + return FindFactoryAsync(stream, cancellationToken); + } + + private static async ValueTask FindFactoryAsync(Stream stream, CancellationToken cancellationToken ) + where T : IFactory + { + stream.NotNull(nameof(stream)); + if (!stream.CanRead || !stream.CanSeek) + { + throw new ArgumentException("Stream should be readable and seekable"); + } + + var factories = Factory.Factories.OfType(); + + var startPosition = stream.Position; + + foreach (var factory in factories) + { + stream.Seek(startPosition, SeekOrigin.Begin); + + if (await factory.IsArchiveAsync(stream, cancellationToken: cancellationToken)) + { + stream.Seek(startPosition, SeekOrigin.Begin); + + return factory; + } + } + + var extensions = string.Join(", ", factories.Select(item => item.Name)); + + throw new InvalidOperationException( + $"Cannot determine compressed stream type. Supported Archive Formats: {extensions}" + ); + } + public static bool IsArchive( string filePath, out ArchiveType? type, diff --git a/tests/SharpCompress.Test/ArchiveTests.cs b/tests/SharpCompress.Test/ArchiveTests.cs index 916c9e2c..44332eef 100644 --- a/tests/SharpCompress.Test/ArchiveTests.cs +++ b/tests/SharpCompress.Test/ArchiveTests.cs @@ -9,6 +9,7 @@ using SharpCompress.Compressors.Xz; using SharpCompress.Crypto; using SharpCompress.IO; using SharpCompress.Readers; +using SharpCompress.Test.Mocks; using SharpCompress.Writers; using SharpCompress.Writers.Zip; using Xunit; @@ -599,7 +600,7 @@ public class ArchiveTests : ReaderTests throwOnDispose: true ) ) - using (var archive = archiveFactory.Open(stream, readerOptions)) + using (var archive = await archiveFactory.OpenAsync(new AsyncOnlyStream(stream), readerOptions)) { try { diff --git a/tests/SharpCompress.Test/WriterTests.cs b/tests/SharpCompress.Test/WriterTests.cs index 1d2d8a13..b09cfee4 100644 --- a/tests/SharpCompress.Test/WriterTests.cs +++ b/tests/SharpCompress.Test/WriterTests.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using SharpCompress.Common; using SharpCompress.IO; using SharpCompress.Readers; +using SharpCompress.Test.Mocks; using SharpCompress.Writers; namespace SharpCompress.Test; @@ -62,7 +63,7 @@ public class WriterTests : TestBase CancellationToken cancellationToken = default ) { - using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive))) + using (Stream stream = new AsyncOnlyStream(File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive)))) { var writerOptions = new WriterOptions(compressionType) { LeaveStreamOpen = true };