diff --git a/src/BizHawk.Client.Common/SharpCompressDearchivalMethod.cs b/src/BizHawk.Client.Common/SharpCompressDearchivalMethod.cs index e994751538..3ce5f8b247 100644 --- a/src/BizHawk.Client.Common/SharpCompressDearchivalMethod.cs +++ b/src/BizHawk.Client.Common/SharpCompressDearchivalMethod.cs @@ -21,15 +21,9 @@ namespace BizHawk.Client.Common offset = 0; isExecutable = false; - try - { - using var arcTest = ArchiveFactory.Open(fileName); // should throw for non-archives - if (arcTest.Type != ArchiveType.Tar) return true; // not expecting false positives from anything but .tar for now - } - catch - { - return false; - } + bool isArchive = ArchiveFactory.IsArchive(fileName, out var type); + if (!isArchive) return false; + if (type is not ArchiveType.Tar) return true; // not expecting false positives from anything but .tar for now // SharpCompress seems to overzealously flag files it thinks are the in original .tar format, so we'll check for false positives. This affects 0.24.0, and the latest at time of writing, 0.27.1. // https://github.com/adamhathcock/sharpcompress/issues/390 @@ -51,26 +45,21 @@ namespace BizHawk.Client.Common public bool CheckSignature(Stream fileStream, string? filenameHint) { if (!fileStream.CanRead || !fileStream.CanSeek) return false; + long initialPosition = fileStream.Position; - try - { - using var arcTest = ArchiveFactory.Open(fileStream); // should throw for non-archives - if (arcTest.Type != ArchiveType.Tar) return true; // not expecting false positives from anything but .tar for now - } - catch - { - return false; - } + bool isArchive = ArchiveFactory.IsArchive(fileStream, out var type); + fileStream.Seek(initialPosition, SeekOrigin.Begin); + if (!isArchive) return false; + if (type is not ArchiveType.Tar) return true; // not expecting false positives from anything but .tar for now // as above, SharpCompress seems to overzealously flag files it thinks are the in original .tar format, so we'll check for false positives if (fileStream.Length < 512) return false; // looking for magic bytes - var seekPos = fileStream.Position; fileStream.Seek(0x101, SeekOrigin.Begin); var buffer = new byte[8]; _ = fileStream.Read(buffer, offset: 0, count: buffer.Length); // if stream is too short, the next check will catch it - fileStream.Seek(seekPos, SeekOrigin.Begin); + fileStream.Seek(initialPosition, SeekOrigin.Begin); var s = buffer.BytesToHexString(); if (s == "7573746172003030" || s == "7573746172202000") return true; // "ustar\000" (libarchive's bsdtar) or "ustar \0" (GNU Tar) diff --git a/src/BizHawk.Tests/Client.Common/dearchive/DearchivalTests.cs b/src/BizHawk.Tests/Client.Common/dearchive/DearchivalTests.cs index 103f108f91..7c24552228 100644 --- a/src/BizHawk.Tests/Client.Common/dearchive/DearchivalTests.cs +++ b/src/BizHawk.Tests/Client.Common/dearchive/DearchivalTests.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Linq; using BizHawk.Client.Common; @@ -36,7 +36,7 @@ namespace BizHawk.Tests.Client.Common.Dearchive .Select(testCase => testCase.Filename)) { var archive = EmbeddedData.GetStream(EMBED_GROUP, filename); - Assert.IsTrue(sc.CheckSignature(archive, filename), $"{filename} is an archive, but wasn't detected as such"); // puts the seek pos of the Stream param back where it was (in this case at the start), but that may not always be true + Assert.IsTrue(sc.CheckSignature(archive, filename), $"{filename} is an archive, but wasn't detected as such"); // puts the seek pos of the Stream param back where it was (in this case at the start) var af = sc.Construct(archive); var items = af.Scan(); Assert.IsNotNull(items, $"{filename} contains 1 file, but it couldn't be enumerated correctly");