Split out MS-ZIP handling for cleaner code

This commit is contained in:
Matt Nadareski
2025-07-29 11:38:30 -04:00
parent fa74963a75
commit 78373dd620

View File

@@ -265,50 +265,65 @@ namespace BinaryObjectScanner.FileType
if (db?.CompressedData == null)
continue;
switch (compressionType)
// Get the uncompressed data block
byte[] data = compressionType switch
{
// Uncompressed data
case CompressionType.TYPE_NONE:
ms.Write(db.CompressedData, 0, db.CompressedData.Length);
ms.Flush();
break;
CompressionType.TYPE_NONE => db.CompressedData,
CompressionType.TYPE_MSZIP => DecompressMSZIPBlock(folderIndex, mszip, i, db),
// MS-ZIP
case CompressionType.TYPE_MSZIP:
long preMsZipPosition = ms.Position;
mszip.CopyTo(db.CompressedData, ms);
long msZipDecompressedSize = ms.Position - preMsZipPosition;
// TODO: Unsupported
CompressionType.TYPE_QUANTUM => [],
CompressionType.TYPE_LZX => [],
// Pad to the correct size but throw a warning about this
if (msZipDecompressedSize < db.UncompressedSize)
{
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);
}
// Should be impossible
_ => [],
};
break;
// Quantum
case CompressionType.TYPE_QUANTUM:
// TODO: Unsupported
break;
// LZX
case CompressionType.TYPE_LZX:
// TODO: Unsupported
break;
}
// Write the uncompressed data block
ms.Write(data, 0, data.Length);
ms.Flush();
}
return ms;
}
/// <summary>
/// Decompress an MS-ZIP block using an existing decompressor
/// </summary>
/// <param name="folderIndex">Index of the folder in the cabinet</param>
/// <param name="mszip">MS-ZIP decompressor with persistent state</param>
/// <param name="blockIndex">Index of the block within the folder</param>
/// <param name="block">Block data to be used for decompression</param>
/// <returns>Byte array representing the decompressed data, empty on error</returns>
/// TODO: Remove once Serialization is updated
private static byte[] DecompressMSZIPBlock(int folderIndex, SabreTools.Compression.MSZIP.Decompressor mszip, int blockIndex, CFDATA block)
{
// Ignore invalid blocks
if (block.CompressedData == null)
return [];
// Decompress to a temporary stream
using var stream = new MemoryStream();
mszip.CopyTo(block.CompressedData, stream);
// Pad to the correct size but throw a warning about this
if (stream.Length < block.UncompressedSize)
{
Console.Error.WriteLine($"Data block {blockIndex} in folder {folderIndex} had mismatching sizes. Expected: {block.UncompressedSize}, Got: {stream.Length}");
byte[] padding = new byte[block.UncompressedSize - stream.Length];
stream.Write(padding, 0, padding.Length);
}
// Return the byte array data
return stream.ToArray();
}
/// <summary>
/// Get the unmasked compression type for a folder
/// </summary>
/// <param name="folder">Folder to get the compression type for</param>
/// <returns>Compression type on success, <see cref="ushort.MaxValue"/> on error</returns>
/// TODO: Remove once Serialization is updated
private static CompressionType GetCompressionType(CFFOLDER folder)
{
if ((folder!.CompressionType & CompressionType.MASK_TYPE) == CompressionType.TYPE_NONE)