diff --git a/BinaryObjectScanner/FileType/MicrosoftCAB.cs b/BinaryObjectScanner/FileType/MicrosoftCAB.cs index a5ba6c8d..c939257c 100644 --- a/BinaryObjectScanner/FileType/MicrosoftCAB.cs +++ b/BinaryObjectScanner/FileType/MicrosoftCAB.cs @@ -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; } + /// + /// Decompress an MS-ZIP block using an existing decompressor + /// + /// Index of the folder in the cabinet + /// MS-ZIP decompressor with persistent state + /// Index of the block within the folder + /// Block data to be used for decompression + /// Byte array representing the decompressed data, empty on error + /// 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(); + } + /// /// Get the unmasked compression type for a folder /// /// Folder to get the compression type for /// Compression type on success, on error + /// TODO: Remove once Serialization is updated private static CompressionType GetCompressionType(CFFOLDER folder) { if ((folder!.CompressionType & CompressionType.MASK_TYPE) == CompressionType.TYPE_NONE)