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