From 7dead8a4b5c24747d5148628d9c52aecc51dcfb4 Mon Sep 17 00:00:00 2001 From: Ibrahim Akgul Date: Thu, 19 Jan 2023 00:02:55 +0300 Subject: [PATCH 1/6] Create UDF Exctractor It was derived IsoExtractor with some minor UDF context changes --- RecursiveExtractor/Extractors/UdfExctractor | 157 ++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 RecursiveExtractor/Extractors/UdfExctractor diff --git a/RecursiveExtractor/Extractors/UdfExctractor b/RecursiveExtractor/Extractors/UdfExctractor new file mode 100644 index 0000000..efc016c --- /dev/null +++ b/RecursiveExtractor/Extractors/UdfExctractor @@ -0,0 +1,157 @@ +using DiscUtils.Udf; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Microsoft.CST.RecursiveExtractor.Extractors +{ + /// + /// The UDF disc image extractor implementation. + /// + public class UdfExtractor : AsyncExtractorInterface + { + /// + /// The constructor takes the Extractor context for recursion. + /// + /// The Extractor context. + public UdfExtractor(Extractor context) + { + Context = context; + } + private readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); + + internal Extractor Context { get; } + + /// + /// Extracts an UDF file + /// + /// + public async IAsyncEnumerable ExtractAsync(FileEntry fileEntry, ExtractorOptions options, ResourceGovernor governor, bool topLevel = true) + { + DiscUtils.DiscFileInfo[]? entries = null; + var failed = false; + try + { + using var cd = new UdfReader(fileEntry.Content); + entries = cd.Root.GetFiles("*.*", SearchOption.AllDirectories).ToArray(); + } + catch (Exception e) + { + Logger.Debug("Failed to open UDF {0}. ({1}:{2})", fileEntry.FullPath, e.GetType(), e.Message); + failed = true; + } + if (failed) + { + if (options.ExtractSelfOnFail) + { + fileEntry.EntryStatus = FileEntryStatus.FailedArchive; + yield return fileEntry; + } + } + else if (entries != null) + { + foreach (var file in entries) + { + var fileInfo = file; + governor.CheckResourceGovernor(fileInfo.Length); + Stream? stream = null; + try + { + stream = fileInfo.OpenRead(); + } + catch (Exception e) + { + Logger.Debug("Failed to extract {0} from UDF {1}. ({2}:{3})", fileInfo.FullName, fileEntry.FullPath, e.GetType(), e.Message); + } + if (stream != null) + { + var name = fileInfo.FullName.Replace('/', Path.DirectorySeparatorChar); + var newFileEntry = await FileEntry.FromStreamAsync(name, stream, fileEntry, fileInfo.CreationTime, fileInfo.LastWriteTime, fileInfo.LastAccessTime, memoryStreamCutoff: options.MemoryStreamCutoff).ConfigureAwait(false); + if (options.Recurse || topLevel) + { + await foreach (var entry in Context.ExtractAsync(newFileEntry, options, governor, false)) + { + yield return entry; + } + } + else + { + yield return newFileEntry; + } + } + } + } + } + + /// + /// Extracts an UDF file + /// + /// + public IEnumerable Extract(FileEntry fileEntry, ExtractorOptions options, ResourceGovernor governor, bool topLevel = true) + { + DiscUtils.DiscFileInfo[]? entries = null; + var failed = false; + try + { + using var cd = new UdfReader(fileEntry.Content); + entries = cd.Root.GetFiles("*.*", SearchOption.AllDirectories).ToArray(); + } + catch(Exception e) + { + Logger.Debug("Failed to open UDF {0}. ({1}:{2})", fileEntry.FullPath, e.GetType(), e.Message); + failed = true; + } + if (failed) + { + if (options.ExtractSelfOnFail) + { + fileEntry.EntryStatus = FileEntryStatus.FailedArchive; + yield return fileEntry; + } + } + else if (entries != null) + { + foreach (var file in entries) + { + var fileInfo = file; + governor.CheckResourceGovernor(fileInfo.Length); + Stream? stream = null; + try + { + stream = fileInfo.OpenRead(); + } + catch (Exception e) + { + Logger.Debug("Failed to extract {0} from UDF {1}. ({2}:{3})", fileInfo.FullName, fileEntry.FullPath, e.GetType(), e.Message); + } + if (stream != null) + { + var name = fileInfo.FullName.Replace('/', Path.DirectorySeparatorChar); + var newFileEntry = new FileEntry(name, stream, fileEntry, createTime: file.CreationTime, modifyTime: file.LastWriteTime, accessTime: file.LastAccessTime, memoryStreamCutoff: options.MemoryStreamCutoff); + if (options.Recurse || topLevel) + { + foreach (var entry in Context.Extract(newFileEntry, options, governor, false)) + { + yield return entry; + } + } + else + { + yield return newFileEntry; + } + } + } + } + else + { + if (options.ExtractSelfOnFail) + { + fileEntry.EntryStatus = FileEntryStatus.FailedArchive; + yield return fileEntry; + } + } + } + } +} From 36ec0287238e7d2321f9e3ae4de30ac86f449716 Mon Sep 17 00:00:00 2001 From: Ibrahim Akgul Date: Thu, 19 Jan 2023 00:15:23 +0300 Subject: [PATCH 2/6] Update Extractor for UDF Add UDF extractror --- RecursiveExtractor/Extractor.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/RecursiveExtractor/Extractor.cs b/RecursiveExtractor/Extractor.cs index 20cc5a4..501671a 100644 --- a/RecursiveExtractor/Extractor.cs +++ b/RecursiveExtractor/Extractor.cs @@ -51,6 +51,7 @@ public void SetDefaultExtractors() SetExtractor(ArchiveFileType.AR, new GnuArExtractor(this)); SetExtractor(ArchiveFileType.GZIP, new GzipExtractor(this)); SetExtractor(ArchiveFileType.ISO_9660, new IsoExtractor(this)); + SetExtractor(ArchiveFileType.UDF, new UdfExtractor(this)); SetExtractor(ArchiveFileType.RAR, new RarExtractor(this)); SetExtractor(ArchiveFileType.RAR5, new RarExtractor(this)); SetExtractor(ArchiveFileType.P7ZIP, new SevenZipExtractor(this)); @@ -663,4 +664,4 @@ public IEnumerable Extract(FileEntry fileEntry, ExtractorOptions? opt } } } -} \ No newline at end of file +} From 2f1f595d3f2c7b864ef4cb8ad4584cd52374acb2 Mon Sep 17 00:00:00 2001 From: Ibrahim Akgul Date: Thu, 19 Jan 2023 00:04:46 +0300 Subject: [PATCH 3/6] Update NuGet Package Add DiscUtils.Udf dependency --- RecursiveExtractor/RecursiveExtractor.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/RecursiveExtractor/RecursiveExtractor.csproj b/RecursiveExtractor/RecursiveExtractor.csproj index 3f01d29..a8b21ec 100644 --- a/RecursiveExtractor/RecursiveExtractor.csproj +++ b/RecursiveExtractor/RecursiveExtractor.csproj @@ -32,6 +32,7 @@ + From 6f90b219165ce82b11a842941b9787c16b2d11b7 Mon Sep 17 00:00:00 2001 From: Ibrahim Akgul Date: Thu, 19 Jan 2023 00:06:05 +0300 Subject: [PATCH 4/6] Update MiniMagic.cs Add enumerate to UDF --- RecursiveExtractor/MiniMagic.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/RecursiveExtractor/MiniMagic.cs b/RecursiveExtractor/MiniMagic.cs index af9f764..f7ed96a 100644 --- a/RecursiveExtractor/MiniMagic.cs +++ b/RecursiveExtractor/MiniMagic.cs @@ -61,6 +61,10 @@ public enum ArchiveFileType /// ISO_9660, /// + /// An UDF disc image. + /// + UDF, + /// /// A VHDX disc image. /// VHDX, @@ -265,4 +269,4 @@ public static ArchiveFileType DetectFileType(Stream fileStream) /// The ArchiveFileType detected public static ArchiveFileType DetectFileType(FileEntry fileEntry) => DetectFileType(fileEntry?.Content ?? new MemoryStream()); } -} \ No newline at end of file +} From 9c45ff1418219f0e59048b374f1e2945f8edb016 Mon Sep 17 00:00:00 2001 From: Ibrahim Akgul Date: Thu, 19 Jan 2023 00:12:54 +0300 Subject: [PATCH 5/6] Update MiniMagic.cs Add enum, and signature check --- RecursiveExtractor/MiniMagic.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RecursiveExtractor/MiniMagic.cs b/RecursiveExtractor/MiniMagic.cs index f7ed96a..bfc7ef9 100644 --- a/RecursiveExtractor/MiniMagic.cs +++ b/RecursiveExtractor/MiniMagic.cs @@ -232,6 +232,10 @@ public static ArchiveFileType DetectFileType(Stream fileStream) { return ArchiveFileType.ISO_9660; } + else if (buffer[0] == 'B' && buffer[1] == 'E' && buffer[2] == 'A' && buffer[3] == '0' && buffer[4] == '1') + { + return ArchiveFileType.UDF; + } } //https://www.microsoft.com/en-us/download/details.aspx?id=23850 - 'Hard Disk Footer Format' From b0cc83d9cf5525ef7125fe58acdb4ef876632f1f Mon Sep 17 00:00:00 2001 From: Gabe Stocco <98900+gfs@users.noreply.github.com> Date: Thu, 19 Jan 2023 17:41:11 -0800 Subject: [PATCH 6/6] Update Tests and add Test Archives for UDF Extractor --- .../ExtractorTests/ExpectedNumFilesTests.cs | 10 ++++++++-- .../ExtractorTests/MiniMagicTests.cs | 2 +- .../RecursiveExtractor.Tests.csproj | 6 ++++++ RecursiveExtractor.Tests/SanitizePathTests.cs | 11 ++--------- .../TestData/TestDataArchives/UdfTest.iso | Bin 0 -> 552960 bytes .../UdfTestWithMultiSystem.iso | Bin 0 -> 583680 bytes .../{UdfExctractor => UdfExtractor.cs} | 0 RecursiveExtractor/MiniMagic.cs | 2 +- 8 files changed, 18 insertions(+), 13 deletions(-) create mode 100644 RecursiveExtractor.Tests/TestData/TestDataArchives/UdfTest.iso create mode 100644 RecursiveExtractor.Tests/TestData/TestDataArchives/UdfTestWithMultiSystem.iso rename RecursiveExtractor/Extractors/{UdfExctractor => UdfExtractor.cs} (100%) diff --git a/RecursiveExtractor.Tests/ExtractorTests/ExpectedNumFilesTests.cs b/RecursiveExtractor.Tests/ExtractorTests/ExpectedNumFilesTests.cs index 9d77004..2cae923 100644 --- a/RecursiveExtractor.Tests/ExtractorTests/ExpectedNumFilesTests.cs +++ b/RecursiveExtractor.Tests/ExtractorTests/ExpectedNumFilesTests.cs @@ -37,7 +37,9 @@ public static IEnumerable ArchiveData new object[] { "TestData.vhdx",3 }, new object[] { "TestData.wim",3 }, new object[] { "EmptyFile.txt", 1 }, - new object[] { "TestDataArchivesNested.Zip", 54 } + new object[] { "TestDataArchivesNested.Zip", 54 }, + new object[] { "UdfTest.iso", 3 }, + new object[] { "UdfTestWithMultiSystem.iso", 3 } }; } } @@ -170,7 +172,11 @@ public void ExtractArchive(string fileName, int expectedNumFiles) var extractor = new Extractor(); var path = Path.Combine(Directory.GetCurrentDirectory(), "TestData", "TestDataArchives", fileName); var results = extractor.Extract(path, GetExtractorOptions()).ToList(); - Assert.AreEqual(expectedNumFiles, results.Count()); + foreach (var result in results) + { + Assert.AreNotEqual(FileEntryStatus.FailedArchive, result.EntryStatus); + } + Assert.AreEqual(expectedNumFiles, results.Count); } [TestMethod] diff --git a/RecursiveExtractor.Tests/ExtractorTests/MiniMagicTests.cs b/RecursiveExtractor.Tests/ExtractorTests/MiniMagicTests.cs index 9965aac..361ae18 100644 --- a/RecursiveExtractor.Tests/ExtractorTests/MiniMagicTests.cs +++ b/RecursiveExtractor.Tests/ExtractorTests/MiniMagicTests.cs @@ -19,7 +19,7 @@ public class MiniMagicTests : BaseExtractorTestClass [DataRow("sysvbanner_1.0-17fakesync1_amd64.deb", ArchiveFileType.DEB)] [DataRow("TestData.a", ArchiveFileType.AR)] [DataRow("TestData.iso", ArchiveFileType.ISO_9660)] - // [DataRow("TestData.vhd", ArchiveFileType.VHD)] + [DataRow("UdfTest.iso", ArchiveFileType.UDF)] [DataRow("TestData.vhdx", ArchiveFileType.VHDX)] [DataRow("TestData.wim", ArchiveFileType.WIM)] [DataRow("Empty.vmdk", ArchiveFileType.VMDK)] diff --git a/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj b/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj index e0a36d3..1f460f2 100644 --- a/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj +++ b/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj @@ -267,5 +267,11 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + diff --git a/RecursiveExtractor.Tests/SanitizePathTests.cs b/RecursiveExtractor.Tests/SanitizePathTests.cs index b304f84..4ac0e0c 100644 --- a/RecursiveExtractor.Tests/SanitizePathTests.cs +++ b/RecursiveExtractor.Tests/SanitizePathTests.cs @@ -1,18 +1,11 @@ // Copyright (c) Microsoft Corporation. Licensed under the MIT License. +using Microsoft.CST.RecursiveExtractor; using Microsoft.VisualStudio.TestTools.UnitTesting; -using NLog; -using NLog.Config; -using NLog.Targets; -using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Runtime.InteropServices; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -namespace Microsoft.CST.RecursiveExtractor.Tests +namespace RecursiveExtractor.Tests { [TestClass] public class SanitizePathTests diff --git a/RecursiveExtractor.Tests/TestData/TestDataArchives/UdfTest.iso b/RecursiveExtractor.Tests/TestData/TestDataArchives/UdfTest.iso new file mode 100644 index 0000000000000000000000000000000000000000..9fdaf1ff1f867f26d0c642d86b8523318b36b94d GIT binary patch literal 552960 zcmeI*PiP$1836E^wf?Ll7h859#x-W!B!nmsRx34)OAm2m*|;@Mu$JTH14IOH1jY$M(>WV|;7(5Xhy_es5-0S~s!fwJK#d{ylm3 z&7U_r@BP;B%{MdBWSK&M009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF zWG~O3YEI`M2oNAZfB=C z8z=6J=SL=w9Zs`TtL--z*Ou1XeSV1M1PBlyK;R(-Mk0p48{5ABUMK%j)G3~4Q}-jGx)R>t}r#>#DuEm9A5vrO#fhkxR;#r98-SU`XP0Ro@Bz-Yw(JJF4| z&vx=JM_r3o3iGw+E-YMZwqj~9OX_1DZwFHM#Mr_7lJtrI0RjXDR$we5{s+;!ciy_4 zKNr1 z^qK$x0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72n?J+9)JJ$ zndsF=2RnJQr+3>tqjw^Yr{&b*Cq0EGz3MN_%$=N{pPg+so2}Wo=@)xGYY!$Tclykt z9dF;~AR8y{jORxtj~!0i4f->O`W&0)1PBlyF!%x^5yO8T-F*MOPCgxV@l?5~^w_-f zuQkrCywUC%LakUC3x@sqfIVZ{^+~aP*NN?b009C7`WG0D`2TTi_V(FM-io>wuN3BM z&s|u!*i1_Xv!p)e@pd3}PmCSRFG;Tm5FkKcUmkrJfFZeqWC< zOcjGjCo<;R%d6LyuCCljL#yS*2(#=^n%gR4FpViB|v}x0RjYuQ=lI4zr63SlYeD6hoIL42oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV6T?1op?@|NSs}_0wD5E1oOU z`&|0oC(In^o%xheq}9(?%OB*KeCa7X=~c_qPqm?n009C72oTs4f%NzPzh3OAlb_m? zJ=zHY0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF 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 z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+0D+?_Pzjar&$02@Pd2lV#fi5<$YYlB@svvh z2oNAZfWXI3AghEwioN>dQ!)O>l)wD`$?V+dl{0brSo}!~ixp{QO3n8CL|*Hz++ORf zuXo6@_K)tnvDFZd$Oh8Y z0(@a|sz6^}T3p>oYb)8YfkGw;5FkK+z}^I^G1~lJQDrmR5$E@|8KnsjAV7csfg>bv zB98yR7~8vc;_lYC^LU((#{wyfX}t1_Ui!=P+hfzWignxP1_sX?JZ$=b#}`*`cfZqF zTUzh-Huw=)92%#~67j5rM1TMR0t5)`M<9#w|DWOpzW&=6i@2JF=R&yu9CTct%AJn+ z+@HPFD_1$5%JmKs!igfdSEsr$j;FH!8O#3p7yD(yNGcou73ox2cDlRPS?Mj35gjLFf26m=ljWHH*5X<@ z{{KN-{*Qm3_sYhT3Nd(}>Xm)2EZexf{_T}(8{aKH&(>QdBS3%v0RjXLKp>6(e=Y9k zU*5YLPtup^qsIUJG5j07vi<{x^xpGV&KP^zCUn{oxHpC`Mlovzjv8^`}61;{PMQ$*K_`K!5;&`vg+_PuKm&uHH@G{43I7ivQ(xg|c1ZfA0;F5gSoV}tQ`Nx=@&x9`2Xp@Ls~$9009C72oNAZfB*pk1okhGg$u=1{}4X~c(I(C z3f<5h2`|RE_$1m}VKKye`bh)`5FkK+009C72oNAZfWXleh=cr)T}ape)3*S#i*c$q z{*QAnrmp}P{~z6VSIY?yAV7cs0RjXF5FkK+Kq>Gi#rOZ?SpR%^``>E#-R#`xl{5F^ zrT_GCfGo7FAFK{*Pxcra624p9^B}h4`N7^_KG*O4vG`?(w7)-`ovFqX zBi-(v0g`6i-p(xiUbtNL|8nm>$|q8ROJBH`Oya*2)6G_Wrnl#K3&iQ}T4$x$_uI+o z?UkZ-Q8vwgI2HK4ZSKrIT-Fi-1PBm#1_f3h7y$?4|Kp6e2OZthU5sLsd|^j)zpxeE zyvR@ zzg&#%#r3E8Zre8j0t5&UCZ_NGHD>rYxGBN*JJ#RH@zmc~ZlV7jr zjoJBntM=N&Y@D8JHRqeP=5(5Py)jvD=k0~Lxn^rVpK7-9xn{fZMn2V;uIKG)Jv|p>YipuS|daW_ls7=f_nzMPk zxzMWBujO$Iaj#ni<1XXorW&zMV>ULTF*DKnM*ezpdSRxX$L7>xC+1^IQfvDAYRtyD znPRioyy*l85FkK+Kp{|kvy24+0t5&UAn;5HRN^<>{yX+K`^jeZQaaE7RtR~_Qa+w? Pi2wlt1PBoL*a`eUgt$re literal 0 HcmV?d00001 diff --git a/RecursiveExtractor/Extractors/UdfExctractor b/RecursiveExtractor/Extractors/UdfExtractor.cs similarity index 100% rename from RecursiveExtractor/Extractors/UdfExctractor rename to RecursiveExtractor/Extractors/UdfExtractor.cs diff --git a/RecursiveExtractor/MiniMagic.cs b/RecursiveExtractor/MiniMagic.cs index bfc7ef9..0c1544b 100644 --- a/RecursiveExtractor/MiniMagic.cs +++ b/RecursiveExtractor/MiniMagic.cs @@ -232,7 +232,7 @@ public static ArchiveFileType DetectFileType(Stream fileStream) { return ArchiveFileType.ISO_9660; } - else if (buffer[0] == 'B' && buffer[1] == 'E' && buffer[2] == 'A' && buffer[3] == '0' && buffer[4] == '1') + if (buffer[0] == 'B' && buffer[1] == 'E' && buffer[2] == 'A' && buffer[3] == '0' && buffer[4] == '1') { return ArchiveFileType.UDF; }