From daf19a561c536a83562e94fd30bb00fe2dc3a476 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Fri, 29 Aug 2025 08:01:27 -0400 Subject: [PATCH] Add UnshieldSharp to ExtractionTool directly --- ExtractionTool/Program.cs | 96 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 7 deletions(-) diff --git a/ExtractionTool/Program.cs b/ExtractionTool/Program.cs index 6559529b..6d6b3f62 100644 --- a/ExtractionTool/Program.cs +++ b/ExtractionTool/Program.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Text.RegularExpressions; using SabreTools.IO.Extensions; using SabreTools.Serialization.Wrappers; @@ -175,14 +176,15 @@ namespace ExtractionTool isv3.Extract(outputDirectory, includeDebug); } - // IS-CAB archive -- Reimplement - // else if (wrapper is InstallShieldCabinet iscab) - // { - // Console.WriteLine("Extracting IS-CAB contents"); - // Console.WriteLine(); + // IS-CAB archive + else if (wrapper is InstallShieldCabinet) + { + Console.WriteLine("Extracting IS-CAB contents"); + Console.WriteLine(); - // iscab.Extract(outputDirectory, includeDebug); - // } + // TODO: Move this handling to Serialization directly + ExtractInstallShieldCabinet(file, outputDirectory, includeDebug); + } // LZ-compressed file, KWAJ variant else if (wrapper is LZKWAJ kwaj) @@ -389,5 +391,85 @@ namespace ExtractionTool return; } } + + /// + /// Handle IS-CAB archives + /// + private static bool ExtractInstallShieldCabinet(string file, string outputDirectory, bool includeDebug) + { + // Get the name of the first cabinet file or header + var directory = Path.GetDirectoryName(file); + string noExtension = Path.GetFileNameWithoutExtension(file); + + bool shouldScanCabinet; + if (directory == null) + { + string filenamePattern = noExtension; + filenamePattern = new Regex(@"\d+$").Replace(filenamePattern, string.Empty); + bool cabinetHeaderExists = File.Exists(filenamePattern + "1.hdr"); + shouldScanCabinet = cabinetHeaderExists + ? file.Equals(filenamePattern + "1.hdr", StringComparison.OrdinalIgnoreCase) + : file.Equals(filenamePattern + "1.cab", StringComparison.OrdinalIgnoreCase); + } + else + { + string filenamePattern = Path.Combine(directory, noExtension); + filenamePattern = new Regex(@"\d+$").Replace(filenamePattern, string.Empty); + bool cabinetHeaderExists = File.Exists(Path.Combine(directory, filenamePattern + "1.hdr")); + 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 anything but the first file + if (!shouldScanCabinet) + return false; + + try + { + if (!File.Exists(file)) + return false; + + var cabfile = UnshieldSharp.InstallShieldCabinet.Open(file); + if (cabfile?.HeaderList == null) + return false; + + for (int i = 0; i < cabfile.HeaderList.FileCount; i++) + { + try + { + // Check if the file is valid first + if (!cabfile.HeaderList.FileIsValid(i)) + continue; + + // Ensure directory separators are consistent + string filename = cabfile.HeaderList.GetFileName(i) ?? $"BAD_FILENAME{i}"; + if (Path.DirectorySeparatorChar == '\\') + filename = filename.Replace('/', '\\'); + else if (Path.DirectorySeparatorChar == '/') + filename = filename.Replace('\\', '/'); + + // Ensure the full output directory exists + filename = Path.Combine(outputDirectory, filename); + var directoryName = Path.GetDirectoryName(filename); + if (directoryName != null && !Directory.Exists(directoryName)) + Directory.CreateDirectory(directoryName); + + cabfile.FileSave(i, filename); + } + catch (Exception ex) + { + if (includeDebug) Console.Error.WriteLine(ex); + } + } + + return true; + } + catch (Exception ex) + { + if (includeDebug) Console.Error.WriteLine(ex); + return false; + } + } } }