diff --git a/BurnOutSharp/FileType/InstallShieldArchiveV3.cs b/BurnOutSharp/FileType/InstallShieldArchiveV3.cs index 06ee9b10..ade79359 100644 --- a/BurnOutSharp/FileType/InstallShieldArchiveV3.cs +++ b/BurnOutSharp/FileType/InstallShieldArchiveV3.cs @@ -30,73 +30,58 @@ namespace BurnOutSharp.FileType /// public ConcurrentDictionary> Scan(Scanner scanner, Stream stream, string file) { - // Get the name of the first cabinet file or header - string directory = Path.GetDirectoryName(file); - string noExtension = Path.GetFileNameWithoutExtension(file); - string filenamePattern = Path.Combine(directory, noExtension); - filenamePattern = new Regex(@"\d+$").Replace(filenamePattern, string.Empty); - - bool cabinetHeaderExists = File.Exists(Path.Combine(directory, filenamePattern + "1.hdr")); - bool shouldScanCabinet = cabinetHeaderExists - ? file.Equals(Path.Combine(directory, filenamePattern + "1.hdr"), StringComparison.OrdinalIgnoreCase) - : file.Equals(Path.Combine(directory, filenamePattern + "1.cab"), StringComparison.OrdinalIgnoreCase); - - // If we have the first file - if (shouldScanCabinet) + // If the archive itself fails + try { - // If the cab file itself fails - try + string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + Directory.CreateDirectory(tempPath); + + UnshieldSharp.Archive.InstallShieldArchiveV3 archive = new UnshieldSharp.Archive.InstallShieldArchiveV3(file); + foreach (CompressedFile cfile in archive.Files.Select(kvp => kvp.Value)) { - string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); - Directory.CreateDirectory(tempPath); - - UnshieldSharp.Archive.InstallShieldArchiveV3 archive = new UnshieldSharp.Archive.InstallShieldArchiveV3(file); - foreach (CompressedFile cfile in archive.Files.Select(kvp => kvp.Value)) - { - // If an individual entry fails - try - { - string tempFile = Path.Combine(tempPath, 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) - { - if (scanner.IncludeDebug) Console.WriteLine(ex); - } - } - - // Collect and format all found protections - var protections = scanner.GetProtections(tempPath); - - // If temp directory cleanup fails + // If an individual entry fails try { - Directory.Delete(tempPath, true); + string tempFile = Path.Combine(tempPath, 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) { if (scanner.IncludeDebug) Console.WriteLine(ex); } + } - // Remove temporary path references - StripFromKeys(protections, tempPath); + // Collect and format all found protections + var protections = scanner.GetProtections(tempPath); - return protections; + // If temp directory cleanup fails + try + { + Directory.Delete(tempPath, true); } catch (Exception ex) { if (scanner.IncludeDebug) Console.WriteLine(ex); } + + // Remove temporary path references + StripFromKeys(protections, tempPath); + + return protections; + } + catch (Exception ex) + { + if (scanner.IncludeDebug) Console.WriteLine(ex); } return null; diff --git a/BurnOutSharp/FileType/MSI.cs b/BurnOutSharp/FileType/MSI.cs index 8ce81520..b448c1be 100644 --- a/BurnOutSharp/FileType/MSI.cs +++ b/BurnOutSharp/FileType/MSI.cs @@ -97,7 +97,7 @@ namespace BurnOutSharp.FileType } /// Adapted from LibMSI - private static string DecodeStreamName(string input) + public static string DecodeStreamName(string input) { if (input == null) return null; diff --git a/BurnOutSharp/FileType/RAR.cs b/BurnOutSharp/FileType/RAR.cs index bb0f2c33..e6e60fec 100644 --- a/BurnOutSharp/FileType/RAR.cs +++ b/BurnOutSharp/FileType/RAR.cs @@ -34,9 +34,9 @@ namespace BurnOutSharp.FileType string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); Directory.CreateDirectory(tempPath); - using (RarArchive zipFile = RarArchive.Open(stream)) + using (RarArchive rarFile = RarArchive.Open(stream)) { - foreach (var entry in zipFile.Entries) + foreach (var entry in rarFile.Entries) { // If an individual entry fails try diff --git a/Test/Program.cs b/Test/Program.cs index 47e3edc8..078c8d41 100644 --- a/Test/Program.cs +++ b/Test/Program.cs @@ -5,9 +5,22 @@ 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 { @@ -23,12 +36,15 @@ namespace Test p.ProgressChanged += Changed; // Set initial values for scanner flags - bool debug = false, archives = true, packers = true, info = false; + bool debug = false, archives = true, packers = true, info = false, extract = false; + string outputPath = string.Empty; var inputPaths = new List(); // Loop through the arguments to get the flags - foreach (string arg in args) + for (int i = 0; i < args.Length; i++) { + string arg = args[i]; + switch (arg) { case "-?": @@ -59,6 +75,16 @@ namespace Test info = true; break; + // case "-e": + // case "--extract": + // extract = true; + // break; + + // case "-o": + // case "--outdir": + // outputPath = i + 1 < args.Length ? args[++i] : null; + // break; + default: inputPaths.Add(arg); break; @@ -77,11 +103,44 @@ namespace Test // Create scanner for all paths var scanner = new Scanner(archives, packers, debug, p); + // If we have extraction, check the output path exists and is valid + if (extract) + { + // Null or empty output path + if (string.IsNullOrWhiteSpace(outputPath)) + { + Console.WriteLine("Output directory required for extraction!"); + Console.WriteLine(); + DisplayHelp(); + Console.WriteLine("Press enter to close the program..."); + Console.ReadLine(); + return; + } + + // Malformed output path or invalid location + try + { + outputPath = Path.GetFullPath(outputPath); + Directory.CreateDirectory(outputPath); + } + catch + { + Console.WriteLine("Output directory could not be created!"); + Console.WriteLine(); + DisplayHelp(); + Console.WriteLine("Press enter to close the program..."); + Console.ReadLine(); + return; + } + } + // Loop through the input paths foreach (string inputPath in inputPaths) { if (info) PrintPathInfo(inputPath); + else if (extract) + ExtractPath(inputPath, outputPath); else GetAndWriteProtections(scanner, inputPath); } @@ -105,6 +164,8 @@ namespace Test Console.WriteLine("-na, --no-archives Disable scanning archives"); Console.WriteLine("-np, --no-packers Disable scanning for packers"); Console.WriteLine("-i, --info Print executable info"); + // Console.WriteLine("-e, --extract Extract archive formats"); + // Console.WriteLine("-o, --outdir [PATH] Set output path for extraction"); } #region Protection @@ -564,5 +625,812 @@ namespace Test } #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 } }