From ac0ed050dcb6f56cd1da190d75fed7665679fe80 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Sun, 22 May 2022 10:17:41 -0700 Subject: [PATCH] Partially fix MSZIP decompression --- .../External/libmspack/CAB/Decompressor.cs | 128 ++++++++++-------- .../External/libmspack/Compression/MSZIP.cs | 2 +- 2 files changed, 74 insertions(+), 56 deletions(-) diff --git a/BurnOutSharp/External/libmspack/CAB/Decompressor.cs b/BurnOutSharp/External/libmspack/CAB/Decompressor.cs index 6028a2eb..57e1492d 100644 --- a/BurnOutSharp/External/libmspack/CAB/Decompressor.cs +++ b/BurnOutSharp/External/libmspack/CAB/Decompressor.cs @@ -354,59 +354,44 @@ namespace LibMSPackSharp.CAB } } + // Close existing file handles + System.Close(State?.InputFileHandle); + System.Close(State?.OutputFileHandle); + // Allocate generic decompression state - if (State == null) + State = new DecompressState() { - State = new DecompressState() { Sys = System }; + Folder = fol, + Data = fol.Data, + Offset = 0, + Block = 0, + Outlen = 0, - State.Sys.Read = SysRead; - State.Sys.Write = SysWrite; - } + Sys = System, - // Do we need to change folder or reset the current folder? - if ((State.Folder != fol) || (State.Offset > file.Header.FolderOffset) || State.DecompressorState == null) - { - // Free any existing decompressor - FreeDecompressionState(); + InputCabinet = fol.Data.Cab, + InputFileHandle = System.Open(fol.Data.Cab.Filename, OpenMode.MSPACK_SYS_OPEN_READ), + OutputFileHandle = null, // Required for skipping existing data + InputPointer = 0, + InputEnd = 0, + }; - // Do we need to open a new cab file? - if (State.InputFileHandle == null || (fol.Data.Cab != State.InputCabinet)) - { - // Close previous file handle if from a different cab - System.Close(State.InputFileHandle); - System.Close(State.OutputFileHandle); + State.Sys.Read = SysRead; + State.Sys.Write = SysWrite; - State.InputCabinet = fol.Data.Cab; - State.InputFileHandle = System.Open(fol.Data.Cab.Filename, OpenMode.MSPACK_SYS_OPEN_READ); - if (State.InputFileHandle == null) - return Error = Error.MSPACK_ERR_OPEN; - } - - // Seek to start of data blocks - if (!System.Seek(State.InputFileHandle, fol.Data.Offset, SeekMode.MSPACK_SYS_SEEK_START)) - return Error = Error.MSPACK_ERR_SEEK; - - // Set up decompressor - if (InitDecompressionState(fol.Header.CompType) != Error.MSPACK_ERR_OK) - return Error; - - // Initialise new folder state - State.Folder = fol; - State.Data = fol.Data; - State.Offset = 0; - State.Block = 0; - State.Outlen = 0; - State.InputPointer = State.InputEnd = 0; - - // Read_error lasts for the lifetime of a decompressor - ReadError = Error.MSPACK_ERR_OK; - } - - // Open file for output - FileStream fh = System.Open(filename, OpenMode.MSPACK_SYS_OPEN_WRITE); - if (fh == null) + if (State.InputFileHandle == null) return Error = Error.MSPACK_ERR_OPEN; + // Seek to start of data blocks + if (!System.Seek(State.InputFileHandle, fol.Data.Offset, SeekMode.MSPACK_SYS_SEEK_START)) + return Error = Error.MSPACK_ERR_SEEK; + + // Set up decompressor + if (InitDecompressionState(fol.Header.CompType) != Error.MSPACK_ERR_OK) + return Error; + + // ReadError lasts for the lifetime of a decompressor + ReadError = Error.MSPACK_ERR_OK; Error = Error.MSPACK_ERR_OK; // If file has more than 0 bytes @@ -417,31 +402,29 @@ namespace LibMSPackSharp.CAB // Get to correct offset. // - use null fh to say 'no writing' to cabd_sys_write() - // - if cabd_sys_read() has an error, it will set self.ReadError + // - if SysRead() has an error, it will set self.ReadError // and pass back MSPACK_ERR_READ - State.OutputFileHandle = null; if ((bytes = file.Header.FolderOffset - State.Offset) != 0) { - State.OutputFileHandle = fh; - InitDecompressionState(fol.Header.CompType); - error = State.Decompress(State.DecompressorState, bytes); Error = (error == Error.MSPACK_ERR_READ) ? ReadError : error; } + // Open the output file handle + State.OutputFileHandle = System.Open(filename, OpenMode.MSPACK_SYS_OPEN_WRITE); + if (State.OutputFileHandle == null) + return Error = Error.MSPACK_ERR_OPEN; + // If getting to the correct offset was error free, unpack file if (Error == Error.MSPACK_ERR_OK) { - State.OutputFileHandle = fh; - InitDecompressionState(fol.Header.CompType); - + UpdateDecompressionState(); error = State.Decompress(State.DecompressorState, filelen); Error = (error == Error.MSPACK_ERR_READ) ? ReadError : error; } } // Close output file - System.Close(fh); System.Close(State.OutputFileHandle); return Error; @@ -543,6 +526,36 @@ namespace LibMSPackSharp.CAB return Error = (State.DecompressorState != null) ? Error.MSPACK_ERR_OK : Error.MSPACK_ERR_NOMEMORY; } + /// + /// Updates the decompression state with a new output + /// + internal Error UpdateDecompressionState() + { + switch (State.CompressionType & CompressionType.COMPTYPE_MASK) + { + case CompressionType.COMPTYPE_NONE: + (State.DecompressorState as NoneState).Output = State.OutputFileHandle; + break; + + case CompressionType.COMPTYPE_MSZIP: + (State.DecompressorState as MSZIPDStream).Output = State.OutputFileHandle; + break; + + case CompressionType.COMPTYPE_QUANTUM: + (State.DecompressorState as QTMDStream).Output = State.OutputFileHandle; + break; + + case CompressionType.COMPTYPE_LZX: + (State.DecompressorState as LZXDStream).Output = State.OutputFileHandle; + break; + + default: + return Error = Error.MSPACK_ERR_DATAFORMAT; + } + + return Error = (State.DecompressorState != null) ? Error.MSPACK_ERR_OK : Error.MSPACK_ERR_NOMEMORY; + } + /// /// Frees decompression state, according to which method was used. /// @@ -654,7 +667,12 @@ namespace LibMSPackSharp.CAB /// internal static int SysWrite(object file, byte[] buffer, int pointer, int bytes) { - if (file is Decompressor self) + // Null output file means skip those bytes + if (file == null) + { + return bytes; + } + else if (file is Decompressor self) { self.State.Offset += (uint)bytes; if (self.State.OutputFileHandle != null) diff --git a/BurnOutSharp/External/libmspack/Compression/MSZIP.cs b/BurnOutSharp/External/libmspack/Compression/MSZIP.cs index 13ffd178..42e3827d 100644 --- a/BurnOutSharp/External/libmspack/Compression/MSZIP.cs +++ b/BurnOutSharp/External/libmspack/Compression/MSZIP.cs @@ -742,7 +742,7 @@ namespace LibMSPackSharp.Compression if (!CompressionStream.MakeDecodeTable(19, 7, bl_len, bl_table, msb: false)) return Error.INF_ERR_BITLENTBL; - // Read literal / distance code lengths */ + // Read literal / distance code lengths for (i = 0; i < (lit_codes + dist_codes); i++) { // Single-level huffman lookup