From 79943560bc326cfaafc69556d2ec421a29510bf6 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Mon, 28 Jul 2025 21:14:51 -0400 Subject: [PATCH] Keep tweaking extraction --- .../Wrappers/MicrosoftCabinet.cs | 51 +++++++++++++++---- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/SabreTools.Serialization/Wrappers/MicrosoftCabinet.cs b/SabreTools.Serialization/Wrappers/MicrosoftCabinet.cs index 3bd8de58..496eba64 100644 --- a/SabreTools.Serialization/Wrappers/MicrosoftCabinet.cs +++ b/SabreTools.Serialization/Wrappers/MicrosoftCabinet.cs @@ -118,7 +118,8 @@ namespace SabreTools.Serialization.Wrappers /// Path to the output directory /// True to include debug data, false otherwise /// Indicates if all files were able to be extracted - public static bool ExtractAll(string filename, string outDir, bool includeDebug) + /// Will extract all items found in the set with forward-only reading + public static bool ExtractSet(string filename, string outDir, bool includeDebug) { // Get a wrapper for the set var current = OpenSet(filename); @@ -144,13 +145,24 @@ namespace SabreTools.Serialization.Wrappers return true; } + /// + /// Extract a cabinet to an output directory, if possible + /// + /// Filename for one cabinet in the set + /// Path to the output directory + /// True to include debug data, false otherwise + /// Indicates if all files were able to be extracted + /// Will read spanned folders but won't attempt to extract unrelated folders + public bool ExtractAll(string filename, string outDir, bool includeDebug) + => ExtractCabinet(filename, outDir, forwardOnly: false, includeDebug); + /// /// Extract a cabinet file to an output directory, if possible /// /// Filename for one cabinet in the set /// Path to the output directory - /// Indicates if the cabinet set should only be read forward /// True to include debug data, false otherwise + /// Indicates if decompression should be done forward-only /// Indicates if all files were able to be extracted private bool ExtractCabinet(string filename, string outDir, bool forwardOnly, bool includeDebug) { @@ -183,9 +195,14 @@ namespace SabreTools.Serialization.Wrappers /// Path to the output directory /// Folder containing the blocks to decompress /// Index of the folder in the cabinet - /// Indicates if the cabinet set should only be read forward + /// Indicates if decompression should be done forward-only /// True to include debug data, false otherwise - private void ExtractFolder(string filename, string outDir, CFFOLDER? folder, int folderIndex, bool forwardOnly, bool includeDebug) + private void ExtractFolder(string filename, + string outDir, + CFFOLDER? folder, + int folderIndex, + bool forwardOnly, + bool includeDebug) { // Decompress the blocks, if possible using var blockStream = DecompressBlocks(filename, folder, folderIndex, forwardOnly); @@ -448,12 +465,14 @@ namespace SabreTools.Serialization.Wrappers /// Filename for one cabinet in the set /// Folder containing the blocks to decompress /// Index of the folder in the cabinet - /// Indicates if the cabinet set should only be read forward + /// Indicates if decompression should be done forward-only /// Stream representing the decompressed data on success, null otherwise public Stream? DecompressBlocks(string filename, CFFOLDER? folder, int folderIndex, bool forwardOnly) { // Ensure data blocks - var dataBlocks = GetDataBlocks(filename, folder, folderIndex, skipPrev: forwardOnly, skipNext: false); + var dataBlocks = forwardOnly + ? GetDataBlocksForward(filename, folder, folderIndex) + : GetDataBlocks(filename, folder, folderIndex); if (dataBlocks == null || dataBlocks.Length == 0) return null; @@ -481,15 +500,15 @@ namespace SabreTools.Serialization.Wrappers // MS-ZIP case CompressionType.TYPE_MSZIP: - long position = ms.Position; + long preMsZipPosition = ms.Position; mszip.CopyTo(db.CompressedData, ms); - long decompressedSize = ms.Position - position; + long msZipDecompressedSize = ms.Position - preMsZipPosition; // Pad to the correct size but throw a warning about this - if (decompressedSize < db.UncompressedSize) + if (msZipDecompressedSize < db.UncompressedSize) { - Console.Error.WriteLine($"Data block {i} in folder {folderIndex} had mismatching sizes. Expected: {db.UncompressedSize}, Got: {decompressedSize}"); - byte[] padding = new byte[db.UncompressedSize - decompressedSize]; + Console.Error.WriteLine($"Data block {i} in folder {folderIndex} had mismatching sizes. Expected: {db.UncompressedSize}, Got: {msZipDecompressedSize}"); + byte[] padding = new byte[db.UncompressedSize - msZipDecompressedSize]; ms.Write(padding, 0, padding.Length); } @@ -580,6 +599,16 @@ namespace SabreTools.Serialization.Wrappers return [.. prevBlocks, .. folder.DataBlocks, .. nextBlocks]; } + /// + /// Get the set of data blocks for a folder using forward reading only + /// + /// Filename for one cabinet in the set + /// Folder containing the blocks to decompress + /// Index of the folder in the cabinet + /// Array of data blocks on success, null otherwise + private CFDATA[]? GetDataBlocksForward(string filename, CFFOLDER? folder, int folderIndex) + => GetDataBlocks(filename, folder, folderIndex, skipPrev: true, skipNext: false); + /// /// Get all files for the current folder index ///