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
}
}