diff --git a/SabreTools.Serialization/Readers/MicrosoftCabinet.cs b/SabreTools.Serialization/Readers/MicrosoftCabinet.cs
index 0e66fdba..57a93965 100644
--- a/SabreTools.Serialization/Readers/MicrosoftCabinet.cs
+++ b/SabreTools.Serialization/Readers/MicrosoftCabinet.cs
@@ -171,8 +171,8 @@ namespace SabreTools.Serialization.Readers
if (header.FolderReservedSize > 0)
folder.ReservedData = data.ReadBytes(header.FolderReservedSize);
-
- if (folder.CabStartOffset > 0)
+
+ /*if (folder.CabStartOffset > 0)
{
long currentPosition = data.Position;
data.SeekIfPossible(folder.CabStartOffset, SeekOrigin.Begin);
@@ -185,11 +185,11 @@ namespace SabreTools.Serialization.Readers
}
data.SeekIfPossible(currentPosition, SeekOrigin.Begin);
- }
+ }*/
return folder;
}
-
+
///
/// Parse a Stream into a data block
///
diff --git a/SabreTools.Serialization/Wrappers/MicrosoftCabinet.Extraction.cs b/SabreTools.Serialization/Wrappers/MicrosoftCabinet.Extraction.cs
index f1923c34..9ab38bc4 100644
--- a/SabreTools.Serialization/Wrappers/MicrosoftCabinet.Extraction.cs
+++ b/SabreTools.Serialization/Wrappers/MicrosoftCabinet.Extraction.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using SabreTools.Data.Models.MicrosoftCabinet;
+using SabreTools.IO.Compression.MSZIP;
using SabreTools.IO.Extensions;
namespace SabreTools.Serialization.Wrappers
@@ -30,8 +31,9 @@ namespace SabreTools.Serialization.Wrappers
/// Open a cabinet set for reading, if possible
///
/// Filename for one cabinet in the set
+ /// True to include debug data, false otherwise
/// Wrapper representing the set, null on error
- private static MicrosoftCabinet? OpenSet(string? filename)
+ private static MicrosoftCabinet? OpenSet(string? filename, bool includeDebug)
{
// If the file is invalid
if (string.IsNullOrEmpty(filename))
@@ -52,7 +54,7 @@ namespace SabreTools.Serialization.Wrappers
while (current.CabinetPrev != null)
{
// Attempt to open the previous cabinet
- var prev = current.OpenPrevious(filename);
+ var prev = current.OpenPrevious(filename, includeDebug);
if (prev?.Header == null)
break;
@@ -71,7 +73,7 @@ namespace SabreTools.Serialization.Wrappers
break;
// Open the next cabinet and try to parse
- var next = current.OpenNext(filename);
+ var next = current.OpenNext(filename, includeDebug);
if (next?.Header == null)
break;
@@ -89,7 +91,8 @@ namespace SabreTools.Serialization.Wrappers
/// Open the next archive, if possible
///
/// Filename for one cabinet in the set
- private MicrosoftCabinet? OpenNext(string? filename)
+ /// True to include debug data, false otherwise
+ private MicrosoftCabinet? OpenNext(string? filename, bool includeDebug = false)
{
// Ignore invalid archives
if (string.IsNullOrEmpty(filename))
@@ -102,22 +105,32 @@ namespace SabreTools.Serialization.Wrappers
string? next = CabinetNext;
if (string.IsNullOrEmpty(next))
return null;
-
+
// Get the full next path
string? folder = Path.GetDirectoryName(filename);
if (folder != null)
next = Path.Combine(folder, next);
// Open and return the next cabinet
- var fs = File.Open(next, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
- return Create(fs);
+ // Catch exceptions due to file not existing, etc
+ try
+ {
+ var fs = File.Open(next, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+ return Create(fs);
+ }
+ catch
+ {
+ if (includeDebug) Console.WriteLine($"Error: Cabinet set part {next} could not be opened!");
+ return null;
+ }
}
///
/// Open the previous archive, if possible
///
/// Filename for one cabinet in the set
- private MicrosoftCabinet? OpenPrevious(string? filename)
+ /// True to include debug data, false otherwise
+ private MicrosoftCabinet? OpenPrevious(string? filename, bool includeDebug)
{
// Ignore invalid archives
if (string.IsNullOrEmpty(filename))
@@ -130,15 +143,24 @@ namespace SabreTools.Serialization.Wrappers
string? prev = CabinetPrev;
if (string.IsNullOrEmpty(prev))
return null;
-
+
// Get the full next path
string? folder = Path.GetDirectoryName(filename);
if (folder != null)
prev = Path.Combine(folder, prev);
// Open and return the previous cabinet
- var fs = File.Open(prev, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
- return Create(fs);
+ // Catch exceptions due to file not existing, etc
+ try
+ {
+ var fs = File.Open(prev, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+ return Create(fs);
+ }
+ catch
+ {
+ if (includeDebug) Console.WriteLine($"Error: Cabinet set part {prev} could not be opened!");
+ return null;
+ }
}
#endregion
@@ -151,83 +173,45 @@ namespace SabreTools.Serialization.Wrappers
// Display warning in debug runs
if (includeDebug) Console.WriteLine("WARNING: LZX and Quantum compression schemes are not supported so some files may be skipped!");
- // Do not ignore previous links by default
- bool ignorePrev = false;
-
// Open the full set if possible
var cabinet = this;
- if (Filename != null)
+ if (Filename == null)
{
- cabinet = OpenSet(Filename);
- ignorePrev = true;
+ if (includeDebug) Console.WriteLine($"Cabinet set could not be opened!");
+ return false;
}
-
+
+ cabinet = OpenSet(Filename, includeDebug);
+ if (cabinet == null)
+ return false;
+
+ // If we have anything but the first file, avoid extraction to avoid repeat extracts
+ // TODO: if/when full msi support is added, somehow this is going to have to take that into account, while also still handling partial sets
+ if (this.Filename != cabinet.Filename)
+ {
+ string firstCabName = Path.GetFileName(cabinet.Filename) ?? string.Empty;
+ if (includeDebug) Console.WriteLine($"Only the first cabinet {firstCabName} will be extracted!");
+ return false;
+ }
+
// If the archive is invalid
if (cabinet?.Folders == null || cabinet.Folders.Length == 0)
return false;
-
- try
- {
- // Loop through the folders
- bool allExtracted = true;
- while (true)
- {
- // Loop through the current folders
- for (int f = 0; f < cabinet.Folders.Length; f++)
- {
- if (f == 0 && (cabinet.Files[0].FolderIndex == FolderIndex.CONTINUED_PREV_AND_NEXT
- || cabinet.Files[0].FolderIndex == FolderIndex.CONTINUED_FROM_PREV))
- continue;
-
- var folder = cabinet.Folders[f];
- allExtracted &= cabinet.ExtractFolder(Filename, outputDirectory, folder, f, ignorePrev, includeDebug);
- }
-
- // Move to the next cabinet, if possible
- Array.ForEach(cabinet.Folders, folder => folder.DataBlocks = []);
-
- cabinet = cabinet.Next;
- cabinet?.Prev = null;
-
- // TODO: already-extracted data isn't being cleared from memory, at least not nearly enough.
- if (cabinet?.Folders == null || cabinet.Folders.Length == 0)
- break;
- }
-
- return allExtracted;
- }
- catch (Exception ex)
- {
- if (includeDebug) Console.Error.WriteLine(ex);
- return false;
- }
+
+ return cabinet.ExtractSet(Filename, outputDirectory, includeDebug);
}
///
- /// Extract the contents of a single folder
+ /// Get filtered array of spanned files for a folder
///
/// Filename for one cabinet in the set, if available
- /// Path to the output directory
- /// Folder containing the blocks to decompress
/// Index of the folder in the cabinet
- /// True to ignore previous links, false otherwise
/// True to include debug data, false otherwise
- /// True if all files extracted, false otherwise
- private bool ExtractFolder(string? filename,
- string outputDirectory,
- CFFOLDER? folder,
- int folderIndex,
- bool ignorePrev,
- bool includeDebug)
+ /// Filtered array of files
+ private CFFILE[] GetSpannedFilesArray(string? filename, int folderIndex, bool includeDebug)
{
- // Decompress the blocks, if possible
- using var blockStream = DecompressBlocks(filename, folder, folderIndex, includeDebug);
- if (blockStream == null || blockStream.Length == 0)
- return false;
-
// Loop through the files
- bool allExtracted = true;
- var filterFiles = GetSpannedFiles(filename, folderIndex, ignorePrev);
+ var filterFiles = GetSpannedFiles(filename, folderIndex, includeDebug);
List fileList = [];
// Filtering, add debug output eventually
@@ -245,99 +229,302 @@ namespace SabreTools.Serialization.Wrappers
fileList.Add(file);
}
- CFFILE[] files = fileList.ToArray();
- blockStream.SeekIfPossible(0, SeekOrigin.Begin);
- for (int i = 0; i < files.Length; i++)
- {
- var file = files[i];
- allExtracted &= ExtractFiles(outputDirectory, blockStream, file, includeDebug);
- }
-
- return allExtracted;
+ return fileList.ToArray();
}
- // TODO: this will apparently improve memory usage/performance, but it's not clear if this implementation is enough for that to happen
///
- /// Extract the contents of a single file, intended to be used with all files in a straight shot
+ /// Get stream representing the output file
///
+ /// Filename for the file that will be extracted to
/// Path to the output directory
- /// Stream representing the uncompressed block data
- /// File information
- /// True to include debug data, false otherwise
- /// True if the file extracted, false otherwise
- private static bool ExtractFiles(string outputDirectory, Stream blockStream, CFFILE file, bool includeDebug)
+ /// Filestream opened for the file
+ private FileStream GetFileStream(string filename, string outputDirectory)
{
+ // Ensure directory separators are consistent
+ 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);
+
+ // Open the output file for writing
+ return File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.None);
+ }
+
+ ///
+ /// Read a datablock from a cabinet
+ ///
+ /// Offset to be read from
+ /// True to include debug data, false otherwise
+ /// Read datablock
+ private CFDATA? ReadBlock(ref long offset, bool includeDebug)
+ {
+
+ // Should only ever occur if it tries to read more than the file, but good to catch in general
+ try
+ {
+ lock (this._dataSourceLock)
+ {
+ this._dataSource.SeekIfPossible(offset, SeekOrigin.Begin);
+ var dataBlock = new CFDATA();
+
+ var dataReservedSize = this.Header.DataReservedSize;
+
+ dataBlock.Checksum = this._dataSource.ReadUInt32LittleEndian();
+ dataBlock.CompressedSize = this._dataSource.ReadUInt16LittleEndian();
+ dataBlock.UncompressedSize = this._dataSource.ReadUInt16LittleEndian();
+
+ if (dataReservedSize > 0)
+ dataBlock.ReservedData = this._dataSource.ReadBytes(dataReservedSize);
+
+ if (dataBlock.CompressedSize > 0)
+ dataBlock.CompressedData = this._dataSource.ReadBytes(dataBlock.CompressedSize);
+
+ offset = _dataSource.Position;
+
+ return dataBlock;
+ }
+ }
+ catch (Exception ex)
+ {
+ if (includeDebug) Console.Error.WriteLine(ex);
+ return null;
+ }
+
+ }
+
+ ///
+ /// Extract the contents of a cabinet set
+ ///
+ /// Filename for one cabinet in the set, if available
+ /// Path to the output directory
+ /// True to include debug data, false otherwise
+ /// True if all files extracted, false otherwise
+ private bool ExtractSet(string? cabFilename, string outputDirectory, bool includeDebug)
+ {
+ var cabinet = this;
+ var currentCabFilename = cabFilename;
+ long offset = 0;
try
{
- byte[] fileData = blockStream.ReadBytes((int)file.FileSize);
+ // Loop through the folders
+ bool allExtracted = true;
+ while (true)
+ {
+ // Loop through the current folders
+ for (int f = 0; f < cabinet.Folders.Length; f++)
+ {
+ if (f == 0 && (cabinet.Files[0].FolderIndex == FolderIndex.CONTINUED_PREV_AND_NEXT
+ || cabinet.Files[0].FolderIndex == FolderIndex.CONTINUED_FROM_PREV))
+ {
+ continue;
+ }
- // Ensure directory separators are consistent
- string filename = file.Name;
- if (Path.DirectorySeparatorChar == '\\')
- filename = filename.Replace('/', '\\');
- else if (Path.DirectorySeparatorChar == '/')
- filename = filename.Replace('\\', '/');
+ var folder = cabinet.Folders[f];
+ CFFILE[] files = cabinet.GetSpannedFilesArray(currentCabFilename, f, includeDebug);
+ var file = files[0];
+ int bytesLeft = (int)file.FileSize;
+ int fileCounter = 0;
+
+ // Cache starting position
+ offset = folder.CabStartOffset;
+
+ var mszip = Decompressor.Create();
+ try
+ {
+ // Ensure folder contains data
+ if (folder.DataCount == 0)
+ return false;
- // 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);
+ // Skip unsupported compression types to avoid opening a blank filestream. This can be altered/removed if these types are ever supported.
+ var compressionType = GetCompressionType(folder);
+ if (compressionType == CompressionType.TYPE_QUANTUM || compressionType == CompressionType.TYPE_LZX)
+ continue;
+
+ var fs = GetFileStream(file.Name, outputDirectory);
- // Open the output file for writing
- using var fs = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.None);
- fs.Write(fileData, 0, fileData.Length);
- fs.Flush();
+ //uint quantumWindowBits = (uint)(((ushort)folder.CompressionType >> 8) & 0x1f);
+
+ if (folder.CabStartOffset <= 0)
+ return false;
+
+ var tempCabinet = cabinet;
+ int j = 0;
+
+ // Loop through the data blocks
+ // Has to be a while loop instead of a for loop due to cab spanning continue blocks
+ while (j < folder.DataCount)
+ {
+ var dataBlock = tempCabinet.ReadBlock(ref offset, includeDebug);
+ if (dataBlock == null)
+ {
+ if (includeDebug) Console.Error.WriteLine($"Error extracting file {file.Name}");
+ break;
+ }
+
+ // Get the data to be processed
+ byte[] blockData = dataBlock.CompressedData;
+
+ // If the block is continued, append
+ bool continuedBlock = false;
+ if (dataBlock.UncompressedSize == 0)
+ {
+ tempCabinet = tempCabinet.Next;
+ if (tempCabinet == null)
+ break; // Next cab is missing, continue
+
+ // CompressionType not updated because there's no way it's possible that it can swap on continued blocks
+ folder = tempCabinet.Folders[0];
+ offset = folder.CabStartOffset;
+ var nextBlock = tempCabinet.ReadBlock(ref offset, includeDebug);
+ if (nextBlock == null)
+ {
+ if (includeDebug) Console.Error.WriteLine($"Error extracting file {file.Name}");
+ break;
+ }
+
+ byte[] nextData = nextBlock.CompressedData;
+ if (nextData.Length == 0)
+ continue;
+
+ continuedBlock = true;
+ blockData = [.. blockData, .. nextData];
+ dataBlock.CompressedSize += nextBlock.CompressedSize;
+ dataBlock.UncompressedSize = nextBlock.UncompressedSize;
+ }
+
+ // Get the uncompressed data block
+ byte[] data = compressionType switch
+ {
+ CompressionType.TYPE_NONE => blockData,
+ CompressionType.TYPE_MSZIP => DecompressMSZIPBlock(f, mszip, j, dataBlock, blockData, includeDebug),
+
+ // TODO: Unsupported
+ CompressionType.TYPE_QUANTUM => [],
+ CompressionType.TYPE_LZX => [],
+
+ // Should be impossible
+ _ => [],
+ };
+
+ if (bytesLeft > 0 && bytesLeft >= data.Length)
+ {
+ fs.Write(data);
+ bytesLeft -= data.Length;
+ }
+ else if (bytesLeft > 0 && bytesLeft < data.Length)
+ {
+ int tempBytesLeft = bytesLeft;
+ fs.Write(data, 0, bytesLeft);
+ fs.Close();
+
+ // reached end of folder
+ if (fileCounter + 1 == files.Length)
+ break;
+
+ file = files[++fileCounter];
+ bytesLeft = (int)file.FileSize;
+ fs = GetFileStream(file.Name, outputDirectory);
+ while (bytesLeft < data.Length - tempBytesLeft)
+ {
+ fs.Write(data, tempBytesLeft, bytesLeft);
+ tempBytesLeft += bytesLeft;
+ fs.Close();
+
+ // reached end of folder
+ if (fileCounter + 1 == files.Length)
+ break;
+
+ file = files[++fileCounter];
+ bytesLeft = (int)file.FileSize;
+ fs = GetFileStream(file.Name, outputDirectory);
+ }
+
+ fs.Write(data, tempBytesLeft, data.Length - tempBytesLeft);
+ bytesLeft -= (data.Length - tempBytesLeft);
+ }
+ else
+ {
+ int tempBytesLeft = bytesLeft;
+ fs.Close();
+
+ // reached end of folder
+ if (fileCounter + 1 == files.Length)
+ break;
+
+ file = files[++fileCounter];
+ bytesLeft = (int)file.FileSize;
+ fs = GetFileStream(file.Name, outputDirectory);
+ while (bytesLeft < data.Length - tempBytesLeft)
+ {
+ fs.Write(data, tempBytesLeft, bytesLeft);
+ tempBytesLeft += bytesLeft;
+ fs.Close();
+
+ // reached end of folder
+ if (fileCounter + 1 == files.Length)
+ break;
+
+ file = files[++fileCounter];
+ bytesLeft = (int)file.FileSize;
+ fs = GetFileStream(file.Name, outputDirectory);
+ }
+
+ fs.Write(data, tempBytesLeft, data.Length - tempBytesLeft);
+ bytesLeft -= (data.Length - tempBytesLeft);
+ }
+
+ // Top if block occurs on http://redump.org/disc/107833/ , middle on https://dbox.tools/titles/pc/57520FA0 , bottom still unobserved
+ // While loop since this also handles 0 byte files. Example file seen in http://redump.org/disc/93312/ , cab Group17.cab, file TRACKSLOC6DYNTEX_BIN
+ while (bytesLeft == 0)
+ {
+ fs.Close();
+
+ // reached end of folder
+ if (fileCounter + 1 == files.Length)
+ break;
+
+ file = files[++fileCounter];
+ bytesLeft = (int)file.FileSize;
+ fs = GetFileStream(file.Name, outputDirectory);
+ }
+
+ if (continuedBlock)
+ j = 0;
+
+ j++;
+ }
+ }
+ catch (Exception ex)
+ {
+ if (includeDebug) Console.Error.WriteLine(ex);
+ return false;
+ }
+ }
+
+ // Move to the next cabinet, if possible
+ cabinet = cabinet.Next;
+ if (cabinet == null) // If the next cabinet is missing, there's no better way to handle this
+ return false;
+
+ currentCabFilename = cabinet.Filename;
+
+ if (cabinet.Folders.Length == 0)
+ break;
+ }
+
+ return allExtracted;
}
catch (Exception ex)
{
if (includeDebug) Console.Error.WriteLine(ex);
return false;
}
-
- return true;
- }
-
- ///
- /// Extract the contents of a single file
- ///
- /// Path to the output directory
- /// Stream representing the uncompressed block data
- /// File information
- /// True to include debug data, false otherwise
- /// True if the file extracted, false otherwise
- private static bool ExtractFile(string outputDirectory, Stream blockStream, CFFILE file, bool includeDebug)
- {
- try
- {
- blockStream.SeekIfPossible(file.FolderStartOffset, SeekOrigin.Begin);
- byte[] fileData = blockStream.ReadBytes((int)file.FileSize);
-
- // Ensure directory separators are consistent
- string filename = file.Name;
- 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);
-
- // Open the output file for writing
- using var fs = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.None);
- fs.Write(fileData, 0, fileData.Length);
- fs.Flush();
- }
- catch (Exception ex)
- {
- if (includeDebug) Console.Error.WriteLine(ex);
- return false;
- }
-
- return true;
}
#endregion
@@ -380,4 +567,4 @@ namespace SabreTools.Serialization.Wrappers
#endregion
}
-}
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Wrappers/MicrosoftCabinet.cs b/SabreTools.Serialization/Wrappers/MicrosoftCabinet.cs
index 5a8c678b..99432d04 100644
--- a/SabreTools.Serialization/Wrappers/MicrosoftCabinet.cs
+++ b/SabreTools.Serialization/Wrappers/MicrosoftCabinet.cs
@@ -173,77 +173,6 @@ namespace SabreTools.Serialization.Wrappers
#region Folders
- ///
- /// Decompress all blocks for a folder
- ///
- /// Filename for one cabinet in the set, if available
- /// Folder containing the blocks to decompress
- /// Index of the folder in the cabinet
- /// True to include debug data, false otherwise
- /// Stream representing the decompressed data on success, null otherwise
- public Stream? DecompressBlocks(string? filename, CFFOLDER? folder, int folderIndex, bool includeDebug)
- {
- // Ensure data blocks
- var dataBlocks = GetDataBlocks(filename, folder, folderIndex);
- if (dataBlocks == null || dataBlocks.Length == 0)
- return null;
-
- // Get the compression type
- var compressionType = GetCompressionType(folder!);
-
- // Setup decompressors
- var mszip = Decompressor.Create();
- //uint quantumWindowBits = (uint)(((ushort)folder.CompressionType >> 8) & 0x1f);
-
- // Loop through the data blocks
- var ms = new MemoryStream();
- for (int i = 0; i < dataBlocks.Length; i++)
- {
- var db = dataBlocks[i];
-
- // Get the data to be processed
- byte[] blockData = db.CompressedData;
-
- // If the block is continued, append
- bool continuedBlock = false;
- if (db.UncompressedSize == 0)
- {
- var nextBlock = dataBlocks[i + 1];
- byte[]? nextData = nextBlock.CompressedData;
- if (nextData == null)
- continue;
-
- continuedBlock = true;
- blockData = [.. blockData, .. nextData];
- db.CompressedSize += nextBlock.CompressedSize;
- db.UncompressedSize = nextBlock.UncompressedSize;
- }
-
- // Get the uncompressed data block
- byte[] data = compressionType switch
- {
- CompressionType.TYPE_NONE => blockData,
- CompressionType.TYPE_MSZIP => DecompressMSZIPBlock(folderIndex, mszip, i, db, blockData, includeDebug),
-
- // TODO: Unsupported
- CompressionType.TYPE_QUANTUM => [],
- CompressionType.TYPE_LZX => [],
-
- // Should be impossible
- _ => [],
- };
-
- // Write the uncompressed data block
- ms.Write(data, 0, data.Length);
- ms.Flush();
-
- // Increment additionally if we had a continued block
- if (continuedBlock) i++;
- }
-
- return ms;
- }
-
///
/// Decompress an MS-ZIP block using an existing decompressor
///
@@ -301,104 +230,20 @@ namespace SabreTools.Serialization.Wrappers
return (CompressionType)ushort.MaxValue;
}
- ///
- /// Get the set of data blocks for a folder
- ///
- /// Filename for one cabinet in the set, if available
- /// Folder containing the blocks to decompress
- /// Index of the folder in the cabinet
- /// Indicates if previous cabinets should be ignored
- /// Indicates if next cabinets should be ignored
- /// Array of data blocks on success, null otherwise
- private CFDATA[]? GetDataBlocks(string? filename, CFFOLDER? folder, int folderIndex, bool skipPrev = false, bool skipNext = false)
- {
- // Skip invalid folders
- if (folder?.DataBlocks == null || folder.DataBlocks.Length == 0)
- return null;
-
- GetData(folder);
-
- // Get all files for the folder
- var files = GetFiles(folderIndex);
- if (files.Length == 0)
- return folder.DataBlocks;
-
- // Check if the folder spans in either direction
- bool spanPrev = Array.Exists(files, f => f.FolderIndex == FolderIndex.CONTINUED_FROM_PREV || f.FolderIndex == FolderIndex.CONTINUED_PREV_AND_NEXT);
- bool spanNext = Array.Exists(files, f => f.FolderIndex == FolderIndex.CONTINUED_TO_NEXT || f.FolderIndex == FolderIndex.CONTINUED_PREV_AND_NEXT);
-
- // If the folder spans backward and Prev is not being skipped
- CFDATA[] prevBlocks = [];
- if (!skipPrev && spanPrev)
- {
- // Try to get Prev if it doesn't exist
- if (Prev?.Header == null)
- Prev = OpenPrevious(filename);
-
- // Get all blocks from Prev
- if (Prev?.Header != null && Prev.Folders != null)
- {
- int prevFolderIndex = Prev.FolderCount - 1;
- var prevFolder = Prev.Folders[prevFolderIndex - 1];
- prevBlocks = Prev.GetDataBlocks(filename, prevFolder, prevFolderIndex, skipNext: true) ?? [];
- }
- }
-
- // If the folder spans forward and Next is not being skipped
- CFDATA[] nextBlocks = [];
- if (!skipNext && spanNext)
- {
- // Try to get Next if it doesn't exist
- if (Next?.Header == null)
- Next = OpenNext(filename);
-
- // Get all blocks from Prev
- if (Next?.Header != null && Next.Folders != null)
- {
- var nextFolder = Next.Folders[0];
- nextBlocks = Next.GetDataBlocks(filename, nextFolder, 0, skipPrev: true) ?? [];
- }
- }
-
- // Return all found blocks in order
- return [.. prevBlocks, .. folder.DataBlocks, .. nextBlocks];
- }
-
- ///
- /// Loads in all the datablocks for the current folder.
- ///
- /// The folder to have the datablocks loaded for
- public void GetData(CFFOLDER folder)
- {
- if (folder.CabStartOffset <= 0)
- return;
-
- uint offset = folder.CabStartOffset;
- for (int i = 0; i < folder.DataCount; i++)
- {
- offset += 8;
-
- if (Header.DataReservedSize > 0)
- {
- folder.DataBlocks[i].ReservedData = ReadRangeFromSource(offset, Header.DataReservedSize);
- offset += Header.DataReservedSize;
- }
-
- if (folder.DataBlocks[i].CompressedSize > 0)
- {
- folder.DataBlocks[i].CompressedData = ReadRangeFromSource(offset, folder.DataBlocks[i].CompressedSize);
- offset += folder.DataBlocks[i].CompressedSize;
- }
- }
- }
-
///
/// Get all files for the current folder, plus connected spanned folders.
///
+ /// Input filename of the cabinet to read from
/// Index of the folder in the cabinet
- /// True to ignore previous links, false otherwise
+ /// True to include debug data, false otherwise
+ /// True if previous cabinets should be skipped, false otherwise.
+ /// True if next cabinets should be skipped, false otherwise.
/// Array of all files for the folder
- private CFFILE[] GetSpannedFiles(string? filename, int folderIndex, bool ignorePrev = false, bool skipPrev = false, bool skipNext = false)
+ private CFFILE[] GetSpannedFiles(string? filename,
+ int folderIndex,
+ bool includeDebug,
+ bool skipPrev = false,
+ bool skipNext = false)
{
// Ignore invalid archives
if (Files.IsNullOrEmpty())
@@ -410,14 +255,12 @@ namespace SabreTools.Serialization.Wrappers
if (string.IsNullOrEmpty(f.Name))
return false;
- // Ignore links to previous cabinets, if required
- if (ignorePrev)
- {
- if (f.FolderIndex == FolderIndex.CONTINUED_FROM_PREV)
- return false;
- else if (f.FolderIndex == FolderIndex.CONTINUED_PREV_AND_NEXT)
- return false;
- }
+ // Ignore links to previous cabinets
+ if (f.FolderIndex == FolderIndex.CONTINUED_FROM_PREV)
+ return false;
+ else if (f.FolderIndex == FolderIndex.CONTINUED_PREV_AND_NEXT)
+ return false;
+
int fileFolder = GetFolderIndex(f);
return fileFolder == folderIndex;
@@ -433,13 +276,13 @@ namespace SabreTools.Serialization.Wrappers
{
// Try to get Prev if it doesn't exist
if (Prev?.Header == null)
- Prev = OpenPrevious(filename);
+ Prev = OpenPrevious(filename, includeDebug);
// Get all files from Prev
if (Prev?.Header != null && Prev.Folders != null)
{
int prevFolderIndex = Prev.FolderCount - 1;
- prevFiles = Prev.GetSpannedFiles(filename, prevFolderIndex, skipNext: true) ?? [];
+ prevFiles = Prev.GetSpannedFiles(filename, prevFolderIndex, includeDebug, skipNext: true) ?? [];
}
}
@@ -449,13 +292,13 @@ namespace SabreTools.Serialization.Wrappers
{
// Try to get Next if it doesn't exist
if (Next?.Header == null)
- Next = OpenNext(filename);
-
+ Next = OpenNext(filename);
+
// Get all files from Prev
if (Next?.Header != null && Next.Folders != null)
{
var nextFolder = Next.Folders[0];
- nextFiles = Next.GetSpannedFiles(filename, 0, skipPrev: true) ?? [];
+ nextFiles = Next.GetSpannedFiles(filename, 0, includeDebug, skipPrev: true) ?? [];
}
}