Files
BinaryObjectScanner/Test/Extractor.cs

993 lines
36 KiB
C#
Raw Normal View History

2023-01-04 10:23:03 -08:00
using System;
using System.IO;
2024-04-24 11:03:09 -04:00
#if NET452_OR_GREATER || NETCOREAPP
2023-01-04 10:23:03 -08:00
using System.Text;
2024-04-24 11:03:09 -04:00
#endif
2023-11-22 12:22:01 -05:00
#if NET40_OR_GREATER || NETCOREAPP
2023-01-04 10:23:03 -08:00
using OpenMcdf;
2023-11-22 12:22:01 -05:00
#endif
2024-04-17 12:12:01 -04:00
using SabreTools.IO.Extensions;
2023-09-16 02:04:47 -04:00
using SabreTools.Serialization.Wrappers;
2023-11-22 12:22:01 -05:00
#if NET462_OR_GREATER || NETCOREAPP
2023-01-04 10:23:03 -08:00
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;
2023-11-14 16:10:10 -05:00
#endif
2023-01-04 10:23:03 -08:00
using UnshieldSharp.Archive;
namespace Test
{
2024-05-15 12:24:40 -04:00
internal class Extractor
2023-01-04 10:23:03 -08:00
{
2024-05-15 12:24:40 -04:00
#region Options
/// <inheritdoc cref="BinaryObjectScanner.Options.IncludeDebug"/>
public bool IncludeDebug => _options?.IncludeDebug ?? false;
/// <summary>
/// Options object for configuration
/// </summary>
private readonly BinaryObjectScanner.Options _options;
#endregion
/// <summary>
/// Constructor
/// </summary>
/// <param name="includeDebug">Enable including debug information</param>
public Extractor(bool includeDebug)
{
2024-10-03 13:02:23 -04:00
_options = new BinaryObjectScanner.Options
2024-05-15 12:24:40 -04:00
{
IncludeDebug = includeDebug,
};
#if NET462_OR_GREATER || NETCOREAPP
// Register the codepages
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
#endif
}
2023-01-04 10:23:03 -08:00
/// <summary>
/// Wrapper to extract data for a single path
/// </summary>
/// <param name="path">File or directory path</param>
/// <param name="outputDirectory">Output directory path</param>
2024-05-15 12:24:40 -04:00
public void ExtractPath(string path, string outputDirectory)
2023-01-04 10:23:03 -08:00
{
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))
{
2024-04-26 22:09:05 -04:00
foreach (string file in IOExtensions.SafeEnumerateFiles(path, "*", SearchOption.AllDirectories))
2023-01-04 10:23:03 -08:00
{
ExtractFile(file, outputDirectory);
}
}
else
{
Console.WriteLine($"{path} does not exist, skipping...");
}
}
/// <summary>
/// Print information for a single file, if possible
/// </summary>
2024-05-15 12:24:40 -04:00
private void ExtractFile(string file, string outputDirectory)
2023-01-04 10:23:03 -08:00
{
Console.WriteLine($"Attempting to extract all files from {file}");
2023-12-13 15:52:03 -05:00
using Stream stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
2023-01-04 10:23:03 -08:00
2024-05-15 12:24:40 -04:00
// Get the extension for certain checks
string extension = Path.GetExtension(file).ToLower().TrimStart('.');
// Get the first 16 bytes for matching
byte[] magic = new byte[16];
try
{
stream.Read(magic, 0, 16);
stream.Seek(0, SeekOrigin.Begin);
}
catch (Exception ex)
{
if (IncludeDebug) Console.WriteLine(ex);
return;
}
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
// Get the file type
2024-05-15 12:24:40 -04:00
WrapperType ft = WrapperFactory.GetFileType(magic, extension);
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
// Executables technically can be "extracted", but let's ignore that
// TODO: Support executables that include other stuff
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
// 7-zip
2024-04-26 22:09:05 -04:00
if (ft == WrapperType.SevenZip)
2023-11-21 10:17:25 -05:00
{
// Build the archive information
Console.WriteLine("Extracting 7-zip contents");
Console.WriteLine();
2023-01-04 10:23:03 -08:00
2023-11-22 12:22:01 -05:00
#if NET20 || NET35 || NET40 || NET452
Console.WriteLine("Extraction is not supported for this framework!");
Console.WriteLine();
#else
2023-11-21 10:17:25 -05:00
// If the 7-zip file itself fails
2023-11-22 12:22:01 -05:00
try
{
2023-11-22 13:28:13 -05:00
using SevenZipArchive sevenZipFile = SevenZipArchive.Open(stream);
foreach (var entry in sevenZipFile.Entries)
2023-01-04 10:23:03 -08:00
{
2023-11-22 13:28:13 -05:00
// If an individual entry fails
try
2023-01-04 10:23:03 -08:00
{
2024-04-24 11:01:10 -04:00
// If the entry is a directory
2023-11-22 13:28:13 -05:00
if (entry.IsDirectory)
continue;
2023-11-22 12:22:01 -05:00
2024-04-24 11:01:10 -04:00
// If the entry has an invalid key
if (entry.Key == null)
continue;
2023-11-22 13:28:13 -05:00
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();
2023-01-04 10:23:03 -08:00
}
}
2023-11-22 12:22:01 -05:00
}
catch (Exception ex)
{
Console.WriteLine($"Something went wrong extracting 7-zip: {ex}");
Console.WriteLine();
}
2023-11-14 16:10:10 -05:00
#endif
2023-11-21 10:17:25 -05:00
}
// BFPK archive
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.BFPK)
2023-11-21 10:17:25 -05:00
{
// Build the BFPK information
Console.WriteLine("Extracting BFPK contents");
Console.WriteLine();
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
var bfpk = BFPK.Create(stream);
if (bfpk == null)
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
Console.WriteLine("Something went wrong parsing BFPK archive");
2023-01-04 10:23:03 -08:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
return;
2023-01-04 10:23:03 -08:00
}
2023-11-21 10:17:25 -05:00
try
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
// Extract the BFPK contents to the directory
BinaryObjectScanner.FileType.BFPK.ExtractAll(bfpk, outputDirectory);
}
catch (Exception ex)
{
Console.WriteLine($"Something went wrong extracting BFPK archive: {ex}");
2023-01-04 10:23:03 -08:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
}
}
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
// BSP
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.BSP)
2023-11-21 10:17:25 -05:00
{
// Build the BSP information
Console.WriteLine("Extracting BSP contents");
Console.WriteLine();
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
var bsp = BSP.Create(stream);
if (bsp == null)
{
Console.WriteLine("Something went wrong parsing BSP");
Console.WriteLine();
return;
2023-01-04 10:23:03 -08:00
}
2023-11-21 10:17:25 -05:00
try
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
// Extract the BSP contents to the directory
BinaryObjectScanner.FileType.BSP.ExtractAllLumps(bsp, outputDirectory);
BinaryObjectScanner.FileType.BSP.ExtractAllTextures(bsp, outputDirectory);
}
catch (Exception ex)
{
Console.WriteLine($"Something went wrong extracting BSP: {ex}");
2023-01-04 10:23:03 -08:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
}
}
// bzip2
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.BZip2)
2023-11-21 10:17:25 -05:00
{
// Build the bzip2 information
Console.WriteLine("Extracting bzip2 contents");
Console.WriteLine();
2023-01-04 10:23:03 -08:00
2023-11-22 12:22:01 -05:00
#if NET20 || NET35 || NET40 || NET452
Console.WriteLine("Extraction is not supported for this framework!");
Console.WriteLine();
#else
2023-11-22 13:28:13 -05:00
using var bz2File = new BZip2Stream(stream, CompressionMode.Decompress, true);
// If an individual entry fails
try
2023-11-22 12:22:01 -05:00
{
2023-11-22 13:28:13 -05:00
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();
2023-11-22 12:22:01 -05:00
}
2023-11-14 16:10:10 -05:00
#endif
2023-11-21 10:17:25 -05:00
}
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
// CFB
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.CFB)
2023-11-21 10:17:25 -05:00
{
// Build the installer information
Console.WriteLine("Extracting CFB contents");
Console.WriteLine();
2023-01-10 10:51:36 -08:00
2023-11-22 12:22:01 -05:00
#if NET45_OR_GREATER || NETCOREAPP
2023-11-21 10:17:25 -05:00
// If the CFB file itself fails
try
{
using var cf = new CompoundFile(stream, CFSUpdateMode.ReadOnly, CFSConfiguration.Default);
cf.RootStorage.VisitEntries((e) =>
2023-01-10 10:51:36 -08:00
{
2023-11-21 10:17:25 -05:00
if (!e.IsStream)
return;
2023-01-10 10:51:36 -08:00
2023-11-21 10:17:25 -05:00
var str = cf.RootStorage.GetStream(e.Name);
if (str == null)
return;
2023-01-10 10:51:36 -08:00
2023-11-21 10:17:25 -05:00
byte[] strData = str.GetData();
if (strData == null)
return;
2023-01-10 10:51:36 -08:00
2023-11-21 10:17:25 -05:00
string decoded = BinaryObjectScanner.FileType.CFB.DecodeStreamName(e.Name)?.TrimEnd('\0') ?? string.Empty;
byte[] nameBytes = Encoding.UTF8.GetBytes(e.Name);
2023-01-10 10:51:36 -08:00
2023-11-21 10:17:25 -05:00
// UTF-8 encoding of 0x4840.
if (nameBytes[0] == 0xe4 && nameBytes[1] == 0xa1 && nameBytes[2] == 0x80)
decoded = decoded.Substring(3);
2023-01-10 10:51:36 -08:00
2023-11-21 10:17:25 -05:00
foreach (char c in Path.GetInvalidFileNameChars())
{
decoded = decoded.Replace(c, '_');
2023-01-10 10:51:36 -08:00
}
2023-11-21 10:17:25 -05:00
string filename = Path.Combine(outputDirectory, decoded);
using Stream fs = File.OpenWrite(filename);
fs.Write(strData, 0, strData.Length);
}, recursive: true);
}
catch (Exception ex)
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
Console.WriteLine($"Something went wrong extracting CFB: {ex}");
2023-01-04 10:23:03 -08:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
}
2023-11-22 12:22:01 -05:00
#endif
2023-11-21 10:17:25 -05:00
}
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
// GCF
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.GCF)
2023-11-21 10:17:25 -05:00
{
// Build the GCF information
Console.WriteLine("Extracting GCF contents");
Console.WriteLine();
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
var gcf = GCF.Create(stream);
if (gcf == null)
{
Console.WriteLine("Something went wrong parsing GCF");
Console.WriteLine();
return;
2023-01-04 10:23:03 -08:00
}
2023-11-21 10:17:25 -05:00
try
{
// Extract the GCF contents to the directory
BinaryObjectScanner.FileType.GCF.ExtractAll(gcf, outputDirectory);
}
catch (Exception ex)
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
Console.WriteLine($"Something went wrong extracting GCF: {ex}");
2023-01-04 10:23:03 -08:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
}
}
// gzip
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.GZIP)
2023-11-21 10:17:25 -05:00
{
// Build the gzip information
Console.WriteLine("Extracting gzip contents");
Console.WriteLine();
2023-01-04 10:23:03 -08:00
2023-11-22 12:22:01 -05:00
#if NET20 || NET35 || NET40 || NET452
Console.WriteLine("Extraction is not supported for this framework!");
Console.WriteLine();
#else
2023-11-22 13:28:13 -05:00
using var zipFile = GZipArchive.Open(stream);
foreach (var entry in zipFile.Entries)
2023-11-22 12:22:01 -05:00
{
2023-11-22 13:28:13 -05:00
// If an individual entry fails
try
2023-01-04 10:23:03 -08:00
{
2024-04-24 11:01:10 -04:00
// If the entry is a directory
2023-11-22 13:28:13 -05:00
if (entry.IsDirectory)
continue;
2023-01-04 10:23:03 -08:00
2024-04-24 11:01:10 -04:00
// If the entry has an invalid key
if (entry.Key == null)
continue;
2023-11-22 13:28:13 -05:00
string tempFile = Path.Combine(outputDirectory, entry.Key);
entry.WriteToFile(tempFile);
}
2023-01-04 10:23:03 -08:00
2023-11-22 13:28:13 -05:00
catch (Exception ex)
{
Console.WriteLine($"Something went wrong extracting gzip entry {entry.Key}: {ex}");
Console.WriteLine();
2023-01-04 10:23:03 -08:00
}
2023-11-22 12:22:01 -05:00
}
2023-11-14 16:10:10 -05:00
#endif
2023-11-21 10:17:25 -05:00
}
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
// InstallShield Archive V3 (Z)
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.InstallShieldArchiveV3)
2023-11-21 10:17:25 -05:00
{
// Build the InstallShield Archive V3 information
Console.WriteLine("Extracting InstallShield Archive V3 contents");
Console.WriteLine();
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
// If the cab file itself fails
try
{
var archive = new InstallShieldArchiveV3(file);
2024-04-24 11:01:10 -04:00
foreach (var cfile in archive.Files)
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
// If an individual entry fails
try
2023-01-04 10:23:03 -08:00
{
2024-04-24 11:01:10 -04:00
string tempFile = Path.Combine(outputDirectory, cfile.Key);
2023-11-21 10:17:25 -05:00
string? directoryName = Path.GetDirectoryName(tempFile);
if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
2023-01-04 10:23:03 -08:00
2024-10-03 12:01:08 -04:00
byte[]? fileContents = archive.Extract(cfile.Key, out string? error);
2023-11-22 12:22:01 -05:00
if (!string.IsNullOrEmpty(error))
2023-11-21 10:17:25 -05:00
continue;
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
if (fileContents != null && fileContents.Length > 0)
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
using FileStream fs = File.OpenWrite(tempFile);
fs.Write(fileContents, 0, fileContents.Length);
2023-01-04 10:23:03 -08:00
}
}
2023-11-21 10:17:25 -05:00
catch (Exception ex)
{
2024-04-24 11:01:10 -04:00
Console.WriteLine($"Something went wrong extracting InstallShield Archive V3 entry {cfile.Value.Name}: {ex}");
2023-11-21 10:17:25 -05:00
Console.WriteLine();
}
2023-01-04 10:23:03 -08:00
}
}
2023-11-21 10:17:25 -05:00
catch (Exception ex)
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
Console.WriteLine($"Something went wrong extracting InstallShield Archive V3: {ex}");
2023-01-04 10:23:03 -08:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
}
}
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
// IS-CAB archive
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.InstallShieldCAB)
2023-11-21 10:17:25 -05:00
{
// Build the archive information
Console.WriteLine("Extracting IS-CAB contents");
Console.WriteLine();
// If the cab file itself fails
try
{
var cabfile = UnshieldSharp.Cabinet.InstallShieldCabinet.Open(file);
2024-04-24 11:01:10 -04:00
if (cabfile?.HeaderList == null)
{
Console.WriteLine("Something went wrong parsing IS-CAB archive");
Console.WriteLine();
return;
}
for (int i = 0; i < cabfile!.HeaderList.FileCount; i++)
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
// If an individual entry fails
try
2023-01-04 10:23:03 -08:00
{
2024-04-24 11:01:10 -04:00
string? filename = cabfile.HeaderList.GetFileName(i);
2023-11-21 10:17:25 -05:00
string tempFile;
2023-01-04 10:23:03 -08:00
try
{
2023-11-21 10:17:25 -05:00
tempFile = Path.Combine(outputDirectory, filename ?? $"BAD_FILENAME{i}");
2023-01-04 10:23:03 -08:00
}
2023-11-21 10:17:25 -05:00
catch
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
tempFile = Path.Combine(outputDirectory, $"BAD_FILENAME{i}");
2023-01-04 10:23:03 -08:00
}
2023-11-21 10:17:25 -05:00
cabfile?.FileSave(i, tempFile);
}
catch (Exception ex)
{
Console.WriteLine($"Something went wrong extracting IS-CAB entry {i}: {ex}");
Console.WriteLine();
2023-01-04 10:23:03 -08:00
}
}
}
2023-11-21 10:17:25 -05:00
catch (Exception ex)
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
Console.WriteLine($"Something went wrong extracting IS-CAB: {ex}");
2023-01-04 10:23:03 -08:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
}
}
2023-01-04 10:23:03 -08:00
#if ((NETFRAMEWORK && !NET20 && !NET35 && !NET40) || NETCOREAPP) && WIN
2023-11-21 10:17:25 -05:00
// Microsoft Cabinet archive
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.MicrosoftCAB)
2023-11-21 10:17:25 -05:00
{
// Build the cabinet information
Console.WriteLine("Extracting MS-CAB contents");
Console.WriteLine();
2023-01-04 10:23:03 -08:00
var cabinet = new LibMSPackN.MSCabinet(file);
2023-11-21 10:17:25 -05:00
if (cabinet == null)
{
Console.WriteLine("Something went wrong parsing MS-CAB archive");
Console.WriteLine();
return;
2023-01-04 10:23:03 -08:00
}
2023-11-21 10:17:25 -05:00
try
2023-01-04 10:23:03 -08:00
{
// Extract the MS-CAB contents to the directory
foreach (var compressedFile in cabinet.GetFiles())
{
try
{
string tempFile = Path.Combine(outputDirectory, compressedFile.Filename);
string? directoryName = Path.GetDirectoryName(tempFile);
if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
compressedFile.ExtractTo(tempFile);
}
catch (Exception ex)
{
Console.WriteLine($"Something went wrong extracting Microsoft Cabinet entry {compressedFile.Filename}: {ex}");
Console.WriteLine();
}
}
2023-11-21 10:17:25 -05:00
}
catch (Exception ex)
{
Console.WriteLine($"Something went wrong extracting MS-CAB: {ex}");
2023-01-04 10:23:03 -08:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
}
}
#endif
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
// Microsoft LZ / LZ32
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.MicrosoftLZ)
2023-11-21 10:17:25 -05:00
{
// Build the Microsoft LZ / LZ32 information
Console.WriteLine("Extracting Microsoft LZ / LZ32 contents");
Console.WriteLine();
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
// If the LZ file itself fails
try
{
byte[]? data = SabreTools.Compression.LZ.Decompressor.Decompress(stream);
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
// Create the temp filename
string tempFile = "temp.bin";
if (!string.IsNullOrEmpty(file))
{
string? expandedFilePath = SabreTools.Compression.LZ.Decompressor.GetExpandedName(file, out _);
tempFile = Path.GetFileName(expandedFilePath)?.TrimEnd('\0') ?? string.Empty;
if (tempFile.EndsWith(".ex"))
tempFile += "e";
else if (tempFile.EndsWith(".dl"))
tempFile += "l";
2023-01-04 10:23:03 -08:00
}
2023-11-21 10:17:25 -05:00
tempFile = Path.Combine(outputDirectory, tempFile);
// Write the file data to a temp file
if (data != null && data.Length > 0)
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
using Stream tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
tempStream.Write(data, 0, data.Length);
2023-01-04 10:23:03 -08:00
}
}
2023-11-21 10:17:25 -05:00
catch (Exception ex)
{
Console.WriteLine($"Something went wrong extracting Microsoft LZ / LZ32: {ex}");
Console.WriteLine();
}
}
2023-01-04 10:23:03 -08:00
2024-02-20 18:45:37 -05:00
#if ((NETFRAMEWORK && !NET20 && !NET35 && !NET40) || NETCOREAPP) && WIN
2023-11-22 12:22:01 -05:00
// MoPaQ (MPQ) archive
2024-04-26 22:13:27 -04:00
else if (ft == WrapperType.MoPaQ)
2023-11-22 12:22:01 -05:00
{
// Build the archive information
Console.WriteLine("Extracting MoPaQ contents");
Console.WriteLine();
2023-01-04 10:23:03 -08:00
2023-11-22 12:22:01 -05:00
// If the MPQ file itself fails
try
{
2023-11-22 13:28:13 -05:00
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)
2023-01-04 10:23:03 -08:00
{
2023-11-22 13:28:13 -05:00
Console.WriteLine("Could not read the listfile, extraction halted!");
Console.WriteLine();
}
2023-11-22 12:22:01 -05:00
2023-11-22 13:28:13 -05:00
// Read the listfile in for processing
using (var sr = new StreamReader(listStream))
{
listfile = sr.ReadToEnd();
}
2023-01-04 10:23:03 -08:00
2023-11-22 13:28:13 -05:00
// 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
2023-11-22 12:22:01 -05:00
{
2023-11-22 13:28:13 -05:00
string tempFile = Path.Combine(outputDirectory, sub);
string? directoryName = Path.GetDirectoryName(tempFile);
if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
2023-11-22 13:28:13 -05:00
mpqArchive.ExtractFile(sub, tempFile);
2023-11-22 12:22:01 -05:00
}
2023-11-22 13:28:13 -05:00
catch (Exception ex)
2023-11-22 12:22:01 -05:00
{
2023-11-22 13:28:13 -05:00
Console.WriteLine($"Something went wrong extracting MoPaQ entry {sub}: {ex}");
Console.WriteLine();
2023-01-04 10:23:03 -08:00
}
}
}
2023-11-22 12:22:01 -05:00
catch (Exception ex)
{
Console.WriteLine($"Something went wrong extracting MoPaQ: {ex}");
Console.WriteLine();
}
}
2023-01-04 10:23:03 -08:00
#endif
2023-11-21 10:17:25 -05:00
// PAK
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.PAK)
2023-11-21 10:17:25 -05:00
{
// Build the archive information
Console.WriteLine("Extracting PAK contents");
Console.WriteLine();
var pak = PAK.Create(stream);
if (pak == null)
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
Console.WriteLine("Something went wrong parsing PAK");
2023-01-04 10:23:03 -08:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
return;
2023-01-15 23:33:09 -08:00
}
2023-11-21 10:17:25 -05:00
try
2023-01-15 23:33:09 -08:00
{
2023-11-21 10:17:25 -05:00
// Extract the PAK contents to the directory
BinaryObjectScanner.FileType.PAK.ExtractAll(pak, outputDirectory);
}
catch (Exception ex)
{
Console.WriteLine($"Something went wrong extracting PAK: {ex}");
2023-01-15 23:33:09 -08:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
}
}
2023-01-15 23:33:09 -08:00
2023-11-21 10:17:25 -05:00
// PFF
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.PFF)
2023-11-21 10:17:25 -05:00
{
// Build the archive information
Console.WriteLine("Extracting PFF contents");
Console.WriteLine();
2023-01-15 23:33:09 -08:00
2023-11-21 10:17:25 -05:00
var pff = PFF.Create(stream);
if (pff == null)
{
Console.WriteLine("Something went wrong parsing PFF");
Console.WriteLine();
return;
2023-01-04 10:23:03 -08:00
}
2023-11-21 10:17:25 -05:00
try
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
// Extract the PFF contents to the directory
BinaryObjectScanner.FileType.PFF.ExtractAll(pff, outputDirectory);
}
catch (Exception ex)
{
Console.WriteLine($"Something went wrong extracting PFF: {ex}");
2023-01-04 10:23:03 -08:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
}
}
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
// PKZIP
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.PKZIP)
2023-11-21 10:17:25 -05:00
{
// Build the archive information
Console.WriteLine("Extracting PKZIP contents");
Console.WriteLine();
2023-11-22 12:22:01 -05:00
#if NET20 || NET35 || NET40 || NET452
Console.WriteLine("Extraction is not supported for this framework!");
Console.WriteLine();
#else
2023-11-21 10:17:25 -05:00
// If the zip file itself fails
2023-11-22 12:22:01 -05:00
try
{
2023-11-22 13:28:13 -05:00
using ZipArchive zipFile = ZipArchive.Open(stream);
foreach (var entry in zipFile.Entries)
2023-01-04 10:23:03 -08:00
{
2023-11-22 13:28:13 -05:00
// If an individual entry fails
try
2023-01-04 10:23:03 -08:00
{
2024-04-24 11:01:10 -04:00
// If the entry is a directory
2023-11-22 13:28:13 -05:00
if (entry.IsDirectory)
continue;
2024-04-24 11:01:10 -04:00
// If the entry has an invalid key
if (entry.Key == null)
continue;
2023-11-22 13:28:13 -05:00
string tempFile = Path.Combine(outputDirectory, entry.Key);
string? directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null)
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
Console.WriteLine($"Something went wrong extracting PKZIP entry {entry.Key}: {ex}");
Console.WriteLine();
2023-01-04 10:23:03 -08:00
}
}
2023-11-22 12:22:01 -05:00
}
catch (Exception ex)
{
Console.WriteLine($"Something went wrong extracting PKZIP: {ex}");
Console.WriteLine();
}
2023-11-14 16:10:10 -05:00
#endif
2023-11-21 10:17:25 -05:00
}
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
// Quantum
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.Quantum)
2023-11-21 10:17:25 -05:00
{
// Build the archive information
Console.WriteLine("Extracting Quantum contents");
Console.WriteLine();
var quantum = Quantum.Create(stream);
if (quantum == null)
2023-09-16 23:09:07 -04:00
{
2023-11-21 10:17:25 -05:00
Console.WriteLine("Something went wrong parsing Quantum");
2023-09-16 23:09:07 -04:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
return;
2023-09-16 23:09:07 -04:00
}
2023-11-21 10:17:25 -05:00
try
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
// Extract the Quantum contents to the directory
BinaryObjectScanner.FileType.Quantum.ExtractAll(quantum, outputDirectory);
}
catch (Exception ex)
{
Console.WriteLine($"Something went wrong extracting Quantum: {ex}");
2023-01-04 10:23:03 -08:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
}
}
// RAR
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.RAR)
2023-11-21 10:17:25 -05:00
{
// Build the archive information
Console.WriteLine("Extracting RAR contents");
Console.WriteLine();
2023-01-04 10:23:03 -08:00
2023-11-22 12:22:01 -05:00
#if NET20 || NET35 || NET40 || NET452
Console.WriteLine("Extraction is not supported for this framework!");
Console.WriteLine();
#else
2023-11-21 10:17:25 -05:00
// If the rar file itself fails
2023-11-22 12:22:01 -05:00
try
{
2023-11-22 13:28:13 -05:00
using RarArchive rarFile = RarArchive.Open(stream);
foreach (var entry in rarFile.Entries)
2023-01-04 10:23:03 -08:00
{
2023-11-22 13:28:13 -05:00
// If an individual entry fails
try
2023-01-04 10:23:03 -08:00
{
2024-04-24 11:01:10 -04:00
// If the entry is a directory
2023-11-22 13:28:13 -05:00
if (entry.IsDirectory)
continue;
2023-11-22 12:22:01 -05:00
2024-04-24 11:01:10 -04:00
// If the entry has an invalid key
if (entry.Key == null)
continue;
2023-11-22 13:28:13 -05:00
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();
2023-01-04 10:23:03 -08:00
}
}
2023-11-22 12:22:01 -05:00
}
catch (Exception ex)
{
Console.WriteLine($"Something went wrong extracting RAR: {ex}");
Console.WriteLine();
}
2023-11-14 16:10:10 -05:00
#endif
2023-11-21 10:17:25 -05:00
}
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
// SGA
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.SGA)
2023-11-21 10:17:25 -05:00
{
// Build the archive information
Console.WriteLine("Extracting SGA contents");
Console.WriteLine();
var sga = SGA.Create(stream);
if (sga == null)
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
Console.WriteLine("Something went wrong parsing SGA");
2023-01-04 10:23:03 -08:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
return;
2023-01-04 10:23:03 -08:00
}
2023-11-21 10:17:25 -05:00
try
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
// Extract the SGA contents to the directory
BinaryObjectScanner.FileType.SGA.ExtractAll(sga, outputDirectory);
}
catch (Exception ex)
{
Console.WriteLine($"Something went wrong extracting SGA: {ex}");
2023-01-04 10:23:03 -08:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
}
}
// Tape Archive
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.RAR)
2023-11-21 10:17:25 -05:00
{
// Build the archive information
Console.WriteLine("Extracting Tape Archive contents");
Console.WriteLine();
2023-01-04 10:23:03 -08:00
2023-11-22 12:22:01 -05:00
#if NET20 || NET35 || NET40 || NET452
Console.WriteLine("Extraction is not supported for this framework!");
Console.WriteLine();
#else
2023-11-21 10:17:25 -05:00
// If the tar file itself fails
2023-11-22 12:22:01 -05:00
try
{
2023-11-22 13:28:13 -05:00
using TarArchive tarFile = TarArchive.Open(stream);
foreach (var entry in tarFile.Entries)
2023-01-04 10:23:03 -08:00
{
2023-11-22 13:28:13 -05:00
// If an individual entry fails
try
2023-01-04 10:23:03 -08:00
{
2024-04-24 11:01:10 -04:00
// If the entry is a directory
2023-11-22 13:28:13 -05:00
if (entry.IsDirectory)
continue;
2023-11-22 12:22:01 -05:00
2024-04-24 11:01:10 -04:00
// If the entry has an invalid key
if (entry.Key == null)
continue;
2023-11-22 13:28:13 -05:00
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();
2023-01-04 10:23:03 -08:00
}
}
2023-11-22 12:22:01 -05:00
}
catch (Exception ex)
{
Console.WriteLine($"Something went wrong extracting Tape Archive: {ex}");
Console.WriteLine();
}
2023-11-14 16:10:10 -05:00
#endif
2023-11-21 10:17:25 -05:00
}
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
// VBSP
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.VBSP)
2023-11-21 10:17:25 -05:00
{
// Build the archive information
Console.WriteLine("Extracting VBSP contents");
Console.WriteLine();
var vbsp = VBSP.Create(stream);
if (vbsp == null)
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
Console.WriteLine("Something went wrong parsing VBSP");
2023-01-04 10:23:03 -08:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
return;
2023-01-04 10:23:03 -08:00
}
2023-11-21 10:17:25 -05:00
try
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
// Extract the VBSP contents to the directory
BinaryObjectScanner.FileType.VBSP.ExtractAllLumps(vbsp, outputDirectory);
}
catch (Exception ex)
{
Console.WriteLine($"Something went wrong extracting VBSP: {ex}");
2023-01-04 10:23:03 -08:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
}
}
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
// VPK
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.VPK)
2023-11-21 10:17:25 -05:00
{
// Build the archive information
Console.WriteLine("Extracting VPK contents");
Console.WriteLine();
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
var vpk = VPK.Create(stream);
if (vpk == null)
{
Console.WriteLine("Something went wrong parsing VPK");
Console.WriteLine();
return;
2023-01-04 10:23:03 -08:00
}
2023-11-21 10:17:25 -05:00
try
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
// Extract the VPK contents to the directory
BinaryObjectScanner.FileType.VPK.ExtractAll(vpk, outputDirectory);
}
catch (Exception ex)
{
Console.WriteLine($"Something went wrong extracting VPK: {ex}");
2023-01-04 10:23:03 -08:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
}
}
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
// WAD
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.WAD)
2023-11-21 10:17:25 -05:00
{
// Build the archive information
Console.WriteLine("Extracting WAD contents");
Console.WriteLine();
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
var wad = WAD.Create(stream);
if (wad == null)
{
Console.WriteLine("Something went wrong parsing WAD");
Console.WriteLine();
return;
2023-01-04 10:23:03 -08:00
}
2023-11-21 10:17:25 -05:00
try
{
// Extract the WAD contents to the directory
BinaryObjectScanner.FileType.WAD.ExtractAllLumps(wad, outputDirectory);
}
catch (Exception ex)
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
Console.WriteLine($"Something went wrong extracting WAD: {ex}");
2023-01-04 10:23:03 -08:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
}
}
// xz
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.RAR)
2023-11-21 10:17:25 -05:00
{
// Build the xz information
Console.WriteLine("Extracting xz contents");
Console.WriteLine();
2023-01-04 10:23:03 -08:00
2023-11-22 12:22:01 -05:00
#if NET20 || NET35 || NET40 || NET452
Console.WriteLine("Extraction is not supported for this framework!");
Console.WriteLine();
#else
2023-11-22 13:28:13 -05:00
using var xzFile = new XZStream(stream);
// If an individual entry fails
try
2023-11-22 12:22:01 -05:00
{
2023-11-22 13:28:13 -05:00
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();
2023-11-22 12:22:01 -05:00
}
2023-11-14 16:10:10 -05:00
#endif
2023-11-21 10:17:25 -05:00
}
2023-01-04 10:23:03 -08:00
2023-11-21 10:17:25 -05:00
// XZP
2024-04-26 22:09:05 -04:00
else if (ft == WrapperType.XZP)
2023-11-21 10:17:25 -05:00
{
// Build the archive information
Console.WriteLine("Extracting XZP contents");
Console.WriteLine();
var xzp = XZP.Create(stream);
if (xzp == null)
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
Console.WriteLine("Something went wrong parsing XZP");
2023-01-04 10:23:03 -08:00
Console.WriteLine();
2023-11-21 10:17:25 -05:00
return;
2023-01-04 10:23:03 -08:00
}
2023-11-21 10:17:25 -05:00
try
{
// Extract the XZP contents to the directory
BinaryObjectScanner.FileType.XZP.ExtractAll(xzp, outputDirectory);
}
catch (Exception ex)
2023-01-04 10:23:03 -08:00
{
2023-11-21 10:17:25 -05:00
Console.WriteLine($"Something went wrong extracting XZP: {ex}");
2023-01-04 10:23:03 -08:00
Console.WriteLine();
}
}
2023-11-21 10:17:25 -05:00
// Everything else
else
{
Console.WriteLine("Not a supported extractable file format, skipping...");
Console.WriteLine();
return;
}
2023-01-04 10:23:03 -08:00
}
}
}