diff --git a/Test/Extractor.cs b/Test/Extractor.cs
new file mode 100644
index 00000000..aa304718
--- /dev/null
+++ b/Test/Extractor.cs
@@ -0,0 +1,829 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Text;
+using BurnOutSharp;
+using BurnOutSharp.Compression;
+using BurnOutSharp.Utilities;
+using BurnOutSharp.Wrappers;
+using OpenMcdf;
+using SharpCompress.Archives;
+using SharpCompress.Archives.GZip;
+using SharpCompress.Archives.Rar;
+using SharpCompress.Archives.SevenZip;
+using SharpCompress.Archives.Tar;
+using SharpCompress.Archives.Zip;
+using SharpCompress.Compressors;
+using SharpCompress.Compressors.BZip2;
+using SharpCompress.Compressors.Xz;
+using UnshieldSharp.Archive;
+using UnshieldSharp.Cabinet;
+
+namespace Test
+{
+ internal static class Extractor
+ {
+ ///
+ /// Wrapper to extract data for a single path
+ ///
+ /// File or directory path
+ /// Output directory path
+ public static void ExtractPath(string path, string outputDirectory)
+ {
+ Console.WriteLine($"Checking possible path: {path}");
+
+ // Check if the file or directory exists
+ if (File.Exists(path))
+ {
+ ExtractFile(path, outputDirectory);
+ }
+ else if (Directory.Exists(path))
+ {
+ foreach (string file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories))
+ {
+ ExtractFile(file, outputDirectory);
+ }
+ }
+ else
+ {
+ Console.WriteLine($"{path} does not exist, skipping...");
+ }
+ }
+
+ ///
+ /// Print information for a single file, if possible
+ ///
+ private static void ExtractFile(string file, string outputDirectory)
+ {
+ Console.WriteLine($"Attempting to extract all files from {file}");
+
+ using (Stream stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
+ {
+ // Read the first 8 bytes
+ byte[] magic = stream.ReadBytes(8);
+ stream.Seek(0, SeekOrigin.Begin);
+
+ // Get the file type
+ SupportedFileType ft = BurnOutSharp.Tools.Utilities.GetFileType(magic);
+
+ // Executables technically can be "extracted", but let's ignore that
+ // TODO: Support executables that include other stuff
+
+ // 7-zip
+ if (ft == SupportedFileType.SevenZip)
+ {
+ // Build the archive information
+ Console.WriteLine("Extracting 7-zip contents");
+ Console.WriteLine();
+
+ // If the 7-zip file itself fails
+ try
+ {
+ using (SevenZipArchive sevenZipFile = SevenZipArchive.Open(stream))
+ {
+ foreach (var entry in sevenZipFile.Entries)
+ {
+ // If an individual entry fails
+ try
+ {
+ // If we have a directory, skip it
+ if (entry.IsDirectory)
+ continue;
+
+ string tempFile = Path.Combine(outputDirectory, entry.Key);
+ entry.WriteToFile(tempFile);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting 7-zip entry {entry.Key}: {ex}");
+ Console.WriteLine();
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting 7-zip: {ex}");
+ Console.WriteLine();
+ }
+ }
+
+ // BFPK archive
+ else if (ft == SupportedFileType.BFPK)
+ {
+ // Build the BFPK information
+ Console.WriteLine("Extracting BFPK contents");
+ Console.WriteLine();
+
+ var bfpk = BFPK.Create(stream);
+ if (bfpk == null)
+ {
+ Console.WriteLine("Something went wrong parsing BFPK archive");
+ Console.WriteLine();
+ return;
+ }
+
+ try
+ {
+ // Extract the BFPK contents to the directory
+ bfpk.ExtractAll(outputDirectory);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting BFPK archive: {ex}");
+ Console.WriteLine();
+ }
+ }
+
+ // BSP
+ else if (ft == SupportedFileType.BSP)
+ {
+ // Build the BSP information
+ Console.WriteLine("Extracting BSP contents");
+ Console.WriteLine();
+
+ var bsp = BSP.Create(stream);
+ if (bsp == null)
+ {
+ Console.WriteLine("Something went wrong parsing BSP");
+ Console.WriteLine();
+ return;
+ }
+
+ try
+ {
+ // Extract the BSP contents to the directory
+ bsp.ExtractAllLumps(outputDirectory);
+ bsp.ExtractAllTextures(outputDirectory);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting BSP: {ex}");
+ Console.WriteLine();
+ }
+ }
+
+ // bzip2
+ else if (ft == SupportedFileType.BZip2)
+ {
+ // Build the bzip2 information
+ Console.WriteLine("Extracting bzip2 contents");
+ Console.WriteLine();
+
+ using (var bz2File = new BZip2Stream(stream, CompressionMode.Decompress, true))
+ {
+ // If an individual entry fails
+ try
+ {
+ string tempFile = Path.Combine(outputDirectory, Guid.NewGuid().ToString());
+ using (FileStream fs = File.OpenWrite(tempFile))
+ {
+ bz2File.CopyTo(fs);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting bzip2: {ex}");
+ Console.WriteLine();
+ }
+ }
+ }
+
+ // GCF
+ else if (ft == SupportedFileType.GCF)
+ {
+ // Build the GCF information
+ Console.WriteLine("Extracting GCF contents");
+ Console.WriteLine();
+
+ var gcf = GCF.Create(stream);
+ if (gcf == null)
+ {
+ Console.WriteLine("Something went wrong parsing GCF");
+ Console.WriteLine();
+ return;
+ }
+
+ try
+ {
+ // Extract the GCF contents to the directory
+ gcf.ExtractAll(outputDirectory);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting GCF: {ex}");
+ Console.WriteLine();
+ }
+ }
+
+ // gzip
+ else if (ft == SupportedFileType.GZIP)
+ {
+ // Build the gzip information
+ Console.WriteLine("Extracting gzip contents");
+ Console.WriteLine();
+
+ using (var zipFile = GZipArchive.Open(stream))
+ {
+ foreach (var entry in zipFile.Entries)
+ {
+ // If an individual entry fails
+ try
+ {
+ // If we have a directory, skip it
+ if (entry.IsDirectory)
+ continue;
+
+ string tempFile = Path.Combine(outputDirectory, entry.Key);
+ entry.WriteToFile(tempFile);
+ }
+
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting gzip entry {entry.Key}: {ex}");
+ Console.WriteLine();
+ }
+ }
+ }
+ }
+
+ // InstallShield Archive V3 (Z)
+ else if (ft == SupportedFileType.InstallShieldArchiveV3)
+ {
+ // Build the InstallShield Archive V3 information
+ Console.WriteLine("Extracting InstallShield Archive V3 contents");
+ Console.WriteLine();
+
+ // If the cab file itself fails
+ try
+ {
+ var archive = new InstallShieldArchiveV3(file);
+ foreach (var cfile in archive.Files.Select(kvp => kvp.Value))
+ {
+ // If an individual entry fails
+ try
+ {
+ string tempFile = Path.Combine(outputDirectory, cfile.FullPath);
+ if (!Directory.Exists(Path.GetDirectoryName(tempFile)))
+ Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
+
+ (byte[] fileContents, string error) = archive.Extract(cfile.FullPath);
+ if (!string.IsNullOrWhiteSpace(error))
+ continue;
+
+ using (FileStream fs = File.OpenWrite(tempFile))
+ {
+ fs.Write(fileContents, 0, fileContents.Length);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting InstallShield Archive V3 entry {cfile.Name}: {ex}");
+ Console.WriteLine();
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting InstallShield Archive V3: {ex}");
+ Console.WriteLine();
+ }
+ }
+
+ // IS-CAB archive
+ else if (ft == SupportedFileType.InstallShieldCAB)
+ {
+ // Build the archive information
+ Console.WriteLine("Extracting IS-CAB contents");
+ Console.WriteLine();
+
+ // If the cab file itself fails
+ try
+ {
+ InstallShieldCabinet cabfile = InstallShieldCabinet.Open(file);
+ for (int i = 0; i < cabfile.FileCount; i++)
+ {
+ // If an individual entry fails
+ try
+ {
+ string filename = cabfile.FileName(i);
+ string tempFile;
+ try
+ {
+ tempFile = Path.Combine(outputDirectory, filename);
+ }
+ catch
+ {
+ tempFile = Path.Combine(outputDirectory, $"BAD_FILENAME{i}");
+ }
+
+ cabfile.FileSave(i, tempFile);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting IS-CAB entry {i}: {ex}");
+ Console.WriteLine();
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting IS-CAB: {ex}");
+ Console.WriteLine();
+ }
+ }
+
+ // Microsoft Cabinet archive
+ else if (ft == SupportedFileType.MicrosoftCAB)
+ {
+ // Build the cabinet information
+ Console.WriteLine("Extracting MS-CAB contents");
+ Console.WriteLine();
+
+ var cabinet = MicrosoftCabinet.Create(stream);
+ if (cabinet == null)
+ {
+ Console.WriteLine("Something went wrong parsing MS-CAB archive");
+ Console.WriteLine();
+ return;
+ }
+
+ try
+ {
+ // Extract the MS-CAB contents to the directory
+ cabinet.ExtractAll(outputDirectory);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting MS-CAB: {ex}");
+ Console.WriteLine();
+ }
+ }
+
+ // Microsoft LZ / LZ32
+ else if (ft == SupportedFileType.MicrosoftLZ)
+ {
+ // Build the Microsoft LZ / LZ32 information
+ Console.WriteLine("Extracting Microsoft LZ / LZ32 contents");
+ Console.WriteLine();
+
+ // If the LZ file itself fails
+ try
+ {
+ byte[] data = LZ.Decompress(stream);
+
+ // Create the temp filename
+ string tempFile = "temp.bin";
+ if (!string.IsNullOrEmpty(file))
+ {
+ string expandedFilePath = LZ.GetExpandedName(file, out _);
+ tempFile = Path.GetFileName(expandedFilePath).TrimEnd('\0');
+ if (tempFile.EndsWith(".ex"))
+ tempFile += "e";
+ else if (tempFile.EndsWith(".dl"))
+ tempFile += "l";
+ }
+
+ tempFile = Path.Combine(outputDirectory, tempFile);
+
+ // Write the file data to a temp file
+ using (Stream tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
+ {
+ tempStream.Write(data, 0, data.Length);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting Microsoft LZ / LZ32: {ex}");
+ Console.WriteLine();
+ }
+ }
+
+#if NET48
+ // MoPaQ (MPQ) archive
+ else if (ft == SupportedFileType.MPQ)
+ {
+ // Build the archive information
+ Console.WriteLine("Extracting MoPaQ contents");
+ Console.WriteLine();
+
+ // If the MPQ file itself fails
+ try
+ {
+ using (var mpqArchive = new StormLibSharp.MpqArchive(file, FileAccess.Read))
+ {
+ // Try to open the listfile
+ string listfile = null;
+ StormLibSharp.MpqFileStream listStream = mpqArchive.OpenFile("(listfile)");
+
+ // If we can't read the listfile, we just return
+ if (!listStream.CanRead)
+ {
+ Console.WriteLine("Could not read the listfile, extraction halted!");
+ Console.WriteLine();
+ }
+
+ // Read the listfile in for processing
+ using (StreamReader sr = new StreamReader(listStream))
+ {
+ listfile = sr.ReadToEnd();
+ }
+
+ // Split the listfile by newlines
+ string[] listfileLines = listfile.Replace("\r\n", "\n").Split('\n');
+
+ // Loop over each entry
+ foreach (string sub in listfileLines)
+ {
+ // If an individual entry fails
+ try
+ {
+ string tempFile = Path.Combine(outputDirectory, sub);
+ Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
+ mpqArchive.ExtractFile(sub, tempFile);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting MoPaQ entry {sub}: {ex}");
+ Console.WriteLine();
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting MoPaQ: {ex}");
+ Console.WriteLine();
+ }
+ }
+#endif
+
+ // MSI
+ else if (ft == SupportedFileType.MSI)
+ {
+ // Build the installer information
+ Console.WriteLine("Extracting MSI contents");
+ Console.WriteLine();
+
+ // If the MSI file itself fails
+ try
+ {
+ using (CompoundFile msi = new CompoundFile(stream, CFSUpdateMode.ReadOnly, CFSConfiguration.Default))
+ {
+ msi.RootStorage.VisitEntries((e) =>
+ {
+ if (!e.IsStream)
+ return;
+
+ var str = msi.RootStorage.GetStream(e.Name);
+ if (str == null)
+ return;
+
+ byte[] strData = str.GetData();
+ if (strData == null)
+ return;
+
+ string decoded = BurnOutSharp.FileType.MSI.DecodeStreamName(e.Name).TrimEnd('\0');
+ byte[] nameBytes = Encoding.UTF8.GetBytes(e.Name);
+
+ // UTF-8 encoding of 0x4840.
+ if (nameBytes[0] == 0xe4 && nameBytes[1] == 0xa1 && nameBytes[2] == 0x80)
+ decoded = decoded.Substring(3);
+
+ foreach (char c in Path.GetInvalidFileNameChars())
+ {
+ decoded = decoded.Replace(c, '_');
+ }
+
+ string filename = Path.Combine(outputDirectory, decoded);
+ using (Stream fs = File.OpenWrite(filename))
+ {
+ fs.Write(strData, 0, strData.Length);
+ }
+ }, recursive: true);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting MSI: {ex}");
+ Console.WriteLine();
+ }
+ }
+
+ // PAK
+ else if (ft == SupportedFileType.PAK)
+ {
+ // Build the archive information
+ Console.WriteLine("Extracting PAK contents");
+ Console.WriteLine();
+
+ var pak = PAK.Create(stream);
+ if (pak == null)
+ {
+ Console.WriteLine("Something went wrong parsing PAK");
+ Console.WriteLine();
+ return;
+ }
+
+ try
+ {
+ // Extract the PAK contents to the directory
+ pak.ExtractAll(outputDirectory);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting MS-CAB: {ex}");
+ Console.WriteLine();
+ }
+ }
+
+ // PKZIP
+ else if (ft == SupportedFileType.PKZIP)
+ {
+ // Build the archive information
+ Console.WriteLine("Extracting PKZIP contents");
+ Console.WriteLine();
+
+ // If the zip file itself fails
+ try
+ {
+ using (ZipArchive zipFile = ZipArchive.Open(stream))
+ {
+ foreach (var entry in zipFile.Entries)
+ {
+ // If an individual entry fails
+ try
+ {
+ // If we have a directory, skip it
+ if (entry.IsDirectory)
+ continue;
+
+ string tempFile = Path.Combine(outputDirectory, entry.Key);
+ Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
+ entry.WriteToFile(tempFile);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting PKZIP entry {entry.Key}: {ex}");
+ Console.WriteLine();
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting PKZIP: {ex}");
+ Console.WriteLine();
+ }
+ }
+
+ // RAR
+ else if (ft == SupportedFileType.RAR)
+ {
+ // Build the archive information
+ Console.WriteLine("Extracting RAR contents");
+ Console.WriteLine();
+
+ // If the rar file itself fails
+ try
+ {
+ using (RarArchive rarFile = RarArchive.Open(stream))
+ {
+ foreach (var entry in rarFile.Entries)
+ {
+ // If an individual entry fails
+ try
+ {
+ // If we have a directory, skip it
+ if (entry.IsDirectory)
+ continue;
+
+ string tempFile = Path.Combine(outputDirectory, entry.Key);
+ entry.WriteToFile(tempFile);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting RAR entry {entry.Key}: {ex}");
+ Console.WriteLine();
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting RAR: {ex}");
+ Console.WriteLine();
+ }
+ }
+
+ // SGA
+ else if (ft == SupportedFileType.SGA)
+ {
+ // Build the archive information
+ Console.WriteLine("Extracting SGA contents");
+ Console.WriteLine();
+
+ var sga = SGA.Create(stream);
+ if (sga == null)
+ {
+ Console.WriteLine("Something went wrong parsing SGA");
+ Console.WriteLine();
+ return;
+ }
+
+ try
+ {
+ // Extract the SGA contents to the directory
+ sga.ExtractAll(outputDirectory);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting MS-CAB: {ex}");
+ Console.WriteLine();
+ }
+ }
+
+ // Tape Archive
+ else if (ft == SupportedFileType.RAR)
+ {
+ // Build the archive information
+ Console.WriteLine("Extracting Tape Archive contents");
+ Console.WriteLine();
+
+ // If the rar file itself fails
+ try
+ {
+ using (TarArchive tarFile = TarArchive.Open(stream))
+ {
+ foreach (var entry in tarFile.Entries)
+ {
+ // If an individual entry fails
+ try
+ {
+ // If we have a directory, skip it
+ if (entry.IsDirectory)
+ continue;
+
+ string tempFile = Path.Combine(outputDirectory, entry.Key);
+ entry.WriteToFile(tempFile);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting Tape Archive entry {entry.Key}: {ex}");
+ Console.WriteLine();
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting Tape Archive: {ex}");
+ Console.WriteLine();
+ }
+ }
+
+ // VBSP
+ else if (ft == SupportedFileType.VBSP)
+ {
+ // Build the archive information
+ Console.WriteLine("Extracting VBSP contents");
+ Console.WriteLine();
+
+ var vbsp = VBSP.Create(stream);
+ if (vbsp == null)
+ {
+ Console.WriteLine("Something went wrong parsing VBSP");
+ Console.WriteLine();
+ return;
+ }
+
+ try
+ {
+ // Extract the VBSP contents to the directory
+ vbsp.ExtractAllLumps(outputDirectory);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting MS-CAB: {ex}");
+ Console.WriteLine();
+ }
+ }
+
+ // VPK
+ else if (ft == SupportedFileType.VPK)
+ {
+ // Build the archive information
+ Console.WriteLine("Extracting VPK contents");
+ Console.WriteLine();
+
+ var vpk = VPK.Create(stream);
+ if (vpk == null)
+ {
+ Console.WriteLine("Something went wrong parsing VPK");
+ Console.WriteLine();
+ return;
+ }
+
+ try
+ {
+ // Extract the VPK contents to the directory
+ vpk.ExtractAll(outputDirectory);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting MS-CAB: {ex}");
+ Console.WriteLine();
+ }
+ }
+
+ // WAD
+ else if (ft == SupportedFileType.WAD)
+ {
+ // Build the archive information
+ Console.WriteLine("Extracting WAD contents");
+ Console.WriteLine();
+
+ var wad = WAD.Create(stream);
+ if (wad == null)
+ {
+ Console.WriteLine("Something went wrong parsing WAD");
+ Console.WriteLine();
+ return;
+ }
+
+ try
+ {
+ // Extract the WAD contents to the directory
+ wad.ExtractAllLumps(outputDirectory);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting MS-CAB: {ex}");
+ Console.WriteLine();
+ }
+ }
+
+ // xz
+ else if (ft == SupportedFileType.RAR)
+ {
+ // Build the xz information
+ Console.WriteLine("Extracting xz contents");
+ Console.WriteLine();
+
+ using (var xzFile = new XZStream(stream))
+ {
+ // If an individual entry fails
+ try
+ {
+ string tempFile = Path.Combine(outputDirectory, Guid.NewGuid().ToString());
+ using (FileStream fs = File.OpenWrite(tempFile))
+ {
+ xzFile.CopyTo(fs);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting xz: {ex}");
+ Console.WriteLine();
+ }
+ }
+ }
+
+ // XZP
+ else if (ft == SupportedFileType.XZP)
+ {
+ // Build the archive information
+ Console.WriteLine("Extracting XZP contents");
+ Console.WriteLine();
+
+ var xzp = XZP.Create(stream);
+ if (xzp == null)
+ {
+ Console.WriteLine("Something went wrong parsing XZP");
+ Console.WriteLine();
+ return;
+ }
+
+ try
+ {
+ // Extract the XZP contents to the directory
+ xzp.ExtractAll(outputDirectory);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Something went wrong extracting MS-CAB: {ex}");
+ Console.WriteLine();
+ }
+ }
+
+ // Everything else
+ else
+ {
+ Console.WriteLine("Not a supported extractable file format, skipping...");
+ Console.WriteLine();
+ return;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Test/Printer.cs b/Test/Printer.cs
new file mode 100644
index 00000000..b189fef1
--- /dev/null
+++ b/Test/Printer.cs
@@ -0,0 +1,398 @@
+using System;
+using System.IO;
+using BurnOutSharp;
+using BurnOutSharp.Matching;
+using BurnOutSharp.Utilities;
+using BurnOutSharp.Wrappers;
+
+namespace Test
+{
+ internal static class Printer
+ {
+ ///
+ /// Wrapper to print information for a single path
+ ///
+ /// File or directory path
+ public static void PrintPathInfo(string path)
+ {
+ Console.WriteLine($"Checking possible path: {path}");
+
+ // Check if the file or directory exists
+ if (File.Exists(path))
+ {
+ PrintFileInfo(path);
+ }
+ else if (Directory.Exists(path))
+ {
+ foreach (string file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories))
+ {
+ PrintFileInfo(file);
+ }
+ }
+ else
+ {
+ Console.WriteLine($"{path} does not exist, skipping...");
+ }
+ }
+
+ ///
+ /// Print information for a single file, if possible
+ ///
+ private static void PrintFileInfo(string file)
+ {
+ Console.WriteLine($"Attempting to print info for {file}");
+
+ using (Stream stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
+ {
+ // Read the first 8 bytes
+ byte[] magic = stream.ReadBytes(8);
+ stream.Seek(0, SeekOrigin.Begin);
+
+ // Get the file type
+ SupportedFileType ft = BurnOutSharp.Tools.Utilities.GetFileType(magic);
+
+ // MS-DOS executable and decendents
+ if (ft == SupportedFileType.Executable)
+ {
+ // Build the executable information
+ Console.WriteLine("Creating MS-DOS executable builder");
+ Console.WriteLine();
+
+ var msdos = MSDOS.Create(stream);
+ if (msdos == null)
+ {
+ Console.WriteLine("Something went wrong parsing MS-DOS executable");
+ Console.WriteLine();
+ return;
+ }
+
+ // Print the executable info to screen
+ msdos.Print();
+
+ // Check for a valid new executable address
+ if (msdos.NewExeHeaderAddr >= stream.Length)
+ {
+ Console.WriteLine("New EXE header address invalid, skipping additional reading...");
+ Console.WriteLine();
+ return;
+ }
+
+ // Try to read the executable info
+ stream.Seek(msdos.NewExeHeaderAddr, SeekOrigin.Begin);
+ magic = stream.ReadBytes(4);
+
+ // New Executable
+ if (magic.StartsWith(BurnOutSharp.Models.NewExecutable.Constants.SignatureBytes))
+ {
+ stream.Seek(0, SeekOrigin.Begin);
+ var newExecutable = NewExecutable.Create(stream);
+ if (newExecutable == null)
+ {
+ Console.WriteLine("Something went wrong parsing New Executable");
+ Console.WriteLine();
+ return;
+ }
+
+ // Print the executable info to screen
+ newExecutable.Print();
+ }
+
+ // Linear Executable
+ if (magic.StartsWith(BurnOutSharp.Models.LinearExecutable.Constants.LESignatureBytes)
+ || magic.StartsWith(BurnOutSharp.Models.LinearExecutable.Constants.LXSignatureBytes))
+ {
+ Console.WriteLine($"Linear executable found. No parsing currently available.");
+ Console.WriteLine();
+ return;
+ }
+
+ // Portable Executable
+ if (magic.StartsWith(BurnOutSharp.Models.PortableExecutable.Constants.SignatureBytes))
+ {
+ stream.Seek(0, SeekOrigin.Begin);
+ var portableExecutable = PortableExecutable.Create(stream);
+ if (portableExecutable == null)
+ {
+ Console.WriteLine("Something went wrong parsing Portable Executable");
+ Console.WriteLine();
+ return;
+ }
+
+ // Print the executable info to screen
+ portableExecutable.Print();
+ }
+
+ // Unknown
+ else
+ {
+ Console.WriteLine($"Unrecognized header signature: {BitConverter.ToString(magic).Replace("-", string.Empty)}");
+ Console.WriteLine();
+ return;
+ }
+ }
+
+ // BFPK archive
+ else if (ft == SupportedFileType.BFPK)
+ {
+ // Build the BFPK information
+ Console.WriteLine("Creating BFPK deserializer");
+ Console.WriteLine();
+
+ var bfpk = BFPK.Create(stream);
+ if (bfpk == null)
+ {
+ Console.WriteLine("Something went wrong parsing BFPK archive");
+ Console.WriteLine();
+ return;
+ }
+
+ // Print the BFPK info to screen
+ bfpk.Print();
+ }
+
+ // BSP
+ else if (ft == SupportedFileType.BSP)
+ {
+ // Build the BSP information
+ Console.WriteLine("Creating BSP deserializer");
+ Console.WriteLine();
+
+ var bsp = BSP.Create(stream);
+ if (bsp == null)
+ {
+ Console.WriteLine("Something went wrong parsing BSP");
+ Console.WriteLine();
+ return;
+ }
+
+ // Print the BSP info to screen
+ bsp.Print();
+ }
+
+ // GCF
+ else if (ft == SupportedFileType.GCF)
+ {
+ // Build the GCF information
+ Console.WriteLine("Creating GCF deserializer");
+ Console.WriteLine();
+
+ var gcf = GCF.Create(stream);
+ if (gcf == null)
+ {
+ Console.WriteLine("Something went wrong parsing GCF");
+ Console.WriteLine();
+ return;
+ }
+
+ // Print the GCF info to screen
+ gcf.Print();
+ }
+
+ // IS-CAB archive
+ else if (ft == SupportedFileType.InstallShieldCAB)
+ {
+ // Build the archive information
+ Console.WriteLine("Creating IS-CAB deserializer");
+ Console.WriteLine();
+
+ // TODO: Write and use printing methods
+ Console.WriteLine("IS-CAB archive printing not currently enabled");
+ Console.WriteLine();
+ return;
+ }
+
+ // MoPaQ (MPQ) archive
+ else if (ft == SupportedFileType.MPQ)
+ {
+ // Build the archive information
+ Console.WriteLine("Creating MoPaQ deserializer");
+ Console.WriteLine();
+
+ // TODO: Write and use printing methods
+ Console.WriteLine("MoPaQ archive printing not currently enabled");
+ Console.WriteLine();
+ return;
+ }
+
+ // MS-CAB archive
+ else if (ft == SupportedFileType.MicrosoftCAB)
+ {
+ // Build the cabinet information
+ Console.WriteLine("Creating MS-CAB deserializer");
+ Console.WriteLine();
+
+ var cabinet = MicrosoftCabinet.Create(stream);
+ if (cabinet == null)
+ {
+ Console.WriteLine("Something went wrong parsing MS-CAB archive");
+ Console.WriteLine();
+ return;
+ }
+
+ // Print the cabinet info to screen
+ cabinet.Print();
+ }
+
+ // NCF
+ else if (ft == SupportedFileType.NCF)
+ {
+ // Build the NCF information
+ Console.WriteLine("Creating NCF deserializer");
+ Console.WriteLine();
+
+ var ncf = NCF.Create(stream);
+ if (ncf == null)
+ {
+ Console.WriteLine("Something went wrong parsing NCF");
+ Console.WriteLine();
+ return;
+ }
+
+ // Print the NCF info to screen
+ ncf.Print();
+ }
+
+ // PAK
+ else if (ft == SupportedFileType.PAK)
+ {
+ // Build the archive information
+ Console.WriteLine("Creating PAK deserializer");
+ Console.WriteLine();
+
+ var pak = PAK.Create(stream);
+ if (pak == null)
+ {
+ Console.WriteLine("Something went wrong parsing PAK");
+ Console.WriteLine();
+ return;
+ }
+
+ // Print the PAK info to screen
+ pak.Print();
+ }
+
+ // Quantum
+ else if (ft == SupportedFileType.Quantum)
+ {
+ // Build the archive information
+ Console.WriteLine("Creating Quantum deserializer");
+ Console.WriteLine();
+
+ var quantum = Quantum.Create(stream);
+ if (quantum == null)
+ {
+ Console.WriteLine("Something went wrong parsing Quantum");
+ Console.WriteLine();
+ return;
+ }
+
+ // Print the Quantum info to screen
+ quantum.Print();
+ }
+
+ // SGA
+ else if (ft == SupportedFileType.SGA)
+ {
+ // Build the archive information
+ Console.WriteLine("Creating SGA deserializer");
+ Console.WriteLine();
+
+ var sga = SGA.Create(stream);
+ if (sga == null)
+ {
+ Console.WriteLine("Something went wrong parsing SGA");
+ Console.WriteLine();
+ return;
+ }
+
+ // Print the SGA info to screen
+ sga.Print();
+ }
+
+ // VBSP
+ else if (ft == SupportedFileType.VBSP)
+ {
+ // Build the archive information
+ Console.WriteLine("Creating VBSP deserializer");
+ Console.WriteLine();
+
+ var vbsp = VBSP.Create(stream);
+ if (vbsp == null)
+ {
+ Console.WriteLine("Something went wrong parsing VBSP");
+ Console.WriteLine();
+ return;
+ }
+
+ // Print the VBSP info to screen
+ vbsp.Print();
+ }
+
+ // VPK
+ else if (ft == SupportedFileType.VPK)
+ {
+ // Build the archive information
+ Console.WriteLine("Creating VPK deserializer");
+ Console.WriteLine();
+
+ var vpk = VPK.Create(stream);
+ if (vpk == null)
+ {
+ Console.WriteLine("Something went wrong parsing VPK");
+ Console.WriteLine();
+ return;
+ }
+
+ // Print the VPK info to screen
+ vpk.Print();
+ }
+
+ // WAD
+ else if (ft == SupportedFileType.WAD)
+ {
+ // Build the archive information
+ Console.WriteLine("Creating WAD deserializer");
+ Console.WriteLine();
+
+ var wad = WAD.Create(stream);
+ if (wad == null)
+ {
+ Console.WriteLine("Something went wrong parsing WAD");
+ Console.WriteLine();
+ return;
+ }
+
+ // Print the WAD info to screen
+ wad.Print();
+ }
+
+ // XZP
+ else if (ft == SupportedFileType.XZP)
+ {
+ // Build the archive information
+ Console.WriteLine("Creating XZP deserializer");
+ Console.WriteLine();
+
+ var xzp = XZP.Create(stream);
+ if (xzp == null)
+ {
+ Console.WriteLine("Something went wrong parsing XZP");
+ Console.WriteLine();
+ return;
+ }
+
+ // Print the XZP info to screen
+ xzp.Print();
+ }
+
+ // Everything else
+ else
+ {
+ Console.WriteLine("Not a recognized file format, skipping...");
+ Console.WriteLine();
+ return;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Test/Program.cs b/Test/Program.cs
index 26b48a38..0a0b945f 100644
--- a/Test/Program.cs
+++ b/Test/Program.cs
@@ -1,26 +1,8 @@
using System;
-using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Text;
using BurnOutSharp;
-using BurnOutSharp.Compression;
-using BurnOutSharp.Matching;
-using BurnOutSharp.Utilities;
-using BurnOutSharp.Wrappers;
-using OpenMcdf;
-using SharpCompress.Archives;
-using SharpCompress.Archives.GZip;
-using SharpCompress.Archives.Rar;
-using SharpCompress.Archives.SevenZip;
-using SharpCompress.Archives.Tar;
-using SharpCompress.Archives.Zip;
-using SharpCompress.Compressors;
-using SharpCompress.Compressors.BZip2;
-using SharpCompress.Compressors.Xz;
-using UnshieldSharp.Archive;
-using UnshieldSharp.Cabinet;
namespace Test
{
@@ -33,7 +15,7 @@ namespace Test
// Create progress indicator
var p = new Progress();
- p.ProgressChanged += Changed;
+ p.ProgressChanged += Protector.Changed;
// Set initial values for scanner flags
bool debug = false, archives = true, packers = true, info = false, extract = false;
@@ -138,11 +120,11 @@ namespace Test
foreach (string inputPath in inputPaths)
{
if (info)
- PrintPathInfo(inputPath);
+ Printer.PrintPathInfo(inputPath);
else if (extract)
- ExtractPath(inputPath, outputPath);
+ Extractor.ExtractPath(inputPath, outputPath);
else
- GetAndWriteProtections(scanner, inputPath);
+ Protector.GetAndWriteProtections(scanner, inputPath);
}
Console.WriteLine("Press enter to close the program...");
@@ -167,1270 +149,5 @@ namespace Test
Console.WriteLine("-x, --extract Extract archive formats");
Console.WriteLine("-o, --outdir [PATH] Set output path for extraction");
}
-
- #region Protection
-
- ///
- /// Wrapper to get and log protections for a single path
- ///
- /// Scanner object to use
- /// File or directory path
- private static void GetAndWriteProtections(Scanner scanner, string path)
- {
- // An invalid path can't be scanned
- if (!Directory.Exists(path) && !File.Exists(path))
- {
- Console.WriteLine($"{path} does not exist, skipping...");
- return;
- }
-
- try
- {
- var protections = scanner.GetProtections(path);
- WriteProtectionResultFile(path, protections);
- }
- catch (Exception ex)
- {
- using (StreamWriter sw = new StreamWriter(File.OpenWrite($"{DateTime.Now:yyyy-MM-dd_HHmmss}-exception.txt")))
- {
- sw.WriteLine(ex);
- }
- }
- }
-
- ///
- /// Write the protection results from a single path to file, if possible
- ///
- /// File or directory path
- /// Dictionary of protections found, if any
- private static void WriteProtectionResultFile(string path, ConcurrentDictionary> protections)
- {
- if (protections == null)
- {
- Console.WriteLine($"No protections found for {path}");
- return;
- }
-
- using (var sw = new StreamWriter(File.OpenWrite($"{DateTime.Now:yyyy-MM-dd_HHmmss}.txt")))
- {
- foreach (string key in protections.Keys.OrderBy(k => k))
- {
- // Skip over files with no protection
- if (protections[key] == null || !protections[key].Any())
- continue;
-
- string line = $"{key}: {string.Join(", ", protections[key].OrderBy(p => p))}";
- Console.WriteLine(line);
- sw.WriteLine(line);
- }
- }
- }
-
- ///
- /// Protection progress changed handler
- ///
- private static void Changed(object source, ProtectionProgress value)
- {
- Console.WriteLine($"{value.Percentage * 100:N2}%: {value.Filename} - {value.Protection}");
- }
-
- #endregion
-
- #region Printing
-
- ///
- /// Wrapper to print information for a single path
- ///
- /// File or directory path
- private static void PrintPathInfo(string path)
- {
- Console.WriteLine($"Checking possible path: {path}");
-
- // Check if the file or directory exists
- if (File.Exists(path))
- {
- PrintFileInfo(path);
- }
- else if (Directory.Exists(path))
- {
- foreach (string file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories))
- {
- PrintFileInfo(file);
- }
- }
- else
- {
- Console.WriteLine($"{path} does not exist, skipping...");
- }
- }
-
- ///
- /// Print information for a single file, if possible
- ///
- private static void PrintFileInfo(string file)
- {
- Console.WriteLine($"Attempting to print info for {file}");
-
- using (Stream stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
- {
- // Read the first 8 bytes
- byte[] magic = stream.ReadBytes(8);
- stream.Seek(0, SeekOrigin.Begin);
-
- // Get the file type
- SupportedFileType ft = BurnOutSharp.Tools.Utilities.GetFileType(magic);
-
- // MS-DOS executable and decendents
- if (ft == SupportedFileType.Executable)
- {
- // Build the executable information
- Console.WriteLine("Creating MS-DOS executable builder");
- Console.WriteLine();
-
- var msdos = MSDOS.Create(stream);
- if (msdos == null)
- {
- Console.WriteLine("Something went wrong parsing MS-DOS executable");
- Console.WriteLine();
- return;
- }
-
- // Print the executable info to screen
- msdos.Print();
-
- // Check for a valid new executable address
- if (msdos.NewExeHeaderAddr >= stream.Length)
- {
- Console.WriteLine("New EXE header address invalid, skipping additional reading...");
- Console.WriteLine();
- return;
- }
-
- // Try to read the executable info
- stream.Seek(msdos.NewExeHeaderAddr, SeekOrigin.Begin);
- magic = stream.ReadBytes(4);
-
- // New Executable
- if (magic.StartsWith(BurnOutSharp.Models.NewExecutable.Constants.SignatureBytes))
- {
- stream.Seek(0, SeekOrigin.Begin);
- var newExecutable = NewExecutable.Create(stream);
- if (newExecutable == null)
- {
- Console.WriteLine("Something went wrong parsing New Executable");
- Console.WriteLine();
- return;
- }
-
- // Print the executable info to screen
- newExecutable.Print();
- }
-
- // Linear Executable
- if (magic.StartsWith(BurnOutSharp.Models.LinearExecutable.Constants.LESignatureBytes)
- || magic.StartsWith(BurnOutSharp.Models.LinearExecutable.Constants.LXSignatureBytes))
- {
- Console.WriteLine($"Linear executable found. No parsing currently available.");
- Console.WriteLine();
- return;
- }
-
- // Portable Executable
- if (magic.StartsWith(BurnOutSharp.Models.PortableExecutable.Constants.SignatureBytes))
- {
- stream.Seek(0, SeekOrigin.Begin);
- var portableExecutable = PortableExecutable.Create(stream);
- if (portableExecutable == null)
- {
- Console.WriteLine("Something went wrong parsing Portable Executable");
- Console.WriteLine();
- return;
- }
-
- // Print the executable info to screen
- portableExecutable.Print();
- }
-
- // Unknown
- else
- {
- Console.WriteLine($"Unrecognized header signature: {BitConverter.ToString(magic).Replace("-", string.Empty)}");
- Console.WriteLine();
- return;
- }
- }
-
- // BFPK archive
- else if (ft == SupportedFileType.BFPK)
- {
- // Build the BFPK information
- Console.WriteLine("Creating BFPK deserializer");
- Console.WriteLine();
-
- var bfpk = BFPK.Create(stream);
- if (bfpk == null)
- {
- Console.WriteLine("Something went wrong parsing BFPK archive");
- Console.WriteLine();
- return;
- }
-
- // Print the BFPK info to screen
- bfpk.Print();
- }
-
- // BSP
- else if (ft == SupportedFileType.BSP)
- {
- // Build the BSP information
- Console.WriteLine("Creating BSP deserializer");
- Console.WriteLine();
-
- var bsp = BSP.Create(stream);
- if (bsp == null)
- {
- Console.WriteLine("Something went wrong parsing BSP");
- Console.WriteLine();
- return;
- }
-
- // Print the BSP info to screen
- bsp.Print();
- }
-
- // GCF
- else if (ft == SupportedFileType.GCF)
- {
- // Build the GCF information
- Console.WriteLine("Creating GCF deserializer");
- Console.WriteLine();
-
- var gcf = GCF.Create(stream);
- if (gcf == null)
- {
- Console.WriteLine("Something went wrong parsing GCF");
- Console.WriteLine();
- return;
- }
-
- // Print the GCF info to screen
- gcf.Print();
- }
-
- // IS-CAB archive
- else if (ft == SupportedFileType.InstallShieldCAB)
- {
- // Build the archive information
- Console.WriteLine("Creating IS-CAB deserializer");
- Console.WriteLine();
-
- // TODO: Write and use printing methods
- Console.WriteLine("IS-CAB archive printing not currently enabled");
- Console.WriteLine();
- return;
- }
-
- // MoPaQ (MPQ) archive
- else if (ft == SupportedFileType.MPQ)
- {
- // Build the archive information
- Console.WriteLine("Creating MoPaQ deserializer");
- Console.WriteLine();
-
- // TODO: Write and use printing methods
- Console.WriteLine("MoPaQ archive printing not currently enabled");
- Console.WriteLine();
- return;
- }
-
- // MS-CAB archive
- else if (ft == SupportedFileType.MicrosoftCAB)
- {
- // Build the cabinet information
- Console.WriteLine("Creating MS-CAB deserializer");
- Console.WriteLine();
-
- var cabinet = MicrosoftCabinet.Create(stream);
- if (cabinet == null)
- {
- Console.WriteLine("Something went wrong parsing MS-CAB archive");
- Console.WriteLine();
- return;
- }
-
- // Print the cabinet info to screen
- cabinet.Print();
- }
-
- // NCF
- else if (ft == SupportedFileType.NCF)
- {
- // Build the NCF information
- Console.WriteLine("Creating NCF deserializer");
- Console.WriteLine();
-
- var ncf = NCF.Create(stream);
- if (ncf == null)
- {
- Console.WriteLine("Something went wrong parsing NCF");
- Console.WriteLine();
- return;
- }
-
- // Print the NCF info to screen
- ncf.Print();
- }
-
- // PAK
- else if (ft == SupportedFileType.PAK)
- {
- // Build the archive information
- Console.WriteLine("Creating PAK deserializer");
- Console.WriteLine();
-
- var pak = PAK.Create(stream);
- if (pak == null)
- {
- Console.WriteLine("Something went wrong parsing PAK");
- Console.WriteLine();
- return;
- }
-
- // Print the PAK info to screen
- pak.Print();
- }
-
- // Quantum
- else if (ft == SupportedFileType.Quantum)
- {
- // Build the archive information
- Console.WriteLine("Creating Quantum deserializer");
- Console.WriteLine();
-
- var quantum = Quantum.Create(stream);
- if (quantum == null)
- {
- Console.WriteLine("Something went wrong parsing Quantum");
- Console.WriteLine();
- return;
- }
-
- // Print the Quantum info to screen
- quantum.Print();
- }
-
- // SGA
- else if (ft == SupportedFileType.SGA)
- {
- // Build the archive information
- Console.WriteLine("Creating SGA deserializer");
- Console.WriteLine();
-
- var sga = SGA.Create(stream);
- if (sga == null)
- {
- Console.WriteLine("Something went wrong parsing SGA");
- Console.WriteLine();
- return;
- }
-
- // Print the SGA info to screen
- sga.Print();
- }
-
- // VBSP
- else if (ft == SupportedFileType.VBSP)
- {
- // Build the archive information
- Console.WriteLine("Creating VBSP deserializer");
- Console.WriteLine();
-
- var vbsp = VBSP.Create(stream);
- if (vbsp == null)
- {
- Console.WriteLine("Something went wrong parsing VBSP");
- Console.WriteLine();
- return;
- }
-
- // Print the VBSP info to screen
- vbsp.Print();
- }
-
- // VPK
- else if (ft == SupportedFileType.VPK)
- {
- // Build the archive information
- Console.WriteLine("Creating VPK deserializer");
- Console.WriteLine();
-
- var vpk = VPK.Create(stream);
- if (vpk == null)
- {
- Console.WriteLine("Something went wrong parsing VPK");
- Console.WriteLine();
- return;
- }
-
- // Print the VPK info to screen
- vpk.Print();
- }
-
- // WAD
- else if (ft == SupportedFileType.WAD)
- {
- // Build the archive information
- Console.WriteLine("Creating WAD deserializer");
- Console.WriteLine();
-
- var wad = WAD.Create(stream);
- if (wad == null)
- {
- Console.WriteLine("Something went wrong parsing WAD");
- Console.WriteLine();
- return;
- }
-
- // Print the WAD info to screen
- wad.Print();
- }
-
- // XZP
- else if (ft == SupportedFileType.XZP)
- {
- // Build the archive information
- Console.WriteLine("Creating XZP deserializer");
- Console.WriteLine();
-
- var xzp = XZP.Create(stream);
- if (xzp == null)
- {
- Console.WriteLine("Something went wrong parsing XZP");
- Console.WriteLine();
- return;
- }
-
- // Print the XZP info to screen
- xzp.Print();
- }
-
- // Everything else
- else
- {
- Console.WriteLine("Not a recognized file format, skipping...");
- Console.WriteLine();
- return;
- }
- }
- }
-
- #endregion
-
- #region Extraction
-
- ///
- /// Wrapper to extract data for a single path
- ///
- /// File or directory path
- /// Output directory path
- private static void ExtractPath(string path, string outputDirectory)
- {
- Console.WriteLine($"Checking possible path: {path}");
-
- // Check if the file or directory exists
- if (File.Exists(path))
- {
- ExtractFile(path, outputDirectory);
- }
- else if (Directory.Exists(path))
- {
- foreach (string file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories))
- {
- ExtractFile(file, outputDirectory);
- }
- }
- else
- {
- Console.WriteLine($"{path} does not exist, skipping...");
- }
- }
-
- ///
- /// Print information for a single file, if possible
- ///
- private static void ExtractFile(string file, string outputDirectory)
- {
- Console.WriteLine($"Attempting to extract all files from {file}");
-
- using (Stream stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
- {
- // Read the first 8 bytes
- byte[] magic = stream.ReadBytes(8);
- stream.Seek(0, SeekOrigin.Begin);
-
- // Get the file type
- SupportedFileType ft = BurnOutSharp.Tools.Utilities.GetFileType(magic);
-
- // Executables technically can be "extracted", but let's ignore that
- // TODO: Support executables that include other stuff
-
- // 7-zip
- if (ft == SupportedFileType.SevenZip)
- {
- // Build the archive information
- Console.WriteLine("Extracting 7-zip contents");
- Console.WriteLine();
-
- // If the 7-zip file itself fails
- try
- {
- using (SevenZipArchive sevenZipFile = SevenZipArchive.Open(stream))
- {
- foreach (var entry in sevenZipFile.Entries)
- {
- // If an individual entry fails
- try
- {
- // If we have a directory, skip it
- if (entry.IsDirectory)
- continue;
-
- string tempFile = Path.Combine(outputDirectory, entry.Key);
- entry.WriteToFile(tempFile);
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting 7-zip entry {entry.Key}: {ex}");
- Console.WriteLine();
- }
- }
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting 7-zip: {ex}");
- Console.WriteLine();
- }
- }
-
- // BFPK archive
- else if (ft == SupportedFileType.BFPK)
- {
- // Build the BFPK information
- Console.WriteLine("Extracting BFPK contents");
- Console.WriteLine();
-
- var bfpk = BFPK.Create(stream);
- if (bfpk == null)
- {
- Console.WriteLine("Something went wrong parsing BFPK archive");
- Console.WriteLine();
- return;
- }
-
- try
- {
- // Extract the BFPK contents to the directory
- bfpk.ExtractAll(outputDirectory);
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting BFPK archive: {ex}");
- Console.WriteLine();
- }
- }
-
- // BSP
- else if (ft == SupportedFileType.BSP)
- {
- // Build the BSP information
- Console.WriteLine("Extracting BSP contents");
- Console.WriteLine();
-
- var bsp = BSP.Create(stream);
- if (bsp == null)
- {
- Console.WriteLine("Something went wrong parsing BSP");
- Console.WriteLine();
- return;
- }
-
- try
- {
- // Extract the BSP contents to the directory
- bsp.ExtractAllLumps(outputDirectory);
- bsp.ExtractAllTextures(outputDirectory);
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting BSP: {ex}");
- Console.WriteLine();
- }
- }
-
- // bzip2
- else if (ft == SupportedFileType.BZip2)
- {
- // Build the bzip2 information
- Console.WriteLine("Extracting bzip2 contents");
- Console.WriteLine();
-
- using (var bz2File = new BZip2Stream(stream, CompressionMode.Decompress, true))
- {
- // If an individual entry fails
- try
- {
- string tempFile = Path.Combine(outputDirectory, Guid.NewGuid().ToString());
- using (FileStream fs = File.OpenWrite(tempFile))
- {
- bz2File.CopyTo(fs);
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting bzip2: {ex}");
- Console.WriteLine();
- }
- }
- }
-
- // GCF
- else if (ft == SupportedFileType.GCF)
- {
- // Build the GCF information
- Console.WriteLine("Extracting GCF contents");
- Console.WriteLine();
-
- var gcf = GCF.Create(stream);
- if (gcf == null)
- {
- Console.WriteLine("Something went wrong parsing GCF");
- Console.WriteLine();
- return;
- }
-
- try
- {
- // Extract the GCF contents to the directory
- gcf.ExtractAll(outputDirectory);
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting GCF: {ex}");
- Console.WriteLine();
- }
- }
-
- // gzip
- else if (ft == SupportedFileType.GZIP)
- {
- // Build the gzip information
- Console.WriteLine("Extracting gzip contents");
- Console.WriteLine();
-
- using (var zipFile = GZipArchive.Open(stream))
- {
- foreach (var entry in zipFile.Entries)
- {
- // If an individual entry fails
- try
- {
- // If we have a directory, skip it
- if (entry.IsDirectory)
- continue;
-
- string tempFile = Path.Combine(outputDirectory, entry.Key);
- entry.WriteToFile(tempFile);
- }
-
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting gzip entry {entry.Key}: {ex}");
- Console.WriteLine();
- }
- }
- }
- }
-
- // InstallShield Archive V3 (Z)
- else if (ft == SupportedFileType.InstallShieldArchiveV3)
- {
- // Build the InstallShield Archive V3 information
- Console.WriteLine("Extracting InstallShield Archive V3 contents");
- Console.WriteLine();
-
- // If the cab file itself fails
- try
- {
- var archive = new InstallShieldArchiveV3(file);
- foreach (var cfile in archive.Files.Select(kvp => kvp.Value))
- {
- // If an individual entry fails
- try
- {
- string tempFile = Path.Combine(outputDirectory, cfile.FullPath);
- if (!Directory.Exists(Path.GetDirectoryName(tempFile)))
- Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
-
- (byte[] fileContents, string error) = archive.Extract(cfile.FullPath);
- if (!string.IsNullOrWhiteSpace(error))
- continue;
-
- using (FileStream fs = File.OpenWrite(tempFile))
- {
- fs.Write(fileContents, 0, fileContents.Length);
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting InstallShield Archive V3 entry {cfile.Name}: {ex}");
- Console.WriteLine();
- }
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting InstallShield Archive V3: {ex}");
- Console.WriteLine();
- }
- }
-
- // IS-CAB archive
- else if (ft == SupportedFileType.InstallShieldCAB)
- {
- // Build the archive information
- Console.WriteLine("Extracting IS-CAB contents");
- Console.WriteLine();
-
- // If the cab file itself fails
- try
- {
- InstallShieldCabinet cabfile = InstallShieldCabinet.Open(file);
- for (int i = 0; i < cabfile.FileCount; i++)
- {
- // If an individual entry fails
- try
- {
- string filename = cabfile.FileName(i);
- string tempFile;
- try
- {
- tempFile = Path.Combine(outputDirectory, filename);
- }
- catch
- {
- tempFile = Path.Combine(outputDirectory, $"BAD_FILENAME{i}");
- }
-
- cabfile.FileSave(i, tempFile);
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting IS-CAB entry {i}: {ex}");
- Console.WriteLine();
- }
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting IS-CAB: {ex}");
- Console.WriteLine();
- }
- }
-
- // Microsoft Cabinet archive
- else if (ft == SupportedFileType.MicrosoftCAB)
- {
- // Build the cabinet information
- Console.WriteLine("Extracting MS-CAB contents");
- Console.WriteLine();
-
- var cabinet = MicrosoftCabinet.Create(stream);
- if (cabinet == null)
- {
- Console.WriteLine("Something went wrong parsing MS-CAB archive");
- Console.WriteLine();
- return;
- }
-
- try
- {
- // Extract the MS-CAB contents to the directory
- cabinet.ExtractAll(outputDirectory);
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting MS-CAB: {ex}");
- Console.WriteLine();
- }
- }
-
- // Microsoft LZ / LZ32
- else if (ft == SupportedFileType.MicrosoftLZ)
- {
- // Build the Microsoft LZ / LZ32 information
- Console.WriteLine("Extracting Microsoft LZ / LZ32 contents");
- Console.WriteLine();
-
- // If the LZ file itself fails
- try
- {
- byte[] data = LZ.Decompress(stream);
-
- // Create the temp filename
- string tempFile = "temp.bin";
- if (!string.IsNullOrEmpty(file))
- {
- string expandedFilePath = LZ.GetExpandedName(file, out _);
- tempFile = Path.GetFileName(expandedFilePath).TrimEnd('\0');
- if (tempFile.EndsWith(".ex"))
- tempFile += "e";
- else if (tempFile.EndsWith(".dl"))
- tempFile += "l";
- }
-
- tempFile = Path.Combine(outputDirectory, tempFile);
-
- // Write the file data to a temp file
- using (Stream tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
- {
- tempStream.Write(data, 0, data.Length);
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting Microsoft LZ / LZ32: {ex}");
- Console.WriteLine();
- }
- }
-
-#if NET48
- // MoPaQ (MPQ) archive
- else if (ft == SupportedFileType.MPQ)
- {
- // Build the archive information
- Console.WriteLine("Extracting MoPaQ contents");
- Console.WriteLine();
-
- // If the MPQ file itself fails
- try
- {
- using (var mpqArchive = new StormLibSharp.MpqArchive(file, FileAccess.Read))
- {
- // Try to open the listfile
- string listfile = null;
- StormLibSharp.MpqFileStream listStream = mpqArchive.OpenFile("(listfile)");
-
- // If we can't read the listfile, we just return
- if (!listStream.CanRead)
- {
- Console.WriteLine("Could not read the listfile, extraction halted!");
- Console.WriteLine();
- }
-
- // Read the listfile in for processing
- using (StreamReader sr = new StreamReader(listStream))
- {
- listfile = sr.ReadToEnd();
- }
-
- // Split the listfile by newlines
- string[] listfileLines = listfile.Replace("\r\n", "\n").Split('\n');
-
- // Loop over each entry
- foreach (string sub in listfileLines)
- {
- // If an individual entry fails
- try
- {
- string tempFile = Path.Combine(outputDirectory, sub);
- Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
- mpqArchive.ExtractFile(sub, tempFile);
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting MoPaQ entry {sub}: {ex}");
- Console.WriteLine();
- }
- }
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting MoPaQ: {ex}");
- Console.WriteLine();
- }
- }
-#endif
-
- // MSI
- else if (ft == SupportedFileType.MSI)
- {
- // Build the installer information
- Console.WriteLine("Extracting MSI contents");
- Console.WriteLine();
-
- // If the MSI file itself fails
- try
- {
- using (CompoundFile msi = new CompoundFile(stream, CFSUpdateMode.ReadOnly, CFSConfiguration.Default))
- {
- msi.RootStorage.VisitEntries((e) =>
- {
- if (!e.IsStream)
- return;
-
- var str = msi.RootStorage.GetStream(e.Name);
- if (str == null)
- return;
-
- byte[] strData = str.GetData();
- if (strData == null)
- return;
-
- string decoded = BurnOutSharp.FileType.MSI.DecodeStreamName(e.Name).TrimEnd('\0');
- byte[] nameBytes = Encoding.UTF8.GetBytes(e.Name);
-
- // UTF-8 encoding of 0x4840.
- if (nameBytes[0] == 0xe4 && nameBytes[1] == 0xa1 && nameBytes[2] == 0x80)
- decoded = decoded.Substring(3);
-
- foreach (char c in Path.GetInvalidFileNameChars())
- {
- decoded = decoded.Replace(c, '_');
- }
-
- string filename = Path.Combine(outputDirectory, decoded);
- using (Stream fs = File.OpenWrite(filename))
- {
- fs.Write(strData, 0, strData.Length);
- }
- }, recursive: true);
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting MSI: {ex}");
- Console.WriteLine();
- }
- }
-
- // PAK
- else if (ft == SupportedFileType.PAK)
- {
- // Build the archive information
- Console.WriteLine("Extracting PAK contents");
- Console.WriteLine();
-
- var pak = PAK.Create(stream);
- if (pak == null)
- {
- Console.WriteLine("Something went wrong parsing PAK");
- Console.WriteLine();
- return;
- }
-
- try
- {
- // Extract the PAK contents to the directory
- pak.ExtractAll(outputDirectory);
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting MS-CAB: {ex}");
- Console.WriteLine();
- }
- }
-
- // PKZIP
- else if (ft == SupportedFileType.PKZIP)
- {
- // Build the archive information
- Console.WriteLine("Extracting PKZIP contents");
- Console.WriteLine();
-
- // If the zip file itself fails
- try
- {
- using (ZipArchive zipFile = ZipArchive.Open(stream))
- {
- foreach (var entry in zipFile.Entries)
- {
- // If an individual entry fails
- try
- {
- // If we have a directory, skip it
- if (entry.IsDirectory)
- continue;
-
- string tempFile = Path.Combine(outputDirectory, entry.Key);
- Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
- entry.WriteToFile(tempFile);
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting PKZIP entry {entry.Key}: {ex}");
- Console.WriteLine();
- }
- }
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting PKZIP: {ex}");
- Console.WriteLine();
- }
- }
-
- // RAR
- else if (ft == SupportedFileType.RAR)
- {
- // Build the archive information
- Console.WriteLine("Extracting RAR contents");
- Console.WriteLine();
-
- // If the rar file itself fails
- try
- {
- using (RarArchive rarFile = RarArchive.Open(stream))
- {
- foreach (var entry in rarFile.Entries)
- {
- // If an individual entry fails
- try
- {
- // If we have a directory, skip it
- if (entry.IsDirectory)
- continue;
-
- string tempFile = Path.Combine(outputDirectory, entry.Key);
- entry.WriteToFile(tempFile);
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting RAR entry {entry.Key}: {ex}");
- Console.WriteLine();
- }
- }
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting RAR: {ex}");
- Console.WriteLine();
- }
- }
-
- // SGA
- else if (ft == SupportedFileType.SGA)
- {
- // Build the archive information
- Console.WriteLine("Extracting SGA contents");
- Console.WriteLine();
-
- var sga = SGA.Create(stream);
- if (sga == null)
- {
- Console.WriteLine("Something went wrong parsing SGA");
- Console.WriteLine();
- return;
- }
-
- try
- {
- // Extract the SGA contents to the directory
- sga.ExtractAll(outputDirectory);
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting MS-CAB: {ex}");
- Console.WriteLine();
- }
- }
-
- // Tape Archive
- else if (ft == SupportedFileType.RAR)
- {
- // Build the archive information
- Console.WriteLine("Extracting Tape Archive contents");
- Console.WriteLine();
-
- // If the rar file itself fails
- try
- {
- using (TarArchive tarFile = TarArchive.Open(stream))
- {
- foreach (var entry in tarFile.Entries)
- {
- // If an individual entry fails
- try
- {
- // If we have a directory, skip it
- if (entry.IsDirectory)
- continue;
-
- string tempFile = Path.Combine(outputDirectory, entry.Key);
- entry.WriteToFile(tempFile);
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting Tape Archive entry {entry.Key}: {ex}");
- Console.WriteLine();
- }
- }
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting Tape Archive: {ex}");
- Console.WriteLine();
- }
- }
-
- // VBSP
- else if (ft == SupportedFileType.VBSP)
- {
- // Build the archive information
- Console.WriteLine("Extracting VBSP contents");
- Console.WriteLine();
-
- var vbsp = VBSP.Create(stream);
- if (vbsp == null)
- {
- Console.WriteLine("Something went wrong parsing VBSP");
- Console.WriteLine();
- return;
- }
-
- try
- {
- // Extract the VBSP contents to the directory
- vbsp.ExtractAllLumps(outputDirectory);
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting MS-CAB: {ex}");
- Console.WriteLine();
- }
- }
-
- // VPK
- else if (ft == SupportedFileType.VPK)
- {
- // Build the archive information
- Console.WriteLine("Extracting VPK contents");
- Console.WriteLine();
-
- var vpk = VPK.Create(stream);
- if (vpk == null)
- {
- Console.WriteLine("Something went wrong parsing VPK");
- Console.WriteLine();
- return;
- }
-
- try
- {
- // Extract the VPK contents to the directory
- vpk.ExtractAll(outputDirectory);
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting MS-CAB: {ex}");
- Console.WriteLine();
- }
- }
-
- // WAD
- else if (ft == SupportedFileType.WAD)
- {
- // Build the archive information
- Console.WriteLine("Extracting WAD contents");
- Console.WriteLine();
-
- var wad = WAD.Create(stream);
- if (wad == null)
- {
- Console.WriteLine("Something went wrong parsing WAD");
- Console.WriteLine();
- return;
- }
-
- try
- {
- // Extract the WAD contents to the directory
- wad.ExtractAllLumps(outputDirectory);
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting MS-CAB: {ex}");
- Console.WriteLine();
- }
- }
-
- // xz
- else if (ft == SupportedFileType.RAR)
- {
- // Build the xz information
- Console.WriteLine("Extracting xz contents");
- Console.WriteLine();
-
- using (var xzFile = new XZStream(stream))
- {
- // If an individual entry fails
- try
- {
- string tempFile = Path.Combine(outputDirectory, Guid.NewGuid().ToString());
- using (FileStream fs = File.OpenWrite(tempFile))
- {
- xzFile.CopyTo(fs);
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting xz: {ex}");
- Console.WriteLine();
- }
- }
- }
-
- // XZP
- else if (ft == SupportedFileType.XZP)
- {
- // Build the archive information
- Console.WriteLine("Extracting XZP contents");
- Console.WriteLine();
-
- var xzp = XZP.Create(stream);
- if (xzp == null)
- {
- Console.WriteLine("Something went wrong parsing XZP");
- Console.WriteLine();
- return;
- }
-
- try
- {
- // Extract the XZP contents to the directory
- xzp.ExtractAll(outputDirectory);
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Something went wrong extracting MS-CAB: {ex}");
- Console.WriteLine();
- }
- }
-
- // Everything else
- else
- {
- Console.WriteLine("Not a supported extractable file format, skipping...");
- Console.WriteLine();
- return;
- }
- }
- }
-
- #endregion
}
}
diff --git a/Test/Protector.cs b/Test/Protector.cs
new file mode 100644
index 00000000..18573840
--- /dev/null
+++ b/Test/Protector.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Concurrent;
+using System.IO;
+using System.Linq;
+using BurnOutSharp;
+
+namespace Test
+{
+ internal static class Protector
+ {
+ ///
+ /// Wrapper to get and log protections for a single path
+ ///
+ /// Scanner object to use
+ /// File or directory path
+ public static void GetAndWriteProtections(Scanner scanner, string path)
+ {
+ // An invalid path can't be scanned
+ if (!Directory.Exists(path) && !File.Exists(path))
+ {
+ Console.WriteLine($"{path} does not exist, skipping...");
+ return;
+ }
+
+ try
+ {
+ var protections = scanner.GetProtections(path);
+ WriteProtectionResultFile(path, protections);
+ }
+ catch (Exception ex)
+ {
+ using (StreamWriter sw = new StreamWriter(File.OpenWrite($"{DateTime.Now:yyyy-MM-dd_HHmmss}-exception.txt")))
+ {
+ sw.WriteLine(ex);
+ }
+ }
+ }
+
+ ///
+ /// Write the protection results from a single path to file, if possible
+ ///
+ /// File or directory path
+ /// Dictionary of protections found, if any
+ private static void WriteProtectionResultFile(string path, ConcurrentDictionary> protections)
+ {
+ if (protections == null)
+ {
+ Console.WriteLine($"No protections found for {path}");
+ return;
+ }
+
+ using (var sw = new StreamWriter(File.OpenWrite($"{DateTime.Now:yyyy-MM-dd_HHmmss}.txt")))
+ {
+ foreach (string key in protections.Keys.OrderBy(k => k))
+ {
+ // Skip over files with no protection
+ if (protections[key] == null || !protections[key].Any())
+ continue;
+
+ string line = $"{key}: {string.Join(", ", protections[key].OrderBy(p => p))}";
+ Console.WriteLine(line);
+ sw.WriteLine(line);
+ }
+ }
+ }
+
+ ///
+ /// Protection progress changed handler
+ ///
+ public static void Changed(object source, ProtectionProgress value)
+ {
+ Console.WriteLine($"{value.Percentage * 100:N2}%: {value.Filename} - {value.Protection}");
+ }
+ }
+}
\ No newline at end of file