From 39f2dd88aaf761b794bded30367e100cb5a842bb Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Thu, 8 Dec 2022 21:32:52 -0800 Subject: [PATCH] Make it easier to support new file types --- BurnOutSharp/Enums.cs | 100 ++++ BurnOutSharp/FileType/BFPK.cs | 3 + BurnOutSharp/FileType/BZip2.cs | 3 + BurnOutSharp/FileType/Executable.cs | 3 + BurnOutSharp/FileType/GZIP.cs | 3 + BurnOutSharp/FileType/IniFile.cs | 3 + .../FileType/InstallShieldArchiveV3.cs | 3 + BurnOutSharp/FileType/InstallShieldCAB.cs | 3 + BurnOutSharp/FileType/MPQ.cs | 3 + BurnOutSharp/FileType/MSI.cs | 3 + BurnOutSharp/FileType/MicrosoftCAB.cs | 5 +- BurnOutSharp/FileType/PKZIP.cs | 3 + BurnOutSharp/FileType/PLJ.cs | 6 +- BurnOutSharp/FileType/RAR.cs | 3 + BurnOutSharp/FileType/SevenZip.cs | 3 + BurnOutSharp/FileType/TapeArchive.cs | 3 + BurnOutSharp/FileType/Textfile.cs | 3 + BurnOutSharp/FileType/Valve.cs | 3 + BurnOutSharp/FileType/XZ.cs | 3 + BurnOutSharp/ProtectionType/ElectronicArts.cs | 4 +- BurnOutSharp/Scanner.cs | 82 +-- BurnOutSharp/Tools/Utilities.cs | 522 +++++++++++++++++- 22 files changed, 718 insertions(+), 49 deletions(-) create mode 100644 BurnOutSharp/Enums.cs diff --git a/BurnOutSharp/Enums.cs b/BurnOutSharp/Enums.cs new file mode 100644 index 00000000..d8e0edeb --- /dev/null +++ b/BurnOutSharp/Enums.cs @@ -0,0 +1,100 @@ +namespace BurnOutSharp +{ + public enum FileTypes + { + /// + /// Unknown or unsupported + /// + UNKNOWN, + + /// + /// BFPK custom archive + /// + BFPK, + + /// + /// bzip2 archive + /// + BZip2, + + /// + /// Executable or library + /// + Executable, + + /// + /// gzip archive + /// + GZIP, + + /// + /// Key-value pair INI file + /// + IniFile, + + /// + /// InstallShield archive v3 + /// + InstallShieldArchiveV3, + + /// + /// InstallShield cabinet file + /// + InstallShieldCAB, + + /// + /// Microsoft cabinet file + /// + MicrosoftCAB, + + /// + /// MPQ game data archive + /// + MPQ, + + /// + /// Microsoft installation package + /// + MSI, + + /// + /// PKWARE ZIP archive and derivatives + /// + PKZIP, + + /// + /// PlayJ audio file + /// + PLJ, + + /// + /// RAR archive + /// + RAR, + + /// + /// 7-zip archive + /// + SevenZip, + + /// + /// Tape archive + /// + TapeArchive, + + /// + /// Various generic textfile formats + /// + Textfile, + + /// + /// Various Valve archive formats + /// + Valve, + + /// + /// xz archive + /// + XZ, + } +} diff --git a/BurnOutSharp/FileType/BFPK.cs b/BurnOutSharp/FileType/BFPK.cs index a487b818..17d06b1e 100644 --- a/BurnOutSharp/FileType/BFPK.cs +++ b/BurnOutSharp/FileType/BFPK.cs @@ -9,6 +9,9 @@ using SharpCompress.Compressors.Deflate; namespace BurnOutSharp.FileType { + /// + /// BFPK custom archive format + /// public class BFPK : IScannable { /// diff --git a/BurnOutSharp/FileType/BZip2.cs b/BurnOutSharp/FileType/BZip2.cs index 38371268..805f0bd3 100644 --- a/BurnOutSharp/FileType/BZip2.cs +++ b/BurnOutSharp/FileType/BZip2.cs @@ -8,6 +8,9 @@ using SharpCompress.Compressors.BZip2; namespace BurnOutSharp.FileType { + /// + /// bzip2 archive + /// public class BZip2 : IScannable { /// diff --git a/BurnOutSharp/FileType/Executable.cs b/BurnOutSharp/FileType/Executable.cs index 1e5aada6..831b34fe 100644 --- a/BurnOutSharp/FileType/Executable.cs +++ b/BurnOutSharp/FileType/Executable.cs @@ -9,6 +9,9 @@ using BurnOutSharp.Wrappers; namespace BurnOutSharp.FileType { + /// + /// Executable or library + /// public class Executable : IScannable { /// diff --git a/BurnOutSharp/FileType/GZIP.cs b/BurnOutSharp/FileType/GZIP.cs index bcad50b3..c2bbf74c 100644 --- a/BurnOutSharp/FileType/GZIP.cs +++ b/BurnOutSharp/FileType/GZIP.cs @@ -8,6 +8,9 @@ using SharpCompress.Archives.GZip; namespace BurnOutSharp.FileType { + /// + /// gzip archive + /// public class GZIP : IScannable { /// diff --git a/BurnOutSharp/FileType/IniFile.cs b/BurnOutSharp/FileType/IniFile.cs index 9afb335f..bdc48dcb 100644 --- a/BurnOutSharp/FileType/IniFile.cs +++ b/BurnOutSharp/FileType/IniFile.cs @@ -6,6 +6,9 @@ using System.Linq; namespace BurnOutSharp.FileType { + /// + /// Key-value pair INI file + /// public class IniFile : IDictionary { private Dictionary _keyValuePairs = new Dictionary(); diff --git a/BurnOutSharp/FileType/InstallShieldArchiveV3.cs b/BurnOutSharp/FileType/InstallShieldArchiveV3.cs index da3aaf21..1389d8e0 100644 --- a/BurnOutSharp/FileType/InstallShieldArchiveV3.cs +++ b/BurnOutSharp/FileType/InstallShieldArchiveV3.cs @@ -9,6 +9,9 @@ using UnshieldSharp.Archive; namespace BurnOutSharp.FileType { + /// + /// InstallShield archive v3 + /// public class InstallShieldArchiveV3 : IScannable { /// diff --git a/BurnOutSharp/FileType/InstallShieldCAB.cs b/BurnOutSharp/FileType/InstallShieldCAB.cs index 264a968e..c1cd7c99 100644 --- a/BurnOutSharp/FileType/InstallShieldCAB.cs +++ b/BurnOutSharp/FileType/InstallShieldCAB.cs @@ -8,6 +8,9 @@ using UnshieldSharp.Cabinet; namespace BurnOutSharp.FileType { + /// + /// InstallShield cabinet file + /// public class InstallShieldCAB : IScannable { /// diff --git a/BurnOutSharp/FileType/MPQ.cs b/BurnOutSharp/FileType/MPQ.cs index d56ff36d..4e362320 100644 --- a/BurnOutSharp/FileType/MPQ.cs +++ b/BurnOutSharp/FileType/MPQ.cs @@ -7,6 +7,9 @@ using StormLibSharp; namespace BurnOutSharp.FileType { + /// + /// MPQ game data archive + /// public class MPQ : IScannable { /// diff --git a/BurnOutSharp/FileType/MSI.cs b/BurnOutSharp/FileType/MSI.cs index 2307ff0f..33fdf485 100644 --- a/BurnOutSharp/FileType/MSI.cs +++ b/BurnOutSharp/FileType/MSI.cs @@ -8,6 +8,9 @@ using OpenMcdf; namespace BurnOutSharp.FileType { + /// + /// Microsoft installation package + /// public class MSI : IScannable { /// diff --git a/BurnOutSharp/FileType/MicrosoftCAB.cs b/BurnOutSharp/FileType/MicrosoftCAB.cs index 8971b03b..24b09c5a 100644 --- a/BurnOutSharp/FileType/MicrosoftCAB.cs +++ b/BurnOutSharp/FileType/MicrosoftCAB.cs @@ -13,7 +13,10 @@ using WixToolset.Dtf.Compression.Cab; namespace BurnOutSharp.FileType { - // Specification available at http://download.microsoft.com/download/5/0/1/501ED102-E53F-4CE0-AA6B-B0F93629DDC6/Exchange/%5BMS-CAB%5D.pdf + /// + /// Microsoft cabinet file + /// + /// Specification available at public class MicrosoftCAB : IScannable { /// diff --git a/BurnOutSharp/FileType/PKZIP.cs b/BurnOutSharp/FileType/PKZIP.cs index 74d3c879..92e66aa7 100644 --- a/BurnOutSharp/FileType/PKZIP.cs +++ b/BurnOutSharp/FileType/PKZIP.cs @@ -8,6 +8,9 @@ using SharpCompress.Archives.Zip; namespace BurnOutSharp.FileType { + /// + /// PKWARE ZIP archive and derivatives + /// public class PKZIP : IScannable { /// diff --git a/BurnOutSharp/FileType/PLJ.cs b/BurnOutSharp/FileType/PLJ.cs index 6b6d90cc..d9c02740 100644 --- a/BurnOutSharp/FileType/PLJ.cs +++ b/BurnOutSharp/FileType/PLJ.cs @@ -1,12 +1,14 @@ using System; using System.Collections.Concurrent; using System.IO; -using System.Linq; using BurnOutSharp.Interfaces; using BurnOutSharp.Tools; namespace BurnOutSharp.FileType { + /// + /// PlayJ audio file + /// public class PLJ : IScannable { /// @@ -40,7 +42,7 @@ namespace BurnOutSharp.FileType byte[] magic = new byte[16]; stream.Read(magic, 0, 16); - if (ShouldScan(magic)) + if (Utilities.GetFileType(magic) == FileTypes.PLJ) { Utilities.AppendToDictionary(protections, file, "PlayJ Audio File"); return protections; diff --git a/BurnOutSharp/FileType/RAR.cs b/BurnOutSharp/FileType/RAR.cs index 777fa7cf..26c31288 100644 --- a/BurnOutSharp/FileType/RAR.cs +++ b/BurnOutSharp/FileType/RAR.cs @@ -8,6 +8,9 @@ using SharpCompress.Archives.Rar; namespace BurnOutSharp.FileType { + /// + /// RAR archive + /// public class RAR : IScannable { /// diff --git a/BurnOutSharp/FileType/SevenZip.cs b/BurnOutSharp/FileType/SevenZip.cs index 69f677f0..d35cc2b5 100644 --- a/BurnOutSharp/FileType/SevenZip.cs +++ b/BurnOutSharp/FileType/SevenZip.cs @@ -8,6 +8,9 @@ using SharpCompress.Archives.SevenZip; namespace BurnOutSharp.FileType { + /// + /// 7-zip archive + /// public class SevenZip : IScannable { /// diff --git a/BurnOutSharp/FileType/TapeArchive.cs b/BurnOutSharp/FileType/TapeArchive.cs index 09437392..96575545 100644 --- a/BurnOutSharp/FileType/TapeArchive.cs +++ b/BurnOutSharp/FileType/TapeArchive.cs @@ -8,6 +8,9 @@ using SharpCompress.Archives.Tar; namespace BurnOutSharp.FileType { + /// + /// Tape archive + /// public class TapeArchive : IScannable { /// diff --git a/BurnOutSharp/FileType/Textfile.cs b/BurnOutSharp/FileType/Textfile.cs index 6b596fa2..d9d9bd49 100644 --- a/BurnOutSharp/FileType/Textfile.cs +++ b/BurnOutSharp/FileType/Textfile.cs @@ -7,6 +7,9 @@ using BurnOutSharp.Tools; namespace BurnOutSharp.FileType { + /// + /// Various generic textfile formats + /// public class Textfile : IScannable { /// diff --git a/BurnOutSharp/FileType/Valve.cs b/BurnOutSharp/FileType/Valve.cs index 65151364..efafc75b 100644 --- a/BurnOutSharp/FileType/Valve.cs +++ b/BurnOutSharp/FileType/Valve.cs @@ -8,6 +8,9 @@ using HLLib.Packages; namespace BurnOutSharp.FileType { + /// + /// Various Valve archive formats + /// public class Valve : IScannable { /// diff --git a/BurnOutSharp/FileType/XZ.cs b/BurnOutSharp/FileType/XZ.cs index 5ad8cc84..e15c86ab 100644 --- a/BurnOutSharp/FileType/XZ.cs +++ b/BurnOutSharp/FileType/XZ.cs @@ -7,6 +7,9 @@ using SharpCompress.Compressors.Xz; namespace BurnOutSharp.FileType { + /// + /// xz archive + /// public class XZ : IScannable { /// diff --git a/BurnOutSharp/ProtectionType/ElectronicArts.cs b/BurnOutSharp/ProtectionType/ElectronicArts.cs index a24a4a46..afd83762 100644 --- a/BurnOutSharp/ProtectionType/ElectronicArts.cs +++ b/BurnOutSharp/ProtectionType/ElectronicArts.cs @@ -46,12 +46,12 @@ namespace BurnOutSharp.ProtectionType { 0x45, 0x52, 0x65, 0x67, 0x20, 0x43, 0x6F, 0x6E, 0x66, 0x69, 0x67, 0x20, 0x46, 0x6F, 0x72, 0x6D - }, Utilities.GetInternalVersion, "EA CdKey Registration Module"), + }, "EA CdKey Registration Module"), }; string match = MatchUtil.GetFirstMatch(file, dataSectionRaw, matchers, includeDebug); if (!string.IsNullOrWhiteSpace(match)) - return match; + return $"{match} {Utilities.GetInternalVersion(pex)}"; } // Get the .rdata section, if it exists diff --git a/BurnOutSharp/Scanner.cs b/BurnOutSharp/Scanner.cs index 2ffa4e2e..db105db3 100644 --- a/BurnOutSharp/Scanner.cs +++ b/BurnOutSharp/Scanner.cs @@ -309,26 +309,40 @@ namespace BurnOutSharp return null; } + // Get the file type either from magic number or extension + FileTypes fileType = Utilities.GetFileType(magic); + if (fileType == FileTypes.UNKNOWN) + fileType = Utilities.GetFileType(extension); + + // If we still got unknown, just return null + if (fileType == FileTypes.UNKNOWN) + return null; + + // Create a scannable for the given file type + var scannable = Utilities.CreateScannable(fileType); + if (scannable == null) + return null; + #region Non-Archive File Types // Executable - if (new Executable().ShouldScan(magic)) + if (scannable is Executable) { - var subProtections = new Executable().Scan(this, stream, fileName); + var subProtections = scannable.Scan(this, stream, fileName); Utilities.AppendToDictionary(protections, subProtections); } // PLJ - if (new PLJ().ShouldScan(magic)) + if (scannable is PLJ) { - var subProtections = new PLJ().Scan(this, stream, fileName); + var subProtections = scannable.Scan(this, stream, fileName); Utilities.AppendToDictionary(protections, subProtections); } // Text-based files - if (new Textfile().ShouldScan(magic, extension)) + if (scannable is Textfile) { - var subProtections = new Textfile().Scan(this, stream, fileName); + var subProtections = scannable.Scan(this, stream, fileName); Utilities.AppendToDictionary(protections, subProtections); } @@ -340,113 +354,113 @@ namespace BurnOutSharp if (ScanArchives) { // 7-Zip archive - if (new SevenZip().ShouldScan(magic)) + if (scannable is SevenZip) { - var subProtections = new SevenZip().Scan(this, stream, fileName); + var subProtections = scannable.Scan(this, stream, fileName); Utilities.PrependToKeys(subProtections, fileName); Utilities.AppendToDictionary(protections, subProtections); } // BFPK archive - if (new BFPK().ShouldScan(magic)) + if (scannable is BFPK) { - var subProtections = new BFPK().Scan(this, stream, fileName); + var subProtections = scannable.Scan(this, stream, fileName); Utilities.PrependToKeys(subProtections, fileName); Utilities.AppendToDictionary(protections, subProtections); } // BZip2 - if (new BZip2().ShouldScan(magic)) + if (scannable is BZip2) { - var subProtections = new BZip2().Scan(this, stream, fileName); + var subProtections = scannable.Scan(this, stream, fileName); Utilities.PrependToKeys(subProtections, fileName); Utilities.AppendToDictionary(protections, subProtections); } // GZIP - if (new GZIP().ShouldScan(magic)) + if (scannable is GZIP) { - var subProtections = new GZIP().Scan(this, stream, fileName); + var subProtections = scannable.Scan(this, stream, fileName); Utilities.PrependToKeys(subProtections, fileName); Utilities.AppendToDictionary(protections, subProtections); } // InstallShield Archive V3 (Z) - if (fileName != null && new InstallShieldArchiveV3().ShouldScan(magic)) + if (fileName != null && scannable is InstallShieldArchiveV3) { - var subProtections = new InstallShieldArchiveV3().Scan(this, fileName); + var subProtections = scannable.Scan(this, fileName); Utilities.PrependToKeys(subProtections, fileName); Utilities.AppendToDictionary(protections, subProtections); } // InstallShield Cabinet - if (fileName != null && new InstallShieldCAB().ShouldScan(magic)) + if (fileName != null && scannable is InstallShieldCAB) { - var subProtections = new InstallShieldCAB().Scan(this, fileName); + var subProtections = scannable.Scan(this, fileName); Utilities.PrependToKeys(subProtections, fileName); Utilities.AppendToDictionary(protections, subProtections); } // Microsoft Cabinet - if (fileName != null && new MicrosoftCAB().ShouldScan(magic)) + if (fileName != null && scannable is MicrosoftCAB) { - var subProtections = new MicrosoftCAB().Scan(this, fileName); + var subProtections = scannable.Scan(this, fileName); Utilities.PrependToKeys(subProtections, fileName); Utilities.AppendToDictionary(protections, subProtections); } // MSI - if (fileName != null && new MSI().ShouldScan(magic)) + if (fileName != null && scannable is MSI) { - var subProtections = new MSI().Scan(this, fileName); + var subProtections = scannable.Scan(this, fileName); Utilities.PrependToKeys(subProtections, fileName); Utilities.AppendToDictionary(protections, subProtections); } // MPQ archive - if (fileName != null && new MPQ().ShouldScan(magic)) + if (fileName != null && scannable is MPQ) { - var subProtections = new MPQ().Scan(this, fileName); + var subProtections = scannable.Scan(this, fileName); Utilities.PrependToKeys(subProtections, fileName); Utilities.AppendToDictionary(protections, subProtections); } // PKZIP archive (and derivatives) - if (new PKZIP().ShouldScan(magic)) + if (scannable is PKZIP) { - var subProtections = new PKZIP().Scan(this, stream, fileName); + var subProtections = scannable.Scan(this, stream, fileName); Utilities.PrependToKeys(subProtections, fileName); Utilities.AppendToDictionary(protections, subProtections); } // RAR archive - if (new RAR().ShouldScan(magic)) + if (scannable is RAR) { - var subProtections = new RAR().Scan(this, stream, fileName); + var subProtections = scannable.Scan(this, stream, fileName); Utilities.PrependToKeys(subProtections, fileName); Utilities.AppendToDictionary(protections, subProtections); } // Tape Archive - if (new TapeArchive().ShouldScan(magic)) + if (scannable is TapeArchive) { - var subProtections = new TapeArchive().Scan(this, stream, fileName); + var subProtections = scannable.Scan(this, stream, fileName); Utilities.PrependToKeys(subProtections, fileName); Utilities.AppendToDictionary(protections, subProtections); } // Valve archive formats - if (fileName != null && new Valve().ShouldScan(magic)) + if (fileName != null && scannable is Valve) { - var subProtections = new Valve().Scan(this, fileName); + var subProtections = scannable.Scan(this, fileName); Utilities.PrependToKeys(subProtections, fileName); Utilities.AppendToDictionary(protections, subProtections); } // XZ - if (new XZ().ShouldScan(magic)) + if (scannable is XZ) { - var subProtections = new XZ().Scan(this, stream, fileName); + var subProtections = scannable.Scan(this, stream, fileName); Utilities.PrependToKeys(subProtections, fileName); Utilities.AppendToDictionary(protections, subProtections); } diff --git a/BurnOutSharp/Tools/Utilities.cs b/BurnOutSharp/Tools/Utilities.cs index 90ef4d2d..a8a007fe 100644 --- a/BurnOutSharp/Tools/Utilities.cs +++ b/BurnOutSharp/Tools/Utilities.cs @@ -5,7 +5,9 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Security.Cryptography; +using BurnOutSharp.Interfaces; using BurnOutSharp.Wrappers; +using psxt001z; namespace BurnOutSharp.Tools { @@ -137,7 +139,7 @@ namespace BurnOutSharp.Tools // Get a list of all of the keys var keys = original.Keys.ToList(); - + // Iterate and reset keys for (int i = 0; i < keys.Count; i++) { @@ -177,6 +179,515 @@ namespace BurnOutSharp.Tools #endregion + #region File Types + + /// + /// Get the supported file type for a magic string + /// + /// Recommend sending in 16 bytes to check + public static FileTypes GetFileType(byte[] magic) + { + // If we have an invalid magic byte array + if (magic == null || magic.Length == 0) + return FileTypes.UNKNOWN; + + #region BFPK + + if (magic.StartsWith(new byte?[] { 0x42, 0x46, 0x50, 0x4b })) + return FileTypes.BFPK; + + #endregion + + #region BZip2 + + if (magic.StartsWith(new byte?[] { 0x42, 0x52, 0x68 })) + return FileTypes.BZip2; + + #endregion + + #region Executable + + // DOS MZ executable file format (and descendants) + if (magic.StartsWith(new byte?[] { 0x4d, 0x5a })) + return FileTypes.Executable; + + /* + // None of the following are supported in scans yet + + // Executable and Linkable Format + if (magic.StartsWith(new byte?[] { 0x7f, 0x45, 0x4c, 0x46 })) + return FileTypes.Executable; + + // Mach-O binary (32-bit) + if (magic.StartsWith(new byte?[] { 0xfe, 0xed, 0xfa, 0xce })) + return FileTypes.Executable; + + // Mach-O binary (32-bit, reverse byte ordering scheme) + if (magic.StartsWith(new byte?[] { 0xce, 0xfa, 0xed, 0xfe })) + return FileTypes.Executable; + + // Mach-O binary (64-bit) + if (magic.StartsWith(new byte?[] { 0xfe, 0xed, 0xfa, 0xcf })) + return FileTypes.Executable; + + // Mach-O binary (64-bit, reverse byte ordering scheme) + if (magic.StartsWith(new byte?[] { 0xcf, 0xfa, 0xed, 0xfe })) + return FileTypes.Executable; + + // Prefrred Executable File Format + if (magic.StartsWith(new byte?[] { 0x4a, 0x6f, 0x79, 0x21, 0x70, 0x65, 0x66, 0x66 })) + return FileTypes.Executable; + */ + + #endregion + + #region GZIP + + if (magic.StartsWith(new byte?[] { 0x1f, 0x8b })) + return FileTypes.GZIP; + + #endregion + + #region IniFile + + // No magic checks for IniFile + + #endregion + + #region InstallShieldArchiveV3 + + if (magic.StartsWith(new byte?[] { 0x13, 0x5D, 0x65, 0x8C })) + return FileTypes.InstallShieldArchiveV3; + + #endregion + + #region InstallShieldCAB + + if (magic.StartsWith(new byte?[] { 0x49, 0x53, 0x63 })) + return FileTypes.InstallShieldCAB; + + #endregion + + #region MicrosoftCAB + + if (magic.StartsWith(new byte?[] { 0x4d, 0x53, 0x43, 0x46 })) + return FileTypes.MicrosoftCAB; + + #endregion + + #region MPQ + + if (magic.StartsWith(new byte?[] { 0x4d, 0x50, 0x51, 0x1a })) + return FileTypes.MPQ; + + #endregion + + #region MSI + + if (magic.StartsWith(new byte?[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 })) + return FileTypes.MSI; + + #endregion + + #region PKZIP + + // PKZIP (Unknown) + if (magic.StartsWith(new byte?[] { 0x50, 0x4b, 0x00, 0x00 })) + return FileTypes.PKZIP; + + // PKZIP + if (magic.StartsWith(new byte?[] { 0x50, 0x4b, 0x03, 0x04 })) + return FileTypes.PKZIP; + + // PKZIP (Empty Archive) + if (magic.StartsWith(new byte?[] { 0x50, 0x4b, 0x05, 0x06 })) + return FileTypes.PKZIP; + + // PKZIP (Spanned Archive) + if (magic.StartsWith(new byte?[] { 0x50, 0x4b, 0x07, 0x08 })) + return FileTypes.PKZIP; + + #endregion + + #region PLJ + + // https://www.iana.org/assignments/media-types/audio/vnd.everad.plj + if (magic.StartsWith(new byte?[] { 0xFF, 0x9D, 0x53, 0x4B })) + return FileTypes.PLJ; + + #endregion + + #region RAR + + // RAR archive version 1.50 onwards + if (magic.StartsWith(new byte?[] { 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 })) + return FileTypes.RAR; + + // RAR archive version 5.0 onwards + if (magic.StartsWith(new byte?[] { 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00 })) + return FileTypes.RAR; + + #endregion + + #region SevenZip + + if (magic.StartsWith(new byte?[] { 0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c })) + return FileTypes.SevenZip; + + #endregion + + #region TapeArchive + + if (magic.StartsWith(new byte?[] { 0x75, 0x73, 0x74, 0x61, 0x72, 0x00, 0x30, 0x30 })) + return FileTypes.TapeArchive; + + if (magic.StartsWith(new byte?[] { 0x75, 0x73, 0x74, 0x61, 0x72, 0x20, 0x20, 0x00 })) + return FileTypes.TapeArchive; + + #endregion + + #region Textfile + + // Not all textfiles can be determined through magic number + + // HTML + if (magic.StartsWith(new byte?[] { 0x3c, 0x68, 0x74, 0x6d, 0x6c })) + return FileTypes.Textfile; + + // HTML and XML + if (magic.StartsWith(new byte?[] { 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45 })) + return FileTypes.Textfile; + + // InstallShield Compiled Rules + if (magic.StartsWith(new byte?[] { 0x61, 0x4C, 0x75, 0x5A })) + return FileTypes.Textfile; + + // Microsoft Office File (old) + if (magic.StartsWith(new byte?[] { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 })) + return FileTypes.Textfile; + + // Rich Text File + if (magic.StartsWith(new byte?[] { 0x7b, 0x5c, 0x72, 0x74, 0x66, 0x31 })) + return FileTypes.Textfile; + + // Windows Help File + if (magic.StartsWith(new byte?[] { 0x3F, 0x5F, 0x03, 0x00 })) + return FileTypes.Textfile; + + #endregion + + #region Valve + + if (HLLib.Packages.Package.GetPackageType(magic) != HLLib.Packages.PackageType.HL_PACKAGE_NONE) + return FileTypes.Valve; + + #endregion + + #region XZ + + if (magic.StartsWith(new byte?[] { 0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00 })) + return FileTypes.XZ; + + #endregion + + // We couldn't find a supported match + return FileTypes.UNKNOWN; + } + + /// + /// Get the supported file type for an extension + /// + /// This is less accurate than a magic string match + public static FileTypes GetFileType(string extension) + { + // If we have an invalid extension + if (string.IsNullOrWhiteSpace(extension)) + return FileTypes.UNKNOWN; + + // Normalize the extension + extension = extension.TrimStart('.').Trim(); + + #region BFPK + + // No extensions registered for BFPK + + #endregion + + #region BZip2 + + if (extension.Equals("bz2", StringComparison.OrdinalIgnoreCase)) + return FileTypes.BZip2; + + #endregion + + #region Executable + + // DOS MZ executable file format (and descendants) + if (extension.Equals("exe", StringComparison.OrdinalIgnoreCase)) + return FileTypes.Executable; + + // DOS MZ library file format (and descendants) + if (extension.Equals("dll", StringComparison.OrdinalIgnoreCase)) + return FileTypes.Executable; + + #endregion + + #region GZIP + + if (extension.Equals("gz", StringComparison.OrdinalIgnoreCase)) + return FileTypes.GZIP; + + #endregion + + #region IniFile + + if (extension.Equals("ini", StringComparison.OrdinalIgnoreCase)) + return FileTypes.IniFile; + + #endregion + + #region InstallShieldArchiveV3 + + if (extension.Equals("z", StringComparison.OrdinalIgnoreCase)) + return FileTypes.InstallShieldArchiveV3; + + #endregion + + #region InstallShieldCAB + + // No extensions registered for InstallShieldCAB + // Both InstallShieldCAB and MicrosoftCAB share the same extension + + #endregion + + #region MicrosoftCAB + + // No extensions registered for InstallShieldCAB + // Both InstallShieldCAB and MicrosoftCAB share the same extension + + #endregion + + #region MPQ + + if (extension.Equals("mpq", StringComparison.OrdinalIgnoreCase)) + return FileTypes.MPQ; + + #endregion + + #region MSI + + if (extension.Equals("msi", StringComparison.OrdinalIgnoreCase)) + return FileTypes.MSI; + + #endregion + + #region PKZIP + + // PKZIP + if (extension.Equals("zip", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // Android package + if (extension.Equals("apk", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // Java archive + if (extension.Equals("jar", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // Google Earth saved working session file + if (extension.Equals("kmz", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // KWord document + if (extension.Equals("kwd", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // Microsoft Office Open XML Format (OOXML) Document + if (extension.Equals("docx", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // Microsoft Office Open XML Format (OOXML) Presentation + if (extension.Equals("pptx", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // Microsoft Office Open XML Format (OOXML) Spreadsheet + if (extension.Equals("xlsx", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // OpenDocument text document + if (extension.Equals("odt", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // OpenDocument presentation + if (extension.Equals("odp", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // OpenDocument text document template + if (extension.Equals("ott", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // Microsoft Open XML paper specification file + if (extension.Equals("oxps", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // OpenOffice spreadsheet + if (extension.Equals("sxc", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // OpenOffice drawing + if (extension.Equals("sxd", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // OpenOffice presentation + if (extension.Equals("sxi", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // OpenOffice word processing + if (extension.Equals("sxw", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // StarOffice spreadsheet + if (extension.Equals("sxc", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // Windows Media compressed skin file + if (extension.Equals("wmz", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // Mozilla Browser Archive + if (extension.Equals("xpi", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // XML paper specification file + if (extension.Equals("xps", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + // eXact Packager Models + if (extension.Equals("xpt", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PKZIP; + + #endregion + + #region PLJ + + // https://www.iana.org/assignments/media-types/audio/vnd.everad.plj + if (extension.Equals("plj", StringComparison.OrdinalIgnoreCase)) + return FileTypes.PLJ; + + #endregion + + #region RAR + + if (extension.Equals("rar", StringComparison.OrdinalIgnoreCase)) + return FileTypes.RAR; + + #endregion + + #region SevenZip + + if (extension.Equals("7z", StringComparison.OrdinalIgnoreCase)) + return FileTypes.SevenZip; + + #endregion + + #region TapeArchive + + if (extension.Equals("tar", StringComparison.OrdinalIgnoreCase)) + return FileTypes.SevenZip; + + #endregion + + #region Textfile + + // "Description in Zip" + if (extension.Equals("diz", StringComparison.OrdinalIgnoreCase)) + return FileTypes.Textfile; + + // Generic textfile (no header) + if (extension.Equals("txt", StringComparison.OrdinalIgnoreCase)) + return FileTypes.Textfile; + + // HTML + if (extension.Equals("htm", StringComparison.OrdinalIgnoreCase)) + return FileTypes.Textfile; + if (extension.Equals("html", StringComparison.OrdinalIgnoreCase)) + return FileTypes.Textfile; + + // InstallShield Script + if (extension.Equals("ins", StringComparison.OrdinalIgnoreCase)) + return FileTypes.Textfile; + + // Microsoft Office File (old) + if (extension.Equals("doc", StringComparison.OrdinalIgnoreCase)) + return FileTypes.Textfile; + + // Rich Text File + if (extension.Equals("rtf", StringComparison.OrdinalIgnoreCase)) + return FileTypes.Textfile; + + // Setup information + if (extension.Equals("inf", StringComparison.OrdinalIgnoreCase)) + return FileTypes.Textfile; + + // Windows Help File + if (extension.Equals("hlp", StringComparison.OrdinalIgnoreCase)) + return FileTypes.Textfile; + + // XML + if (extension.Equals("xml", StringComparison.OrdinalIgnoreCase)) + return FileTypes.Textfile; + + #endregion + + #region Valve + + // No extensions registered for Valve + + #endregion + + #region XZ + + if (extension.Equals("xz", StringComparison.OrdinalIgnoreCase)) + return FileTypes.XZ; + + #endregion + + // We couldn't find a supported match + return FileTypes.UNKNOWN; + } + + /// + /// Create an instance of a scannable based on file type + /// + public static IScannable CreateScannable(FileTypes fileType) + { + switch (fileType) + { + case FileTypes.BFPK: return new FileType.BFPK(); + case FileTypes.BZip2: return new FileType.BZip2(); + case FileTypes.Executable: return new FileType.Executable(); + case FileTypes.GZIP: return new FileType.GZIP(); + //case FileTypes.IniFile: return new FileType.IniFile(); + case FileTypes.InstallShieldArchiveV3: return new FileType.InstallShieldArchiveV3(); + case FileTypes.InstallShieldCAB: return new FileType.InstallShieldCAB(); + case FileTypes.MicrosoftCAB: return new FileType.MicrosoftCAB(); + case FileTypes.MPQ: return new FileType.MPQ(); + case FileTypes.MSI: return new FileType.MSI(); + case FileTypes.PKZIP: return new FileType.PKZIP(); + case FileTypes.PLJ: return new FileType.PLJ(); + case FileTypes.RAR: return new FileType.RAR(); + case FileTypes.SevenZip: return new FileType.SevenZip(); + case FileTypes.TapeArchive: return new FileType.TapeArchive(); + case FileTypes.Textfile: return new FileType.Textfile(); + case FileTypes.Valve: return new FileType.Valve(); + case FileTypes.XZ: return new FileType.XZ(); + default: return null; + } + } + + #endregion + #region Processed Executable Information /// @@ -286,15 +797,6 @@ namespace BurnOutSharp.Tools #region Wrappers for Matchers - /// - /// Wrapper for GetInternalVersion for use in content matching - /// - /// File to check for version - /// Byte array representing the file contents - /// Last matched positions in the contents - /// Version string, null on error - public static string GetInternalVersion(string file, byte[] fileContent, List positions) => GetInternalVersion(file); - /// /// Wrapper for GetInternalVersion for use in path matching ///