diff --git a/src/SharpCompress/Archives/ArchiveFactory.cs b/src/SharpCompress/Archives/ArchiveFactory.cs index 3f479327..02c10699 100644 --- a/src/SharpCompress/Archives/ArchiveFactory.cs +++ b/src/SharpCompress/Archives/ArchiveFactory.cs @@ -239,4 +239,6 @@ public static IEnumerable GetFileParts(FileInfo part1) } } } + + public static IArchiveFactory AutoFactory { get; } = new AutoArchiveFactory(); } diff --git a/src/SharpCompress/Archives/AutoArchiveFactory.cs b/src/SharpCompress/Archives/AutoArchiveFactory.cs new file mode 100644 index 00000000..14038ea1 --- /dev/null +++ b/src/SharpCompress/Archives/AutoArchiveFactory.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common; +using SharpCompress.Readers; + +namespace SharpCompress.Archives; + +class AutoArchiveFactory : IArchiveFactory +{ + public string Name => nameof(AutoArchiveFactory); + + public ArchiveType? KnownArchiveType => null; + + public IEnumerable GetSupportedExtensions() => throw new NotSupportedException(); + + public bool IsArchive(Stream stream, string? password = null) => + throw new NotSupportedException(); + + public FileInfo? GetFilePart(int index, FileInfo part1) => throw new NotSupportedException(); + + public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) => + ArchiveFactory.Open(stream, readerOptions); + + public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) => + ArchiveFactory.Open(fileInfo, readerOptions); +} diff --git a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs index ee165982..88a85e96 100644 --- a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs +++ b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs @@ -163,7 +163,7 @@ private void LoadFactory(Stream stream) { stream.Position = 0; var reader = new ArchiveReader(); - reader.Open(stream); + reader.Open(stream, lookForHeader: ReaderOptions.LookForHeader); _database = reader.ReadDatabase(new PasswordProvider(ReaderOptions.Password)); } } diff --git a/src/SharpCompress/Common/SevenZip/ArchiveReader.cs b/src/SharpCompress/Common/SevenZip/ArchiveReader.cs index 3e506e0e..83eae537 100644 --- a/src/SharpCompress/Common/SevenZip/ArchiveReader.cs +++ b/src/SharpCompress/Common/SevenZip/ArchiveReader.cs @@ -1220,23 +1220,46 @@ out digests #region Public Methods - public void Open(Stream stream) + public void Open(Stream stream, bool lookForHeader) { Close(); _streamOrigin = stream.Position; _streamEnding = stream.Length; - // TODO: Check Signature! - _header = new byte[0x20]; - for (var offset = 0; offset < 0x20; ) + var canScan = lookForHeader ? 0x80000 - 20 : 0; + while (true) { - var delta = stream.Read(_header, offset, 0x20 - offset); - if (delta == 0) + // TODO: Check Signature! + _header = new byte[0x20]; + for (var offset = 0; offset < 0x20; ) { - throw new EndOfStreamException(); + var delta = stream.Read(_header, offset, 0x20 - offset); + if (delta == 0) + { + throw new EndOfStreamException(); + } + + offset += delta; + } + + if ( + !lookForHeader + || _header + .AsSpan(0, length: 6) + .SequenceEqual([0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C]) + ) + { + break; + } + + if (canScan == 0) + { + throw new InvalidFormatException("Unable to find 7z signature"); } - offset += delta; + + canScan--; + stream.Position = ++_streamOrigin; } _stream = stream; diff --git a/tests/SharpCompress.Test/ArchiveTests.cs b/tests/SharpCompress.Test/ArchiveTests.cs index 7d94b29d..29903efe 100644 --- a/tests/SharpCompress.Test/ArchiveTests.cs +++ b/tests/SharpCompress.Test/ArchiveTests.cs @@ -73,27 +73,45 @@ CompressionType compression } } - protected void ArchiveStreamRead(string testArchive, ReaderOptions? readerOptions = null) + protected void ArchiveStreamRead(string testArchive, ReaderOptions? readerOptions = null) => + ArchiveStreamRead(ArchiveFactory.AutoFactory, testArchive, readerOptions); + + protected void ArchiveStreamRead( + IArchiveFactory archiveFactory, + string testArchive, + ReaderOptions? readerOptions = null + ) { testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); - ArchiveStreamRead(readerOptions, testArchive); + ArchiveStreamRead(archiveFactory, readerOptions, testArchive); } protected void ArchiveStreamRead( ReaderOptions? readerOptions = null, params string[] testArchives + ) => ArchiveStreamRead(ArchiveFactory.AutoFactory, readerOptions, testArchives); + + protected void ArchiveStreamRead( + IArchiveFactory archiveFactory, + ReaderOptions? readerOptions = null, + params string[] testArchives ) => ArchiveStreamRead( + archiveFactory, readerOptions, testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x)) ); - protected void ArchiveStreamRead(ReaderOptions? readerOptions, IEnumerable testArchives) + protected void ArchiveStreamRead( + IArchiveFactory archiveFactory, + ReaderOptions? readerOptions, + IEnumerable testArchives + ) { foreach (var path in testArchives) { using (var stream = NonDisposingStream.Create(File.OpenRead(path), true)) - using (var archive = ArchiveFactory.Open(stream, readerOptions)) + using (var archive = archiveFactory.Open(stream, readerOptions)) { try { @@ -218,10 +236,14 @@ IEnumerable testArchives } } - protected void ArchiveFileRead(string testArchive, ReaderOptions? readerOptions = null) + protected void ArchiveFileRead( + IArchiveFactory archiveFactory, + string testArchive, + ReaderOptions? readerOptions = null + ) { testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); - using (var archive = ArchiveFactory.Open(testArchive, readerOptions)) + using (var archive = archiveFactory.Open(new FileInfo(testArchive), readerOptions)) { foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { @@ -234,6 +256,9 @@ protected void ArchiveFileRead(string testArchive, ReaderOptions? readerOptions VerifyFiles(); } + protected void ArchiveFileRead(string testArchive, ReaderOptions? readerOptions = null) => + ArchiveFileRead(ArchiveFactory.AutoFactory, testArchive, readerOptions); + protected void ArchiveFileSkip( string testArchive, string fileOrder, diff --git a/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs b/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs index 32d978a2..544741ef 100644 --- a/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs +++ b/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs @@ -4,6 +4,7 @@ using SharpCompress.Archives; using SharpCompress.Archives.SevenZip; using SharpCompress.Common; +using SharpCompress.Factories; using SharpCompress.Readers; using Xunit; @@ -54,6 +55,14 @@ public void SevenZipArchive_PPMd_StreamRead_Extract_All() => [Fact] public void SevenZipArchive_LZMA2_PathRead() => ArchiveFileRead("7Zip.LZMA2.7z"); + [Fact] + public void SevenZipArchive_LZMA2_EXE_StreamRead() => + ArchiveStreamRead(new SevenZipFactory(), "7Zip.LZMA2.exe", new() { LookForHeader = true }); + + [Fact] + public void SevenZipArchive_LZMA2_EXE_PathRead() => + ArchiveFileRead(new SevenZipFactory(), "7Zip.LZMA2.exe", new() { LookForHeader = true }); + [Fact] public void SevenZipArchive_LZMA2AES_StreamRead() => ArchiveStreamRead("7Zip.LZMA2.Aes.7z", new ReaderOptions { Password = "testpassword" }); diff --git a/tests/TestArchives/Archives/7Zip.LZMA2.exe b/tests/TestArchives/Archives/7Zip.LZMA2.exe new file mode 100644 index 00000000..889c8318 Binary files /dev/null and b/tests/TestArchives/Archives/7Zip.LZMA2.exe differ