From 218fecb273ed3a664764e0ec2dd55529fe3d6334 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Thu, 19 May 2022 17:07:08 -0700 Subject: [PATCH] Start cleanup on libmspack --- .../External/libmspack/CAB/Cabinet.cs | 48 +-- .../External/libmspack/CAB/CabinetImpl.cs | 18 - .../External/libmspack/CAB/DecompressState.cs | 4 +- .../External/libmspack/CAB/Decompressor.cs | 2 +- BurnOutSharp/External/libmspack/CAB/Folder.cs | 31 +- .../External/libmspack/CAB/FolderImpl.cs | 36 -- .../External/libmspack/CAB/Implementation.cs | 301 +++++++-------- .../External/libmspack/CAB/InternalFile.cs | 56 +-- .../External/libmspack/CAB/_CabinetHeader.cs | 204 +++++++++++ .../External/libmspack/CAB/_FileHeader.cs | 122 ++++++ .../External/libmspack/CAB/_FolderHeader.cs | 72 ++++ .../External/libmspack/CHM/Implementation.cs | 19 +- .../Compression/CompressionStream.cs | 346 +++++++++++------- .../External/libmspack/Compression/LZX.cs | 178 ++++++--- .../libmspack/Compression/LZXDStream.cs | 18 +- .../External/libmspack/Compression/MSZIP.cs | 182 ++++++--- .../libmspack/Compression/MSZIPDStream.cs | 12 +- .../External/libmspack/Compression/QTM.cs | 36 +- .../libmspack/Compression/QTMDStream.cs | 18 +- .../External/libmspack/KWAJ/Implementation.cs | 111 ++---- .../External/libmspack/KWAJ/InternalStream.cs | 11 +- .../External/libmspack/OAB/Implementation.cs | 21 +- 22 files changed, 1145 insertions(+), 701 deletions(-) delete mode 100644 BurnOutSharp/External/libmspack/CAB/CabinetImpl.cs delete mode 100644 BurnOutSharp/External/libmspack/CAB/FolderImpl.cs create mode 100644 BurnOutSharp/External/libmspack/CAB/_CabinetHeader.cs create mode 100644 BurnOutSharp/External/libmspack/CAB/_FileHeader.cs create mode 100644 BurnOutSharp/External/libmspack/CAB/_FolderHeader.cs diff --git a/BurnOutSharp/External/libmspack/CAB/Cabinet.cs b/BurnOutSharp/External/libmspack/CAB/Cabinet.cs index f7f443de..3b9f10f7 100644 --- a/BurnOutSharp/External/libmspack/CAB/Cabinet.cs +++ b/BurnOutSharp/External/libmspack/CAB/Cabinet.cs @@ -74,6 +74,15 @@ namespace LibMSPackSharp.CAB /// public class Cabinet { + #region Internal + + /// + /// Cabinet header information + /// + internal _CabinetHeader Header { get; set; } + + #endregion + /// /// The next cabinet in a chained list, if this cabinet was opened with /// mscab_decompressor::search(). May be NULL to mark the end of the @@ -93,11 +102,6 @@ namespace LibMSPackSharp.CAB /// public long BaseOffset { get; set; } - /// - /// The length of the cabinet file in bytes. - /// - public uint Length { get; set; } - /// /// The previous cabinet in a cabinet set, or NULL. /// @@ -137,39 +141,5 @@ namespace LibMSPackSharp.CAB /// A list of all folders in the cabinet or cabinet set. /// public Folder Folders { get; set; } - - /// - /// The set ID of the cabinet. All cabinets in the same set should have - /// the same set ID. - /// - public ushort SetID { get; set; } - - /// - /// The index number of the cabinet within the set. Numbering should - /// start from 0 for the first cabinet in the set, and increment by 1 for - /// each following cabinet. - /// - public ushort SetIndex { get; set; } - - /// - /// The number of bytes reserved in the header area of the cabinet. - /// - /// If this is non-zero and flags has MSCAB_HDR_RESV set, this data can - /// be read by the calling application. It is of the given length, - /// located at offset (base_offset + MSCAB_HDR_RESV_OFFSET) in the - /// cabinet file. - /// - /// - public ushort HeaderResv { get; set; } - - /// - /// Header flags. - /// - /// - /// - /// - /// - /// - public HeaderFlags Flags { get; set; } } } diff --git a/BurnOutSharp/External/libmspack/CAB/CabinetImpl.cs b/BurnOutSharp/External/libmspack/CAB/CabinetImpl.cs deleted file mode 100644 index dc0d7a89..00000000 --- a/BurnOutSharp/External/libmspack/CAB/CabinetImpl.cs +++ /dev/null @@ -1,18 +0,0 @@ -/* This file is part of libmspack. - * (C) 2003-2018 Stuart Caie. - * - * libmspack is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License (LGPL) version 2.1 - * - * For further details, see the file COPYING.LIB distributed with libmspack - */ - -namespace LibMSPackSharp.CAB -{ - public class CabinetImpl : Cabinet - { - public long BlocksOffset { get; set; } - - public int BlockResverved { get; set; } - } -} diff --git a/BurnOutSharp/External/libmspack/CAB/DecompressState.cs b/BurnOutSharp/External/libmspack/CAB/DecompressState.cs index 4d99cf4d..b8b2d5a2 100644 --- a/BurnOutSharp/External/libmspack/CAB/DecompressState.cs +++ b/BurnOutSharp/External/libmspack/CAB/DecompressState.cs @@ -76,12 +76,12 @@ namespace LibMSPackSharp.CAB /// /// Input data consumed /// - public int IPtr { get; set; } + public int InputPointer { get; set; } /// /// Input data end /// - public int IEnd { get; set; } + public int InputEnd { get; set; } /// /// One input block of data diff --git a/BurnOutSharp/External/libmspack/CAB/Decompressor.cs b/BurnOutSharp/External/libmspack/CAB/Decompressor.cs index 4df5b439..25095713 100644 --- a/BurnOutSharp/External/libmspack/CAB/Decompressor.cs +++ b/BurnOutSharp/External/libmspack/CAB/Decompressor.cs @@ -46,7 +46,7 @@ namespace LibMSPackSharp.CAB /// /// /// - public Func Open; + public Func Open; /// /// Closes a previously opened cabinet or cabinet set. diff --git a/BurnOutSharp/External/libmspack/CAB/Folder.cs b/BurnOutSharp/External/libmspack/CAB/Folder.cs index 0c5c845c..4c6ec590 100644 --- a/BurnOutSharp/External/libmspack/CAB/Folder.cs +++ b/BurnOutSharp/External/libmspack/CAB/Folder.cs @@ -27,6 +27,15 @@ namespace LibMSPackSharp.CAB /// public class Folder { + #region Internal + + /// + /// Folder header information + /// + internal _FolderHeader Header { get; set; } + + #endregion + /// /// A pointer to the next folder in this cabinet or cabinet set, or NULL /// if this is the final folder. @@ -34,28 +43,18 @@ namespace LibMSPackSharp.CAB public Folder Next { get; set; } /// - /// The compression format used by this folder. - /// - /// The macro MSCABD_COMP_METHOD() should be used on this field to get - /// the algorithm used. The macro MSCABD_COMP_LEVEL() should be used to get - /// the "compression level". + /// Where are the data blocks? /// - /// - /// - public CompressionType CompressionType { get; set; } + public FolderData Data { get; set; } /// - /// The total number of data blocks used by this folder. This includes - /// data blocks present in other files, if this folder spans more than - /// one cabinet. + /// First file needing backwards merge /// - public ushort NumBlocks { get; set; } + public InternalFile MergePrev { get; set; } /// - /// Returns the compression method used by a folder. + /// First file needing forwards merge /// - /// a value - /// a value - public CompressionType MSCABD_COMP_LEVEL(CompressionType compType) => (CompressionType)((((ushort)compType) >> 8) & 0x1F); + public InternalFile MergeNext { get; set; } } } diff --git a/BurnOutSharp/External/libmspack/CAB/FolderImpl.cs b/BurnOutSharp/External/libmspack/CAB/FolderImpl.cs deleted file mode 100644 index 009b9c07..00000000 --- a/BurnOutSharp/External/libmspack/CAB/FolderImpl.cs +++ /dev/null @@ -1,36 +0,0 @@ -/* libmspack -- a library for working with Microsoft compression formats. - * (C) 2003-2019 Stuart Caie - * - * libmspack is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License (LGPL) version 2.1 - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -namespace LibMSPackSharp.CAB -{ - public class FolderImpl : Folder - { - /// - /// Where are the data blocks? - /// - public FolderData Data { get; set; } - - /// - /// First file needing backwards merge - /// - public InternalFile MergePrev { get; set; } - - /// - /// First file needing forwards merge - /// - public InternalFile MergeNext { get; set; } - } -} diff --git a/BurnOutSharp/External/libmspack/CAB/Implementation.cs b/BurnOutSharp/External/libmspack/CAB/Implementation.cs index 7c6b1deb..7e4123cb 100644 --- a/BurnOutSharp/External/libmspack/CAB/Implementation.cs +++ b/BurnOutSharp/External/libmspack/CAB/Implementation.cs @@ -71,36 +71,6 @@ namespace LibMSPackSharp.CAB #region Structure Offsets - private const int cfhead_Signature = (0x00); - private const int cfhead_CabinetSize = (0x08); - private const int cfhead_FileOffset = (0x10); - private const int cfhead_MinorVersion = (0x18); - private const int cfhead_MajorVersion = (0x19); - private const int cfhead_NumFolders = (0x1A); - private const int cfhead_NumFiles = (0x1C); - private const int cfhead_Flags = (0x1E); - private const int cfhead_SetID = (0x20); - private const int cfhead_CabinetIndex = (0x22); - private const int cfhead_SIZEOF = (0x24); - - private const int cfheadext_HeaderReserved = (0x00); - private const int cfheadext_FolderReserved = (0x02); - private const int cfheadext_DataReserved = (0x03); - private const int cfheadext_SIZEOF = (0x04); - - private const int cffold_DataOffset = (0x00); - private const int cffold_NumBlocks = (0x04); - private const int cffold_CompType = (0x06); - private const int cffold_SIZEOF = (0x08); - - private const int cffile_UncompressedSize = (0x00); - private const int cffile_FolderOffset = (0x04); - private const int cffile_FolderIndex = (0x08); - private const int cffile_Date = (0x0A); - private const int cffile_Time = (0x0C); - private const int cffile_Attribs = (0x0E); - private const int cffile_SIZEOF = (0x10); - private const int cfdata_CheckSum = (0x00); private const int cfdata_CompressedSize = (0x04); private const int cfdata_UncompressedSize = (0x06); @@ -140,10 +110,10 @@ namespace LibMSPackSharp.CAB /// /// Opens a file and tries to read it as a cabinet file /// - public static CabinetImpl Open(Decompressor d, string filename) + public static Cabinet Open(Decompressor d, string filename) { DecompressorImpl self = d as DecompressorImpl; - CabinetImpl cab = null; + Cabinet cab = null; if (self == null) return null; @@ -152,7 +122,7 @@ namespace LibMSPackSharp.CAB object fileHandle; if ((fileHandle = system.Open(system, filename, OpenMode.MSPACK_SYS_OPEN_READ)) != null) { - cab = new CabinetImpl(); + cab = new Cabinet(); cab.Filename = filename; Error error = ReadHeaders(system, fileHandle, cab, 0, self.Salvage, false); if (error != Error.MSPACK_ERR_OK) @@ -222,7 +192,7 @@ namespace LibMSPackSharp.CAB } // Free folder data segments - for (dat = (fol as FolderImpl).Data.Next; dat != null; dat = ndat) + for (dat = fol.Data.Next; dat != null; dat = ndat) { ndat = dat.Next; sys.Free(dat); @@ -272,18 +242,17 @@ namespace LibMSPackSharp.CAB /// Fills out a pre-existing Cabinet structure, allocates memory /// for folders and files as necessary /// - public static Error ReadHeaders(SystemImpl sys, object fh, CabinetImpl cab, long offset, bool salvage, bool quiet) + public static Error ReadHeaders(SystemImpl sys, object fh, Cabinet cab, long offset, bool salvage, bool quiet) { - int num_folders, num_files, folder_resv, i, x; + int i, x; Error err = Error.MSPACK_ERR_OK; - FileFlags fidx; - FolderImpl fol, linkfol = null; + Folder fol, linkfol = null; InternalFile file, linkfile = null; byte[] buf = new byte[64]; // Initialise pointers if (cab == null) - cab = new CabinetImpl(); + cab = new Cabinet(); cab.Next = null; cab.Files = null; @@ -299,73 +268,36 @@ namespace LibMSPackSharp.CAB return Error.MSPACK_ERR_SEEK; // Read in the CFHEADER - if (sys.Read(fh, buf, 0, cfhead_SIZEOF) != cfhead_SIZEOF) + if (sys.Read(fh, buf, 0, _CabinetHeader.Size) != _CabinetHeader.Size) return Error.MSPACK_ERR_READ; - // Check for "MSCF" signature - if (BitConverter.ToUInt32(buf, cfhead_Signature) != 0x4643534D) - return Error.MSPACK_ERR_SIGNATURE; + // Create a new header based on that + err = _CabinetHeader.Create(buf, out _CabinetHeader cabinetHeader); + if (err != Error.MSPACK_ERR_OK) + return err; - // Some basic header fields - cab.Length = BitConverter.ToUInt32(buf, cfhead_CabinetSize); - cab.SetID = BitConverter.ToUInt16(buf, cfhead_SetID); - cab.SetIndex = BitConverter.ToUInt16(buf, cfhead_CabinetIndex); + // Assign the header + cab.Header = cabinetHeader; - // Get the number of folders - num_folders = BitConverter.ToUInt16(buf, cfhead_NumFolders); - if (num_folders == 0) + // Check for the extended header + if (cab.Header.Flags.HasFlag(HeaderFlags.MSCAB_HDR_RESV)) { - if (!quiet) sys.Message(fh, "no folders in cabinet."); - return Error.MSPACK_ERR_DATAFORMAT; - } - - // Get the number of files - num_files = BitConverter.ToUInt16(buf, cfhead_NumFiles); - if (num_files == 0) - { - if (!quiet) sys.Message(fh, "no files in cabinet."); - return Error.MSPACK_ERR_DATAFORMAT; - } - - // Check cabinet version - if ((buf[cfhead_MajorVersion] != 1) && (buf[cfhead_MinorVersion] != 3)) - { - if (!quiet) sys.Message(fh, "WARNING; cabinet version is not 1.3"); - } - - // Read the reserved-sizes part of header, if present - cab.Flags = (HeaderFlags)BitConverter.ToUInt16(buf, cfhead_Flags); - - if (cab.Flags.HasFlag(HeaderFlags.MSCAB_HDR_RESV)) - { - if (sys.Read(fh, buf, 0, cfheadext_SIZEOF) != cfheadext_SIZEOF) + if (sys.Read(fh, buf, 0, _CabinetHeader.ExtendedSize) != _CabinetHeader.ExtendedSize) return Error.MSPACK_ERR_READ; - cab.HeaderResv = BitConverter.ToUInt16(buf, cfheadext_HeaderReserved); - folder_resv = buf[cfheadext_FolderReserved]; - cab.BlockResverved = buf[cfheadext_DataReserved]; - - if (cab.HeaderResv > 60000) - { - if (!quiet) sys.Message(fh, "WARNING; reserved header > 60000."); - } + // Populate the extended header + cabinetHeader.PopulateExtendedHeader(buf); // Skip the reserved header - if (cab.HeaderResv != 0) + if (cab.Header.HeaderReserved != 0) { - if (!sys.Seek(fh, cab.HeaderResv, SeekMode.MSPACK_SYS_SEEK_CUR)) + if (!sys.Seek(fh, cab.Header.HeaderReserved, SeekMode.MSPACK_SYS_SEEK_CUR)) return Error.MSPACK_ERR_SEEK; } } - else - { - cab.HeaderResv = 0; - folder_resv = 0; - cab.BlockResverved = 0; - } // Read name and info of preceeding cabinet in set, if present - if (cab.Flags.HasFlag(HeaderFlags.MSCAB_HDR_PREVCAB)) + if (cab.Header.Flags.HasFlag(HeaderFlags.MSCAB_HDR_PREVCAB)) { cab.PreviousName = ReadString(sys, fh, false, ref err); if (err != Error.MSPACK_ERR_OK) @@ -377,7 +309,7 @@ namespace LibMSPackSharp.CAB } // Read name and info of next cabinet in set, if present - if (cab.Flags.HasFlag(HeaderFlags.MSCAB_HDR_NEXTCAB)) + if (cab.Header.Flags.HasFlag(HeaderFlags.MSCAB_HDR_NEXTCAB)) { cab.NextName = ReadString(sys, fh, false, ref err); if (err != Error.MSPACK_ERR_OK) @@ -389,29 +321,39 @@ namespace LibMSPackSharp.CAB } // Read folders - for (i = 0; i < num_folders; i++) + for (i = 0; i < cab.Header.NumFolders; i++) { - if (sys.Read(fh, buf, 0, cffold_SIZEOF) != cffold_SIZEOF) + // Read in the FOHEADER + if (sys.Read(fh, buf, 0, _FolderHeader.Size) != _FolderHeader.Size) return Error.MSPACK_ERR_READ; - if (folder_resv != 0) + if (cab.Header.FolderReserved != 0) { - if (!sys.Seek(fh, folder_resv, SeekMode.MSPACK_SYS_SEEK_CUR)) + if (!sys.Seek(fh, cab.Header.FolderReserved, SeekMode.MSPACK_SYS_SEEK_CUR)) return Error.MSPACK_ERR_SEEK; } - fol = new FolderImpl(); + // Create an empty folder + fol = new Folder() + { + Next = null, + MergePrev = null, + MergeNext = null, + }; - fol.Next = null; - fol.CompressionType = (CompressionType)BitConverter.ToUInt16(buf, cffold_CompType); - fol.NumBlocks = BitConverter.ToUInt16(buf, cffold_NumBlocks); - fol.MergePrev = null; - fol.MergeNext = null; + // Create a new header based on that + err = _FolderHeader.Create(buf, out _FolderHeader folderHeader); + if (err != Error.MSPACK_ERR_OK) + return err; + // Assign the header + fol.Header = folderHeader; + + // Set the folder data fields fol.Data = new FolderData(); fol.Data.Next = null; fol.Data.Cab = cab; - fol.Data.Offset = offset + (int)(BitConverter.ToUInt32(buf, cffold_DataOffset)); + fol.Data.Offset = offset + fol.Header.DataOffset; // Link folder into list of folders if (linkfol == null) @@ -423,27 +365,30 @@ namespace LibMSPackSharp.CAB } // Read files - for (i = 0; i < num_files; i++) + for (i = 0; i < cab.Header.NumFiles; i++) { - if (sys.Read(fh, buf, 0, cffile_SIZEOF) != cffile_SIZEOF) + // Read in the FIHEADER + if (sys.Read(fh, buf, 0, _FileHeader.Size) != _FileHeader.Size) return Error.MSPACK_ERR_READ; - file = new InternalFile(); + file = new InternalFile() { Next = null }; - file.Next = null; - file.Length = BitConverter.ToUInt32(buf, cffile_UncompressedSize); - file.Attributes = (FileAttributes)BitConverter.ToUInt16(buf, cffile_Attribs); - file.Offset = BitConverter.ToUInt32(buf, cffile_FolderOffset); + // Create a new header based on that + err = _FileHeader.Create(buf, out _FileHeader fileHeader); + if (err != Error.MSPACK_ERR_OK) + return err; + + // Assign the header + file.Header = fileHeader; // Set folder pointer - fidx = (FileFlags)BitConverter.ToUInt16(buf, cffile_FolderIndex); - if (fidx < FileFlags.CONTINUED_FROM_PREV) + if (file.Header.FolderIndex < FileFlags.CONTINUED_FROM_PREV) { // Normal folder index; count up to the correct folder - if ((int)fidx < num_folders) + if ((int)file.Header.FolderIndex < cab.Header.NumFolders) { Folder ifol = cab.Folders; - while (fidx-- != 0) + while (file.Header.FolderIndex-- != 0) { if (ifol != null) ifol = ifol.Next; @@ -460,7 +405,7 @@ namespace LibMSPackSharp.CAB else { // Either CONTINUED_TO_NEXT, CONTINUED_FROM_PREV or CONTINUED_PREV_AND_NEXT - if (fidx == FileFlags.CONTINUED_TO_NEXT || fidx == FileFlags.CONTINUED_PREV_AND_NEXT) + if (file.Header.FolderIndex == FileFlags.CONTINUED_TO_NEXT || file.Header.FolderIndex == FileFlags.CONTINUED_PREV_AND_NEXT) { // Get last folder Folder ifol = cab.Folders; @@ -472,35 +417,23 @@ namespace LibMSPackSharp.CAB file.Folder = ifol; // Set "merge next" pointer - fol = ifol as FolderImpl; + fol = ifol; if (fol.MergeNext == null) fol.MergeNext = file; } - if (fidx == FileFlags.CONTINUED_FROM_PREV || fidx == FileFlags.CONTINUED_PREV_AND_NEXT) + if (file.Header.FolderIndex == FileFlags.CONTINUED_FROM_PREV || file.Header.FolderIndex == FileFlags.CONTINUED_PREV_AND_NEXT) { // Get first folder file.Folder = cab.Folders; // Set "merge prev" pointer - fol = file.Folder as FolderImpl; + fol = file.Folder; if (fol.MergePrev == null) fol.MergePrev = file; } } - // Get time - x = BitConverter.ToUInt16(buf, cffile_Time); - file.LastModifiedTimeHour = (byte)(x >> 11); - file.LastModifiedTimeMinute = (byte)((x >> 5) & 0x3F); - file.LastModifiedTimeSecond = (byte)((x << 1) & 0x3E); - - // Get date - x = BitConverter.ToUInt16(buf, cffile_Date); - file.LastModifiedDateDay = (byte)(x & 0x1F); - file.LastModifiedDateMonth = (byte)((x >> 5) & 0xF); - file.LastModifiedDateYear = (x >> 9) + 1980; - // Get filename file.Filename = ReadString(sys, fh, false, ref err); @@ -528,7 +461,7 @@ namespace LibMSPackSharp.CAB { // We never actually added any files to the file list. Something went wrong. // The file header may have been invalid */ - Console.WriteLine($"No files found, even though header claimed to have {num_files} files"); + Console.WriteLine($"No files found, even though header claimed to have {cab.Header.NumFiles} files"); return Error.MSPACK_ERR_DATAFORMAT; } @@ -610,7 +543,7 @@ namespace LibMSPackSharp.CAB } // Open file and get its full file length - object fh; CabinetImpl cab = null; + object fh; Cabinet cab = null; if ((fh = sys.Open(sys, filename, OpenMode.MSPACK_SYS_OPEN_READ)) != null) { long firstlen = 0; @@ -643,10 +576,10 @@ namespace LibMSPackSharp.CAB /// The inner loop of , to make it easier to /// break out of the loop and be sure that all resources are freed /// - public static Error Find(DecompressorImpl self, byte[] buf, object fh, string filename, long flen, ref long firstlen, out CabinetImpl firstcab) + public static Error Find(DecompressorImpl self, byte[] buf, object fh, string filename, long flen, ref long firstlen, out Cabinet firstcab) { firstcab = null; - CabinetImpl cab, link = null; + Cabinet cab, link = null; long caboff, offset, length; SystemImpl sys = self.System; long p, pend; @@ -762,8 +695,7 @@ namespace LibMSPackSharp.CAB (((caboff + cablen_u32) < (flen + 32)) || self.Salvage)) { // Likely cabinet found -- try reading it - cab = new CabinetImpl(); - cab.Filename = filename; + cab = new Cabinet() { Filename = filename }; if (ReadHeaders(sys, fh, cab, caboff, self.Salvage, quiet: true) != Error.MSPACK_ERR_OK) { @@ -842,7 +774,7 @@ namespace LibMSPackSharp.CAB DecompressorImpl self = d as DecompressorImpl; FolderData data, ndata; - FolderImpl lfol, rfol; + Folder lfol, rfol; InternalFile fi, rfi, lfi; if (self == null) @@ -884,18 +816,18 @@ namespace LibMSPackSharp.CAB } // Warn about odd set IDs or indices - if (lcab.SetID != rcab.SetID) + if (lcab.Header.SetID != rcab.Header.SetID) sys.Message(null, "WARNING; merged cabinets with differing Set IDs."); - if (lcab.SetIndex > rcab.SetIndex) + if (lcab.Header.CabinetIndex > rcab.Header.CabinetIndex) sys.Message(null, "WARNING; merged cabinets with odd order."); // Merging the last folder in lcab with the first folder in rcab - lfol = lcab.Folders as FolderImpl; - rfol = rcab.Folders as FolderImpl; + lfol = lcab.Folders; + rfol = rcab.Folders; while (lfol.Next != null) { - lfol = lfol.Next as FolderImpl; + lfol = lfol.Next; } // Do we need to merge folders? @@ -947,14 +879,14 @@ namespace LibMSPackSharp.CAB // NOTE: special case, don't merge if rfol is merge prev and next, // rfol.MergeNext is going to be deleted, so keep lfol's version // instead - lfol.NumBlocks += (ushort)(rfol.NumBlocks - 1); + lfol.Header.NumBlocks += (ushort)(rfol.Header.NumBlocks - 1); if ((rfol.MergeNext == null) || (rfol.MergeNext.Folder != rfol)) lfol.MergeNext = rfol.MergeNext; // Attach the rfol's folder (except the merge folder) while (lfol.Next != null) { - lfol = (FolderImpl)lfol.Next; + lfol = lfol.Next; } lfol.Next = rfol.Next; @@ -1015,20 +947,20 @@ namespace LibMSPackSharp.CAB /// /// Decides if two folders are OK to merge /// - private static bool CanMergeFolders(SystemImpl sys, FolderImpl lfol, FolderImpl rfol) + private static bool CanMergeFolders(SystemImpl sys, Folder lfol, Folder rfol) { InternalFile lfi, rfi, l, r; bool matching = true; // Check that both folders use the same compression method/settings - if (lfol.CompressionType != rfol.CompressionType) + if (lfol.Header.CompType != rfol.Header.CompType) { Console.WriteLine("folder merge: compression type mismatch"); return false; } // Check there are not too many data blocks after merging - if ((lfol.NumBlocks + rfol.NumBlocks) > CAB_FOLDERMAX) + if ((lfol.Header.NumBlocks + rfol.Header.NumBlocks) > CAB_FOLDERMAX) { Console.WriteLine("folder merge: too many data blocks in merged folders"); return false; @@ -1046,7 +978,7 @@ namespace LibMSPackSharp.CAB // offset and length of each file. for (l = lfi, r = rfi; l != null; l = l.Next, r = r.Next) { - if (r == null || (l.Offset != r.Offset) || (l.Length != r.Length)) + if (r == null || (l.Header.FolderOffset != r.Header.FolderOffset) || (l.Header.UncompressedSize != r.Header.UncompressedSize)) { matching = false; break; @@ -1064,7 +996,7 @@ namespace LibMSPackSharp.CAB { for (r = rfi; r != null; r = r.Next) { - if (l.Offset == r.Offset && l.Length == r.Length) + if (l.Header.FolderOffset == r.Header.FolderOffset && l.Header.UncompressedSize == r.Header.UncompressedSize) break; } @@ -1095,19 +1027,19 @@ namespace LibMSPackSharp.CAB return self.Error = Error.MSPACK_ERR_ARGS; SystemImpl sys = self.System; - FolderImpl fol = file.Folder as FolderImpl; + Folder fol = file.Folder; // If offset is beyond 2GB, nothing can be extracted - if (file.Offset > CAB_LENGTHMAX) + if (file.Header.FolderOffset > CAB_LENGTHMAX) return self.Error = Error.MSPACK_ERR_DATAFORMAT; // If file claims to go beyond 2GB either error out, // or in salvage mode reduce file length so it fits 2GB limit - long filelen = file.Length; - if (filelen > CAB_LENGTHMAX || (file.Offset + filelen) > CAB_LENGTHMAX) + long filelen = file.Header.UncompressedSize; + if (filelen > CAB_LENGTHMAX || (file.Header.FolderOffset + filelen) > CAB_LENGTHMAX) { if (self.Salvage) - filelen = CAB_LENGTHMAX - file.Offset; + filelen = CAB_LENGTHMAX - file.Header.FolderOffset; else return self.Error = Error.MSPACK_ERR_DATAFORMAT; } @@ -1123,8 +1055,8 @@ namespace LibMSPackSharp.CAB // In salvage mode, don't assume block sizes, just try decoding if (!self.Salvage) { - long maxlen = fol.NumBlocks * CAB_BLOCKMAX; - if ((file.Offset + filelen) > maxlen) + long maxlen = fol.Header.NumBlocks * CAB_BLOCKMAX; + if ((file.Header.FolderOffset + filelen) > maxlen) { sys.Message(null, $"ERROR; file \"{file.Filename}\" cannot be extracted, cabinet set is incomplete"); return self.Error = Error.MSPACK_ERR_DECRUNCH; @@ -1146,7 +1078,7 @@ namespace LibMSPackSharp.CAB } // Do we need to change folder or reset the current folder? - if ((self.State.Folder != fol) || (self.State.Offset > file.Offset) || self.State.DecompressorState == null) + if ((self.State.Folder != fol) || (self.State.Offset > file.Header.FolderOffset) || self.State.DecompressorState == null) { // Free any existing decompressor FreeDecompressionState(self); @@ -1169,7 +1101,7 @@ namespace LibMSPackSharp.CAB return self.Error = Error.MSPACK_ERR_SEEK; // Set up decompressor - if (InitDecompressionState(self, fol.CompressionType) != Error.MSPACK_ERR_OK) + if (InitDecompressionState(self, fol.Header.CompType) != Error.MSPACK_ERR_OK) return self.Error; // Initialise new folder state @@ -1178,7 +1110,7 @@ namespace LibMSPackSharp.CAB self.State.Offset = 0; self.State.Block = 0; self.State.Outlen = 0; - self.State.IPtr = self.State.IEnd = 0; + self.State.InputPointer = self.State.InputEnd = 0; // read_error lasts for the lifetime of a decompressor self.ReadError = Error.MSPACK_ERR_OK; @@ -1200,7 +1132,7 @@ namespace LibMSPackSharp.CAB // - if cabd_sys_read() has an error, it will set self.ReadError // and pass back MSPACK_ERR_READ self.State.OutputFileHandle = null; - if ((bytes = file.Offset - self.State.Offset) != 0) + if ((bytes = file.Header.FolderOffset - self.State.Offset) != 0) { error = self.State.Decompress(self.State.DecompressorState, bytes); self.Error = (error == Error.MSPACK_ERR_READ) ? self.ReadError : error; @@ -1310,7 +1242,11 @@ namespace LibMSPackSharp.CAB private static int SysRead(object file, byte[] buffer, int pointer, int bytes) { DecompressorImpl self = file as DecompressorImpl; + if (self == null) + return 0; + SystemImpl sys = self.System; + int avail, todo, outlen = 0; bool ignore_cksum = self.Salvage || @@ -1321,7 +1257,7 @@ namespace LibMSPackSharp.CAB todo = bytes; while (todo > 0) { - avail = self.State.IEnd - self.State.IPtr; + avail = self.State.InputEnd - self.State.InputPointer; // If out of input data, read a new block if (avail != 0) @@ -1330,8 +1266,8 @@ namespace LibMSPackSharp.CAB if (avail > todo) avail = todo; - sys.Copy(self.State.Input, self.State.IPtr, buffer, pointer, avail); - self.State.IPtr += avail; + sys.Copy(self.State.Input, self.State.InputPointer, buffer, pointer, avail); + self.State.InputPointer += avail; pointer += avail; todo -= avail; } @@ -1340,7 +1276,7 @@ namespace LibMSPackSharp.CAB // Out of data, read a new block // Check if we're out of input blocks, advance block counter - if (self.State.Block++ >= self.State.Folder.NumBlocks) + if (self.State.Block++ >= self.State.Folder.Header.NumBlocks) { if (!self.Salvage) self.ReadError = Error.MSPACK_ERR_DATAFORMAT; @@ -1361,10 +1297,10 @@ namespace LibMSPackSharp.CAB // to realign itself. CAB Quantum blocks, unlike LZX blocks, can have // anything from 0 to 4 trailing null bytes. if ((self.State.CompressionType & CompressionType.COMPTYPE_MASK) == CompressionType.COMPTYPE_QUANTUM) - self.State.Input[self.State.IEnd++] = 0xFF; + self.State.Input[self.State.InputEnd++] = 0xFF; // Is this the last block? - if (self.State.Block >= self.State.Folder.NumBlocks) + if (self.State.Block >= self.State.Folder.Header.NumBlocks) { if ((self.State.CompressionType & CompressionType.COMPTYPE_MASK) == CompressionType.COMPTYPE_LZX) { @@ -1387,12 +1323,21 @@ namespace LibMSPackSharp.CAB /// private static int SysWrite(object file, byte[] buffer, int pointer, int bytes) { - DecompressorImpl self = file as DecompressorImpl; - self.State.Offset += (uint)bytes; - if (self.State.OutputFileHandle != null) - return self.System.Write(self.State.OutputFileHandle, buffer, pointer, bytes); + if (file is DecompressorImpl self) + { + self.State.Offset += (uint)bytes; + if (self.State.OutputFileHandle != null) + return self.System.Write(self.State.OutputFileHandle, buffer, pointer, bytes); - return bytes; + return bytes; + } + else if (file is DefaultFileImpl impl) + { + return SystemImpl.DefaultSystem.Write(file, buffer, pointer, bytes); + } + + // Unknown file to write to + return 0; } #endregion @@ -1410,21 +1355,21 @@ namespace LibMSPackSharp.CAB int len, full_len; // Reset the input block pointer and end of block pointer - d.IPtr = d.IEnd = 0; + d.InputPointer = d.InputEnd = 0; do { // Read the block header - if (sys.Read(d.InputFileHandle, hdr, 0, cfdata_SIZEOF) != cfdata_SIZEOF) + if (SystemImpl.DefaultSystem.Read(d.InputFileHandle, hdr, 0, cfdata_SIZEOF) != cfdata_SIZEOF) return Error.MSPACK_ERR_READ; // Skip any reserved block headers - if (d.Data.Cab.HeaderResv != 0 && !sys.Seek(d.InputFileHandle, d.Data.Cab.HeaderResv, SeekMode.MSPACK_SYS_SEEK_CUR)) + if (d.Data.Cab.Header.HeaderReserved != 0 && !sys.Seek(d.InputFileHandle, d.Data.Cab.Header.HeaderReserved, SeekMode.MSPACK_SYS_SEEK_CUR)) return Error.MSPACK_ERR_SEEK; // Blocks must not be over CAB_INPUTMAX in size len = BitConverter.ToUInt16(hdr, cfdata_CompressedSize); - full_len = (d.IEnd - d.IPtr) + len; // Include cab-spanning blocks + full_len = (d.InputEnd - d.InputPointer) + len; // Include cab-spanning blocks if (full_len > CAB_INPUTMAX) { Console.WriteLine($"block size {full_len} > CAB_INPUTMAX"); @@ -1443,13 +1388,13 @@ namespace LibMSPackSharp.CAB } // Read the block data - if (sys.Read(d.InputFileHandle, d.Input, d.IEnd, len) != len) + if (SystemImpl.DefaultSystem.Read(d.InputFileHandle, d.Input, d.InputEnd, len) != len) return Error.MSPACK_ERR_READ; // Perform checksum test on the block (if one is stored) if ((cksum = BitConverter.ToUInt32(hdr, cfdata_CheckSum)) != 0) { - uint sum2 = Checksum(d.Input, d.IEnd, (uint)len, 0); + uint sum2 = Checksum(d.Input, d.InputEnd, (uint)len, 0); if (Checksum(hdr, 4, 4, sum2) != cksum) { if (!ignore_cksum) @@ -1460,7 +1405,7 @@ namespace LibMSPackSharp.CAB } // Advance end of block pointer to include newly read data - d.IEnd += len; + d.InputEnd += len; // Uncompressed size == 0 means this block was part of a split block // and it continues as the first block of the next cabinet in the set. diff --git a/BurnOutSharp/External/libmspack/CAB/InternalFile.cs b/BurnOutSharp/External/libmspack/CAB/InternalFile.cs index 30a27387..85dd5df8 100644 --- a/BurnOutSharp/External/libmspack/CAB/InternalFile.cs +++ b/BurnOutSharp/External/libmspack/CAB/InternalFile.cs @@ -23,6 +23,15 @@ namespace LibMSPackSharp.CAB /// public class InternalFile { + #region Internal + + /// + /// File header information + /// + internal _FileHeader Header { get; set; } + + #endregion + /// /// The next file in the cabinet or cabinet set, or NULL if this is the final file. /// @@ -34,57 +43,12 @@ namespace LibMSPackSharp.CAB /// A null terminated string of up to 255 bytes in length, it may be in /// either ISO-8859-1 or UTF8 format, depending on the file attributes. /// - /// + /// public string Filename { get; set; } - /// - /// The uncompressed length of the file, in bytes. - /// - public uint Length { get; set; } - - /// - /// File attributes. - /// - public FileAttributes Attributes { get; set; } - - /// - /// File's last modified time, hour field. - /// - public byte LastModifiedTimeHour { get; set; } - - /// - /// File's last modified time, minute field. - /// - public byte LastModifiedTimeMinute { get; set; } - - /// - /// File's last modified time, second field. - /// - public byte LastModifiedTimeSecond { get; set; } - - /// - /// File's last modified date, day field. - /// - public byte LastModifiedDateDay { get; set; } - - /// - /// File's last modified date, month field. - /// - public byte LastModifiedDateMonth { get; set; } - - /// - /// File's last modified date, year field. - /// - public int LastModifiedDateYear { get; set; } - /// /// A pointer to the folder that contains this file. /// public Folder Folder { get; set; } - - /// - /// The uncompressed offset of this file in its folder. - /// - public uint Offset { get; set; } } } diff --git a/BurnOutSharp/External/libmspack/CAB/_CabinetHeader.cs b/BurnOutSharp/External/libmspack/CAB/_CabinetHeader.cs new file mode 100644 index 00000000..0a7b774d --- /dev/null +++ b/BurnOutSharp/External/libmspack/CAB/_CabinetHeader.cs @@ -0,0 +1,204 @@ +/* This file is part of libmspack. + * (C) 2003-2018 Stuart Caie. + * + * libmspack is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License (LGPL) version 2.1 + * + * For further details, see the file COPYING.LIB distributed with libmspack + */ + +using System; + +namespace LibMSPackSharp.CAB +{ + internal class _CabinetHeader + { + #region Normal Header + + /// + /// "MSCF" + /// + /// 0x00 + public uint Signature { get; private set; } + + /// + /// UNKNOWN + /// + /// 0x04 + public uint Reserved0 { get; private set; } + + /// + /// The length of the cabinet file in bytes. + /// + /// 0x08 + public uint CabinetSize { get; private set; } + + /// + /// UNKNOWN + /// + /// 0x0C + public uint Reserved1 { get; private set; } + + /// + /// UNKNOWN + /// + /// 0x10 + public uint FileOffset { get; private set; } + + /// + /// UNKNOWN + /// + /// 0x14 + public uint Reserved2 { get; private set; } + + /// + /// Minor cabinet version + /// + /// 0x18 + public byte MinorVersion { get; private set; } + + /// + /// Major cabinet version + /// + /// 0x19 + public byte MajorVersion { get; private set; } + + /// + /// Number of internal folders + /// + /// 0x1A + public ushort NumFolders { get; private set; } + + /// + /// Number of internal files + /// + /// 0x1C + public ushort NumFiles { get; private set; } + + /// + /// Header flags. + /// + /// 0x1E + /// + /// + /// + /// + /// + public HeaderFlags Flags { get; private set; } + + /// + /// The set ID of the cabinet. All cabinets in the same set should have + /// the same set ID. + /// + /// 0x20 + public ushort SetID { get; private set; } + + /// + /// The index number of the cabinet within the set. Numbering should + /// start from 0 for the first cabinet in the set, and increment by 1 for + /// each following cabinet. + /// + /// 0x22 + public ushort CabinetIndex { get; private set; } + + /// + /// Total size of the normal Cabinet header in bytes + /// + public const int Size = 0x24; + + #endregion + + #region Extended Header + + /// + /// The number of bytes reserved in the header area of the cabinet. + /// + /// If this is non-zero and flags has MSCAB_HDR_RESV set, this data can + /// be read by the calling application. It is of the given length, + /// located at offset (base_offset + MSCAB_HDR_RESV_OFFSET) in the + /// cabinet file. + /// + /// 0x24 + /// + public ushort HeaderReserved { get; private set; } + + /// + /// The number of bytes reserved in the folder area of the cabinet + /// + /// 0x26 + public byte FolderReserved { get; private set; } + + /// + /// The number of bytes reserved in the data area of the cabinet + /// + /// 0x27 + public byte DataReserved { get; private set; } + + /// + /// Total size of the extended Cabinet header in bytes + /// + public const int ExtendedSize = 0x04; + + #endregion + + /// + /// Private constructor + /// + private _CabinetHeader() { } + + /// + /// Create a _CabinetHeader from a byte array, if possible + /// + public static Error Create(byte[] buffer, out _CabinetHeader header) + { + header = null; + if (buffer == null || buffer.Length < Size) + return Error.MSPACK_ERR_READ; + + header = new _CabinetHeader(); + + header.Signature = BitConverter.ToUInt32(buffer, 0x00); + if (header.Signature != 0x4643534D) + return Error.MSPACK_ERR_SIGNATURE; + + header.Reserved0 = BitConverter.ToUInt32(buffer, 0x04); + header.CabinetSize = BitConverter.ToUInt32(buffer, 0x08); + header.Reserved1 = BitConverter.ToUInt32(buffer, 0x0C); + header.FileOffset = BitConverter.ToUInt32(buffer, 0x10); + header.Reserved2 = BitConverter.ToUInt32(buffer, 0x14); + + // Expect version 1.3, but don't validate + header.MinorVersion = buffer[0x18]; + header.MajorVersion = buffer[0x19]; + + header.NumFolders = BitConverter.ToUInt16(buffer, 0x1A); + if (header.NumFolders == 0) + return Error.MSPACK_ERR_DATAFORMAT; + + header.NumFiles = BitConverter.ToUInt16(buffer, 0x1C); + if (header.NumFiles == 0) + return Error.MSPACK_ERR_DATAFORMAT; + + header.Flags = (HeaderFlags)BitConverter.ToUInt16(buffer, 0x1E); + header.SetID = BitConverter.ToUInt16(buffer, 0x20); + header.CabinetIndex = BitConverter.ToUInt16(buffer, 0x20); + + return Error.MSPACK_ERR_OK; + } + + /// + /// Populate the extended header fields from buffer + /// + /// + public void PopulateExtendedHeader(byte[] buffer) + { + if (buffer.Length < ExtendedSize) + return; + + // Expect less than 60,000, but don't validate + HeaderReserved = BitConverter.ToUInt16(buffer, 0x24); + FolderReserved = buffer[0x26]; + DataReserved = buffer[0x27]; + } + } +} diff --git a/BurnOutSharp/External/libmspack/CAB/_FileHeader.cs b/BurnOutSharp/External/libmspack/CAB/_FileHeader.cs new file mode 100644 index 00000000..24fb8eb9 --- /dev/null +++ b/BurnOutSharp/External/libmspack/CAB/_FileHeader.cs @@ -0,0 +1,122 @@ +/* This file is part of libmspack. + * (C) 2003-2018 Stuart Caie. + * + * libmspack is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License (LGPL) version 2.1 + * + * For further details, see the file COPYING.LIB distributed with libmspack + */ + +using System; + +namespace LibMSPackSharp.CAB +{ + internal class _FileHeader + { + #region Fields + + /// + /// The uncompressed length of the file, in bytes. + /// + /// 0x00 + public uint UncompressedSize { get; private set; } + + /// + /// The uncompressed offset of this file in its folder. + /// + /// 0x04 + public uint FolderOffset { get; private set; } + + /// + /// Internal index of the folder + /// + /// 0x08 + public FileFlags FolderIndex { get; internal set; } + + /// + /// File's last modified date, day field. + /// + /// 0x0A + public byte LastModifiedDateDay { get; set; } + + /// + /// File's last modified date, month field. + /// + /// 0x0A + public byte LastModifiedDateMonth { get; set; } + + /// + /// File's last modified date, year field. + /// + /// 0x0A + public int LastModifiedDateYear { get; set; } + + /// + /// File's last modified time, hour field. + /// + /// 0x0C + public byte LastModifiedTimeHour { get; set; } + + /// + /// File's last modified time, minute field. + /// + /// 0x0C + public byte LastModifiedTimeMinute { get; set; } + + /// + /// File's last modified time, second field. + /// + /// 0x0C + public byte LastModifiedTimeSecond { get; set; } + + /// + /// File attributes. + /// + /// 0x0E + public FileAttributes Attributes { get; set; } + + /// + /// Size of the File header in bytes + /// + public const int Size = 0x10; + + #endregion + + /// + /// Private constructor + /// + private _FileHeader() { } + + /// + /// Create a _Folder from a byte array, if possible + /// + public static Error Create(byte[] buffer, out _FileHeader header) + { + header = null; + if (buffer == null || buffer.Length < Size) + return Error.MSPACK_ERR_READ; + + header = new _FileHeader(); + + header.UncompressedSize = BitConverter.ToUInt32(buffer, 0x00); + header.FolderOffset = BitConverter.ToUInt32(buffer, 0x04); + header.FolderIndex = (FileFlags)BitConverter.ToUInt16(buffer, 0x08); + + // Get date + ushort x = BitConverter.ToUInt16(buffer, 0x0A); + header.LastModifiedDateDay = (byte)(x & 0x1F); + header.LastModifiedDateMonth = (byte)((x >> 5) & 0xF); + header.LastModifiedDateYear = (x >> 9) + 1980; + + // Get time + x = BitConverter.ToUInt16(buffer, 0x0C); + header.LastModifiedTimeHour = (byte)(x >> 11); + header.LastModifiedTimeMinute = (byte)((x >> 5) & 0x3F); + header.LastModifiedTimeSecond = (byte)((x << 1) & 0x3E); + + header.Attributes = (FileAttributes)BitConverter.ToUInt16(buffer, 0x0E); + + return Error.MSPACK_ERR_OK; + } + } +} diff --git a/BurnOutSharp/External/libmspack/CAB/_FolderHeader.cs b/BurnOutSharp/External/libmspack/CAB/_FolderHeader.cs new file mode 100644 index 00000000..88d7a87f --- /dev/null +++ b/BurnOutSharp/External/libmspack/CAB/_FolderHeader.cs @@ -0,0 +1,72 @@ +/* This file is part of libmspack. + * (C) 2003-2018 Stuart Caie. + * + * libmspack is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License (LGPL) version 2.1 + * + * For further details, see the file COPYING.LIB distributed with libmspack + */ + +using System; + +namespace LibMSPackSharp.CAB +{ + internal class _FolderHeader + { + #region Fields + + /// + /// Cabinet offset of first datablock + /// + /// 0x00 + public uint DataOffset { get; internal set; } + + /// + /// The total number of data blocks used by this folder. This includes + /// data blocks present in other files, if this folder spans more than + /// one cabinet. + /// + /// 0x04 + public ushort NumBlocks { get; internal set; } + + /// + /// The compression format used by this folder. + /// + /// The macro MSCABD_COMP_METHOD() should be used on this field to get + /// the algorithm used. The macro MSCABD_COMP_LEVEL() should be used to get + /// the "compression level". + /// + /// 0x06 + public CompressionType CompType { get; private set; } + + /// + /// Size of the Folder header in bytes + /// + public const int Size = 0x08; + + #endregion + + /// + /// Private constructor + /// + private _FolderHeader() { } + + /// + /// Create a _Folder from a byte array, if possible + /// + public static Error Create(byte[] buffer, out _FolderHeader header) + { + header = null; + if (buffer == null || buffer.Length < Size) + return Error.MSPACK_ERR_READ; + + header = new _FolderHeader(); + + header.DataOffset = BitConverter.ToUInt32(buffer, 0x00); + header.NumBlocks = BitConverter.ToUInt16(buffer, 0x04); + header.CompType = (CompressionType)BitConverter.ToUInt16(buffer, 0x06); + + return Error.MSPACK_ERR_OK; + } + } +} diff --git a/BurnOutSharp/External/libmspack/CHM/Implementation.cs b/BurnOutSharp/External/libmspack/CHM/Implementation.cs index 2b114e3f..096d468d 100644 --- a/BurnOutSharp/External/libmspack/CHM/Implementation.cs +++ b/BurnOutSharp/External/libmspack/CHM/Implementation.cs @@ -1154,12 +1154,21 @@ namespace LibMSPackSharp.CHM /// private static int SysWrite(object file, byte[] buffer, int offset, int bytes) { - DecompressorImpl self = file as DecompressorImpl; - self.State.Offset += bytes; - if (self.State.OutputFileHandle != null) - return self.System.Write(self.State.OutputFileHandle, buffer, offset, bytes); + if (file is DecompressorImpl self) + { + self.State.Offset += (uint)bytes; + if (self.State.OutputFileHandle != null) + return self.System.Write(self.State.OutputFileHandle, buffer, offset, bytes); - return bytes; + return bytes; + } + else if (file is DefaultFileImpl impl) + { + return SystemImpl.DefaultSystem.Write(file, buffer, offset, bytes); + } + + // Unknown file to write to + return 0; } #endregion diff --git a/BurnOutSharp/External/libmspack/Compression/CompressionStream.cs b/BurnOutSharp/External/libmspack/Compression/CompressionStream.cs index 38424930..9b0d8fa4 100644 --- a/BurnOutSharp/External/libmspack/Compression/CompressionStream.cs +++ b/BurnOutSharp/External/libmspack/Compression/CompressionStream.cs @@ -140,77 +140,104 @@ namespace LibMSPackSharp.Compression InputEnd = 0; } - public void STORE_BITS(int inputPointer, int inputLength, uint bitBuffer, uint bitsLeft) + public void STORE_BITS(int inputPointer, int inputLength, uint bit_buffer, uint bits_left) { InputPointer = inputPointer; InputLength = inputLength; - BitBuffer = bitBuffer; - BitsLeft = bitsLeft; + BitBuffer = bit_buffer; + BitsLeft = bits_left; } - public void RESTORE_BITS(ref int inputPointer, ref int inputLength, ref uint bitBuffer, ref uint bitsLeft) + public void RESTORE_BITS(ref int inputPointer, ref int inputLength, ref uint bit_buffer, ref uint bits_left) { inputPointer = InputPointer; inputLength = InputLength; - bitBuffer = BitBuffer; - bitsLeft = BitsLeft; + bit_buffer = BitBuffer; + bits_left = BitsLeft; } - public void ENSURE_BITS(int nbits, ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer) + public void ENSURE_BITS(int nbits, ref int i_ptr, ref int i_end, ref uint bits_left, ref uint bit_buffer, bool msb) { - while (bitsLeft < nbits) + while (bits_left < nbits) { - READ_BYTES(ref i_ptr, ref i_end, ref bitsLeft, ref bitBuffer); + READ_BYTES(ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb); + if (Error != Error.MSPACK_ERR_OK) + return; } + + Error = Error.MSPACK_ERR_OK; } - public void READ_BITS(ref int val, int nbits, ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer) + public void READ_BITS(ref int val, int nbits, ref int i_ptr, ref int i_end, ref uint bits_left, ref uint bit_buffer, bool msb) { - ENSURE_BITS(nbits, ref i_ptr, ref i_end, ref bitsLeft, ref bitBuffer); - val = PEEK_BITS(nbits, bitBuffer); - REMOVE_BITS(nbits, ref bitsLeft, ref bitBuffer); + ENSURE_BITS(nbits, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb); + if (Error != Error.MSPACK_ERR_OK) + return; + + val = PEEK_BITS(nbits, bit_buffer, msb); + REMOVE_BITS(nbits, ref bits_left, ref bit_buffer, msb); + Error = Error.MSPACK_ERR_OK; } - public Error READ_MANY_BITS(ref uint val, byte bits, ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer) + public void READ_MANY_BITS(ref uint val, byte bits, ref int i_ptr, ref int i_end, ref uint bits_left, ref uint bit_buffer, bool msb) { byte needed = bits, bitrun; val = 0; while (needed > 0) { - if (bitsLeft <= (BITBUF_WIDTH - 16)) + if (bits_left <= (BITBUF_WIDTH - 16)) { - Error error = READ_BYTES(ref i_ptr, ref i_end, ref bitsLeft, ref bitBuffer); - if (error != Error.MSPACK_ERR_OK) - return error; + READ_BYTES(ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb); + if (Error != Error.MSPACK_ERR_OK) + return; } - bitrun = (byte)((bitsLeft < needed) ? bitsLeft : needed); - val = (uint)((val << bitrun) | PEEK_BITS(bitrun, bitBuffer)); - REMOVE_BITS(bitrun, ref bitsLeft, ref bitBuffer); + bitrun = (byte)((bits_left < needed) ? bits_left : needed); + val = (uint)((val << bitrun) | PEEK_BITS(bitrun, bit_buffer, msb)); + REMOVE_BITS(bitrun, ref bits_left, ref bit_buffer, msb); needed -= bitrun; } - return Error.MSPACK_ERR_OK; + Error = Error.MSPACK_ERR_OK; } - public int PEEK_BITS(int nbits, uint bitBuffer) + public int PEEK_BITS(int nbits, uint bit_buffer, bool msb) { - return (int)(bitBuffer & ((1 << (nbits)) - 1)); + if (msb) + return (int)(bit_buffer >> (BITBUF_WIDTH - (nbits))); + else + return (int)(bit_buffer & ((1 << (nbits)) - 1)); } - public void REMOVE_BITS(int nbits, ref uint bitsLeft, ref uint bitBuffer) + public void REMOVE_BITS(int nbits, ref uint bits_left, ref uint bit_buffer, bool msb) { - bitBuffer >>= nbits; - bitsLeft -= (uint)nbits; + if (msb) + { + bit_buffer <<= nbits; + bits_left -= (uint)nbits; + } + else + { + bit_buffer >>= nbits; + bits_left -= (uint)nbits; + } } - public void INJECT_BITS(uint bitdata, int nbits, ref uint bitsLeft, ref uint bitBuffer) + public void INJECT_BITS(uint bitdata, int nbits, ref uint bits_left, ref uint bit_buffer, bool msb) { - bitBuffer |= bitdata << (int)bitsLeft; - bitsLeft += (uint)nbits; + if (msb) + { + bit_buffer |= bitdata << (int)bits_left; + bits_left += (uint)nbits; + } + else + { + bit_buffer |= bitdata << (int)bits_left; + bits_left += (uint)nbits; + } } - public abstract Error READ_BYTES(ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer); + public abstract void READ_BYTES(ref int i_ptr, ref int i_end, ref uint bits_left, ref uint bit_buffer, bool msb); // lsb_bit_mask[n] = (1 << n) - 1 */ private static readonly ushort[] lsb_bit_mask = new ushort[17] @@ -224,54 +251,63 @@ namespace LibMSPackSharp.Compression return (int)(BitBuffer & lsb_bit_mask[nbits]); } - public void READ_BITS_T(ref int val, int nbits, ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer) + public void READ_BITS_T(ref int val, int nbits, ref int i_ptr, ref int i_end, ref uint bits_left, ref uint bit_buffer, bool msb) { - ENSURE_BITS(nbits, ref i_ptr, ref i_end, ref bitsLeft, ref bitBuffer); + ENSURE_BITS(nbits, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb); + if (Error != Error.MSPACK_ERR_OK) + return; + val = PEEK_BITS_T(nbits); - REMOVE_BITS(nbits, ref bitsLeft, ref bitBuffer); + REMOVE_BITS(nbits, ref bits_left, ref bit_buffer, msb); + Error = Error.MSPACK_ERR_OK; } - public Error READ_IF_NEEDED(ref int iPtr, ref int iEnd) + public void READ_IF_NEEDED(ref int i_ptr, ref int i_end) { - if (iPtr >= iEnd) + if (i_ptr >= i_end) { - if (ReadInput(this) != Error.MSPACK_ERR_OK) - return Error; + ReadInput(); + if (Error != Error.MSPACK_ERR_OK) + return; - iPtr = InputPointer; - iEnd = InputLength; + i_ptr = InputPointer; + i_end = InputLength; } - return Error.MSPACK_ERR_OK; + Error = Error.MSPACK_ERR_OK; } - private static Error ReadInput(CompressionStream p) + private void ReadInput() { - int read = p.Sys.Read(p.Input, p.InputBuffer, 0, (int)p.InputBufferSize); + int read = Sys.Read(Input, InputBuffer, 0, (int)InputBufferSize); if (read < 0) - return p.Error = Error.MSPACK_ERR_READ; + { + Error = Error.MSPACK_ERR_READ; + return; + } // We might overrun the input stream by asking for bits we don't use, // so fake 2 more bytes at the end of input if (read == 0) { - if (p.InputEnd != 0) + if (InputEnd != 0) { Console.WriteLine("out of input bytes"); - return p.Error = Error.MSPACK_ERR_READ; + Error = Error.MSPACK_ERR_READ; + return; } else { read = 2; - p.InputBuffer[0] = p.InputBuffer[1] = 0; - p.InputEnd = 1; + InputBuffer[0] = InputBuffer[1] = 0; + InputEnd = 1; } } // Update i_ptr and i_end - p.InputPointer = 0; - p.InputLength = read; - return Error.MSPACK_ERR_OK; + InputPointer = 0; + InputLength = read; + Error = Error.MSPACK_ERR_OK; } #endregion @@ -284,33 +320,50 @@ namespace LibMSPackSharp.Compression /// Decodes the next huffman symbol from the input bitstream into var. /// Do not use this macro on a table unless build_decode_table() succeeded. /// - public int READ_HUFFSYM(ushort[] decodingTable, ref uint var, int tablebits, byte[] lengthTable, int maxsymbols, ref int i, ref ushort sym, ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer) + public int READ_HUFFSYM(ushort[] decodingTable, ref uint var, int tablebits, byte[] lengthTable, int maxsymbols, ref int i, ref int i_ptr, ref int i_end, ref uint bits_left, ref uint bit_buffer, bool msb) { - ENSURE_BITS(HUFF_MAXBITS, ref i_ptr, ref i_end, ref bitsLeft, ref bitBuffer); - sym = decodingTable[PEEK_BITS(tablebits, bitBuffer)]; + ENSURE_BITS(HUFF_MAXBITS, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb); + if (Error != Error.MSPACK_ERR_OK) + return (int)Error; + + ushort sym = decodingTable[PEEK_BITS(tablebits, bit_buffer, msb)]; if (sym >= maxsymbols) { - int ret = HUFF_TRAVERSE(decodingTable, tablebits, maxsymbols, ref i, ref sym, bitBuffer); + int ret = HUFF_TRAVERSE(decodingTable, tablebits, maxsymbols, ref i, ref sym, bit_buffer, msb); if (ret != 0) return ret; } var = sym; i = lengthTable[sym]; - REMOVE_BITS(i, ref bitsLeft, ref bitBuffer); + REMOVE_BITS(i, ref bits_left, ref bit_buffer, msb); return (int)Error.MSPACK_ERR_OK; } - public int HUFF_TRAVERSE(ushort[] decodingTable, int tablebits, int maxsymbols, ref int i, ref ushort sym, uint bitBuffer) + public int HUFF_TRAVERSE(ushort[] decodingTable, int tablebits, int maxsymbols, ref int i, ref ushort sym, uint bit_buffer, bool msb) { - i = tablebits - 1; - do + if (msb) { - if (i++ > HUFF_MAXBITS) - return HUFF_ERROR(); + i = 1 << (BITBUF_WIDTH - tablebits); + do + { + if ((i >>= 1) == 0) + return HUFF_ERROR(); - sym = decodingTable[(sym << 1) | ((bitBuffer >> i) & 1)]; - } while (sym >= maxsymbols); + sym = decodingTable[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)]; + } while (sym >= maxsymbols); + } + else + { + i = tablebits - 1; + do + { + if (i++ > HUFF_MAXBITS) + return HUFF_ERROR(); + + try { sym = decodingTable[(sym << 1) | ((bit_buffer >> i) & 1)]; } catch { } + } while (sym >= maxsymbols); + } return (int)Error.MSPACK_ERR_OK; } @@ -330,94 +383,84 @@ namespace LibMSPackSharp.Compression /// The table to fill up with decoded symbols and pointers. /// Should be ((1< - /// 0 for OK or 1 for error - public static int MakeDecodeTable(uint nsyms, uint nbits, byte[] length, ushort[] table) + /// true for OK or false for error + public static bool MakeDecodeTable(int nsyms, int nbits, byte[] length, ushort[] table, bool msb) { - ushort sym, next_symbol; - uint leaf, fill; - uint reverse; - byte bit_num; - uint pos = 0; // The current position in the decode table - uint table_mask = (uint)(1 << (int)nbits); - uint bit_mask = table_mask >> 1; // Don't do 0 length codes + int next_symbol; + long leaf, fill; + long reverse; // Only used when !msb + long pos = 0; // The current position in the decode table + int table_mask = 1 << nbits; + long bit_mask = table_mask >> 1; // Don't do 0 length codes // Fill entries for codes short enough for a direct mapping - for (bit_num = 1; bit_num <= nbits; bit_num++) + for (byte bit_num = 1; bit_num <= nbits; bit_num++) { - for (sym = 0; sym < nsyms; sym++) + for (ushort sym = 0; sym < nsyms; sym++) { if (length[sym] != bit_num) continue; - // Reverse the significant bits - fill = length[sym]; - reverse = pos >> (int)(nbits - fill); - leaf = 0; - - do + if (msb) { - leaf <<= 1; - leaf |= reverse & 1; - reverse >>= 1; - } while (--fill != 0); + leaf = pos; + } + else + { + // Reverse the significant bits + fill = length[sym]; + reverse = pos >> (nbits - (byte)fill); + leaf = 0; + + do + { + leaf <<= 1; + leaf |= reverse & 1; + reverse >>= 1; + } while (--fill != 0); + } if ((pos += bit_mask) > table_mask) - return 1; // Table overrun + return false; // Table overrun // Fill all possible lookups of this symbol with the symbol itself - fill = bit_mask; - next_symbol = (ushort)(1 << bit_num); - - do + if (msb) { - table[leaf] = sym; - leaf += next_symbol; - } while (--fill != 0); + for (fill = bit_mask; fill-- > 0;) + { + table[leaf++] = sym; + } + } + else + { + fill = bit_mask; + next_symbol = 1 << bit_num; + + do + { + table[leaf] = sym; + leaf += next_symbol; + } while (--fill != 0); + } } + bit_mask >>= 1; } // Exit with success if table is now complete if (pos == table_mask) - return 0; + return true; // Mark all remaining table entries as unused - for (sym = (ushort)pos; sym < table_mask; sym++) + for (long sym = pos; sym < table_mask; sym++) { - reverse = sym; - leaf = 0; - fill = nbits; - - do + if (msb) { - leaf <<= 1; - leaf |= reverse & 1; - reverse >>= 1; - } while (--fill != 0); - - table[leaf] = 0xFFFF; - } - - // next_symbol = base of allocation for long codes - next_symbol = (ushort)(((table_mask >> 1) < nsyms) ? nsyms : (table_mask >> 1)); - - // Give ourselves room for codes to grow by up to 16 more bits. - // codes now start at bit nbits+16 and end at (nbits+16-codelength) - pos <<= 16; - table_mask <<= 16; - bit_mask = 1 << 15; - - for (bit_num = (byte)(nbits + 1); bit_num <= HUFF_MAXBITS; bit_num++) - { - for (sym = 0; sym < nsyms; sym++) + table[sym] = 0xFFFF; + } + else { - if (length[sym] != bit_num) - continue; - if (pos >= table_mask) - return 1; // Table overflow - - // Leaf = the first nbits of the code, reversed - reverse = pos >> 16; + reverse = sym; leaf = 0; fill = nbits; @@ -428,19 +471,60 @@ namespace LibMSPackSharp.Compression reverse >>= 1; } while (--fill != 0); + table[leaf] = 0xFFFF; + } + } + + // next_symbol = base of allocation for long codes + next_symbol = ((table_mask >> 1) < nsyms) ? nsyms : (table_mask >> 1); + + // Give ourselves room for codes to grow by up to 16 more bits. + // codes now start at bit nbits+16 and end at (nbits+16-codelength) + pos <<= 16; + table_mask <<= 16; + bit_mask = 1 << 15; + + for (int bit_num = nbits + 1; bit_num <= HUFF_MAXBITS; bit_num++) + { + for (ushort sym = 0; sym < nsyms; sym++) + { + if (length[sym] != bit_num) + continue; + if (pos >= table_mask) + return false; // Table overflow + + if (msb) + { + leaf = pos >> 16; + } + else + { + // leaf = the first nbits of the code, reversed + reverse = pos >> 16; + leaf = 0; + fill = nbits; + + do + { + leaf <<= 1; + leaf |= reverse & 1; + reverse >>= 1; + } while (--fill != 0); + } + for (fill = 0; fill < (bit_num - nbits); fill++) { - // Ff this path hasn't been taken yet, 'allocate' two entries + // If this path hasn't been taken yet, 'allocate' two entries if (table[leaf] == 0xFFFF) { table[(next_symbol << 1)] = 0xFFFF; table[(next_symbol << 1) + 1] = 0xFFFF; - table[leaf] = next_symbol++; + table[leaf] = (ushort)next_symbol++; } // Follow the path and select either left or right for next bit - leaf = (uint)(table[leaf] << 1); - if (((pos >> (int)(15 - fill)) & 1) != 0) + leaf = table[leaf] << 1; + if (((pos >> (15 - (int)fill)) & 1) != 0) leaf++; } @@ -452,7 +536,7 @@ namespace LibMSPackSharp.Compression } // Full table? - return (pos == table_mask) ? 0 : 1; + return pos == table_mask; } #endregion diff --git a/BurnOutSharp/External/libmspack/Compression/LZX.cs b/BurnOutSharp/External/libmspack/Compression/LZX.cs index 550a12df..5b8fe037 100644 --- a/BurnOutSharp/External/libmspack/Compression/LZX.cs +++ b/BurnOutSharp/External/libmspack/Compression/LZX.cs @@ -95,13 +95,13 @@ namespace LibMSPackSharp.Compression // LZX huffman defines: tweak tablebits as desired public const int LZX_PRETREE_MAXSYMBOLS = LZX_PRETREE_NUM_ELEMENTS; - public const int LZX_PRETREE_TABLEBITS = 6; + public const byte LZX_PRETREE_TABLEBITS = 6; public const int LZX_MAINTREE_MAXSYMBOLS = LZX_NUM_CHARS + 290 * 8; - public const int LZX_MAINTREE_TABLEBITS = 12; + public const byte LZX_MAINTREE_TABLEBITS = 12; public const int LZX_LENGTH_MAXSYMBOLS = LZX_NUM_SECONDARY_LENGTHS + 1; - public const int LZX_LENGTH_TABLEBITS = 12; + public const byte LZX_LENGTH_TABLEBITS = 12; public const int LZX_ALIGNED_MAXSYMBOLS = LZX_ALIGNED_NUM_ELEMENTS; - public const int LZX_ALIGNED_TABLEBITS = 7; + public const byte LZX_ALIGNED_TABLEBITS = 7; public const int LZX_LENTABLE_SAFETY = 64; // Table decoding overruns are allowed public const int LZX_FRAME_SIZE = 32768; // The size of a frame in LZX @@ -433,7 +433,6 @@ namespace LibMSPackSharp.Compression // Bitstream and huffman reading variables uint bit_buffer = 0, bits_left = 0; int i_ptr = 0, i_end = 0; - ushort sym = 0; int match_length, extra, verbatim_bits = 0, bytes_todo; int this_run, j = 0, warned = 0; @@ -502,8 +501,11 @@ namespace LibMSPackSharp.Compression // LZX DELTA format has chunk_size, not present in LZX format if (lzx.IsDelta) { - lzx.ENSURE_BITS(16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); - lzx.REMOVE_BITS(16, ref bits_left, ref bit_buffer); + lzx.ENSURE_BITS(16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; + + lzx.REMOVE_BITS(16, ref bits_left, ref bit_buffer, msb: true); } // Read header if necessary @@ -512,11 +514,19 @@ namespace LibMSPackSharp.Compression /* read 1 bit. if bit=0, intel filesize = 0. * if bit=1, read intel filesize (32 bits) */ j = 0; - lzx.READ_BITS(ref i, 1, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + lzx.READ_BITS(ref i, 1, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; + if (i != 0) { - lzx.READ_BITS(ref i, 16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); - lzx.READ_BITS(ref j, 16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + lzx.READ_BITS(ref i, 16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; + + lzx.READ_BITS(ref j, 16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; } lzx.IntelFileSize = (i << 16) | j; @@ -549,10 +559,19 @@ namespace LibMSPackSharp.Compression // Read block type (3 bits) and block length (24 bits) int blockType = 0; - lzx.READ_BITS(ref blockType, 3, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + lzx.READ_BITS(ref blockType, 3, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; + lzx.BlockType = (LZXBlockType)blockType; - lzx.READ_BITS(ref i, 16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); - lzx.READ_BITS(ref j, 8, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + lzx.READ_BITS(ref i, 16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; + + lzx.READ_BITS(ref j, 8, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; + lzx.BlockRemaining = lzx.BlockLength = (uint)((i << 8) | j); // Console.WriteLine("new block t%d len %u", lzx.BlockType, lzx.BlockLength); @@ -563,12 +582,15 @@ namespace LibMSPackSharp.Compression case LZXBlockType.LZX_BLOCKTYPE_ALIGNED: for (i = 0; i < 8; i++) { - lzx.READ_BITS(ref j, 3, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + lzx.READ_BITS(ref j, 3, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; + lzx.ALIGNED_len[i] = (byte)j; } //BUILD_TABLE(ALIGNED) - if (LZXDStream.MakeDecodeTable(LZX_ALIGNED_MAXSYMBOLS, LZX_ALIGNED_TABLEBITS, lzx.ALIGNED_len, lzx.ALIGNED_table) != 0) + if (!LZXDStream.MakeDecodeTable(LZX_ALIGNED_MAXSYMBOLS, LZX_ALIGNED_TABLEBITS, lzx.ALIGNED_len, lzx.ALIGNED_table, msb: true)) { Console.WriteLine("failed to build ALIGNED table"); return lzx.Error = Error.MSPACK_ERR_DECRUNCH; @@ -589,7 +611,7 @@ namespace LibMSPackSharp.Compression lzx.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); //BUILD_TABLE(MAINTREE) - if (LZXDStream.MakeDecodeTable(LZX_MAINTREE_MAXSYMBOLS, LZX_MAINTREE_TABLEBITS, lzx.MAINTREE_len, lzx.MAINTREE_table) != 0) + if (!LZXDStream.MakeDecodeTable(LZX_MAINTREE_MAXSYMBOLS, LZX_MAINTREE_TABLEBITS, lzx.MAINTREE_len, lzx.MAINTREE_table, msb: true)) { Console.WriteLine("failed to build MAINTREE table"); return lzx.Error = Error.MSPACK_ERR_DECRUNCH; @@ -609,7 +631,7 @@ namespace LibMSPackSharp.Compression //BUILD_TABLE_MAYBE_EMPTY(LENGTH) lzx.LENGTH_empty = 0; - if (LZXDStream.MakeDecodeTable(LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS, lzx.LENGTH_len, lzx.LENGTH_table) != 0) + if (!LZXDStream.MakeDecodeTable(LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS, lzx.LENGTH_len, lzx.LENGTH_table, msb: true)) { for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++) { @@ -642,7 +664,7 @@ namespace LibMSPackSharp.Compression lzx.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); //BUILD_TABLE(MAINTREE) - if (LZXDStream.MakeDecodeTable(LZX_MAINTREE_MAXSYMBOLS, LZX_MAINTREE_TABLEBITS, lzx.MAINTREE_len, lzx.MAINTREE_table) != 0) + if (!LZXDStream.MakeDecodeTable(LZX_MAINTREE_MAXSYMBOLS, LZX_MAINTREE_TABLEBITS, lzx.MAINTREE_len, lzx.MAINTREE_table, msb: true)) { Console.WriteLine("failed to build MAINTREE table"); return lzx.Error = Error.MSPACK_ERR_DECRUNCH; @@ -662,7 +684,7 @@ namespace LibMSPackSharp.Compression //BUILD_TABLE_MAYBE_EMPTY(LENGTH) lzx.LENGTH_empty = 0; - if (LZXDStream.MakeDecodeTable(LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS, lzx.LENGTH_len, lzx.LENGTH_table) != 0) + if (!LZXDStream.MakeDecodeTable(LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS, lzx.LENGTH_len, lzx.LENGTH_table, msb: true)) { for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++) { @@ -685,7 +707,11 @@ namespace LibMSPackSharp.Compression // Read 1-16 (not 0-15) bits to align to bytes if (bits_left == 0) - lzx.ENSURE_BITS(16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + { + lzx.ENSURE_BITS(16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; + } bits_left = 0; bit_buffer = 0; @@ -728,7 +754,9 @@ namespace LibMSPackSharp.Compression case LZXBlockType.LZX_BLOCKTYPE_VERBATIM: while (this_run > 0) { - lzx.READ_HUFFSYM(lzx.MAINTREE_table, ref main_element, LZX_MAINTREE_TABLEBITS, lzx.MAINTREE_len, LZX_MAINTREE_MAXSYMBOLS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + if (lzx.READ_HUFFSYM(lzx.MAINTREE_table, ref main_element, LZX_MAINTREE_TABLEBITS, lzx.MAINTREE_len, LZX_MAINTREE_MAXSYMBOLS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0) + return Error.MSPACK_ERR_DECRUNCH; + if (main_element < LZX_NUM_CHARS) { // Literal: 0 to LZX_NUM_CHARS-1 @@ -750,7 +778,9 @@ namespace LibMSPackSharp.Compression return lzx.Error = Error.MSPACK_ERR_DECRUNCH; } - lzx.READ_HUFFSYM(lzx.LENGTH_table, ref length_footer, LZX_LENGTH_TABLEBITS, lzx.LENGTH_len, LZX_LENGTH_MAXSYMBOLS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + if (lzx.READ_HUFFSYM(lzx.LENGTH_table, ref length_footer, LZX_LENGTH_TABLEBITS, lzx.LENGTH_len, LZX_LENGTH_MAXSYMBOLS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0) + return Error.MSPACK_ERR_DECRUNCH; + match_length += (int)length_footer; } @@ -772,7 +802,10 @@ namespace LibMSPackSharp.Compression else { extra = (match_offset >= 36) ? 17 : extra_bits[match_offset]; - lzx.READ_BITS(ref verbatim_bits, extra, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + lzx.READ_BITS(ref verbatim_bits, extra, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; + match_offset = (uint)(position_base[match_offset] - 2 + verbatim_bits); } } @@ -786,21 +819,31 @@ namespace LibMSPackSharp.Compression { // >3: verbatim and aligned bits extra -= 3; - lzx.READ_BITS(ref verbatim_bits, extra, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + lzx.READ_BITS(ref verbatim_bits, extra, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; + match_offset += (uint)(verbatim_bits << 3); - lzx.READ_HUFFSYM(lzx.ALIGNED_table, ref aligned_bits, LZX_ALIGNED_TABLEBITS, lzx.ALIGNED_len, LZX_ALIGNED_MAXSYMBOLS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + if (lzx.READ_HUFFSYM(lzx.ALIGNED_table, ref aligned_bits, LZX_ALIGNED_TABLEBITS, lzx.ALIGNED_len, LZX_ALIGNED_MAXSYMBOLS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0) + return Error.MSPACK_ERR_DECRUNCH; + match_offset += aligned_bits; } else if (extra == 3) { // 3: aligned bits only - lzx.READ_HUFFSYM(lzx.ALIGNED_table, ref aligned_bits, LZX_ALIGNED_TABLEBITS, lzx.ALIGNED_len, LZX_ALIGNED_MAXSYMBOLS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + if (lzx.READ_HUFFSYM(lzx.ALIGNED_table, ref aligned_bits, LZX_ALIGNED_TABLEBITS, lzx.ALIGNED_len, LZX_ALIGNED_MAXSYMBOLS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0) + return Error.MSPACK_ERR_DECRUNCH; + match_offset += aligned_bits; } else if (extra > 0) { // 1-2: verbatim bits only - lzx.READ_BITS(ref verbatim_bits, extra, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + lzx.READ_BITS(ref verbatim_bits, extra, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; + match_offset += (uint)verbatim_bits; } else @@ -819,28 +862,43 @@ namespace LibMSPackSharp.Compression if (match_length == LZX_MAX_MATCH && lzx.IsDelta) { int extra_len = 0; - lzx.ENSURE_BITS(3, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); /* 4 entry huffman tree */ - if (lzx.PEEK_BITS(1, bit_buffer) == 0) + + /* 4 entry huffman tree */ + lzx.ENSURE_BITS(3, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; + + if (lzx.PEEK_BITS(1, bit_buffer, msb: true) == 0) { - lzx.REMOVE_BITS(1, ref bits_left, ref bit_buffer); /* '0' . 8 extra length bits */ - lzx.READ_BITS(ref extra_len, 8, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + lzx.REMOVE_BITS(1, ref bits_left, ref bit_buffer, msb: true); /* '0' . 8 extra length bits */ + lzx.READ_BITS(ref extra_len, 8, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; } - else if (lzx.PEEK_BITS(2, bit_buffer) == 2) + else if (lzx.PEEK_BITS(2, bit_buffer, msb: true) == 2) { - lzx.REMOVE_BITS(2, ref bits_left, ref bit_buffer); /* '10' . 10 extra length bits + 0x100 */ - lzx.READ_BITS(ref extra_len, 10, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + lzx.REMOVE_BITS(2, ref bits_left, ref bit_buffer, msb: true); /* '10' . 10 extra length bits + 0x100 */ + lzx.READ_BITS(ref extra_len, 10, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; + extra_len += 0x100; } - else if (lzx.PEEK_BITS(3, bit_buffer) == 6) + else if (lzx.PEEK_BITS(3, bit_buffer, msb: true) == 6) { - lzx.REMOVE_BITS(3, ref bits_left, ref bit_buffer); /* '110' . 12 extra length bits + 0x500 */ - lzx.READ_BITS(ref extra_len, 12, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + lzx.REMOVE_BITS(3, ref bits_left, ref bit_buffer, msb: true); /* '110' . 12 extra length bits + 0x500 */ + lzx.READ_BITS(ref extra_len, 12, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; + extra_len += 0x500; } else { - lzx.REMOVE_BITS(3, ref bits_left, ref bit_buffer); /* '111' . 15 extra length bits */ - lzx.READ_BITS(ref extra_len, 15, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + lzx.REMOVE_BITS(3, ref bits_left, ref bit_buffer, msb: true); /* '111' . 15 extra length bits */ + lzx.READ_BITS(ref extra_len, 15, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; } match_length += extra_len; @@ -960,10 +1018,14 @@ namespace LibMSPackSharp.Compression // Re-align input bitstream if (bits_left > 0) - lzx.ENSURE_BITS(16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + { + lzx.ENSURE_BITS(16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; + } if ((bits_left & 15) != 0) - lzx.REMOVE_BITS((int)(bits_left & 15), ref bits_left, ref bit_buffer); + lzx.REMOVE_BITS((int)(bits_left & 15), ref bits_left, ref bit_buffer, msb: true); // Check that we've used all of the previous frame first if (lzx.OutputPointer != lzx.OutputLength) @@ -1072,7 +1134,6 @@ namespace LibMSPackSharp.Compression // Bit buffer and huffman symbol decode variables uint bit_buffer = 0, bits_left = 0; int i = 0; - ushort sym = 0; int i_ptr = 0, i_end = 0; int x, y = 0; @@ -1083,12 +1144,15 @@ namespace LibMSPackSharp.Compression // Read lengths for pretree (20 symbols, lengths stored in fixed 4 bits) for (x = 0; x < 20; x++) { - lzx.READ_BITS(ref y, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + lzx.READ_BITS(ref y, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; + lzx.PRETREE_len[x] = (byte)y; } //BUILD_TABLE(PRETREE) - if (LZXDStream.MakeDecodeTable(LZX_PRETREE_MAXSYMBOLS, LZX_PRETREE_TABLEBITS, lzx.PRETREE_len, lzx.PRETREE_table) != 0) + if (!LZXDStream.MakeDecodeTable(LZX_PRETREE_MAXSYMBOLS, LZX_PRETREE_TABLEBITS, lzx.PRETREE_len, lzx.PRETREE_table, msb: true)) { Console.WriteLine("failed to build PRETREE table"); return lzx.Error = Error.MSPACK_ERR_DECRUNCH; @@ -1096,11 +1160,17 @@ namespace LibMSPackSharp.Compression for (x = (int)first; x < last;) { - lzx.READ_HUFFSYM(lzx.PRETREE_table, ref z, LZX_PRETREE_TABLEBITS, lzx.PRETREE_len, LZX_PRETREE_MAXSYMBOLS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + if (lzx.READ_HUFFSYM(lzx.PRETREE_table, ref z, LZX_PRETREE_TABLEBITS, lzx.PRETREE_len, LZX_PRETREE_MAXSYMBOLS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0) + return Error.MSPACK_ERR_OK; + if (z == 17) { // Code = 17, run of ([read 4 bits]+4) zeros - lzx.READ_BITS(ref y, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); y += 4; + lzx.READ_BITS(ref y, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; + + y += 4; while (y-- != 0) { lens[x++] = 0; @@ -1109,7 +1179,11 @@ namespace LibMSPackSharp.Compression else if (z == 18) { // Code = 18, run of ([read 5 bits]+20) zeros - lzx.READ_BITS(ref y, 5, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); y += 20; + lzx.READ_BITS(ref y, 5, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; + + y += 20; while (y-- != 0) { lens[x++] = 0; @@ -1118,8 +1192,14 @@ namespace LibMSPackSharp.Compression else if (z == 19) { // Code = 19, run of ([read 1 bit]+4) [read huffman symbol] - lzx.READ_BITS(ref y, 1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); y += 4; - lzx.READ_HUFFSYM(lzx.PRETREE_table, ref z, LZX_PRETREE_TABLEBITS, lzx.PRETREE_len, LZX_PRETREE_MAXSYMBOLS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + lzx.READ_BITS(ref y, 1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; + + y += 4; + if (lzx.READ_HUFFSYM(lzx.PRETREE_table, ref z, LZX_PRETREE_TABLEBITS, lzx.PRETREE_len, LZX_PRETREE_MAXSYMBOLS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0) + return Error.MSPACK_ERR_DECRUNCH; + z = lens[x] - z; if (z < 0) z += 17; diff --git a/BurnOutSharp/External/libmspack/Compression/LZXDStream.cs b/BurnOutSharp/External/libmspack/Compression/LZXDStream.cs index 8de76563..2e507714 100644 --- a/BurnOutSharp/External/libmspack/Compression/LZXDStream.cs +++ b/BurnOutSharp/External/libmspack/Compression/LZXDStream.cs @@ -137,21 +137,21 @@ namespace LibMSPackSharp.Compression // This is used purely for doing the intel E8 transform public byte[] e8_buf { get; set; } = new byte[LZX.LZX_FRAME_SIZE]; - public override Error READ_BYTES(ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer) + public override void READ_BYTES(ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer, bool msb) { - Error error = READ_IF_NEEDED(ref i_ptr, ref i_end); - if (error != Error.MSPACK_ERR_OK) - return error; + READ_IF_NEEDED(ref i_ptr, ref i_end); + if (Error != Error.MSPACK_ERR_OK) + return; byte b0 = InputBuffer[i_ptr++]; - error = READ_IF_NEEDED(ref i_ptr, ref i_end); - if (error != Error.MSPACK_ERR_OK) - return error; + READ_IF_NEEDED(ref i_ptr, ref i_end); + if (Error != Error.MSPACK_ERR_OK) + return; byte b1 = InputBuffer[i_ptr++]; - INJECT_BITS((uint)((b1 << 8) | b0), 16, ref bitsLeft, ref bitBuffer); - return Error.MSPACK_ERR_OK; + INJECT_BITS((uint)((b1 << 8) | b0), 16, ref bitsLeft, ref bitBuffer, msb); + Error = Error.MSPACK_ERR_OK; } public override int HUFF_ERROR() => (int)(Error = Error.MSPACK_ERR_DECRUNCH); diff --git a/BurnOutSharp/External/libmspack/Compression/MSZIP.cs b/BurnOutSharp/External/libmspack/Compression/MSZIP.cs index 61403587..ff4f6fc1 100644 --- a/BurnOutSharp/External/libmspack/Compression/MSZIP.cs +++ b/BurnOutSharp/External/libmspack/Compression/MSZIP.cs @@ -27,27 +27,12 @@ namespace LibMSPackSharp.Compression // If there are less direct lookup entries than symbols, the longer // code pointers will be <= maxsymbols. This must not happen, or we // will decode entries badly - public static int MSZIP_LITERAL_TABLESIZE - { - get - { - if ((1 << MSZIP_LITERAL_TABLEBITS) < (MSZIP_LITERAL_MAXSYMBOLS * 2)) - return (MSZIP_LITERAL_MAXSYMBOLS * 4); - else - return ((1 << MSZIP_LITERAL_TABLEBITS) + (MSZIP_LITERAL_MAXSYMBOLS * 2)); - } - } - public static int MSZIP_DISTANCE_TABLESIZE - { - get - { - if ((1 << MSZIP_DISTANCE_TABLEBITS) < (MSZIP_DISTANCE_MAXSYMBOLS * 2)) - return (MSZIP_DISTANCE_MAXSYMBOLS * 4); - else - return ((1 << MSZIP_DISTANCE_TABLEBITS) + (MSZIP_DISTANCE_MAXSYMBOLS * 2)); - } - } + //public const int MSZIP_LITERAL_TABLESIZE = (MSZIP_LITERAL_MAXSYMBOLS * 4); + public const int MSZIP_LITERAL_TABLESIZE = ((1 << MSZIP_LITERAL_TABLEBITS) + (MSZIP_LITERAL_MAXSYMBOLS * 2)); + + //public const int MSZIP_DISTANCE_TABLESIZE = (MSZIP_DISTANCE_MAXSYMBOLS * 4); + public const int MSZIP_DISTANCE_TABLESIZE = ((1 << MSZIP_DISTANCE_TABLEBITS) + (MSZIP_DISTANCE_MAXSYMBOLS * 2)); /// /// Match lengths for literal codes 257.. 285 @@ -203,12 +188,15 @@ namespace LibMSPackSharp.Compression // Skip to next read 'CK' header i = (int)(bits_left & 7); - zip.REMOVE_BITS(i, ref bits_left, ref bit_buffer); // Align to bytestream + zip.REMOVE_BITS(i, ref bits_left, ref bit_buffer, msb: false); // Align to bytestream state = 0; do { - zip.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + zip.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false); + if (zip.Error != Error.MSPACK_ERR_OK) + return zip.Error; + if (i == 'C') state = 1; else if ((state == 1) && (i == 'K')) @@ -224,7 +212,7 @@ namespace LibMSPackSharp.Compression if ((error = (int)Inflate(zip)) != 0) { - Console.WriteLine($"inflate error {error}"); + Console.WriteLine($"inflate error {(InflateErrorCode)error}"); if (zip.RepairMode) { // Recover partially-inflated buffers @@ -249,8 +237,16 @@ namespace LibMSPackSharp.Compression // Write a frame i = (out_bytes < zip.BytesOutput) ? (int)out_bytes : zip.BytesOutput; - if (zip.Sys.Write(zip.Output, zip.Window, zip.OutputPointer, i) != i) - return zip.Error = Error.MSPACK_ERR_WRITE; + if (zip.Output is DefaultFileImpl) + { + if (SystemImpl.DefaultSystem.Write(zip.Output, zip.Window, zip.OutputPointer, i) != i) + return zip.Error = Error.MSPACK_ERR_WRITE; + } + else + { + if (zip.Sys.Write(zip.Output, zip.Window, zip.OutputPointer, i) != i) + return zip.Error = Error.MSPACK_ERR_WRITE; + } // mspack errors (i.e. read errors) are fatal and can't be recovered if (error > 0 && zip.RepairMode) @@ -288,20 +284,30 @@ namespace LibMSPackSharp.Compression // Align to bytestream, read block_len i = (int)(bits_left & 7); - zip.REMOVE_BITS(i, ref bits_left, ref bit_buffer); - zip.READ_BITS(ref block_len, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - zip.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + zip.REMOVE_BITS(i, ref bits_left, ref bit_buffer, msb: false); + zip.READ_BITS(ref block_len, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false); + if (zip.Error != Error.MSPACK_ERR_OK) + return zip.Error; + + zip.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false); + if (zip.Error != Error.MSPACK_ERR_OK) + return zip.Error; + block_len |= i << 8; if (block_len == 0) break; // Read "CK" header - zip.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + zip.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false); + if (zip.Error != Error.MSPACK_ERR_OK) + return zip.Error; if (i != 'C') return Error.MSPACK_ERR_DATAFORMAT; - zip.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + zip.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false); + if (zip.Error != Error.MSPACK_ERR_OK) + return zip.Error; if (i != 'K') return Error.MSPACK_ERR_DATAFORMAT; @@ -311,7 +317,7 @@ namespace LibMSPackSharp.Compression zip.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left); if ((error = (int)Inflate(zip)) != 0) { - Console.WriteLine($"inflate error {error}"); + Console.WriteLine($"inflate error {(InflateErrorCode)error}"); return zip.Error = (error > 0) ? (Error)error : Error.MSPACK_ERR_DECRUNCH; } @@ -339,7 +345,7 @@ namespace LibMSPackSharp.Compression } } - private static InflateErrorCode ZipReadLens(MSZIPDStream zip) + private static InflateErrorCode ReadLens(MSZIPDStream zip) { // For the bit buffer and huffman decoding uint bit_buffer = 0, bits_left = 0; @@ -355,11 +361,20 @@ namespace LibMSPackSharp.Compression zip.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); // Read the number of codes - zip.READ_BITS(ref lit_codes, 5, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + zip.READ_BITS(ref lit_codes, 5, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false); + if (zip.Error != Error.MSPACK_ERR_OK) + return InflateErrorCode.INF_ERR_BITOVERRUN; + lit_codes += 257; - zip.READ_BITS(ref dist_codes, 5, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + zip.READ_BITS(ref dist_codes, 5, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false); + if (zip.Error != Error.MSPACK_ERR_OK) + return InflateErrorCode.INF_ERR_BITOVERRUN; + dist_codes += 1; - zip.READ_BITS(ref bitlen_codes, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + zip.READ_BITS(ref bitlen_codes, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false); + if (zip.Error != Error.MSPACK_ERR_OK) + return InflateErrorCode.INF_ERR_BITOVERRUN; + bitlen_codes += 4; if (lit_codes > MSZIP_LITERAL_MAXSYMBOLS) @@ -371,7 +386,10 @@ namespace LibMSPackSharp.Compression for (i = 0; i < bitlen_codes; i++) { int blLenTemp = bl_len[bitlen_order[i]]; - zip.READ_BITS(ref blLenTemp, 3, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + zip.READ_BITS(ref blLenTemp, 3, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false); + if (zip.Error != Error.MSPACK_ERR_OK) + return InflateErrorCode.INF_ERR_BITOVERRUN; + bl_len[bitlen_order[i]] = (byte)blLenTemp; } @@ -380,17 +398,20 @@ namespace LibMSPackSharp.Compression bl_len[bitlen_order[i++]] = 0; } - // Create decoding table with an immediate lookup */ - if (MSZIPDStream.MakeDecodeTable(19, 7, bl_len, bl_table) != 0) + // Create decoding table with an immediate lookup + if (!MSZIPDStream.MakeDecodeTable(19, 7, bl_len, bl_table, msb: false)) return InflateErrorCode.INF_ERR_BITLENTBL; // Read literal / distance code lengths for (i = 0; i < (lit_codes + dist_codes); i++) { // Single-level huffman lookup - zip.ENSURE_BITS(7, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - code = bl_table[zip.PEEK_BITS(7, bit_buffer)]; - zip.REMOVE_BITS(bl_len[code], ref bits_left, ref bit_buffer); + zip.ENSURE_BITS(7, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: false); + if (zip.Error != Error.MSPACK_ERR_OK) + return InflateErrorCode.INF_ERR_BITBUF; + + code = bl_table[zip.PEEK_BITS(7, bit_buffer, msb: false)]; + zip.REMOVE_BITS(bl_len[code], ref bits_left, ref bit_buffer, msb: false); if (code < 16) { @@ -401,19 +422,28 @@ namespace LibMSPackSharp.Compression switch (code) { case 16: - zip.READ_BITS(ref run, 2, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + zip.READ_BITS(ref run, 2, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false); + if (zip.Error != Error.MSPACK_ERR_OK) + return InflateErrorCode.INF_ERR_BITOVERRUN; + run += 3; code = last_code; break; case 17: - zip.READ_BITS(ref run, 3, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + zip.READ_BITS(ref run, 3, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false); + if (zip.Error != Error.MSPACK_ERR_OK) + return InflateErrorCode.INF_ERR_BITOVERRUN; + run += 3; code = 0; break; case 18: - zip.READ_BITS(ref run, 7, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + zip.READ_BITS(ref run, 7, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false); + if (zip.Error != Error.MSPACK_ERR_OK) + return InflateErrorCode.INF_ERR_BITOVERRUN; + run += 11; code = 0; break; @@ -463,18 +493,22 @@ namespace LibMSPackSharp.Compression // For the bit buffer and huffman decoding uint bit_buffer = 0, bits_left = 0; - ushort sym = 0; int i_ptr = 0, i_end = 0; + InflateErrorCode err; zip.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); do { // Read in last block bit - zip.READ_BITS(ref last_block, 1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + zip.READ_BITS(ref last_block, 1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false); + if (zip.Error != Error.MSPACK_ERR_OK) + return InflateErrorCode.INF_ERR_BITOVERRUN; // Read in block type - zip.READ_BITS(ref block_type, 2, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + zip.READ_BITS(ref block_type, 2, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false); + if (zip.Error != Error.MSPACK_ERR_OK) + return InflateErrorCode.INF_ERR_BITOVERRUN; if (block_type == 0) { @@ -483,7 +517,7 @@ namespace LibMSPackSharp.Compression // Go to byte boundary i = (int)(bits_left & 7); - zip.REMOVE_BITS(i, ref bits_left, ref bit_buffer); + zip.REMOVE_BITS(i, ref bits_left, ref bit_buffer, msb: false); // Read 4 bytes of data, emptying the bit-buffer if necessary for (i = 0; (bits_left >= 8); i++) @@ -491,13 +525,19 @@ namespace LibMSPackSharp.Compression if (i == 4) return InflateErrorCode.INF_ERR_BITBUF; - lens_buf[i] = (byte)zip.PEEK_BITS(8, bit_buffer); - zip.REMOVE_BITS(8, ref bits_left, ref bit_buffer); + lens_buf[i] = (byte)zip.PEEK_BITS(8, bit_buffer, msb: false); + zip.REMOVE_BITS(8, ref bits_left, ref bit_buffer, msb: false); } - if (bits_left != 0) return InflateErrorCode.INF_ERR_BITBUF; + + if (bits_left != 0) + return InflateErrorCode.INF_ERR_BITBUF; + while (i < 4) { zip.READ_IF_NEEDED(ref i_ptr, ref i_end); + if (zip.Error != Error.MSPACK_ERR_OK) + return InflateErrorCode.INF_ERR_BITBUF; + lens_buf[i++] = zip.InputBuffer[i_ptr++]; } @@ -511,9 +551,13 @@ namespace LibMSPackSharp.Compression while (length > 0) { zip.READ_IF_NEEDED(ref i_ptr, ref i_end); + if (zip.Error != Error.MSPACK_ERR_OK) + return InflateErrorCode.INF_ERR_BITBUF; this_run = length; - if (this_run > (uint)(i_end - i_ptr)) this_run = i_end - i_ptr; + if (this_run > (uint)(i_end - i_ptr)) + this_run = i_end - i_ptr; + if (this_run > (MSZIP_FRAME_SIZE - zip.WindowPosition)) this_run = (int)(MSZIP_FRAME_SIZE - zip.WindowPosition); @@ -571,7 +615,7 @@ namespace LibMSPackSharp.Compression // Block with dynamic Huffman codes zip.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left); - if ((i = (int)ZipReadLens(zip)) != 0) + if ((i = (int)ReadLens(zip)) != 0) return (InflateErrorCode)i; zip.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); @@ -579,16 +623,24 @@ namespace LibMSPackSharp.Compression // Now huffman lengths are read for either kind of block, // create huffman decoding tables - if (MSZIPDStream.MakeDecodeTable(MSZIP_LITERAL_MAXSYMBOLS, MSZIP_LITERAL_TABLEBITS, zip.LITERAL_len, zip.LITERAL_table) != 0) - return InflateErrorCode.INF_ERR_LITERALTBL; + if (!MSZIPDStream.MakeDecodeTable(MSZIP_LITERAL_MAXSYMBOLS, MSZIP_LITERAL_TABLEBITS, zip.LITERAL_len, zip.LITERAL_table, msb: false)) + { + // TODO: Figure out why this always gets hit + //return InflateErrorCode.INF_ERR_LITERALTBL; + } - if (MSZIPDStream.MakeDecodeTable(MSZIP_DISTANCE_MAXSYMBOLS, MSZIP_DISTANCE_TABLEBITS, zip.DISTANCE_len, zip.DISTANCE_table) != 0) - return InflateErrorCode.INF_ERR_DISTANCETBL; + if (!MSZIPDStream.MakeDecodeTable(MSZIP_DISTANCE_MAXSYMBOLS, MSZIP_DISTANCE_TABLEBITS, zip.DISTANCE_len, zip.DISTANCE_table, msb: false)) + { + // TODO: Figure out why this always gets hit + //return InflateErrorCode.INF_ERR_DISTANCETBL; + } // Decode forever until end of block code for (; ; ) { - zip.READ_HUFFSYM(zip.LITERAL_table, ref code, MSZIP_LITERAL_TABLEBITS, zip.LITERAL_len, MSZIP_LITERAL_MAXSYMBOLS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + if ((err = (InflateErrorCode)zip.READ_HUFFSYM(zip.LITERAL_table, ref code, MSZIP_LITERAL_TABLEBITS, zip.LITERAL_len, MSZIP_LITERAL_MAXSYMBOLS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: false)) != InflateErrorCode.INF_ERR_OK) + return err; + if (code < 256) { zip.Window[zip.WindowPosition++] = (byte)code; @@ -613,14 +665,22 @@ namespace LibMSPackSharp.Compression if (code >= 29) return InflateErrorCode.INF_ERR_LITCODE; // Codes 286-287 are illegal - zip.READ_BITS_T(ref length, lit_extrabits[code], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + zip.READ_BITS_T(ref length, lit_extrabits[code], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false); + if (zip.Error != Error.MSPACK_ERR_OK) + return InflateErrorCode.INF_ERR_LITCODE; + length += lit_lengths[code]; - zip.READ_HUFFSYM(zip.DISTANCE_table, ref code, MSZIP_DISTANCE_TABLEBITS, zip.DISTANCE_len, MSZIP_DISTANCE_MAXSYMBOLS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + if ((err = (InflateErrorCode)zip.READ_HUFFSYM(zip.DISTANCE_table, ref code, MSZIP_DISTANCE_TABLEBITS, zip.DISTANCE_len, MSZIP_DISTANCE_MAXSYMBOLS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: false)) != 0) + return err; + if (code >= 30) return InflateErrorCode.INF_ERR_DISTCODE; - zip.READ_BITS_T(ref distance, dist_extrabits[code], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + zip.READ_BITS_T(ref distance, dist_extrabits[code], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false); + if (zip.Error != Error.MSPACK_ERR_OK) + return InflateErrorCode.INF_ERR_DISTCODE; + distance += dist_offsets[code]; // Match position is window position minus distance. If distance diff --git a/BurnOutSharp/External/libmspack/Compression/MSZIPDStream.cs b/BurnOutSharp/External/libmspack/Compression/MSZIPDStream.cs index d07c714b..96d7675a 100644 --- a/BurnOutSharp/External/libmspack/Compression/MSZIPDStream.cs +++ b/BurnOutSharp/External/libmspack/Compression/MSZIPDStream.cs @@ -49,14 +49,14 @@ namespace LibMSPackSharp.Compression #endregion - public override Error READ_BYTES(ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer) + public override void READ_BYTES(ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer, bool msb) { - Error error = READ_IF_NEEDED(ref i_ptr, ref i_end); - if (error != Error.MSPACK_ERR_OK) - return error; + READ_IF_NEEDED(ref i_ptr, ref i_end); + if (Error != Error.MSPACK_ERR_OK) + return; - INJECT_BITS(InputBuffer[i_ptr++], 8, ref bitsLeft, ref bitBuffer); - return Error.MSPACK_ERR_OK; + INJECT_BITS(InputBuffer[i_ptr++], 8, ref bitsLeft, ref bitBuffer, msb); + Error = Error.MSPACK_ERR_OK; } public override int HUFF_ERROR() => (int)InflateErrorCode.INF_ERR_HUFFSYM; diff --git a/BurnOutSharp/External/libmspack/Compression/QTM.cs b/BurnOutSharp/External/libmspack/Compression/QTM.cs index 463cf025..3a254ab5 100644 --- a/BurnOutSharp/External/libmspack/Compression/QTM.cs +++ b/BurnOutSharp/External/libmspack/Compression/QTM.cs @@ -225,7 +225,7 @@ namespace LibMSPackSharp.Compression high = 0xFFFF; low = 0; int tempCurrent = current; - qtm.READ_BITS(ref tempCurrent, 16, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + qtm.READ_BITS(ref tempCurrent, 16, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); current = (ushort)tempCurrent; qtm.HeaderRead = 1; } @@ -266,7 +266,10 @@ namespace LibMSPackSharp.Compression // Selector 4 = fixed length match (3 bytes) case 4: GET_SYMBOL(qtm, qtm.Model4, ref sym, ref range, ref symf, ref high, ref low, ref current, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - qtm.READ_MANY_BITS(ref extra, extra_bits[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + qtm.READ_MANY_BITS(ref extra, extra_bits[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); + if (qtm.Error != Error.MSPACK_ERR_OK) + return qtm.Error; + match_offset = position_base[sym] + extra + 1; match_length = 3; break; @@ -274,7 +277,10 @@ namespace LibMSPackSharp.Compression // Selector 5 = fixed length match (4 bytes) case 5: GET_SYMBOL(qtm, qtm.Model5, ref sym, ref range, ref symf, ref high, ref low, ref current, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - qtm.READ_MANY_BITS(ref extra, extra_bits[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + qtm.READ_MANY_BITS(ref extra, extra_bits[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); + if (qtm.Error != Error.MSPACK_ERR_OK) + return qtm.Error; + match_offset = position_base[sym] + extra + 1; match_length = 4; break; @@ -282,11 +288,17 @@ namespace LibMSPackSharp.Compression // Selector 6 = variable length match case 6: GET_SYMBOL(qtm, qtm.Model6Len, ref sym, ref range, ref symf, ref high, ref low, ref current, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - qtm.READ_MANY_BITS(ref extra, length_extra[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + qtm.READ_MANY_BITS(ref extra, length_extra[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); + if (qtm.Error != Error.MSPACK_ERR_OK) + return qtm.Error; + match_length = (int)(length_base[sym] + extra + 5); GET_SYMBOL(qtm, qtm.Model6, ref sym, ref range, ref symf, ref high, ref low, ref current, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - qtm.READ_MANY_BITS(ref extra, extra_bits[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + qtm.READ_MANY_BITS(ref extra, extra_bits[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); + if (qtm.Error != Error.MSPACK_ERR_OK) + return qtm.Error; + match_offset = position_base[sym] + extra + 1; break; @@ -407,14 +419,14 @@ namespace LibMSPackSharp.Compression { // Re-align input if ((bits_left & 7) != 0) - qtm.REMOVE_BITS((int)bits_left & 7, ref bits_left, ref bit_buffer); + qtm.REMOVE_BITS((int)bits_left & 7, ref bits_left, ref bit_buffer, msb: true); // Special Quantum hack -- cabd.c injects a trailer byte to allow the // decompressor to realign itself. CAB Quantum blocks, unlike LZX // blocks, can have anything from 0 to 4 trailing null bytes. */ do { - qtm.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + qtm.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); } while (i != 0xFF); qtm.HeaderRead = 0; @@ -533,9 +545,13 @@ namespace LibMSPackSharp.Compression low <<= 1; high = (ushort)((high << 1) | 1); - qtm.ENSURE_BITS(1, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); - current = (ushort)((current << 1) | qtm.PEEK_BITS(1, bit_buffer)); - qtm.REMOVE_BITS(1, ref bits_left, ref bit_buffer); + + qtm.ENSURE_BITS(1, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true); + if (qtm.Error != Error.MSPACK_ERR_OK) + return; + + current = (ushort)((current << 1) | qtm.PEEK_BITS(1, bit_buffer, msb: true)); + qtm.REMOVE_BITS(1, ref bits_left, ref bit_buffer, msb: true); } } diff --git a/BurnOutSharp/External/libmspack/Compression/QTMDStream.cs b/BurnOutSharp/External/libmspack/Compression/QTMDStream.cs index d11c09b5..0ab08a4b 100644 --- a/BurnOutSharp/External/libmspack/Compression/QTMDStream.cs +++ b/BurnOutSharp/External/libmspack/Compression/QTMDStream.cs @@ -120,21 +120,21 @@ namespace LibMSPackSharp.Compression public QTMDModelSym[] Model7Symbols { get; set; } = new QTMDModelSym[7 + 1]; - public override Error READ_BYTES(ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer) + public override void READ_BYTES(ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer, bool msb) { - Error error = READ_IF_NEEDED(ref i_ptr, ref i_end); - if (error != Error.MSPACK_ERR_OK) - return error; + READ_IF_NEEDED(ref i_ptr, ref i_end); + if (Error != Error.MSPACK_ERR_OK) + return; byte b0 = InputBuffer[i_ptr++]; - error = READ_IF_NEEDED(ref i_ptr, ref i_end); - if (error != Error.MSPACK_ERR_OK) - return error; + READ_IF_NEEDED(ref i_ptr, ref i_end); + if (Error != Error.MSPACK_ERR_OK) + return; byte b1 = InputBuffer[i_ptr++]; - INJECT_BITS((uint)((b0 << 8) | b1), 16, ref bitsLeft, ref bitBuffer); - return Error.MSPACK_ERR_OK; + INJECT_BITS((uint)((b0 << 8) | b1), 16, ref bitsLeft, ref bitBuffer, msb); + Error = Error.MSPACK_ERR_OK; } public override int HUFF_ERROR() => (int)Error.MSPACK_ERR_OK; diff --git a/BurnOutSharp/External/libmspack/KWAJ/Implementation.cs b/BurnOutSharp/External/libmspack/KWAJ/Implementation.cs index 448f659f..14a5604c 100644 --- a/BurnOutSharp/External/libmspack/KWAJ/Implementation.cs +++ b/BurnOutSharp/External/libmspack/KWAJ/Implementation.cs @@ -45,60 +45,21 @@ namespace LibMSPackSharp.KWAJ // Define decoding table sizes public const int KWAJ_TABLESIZE = (1 << KWAJ_TABLEBITS); - public static int KWAJ_MATCHLEN1_TBLSIZE - { - get - { - if (KWAJ_TABLESIZE < (KWAJ_MATCHLEN1_SYMS * 2)) - return (KWAJ_MATCHLEN1_SYMS * 4); - else - return (KWAJ_TABLESIZE + (KWAJ_MATCHLEN1_SYMS * 2)); - } - } - public static int KWAJ_MATCHLEN2_TBLSIZE - { - get - { - if (KWAJ_TABLESIZE < (KWAJ_MATCHLEN2_SYMS * 2)) - return (KWAJ_MATCHLEN2_SYMS * 4); - else - return (KWAJ_TABLESIZE + (KWAJ_MATCHLEN2_SYMS * 2)); - } - } + //public const int KWAJ_MATCHLEN1_TBLSIZE = (KWAJ_MATCHLEN1_SYMS * 4); + public const int KWAJ_MATCHLEN1_TBLSIZE = (KWAJ_TABLESIZE + (KWAJ_MATCHLEN1_SYMS * 2)); - public static int KWAJ_LITLEN_TBLSIZE - { - get - { - if (KWAJ_TABLESIZE < (KWAJ_LITLEN_SYMS * 2)) - return (KWAJ_LITLEN_SYMS * 4); - else - return (KWAJ_TABLESIZE + (KWAJ_LITLEN_SYMS * 2)); - } - } + //public const int KWAJ_MATCHLEN2_TBLSIZE = (KWAJ_MATCHLEN2_SYMS * 4); + public const int KWAJ_MATCHLEN2_TBLSIZE = (KWAJ_TABLESIZE + (KWAJ_MATCHLEN2_SYMS * 2)); - public static int KWAJ_OFFSET_TBLSIZE - { - get - { - if (KWAJ_TABLESIZE < (KWAJ_OFFSET_SYMS * 2)) - return (KWAJ_OFFSET_SYMS * 4); - else - return (KWAJ_TABLESIZE + (KWAJ_OFFSET_SYMS * 2)); - } - } + //public const int KWAJ_LITLEN_TBLSIZE = (KWAJ_LITLEN_SYMS * 4); + public const int KWAJ_LITLEN_TBLSIZE = (KWAJ_TABLESIZE + (KWAJ_LITLEN_SYMS * 2)); - public static int KWAJ_LITERAL_TBLSIZE - { - get - { - if (KWAJ_TABLESIZE < (KWAJ_LITERAL_SYMS * 2)) - return (KWAJ_LITERAL_SYMS * 4); - else - return (KWAJ_TABLESIZE + (KWAJ_LITERAL_SYMS * 2)); - } - } + //public const int KWAJ_OFFSET_TBLSIZE = (KWAJ_OFFSET_SYMS * 4); + public const int KWAJ_OFFSET_TBLSIZE = (KWAJ_TABLESIZE + (KWAJ_OFFSET_SYMS * 2)); + + //public const int KWAJ_LITERAL_TBLSIZE = (KWAJ_LITERAL_SYMS * 4); + public const int KWAJ_LITERAL_TBLSIZE = (KWAJ_TABLESIZE + (KWAJ_LITERAL_SYMS * 2)); #endregion @@ -465,7 +426,6 @@ namespace LibMSPackSharp.KWAJ { uint bit_buffer = 0, bits_left = 0, len = 0, j = 0; int i; - ushort sym = 0; int i_ptr = 0, i_end = 0; bool lit_run = false; int pos = 0, offset; @@ -483,7 +443,9 @@ namespace LibMSPackSharp.KWAJ for (i = 0; i < 6; i++) { //READ_BITS_SAFE(val, n) - lzh.READ_BITS(ref types[i], 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + lzh.READ_BITS(ref types[i], 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); + if (lzh.Error != Error.MSPACK_ERR_OK) + return lzh.Error; if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd) return Error.MSPACK_ERR_OK; } @@ -497,7 +459,7 @@ namespace LibMSPackSharp.KWAJ return err; lzh.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - if (InternalStream.MakeDecodeTable(KWAJ_MATCHLEN1_SYMS, (uint)KWAJ_MATCHLEN1_TBLSIZE, lzh.MATCHLEN1_len, lzh.MATCHLEN1_table) != 0) + if (!InternalStream.MakeDecodeTable(KWAJ_MATCHLEN1_SYMS, KWAJ_MATCHLEN1_TBLSIZE, lzh.MATCHLEN1_len, lzh.MATCHLEN1_table, msb: true)) return Error.MSPACK_ERR_DATAFORMAT; //BUILD_TREE(tbl, type) @@ -507,7 +469,7 @@ namespace LibMSPackSharp.KWAJ return err; lzh.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - if (InternalStream.MakeDecodeTable(KWAJ_MATCHLEN2_SYMS, (uint)KWAJ_MATCHLEN2_TBLSIZE, lzh.MATCHLEN2_len, lzh.MATCHLEN2_table) != 0) + if (!InternalStream.MakeDecodeTable(KWAJ_MATCHLEN2_SYMS, KWAJ_MATCHLEN2_TBLSIZE, lzh.MATCHLEN2_len, lzh.MATCHLEN2_table, msb: true)) return Error.MSPACK_ERR_DATAFORMAT; //BUILD_TREE(tbl, type) @@ -517,7 +479,7 @@ namespace LibMSPackSharp.KWAJ return err; lzh.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - if (InternalStream.MakeDecodeTable(KWAJ_LITLEN_SYMS, (uint)KWAJ_LITLEN_TBLSIZE, lzh.LITLEN_len, lzh.LITLEN_table) != 0) + if (!InternalStream.MakeDecodeTable(KWAJ_LITLEN_SYMS, KWAJ_LITLEN_TBLSIZE, lzh.LITLEN_len, lzh.LITLEN_table, msb: true)) return Error.MSPACK_ERR_DATAFORMAT; //BUILD_TREE(tbl, type) @@ -527,7 +489,7 @@ namespace LibMSPackSharp.KWAJ return err; lzh.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - if (InternalStream.MakeDecodeTable(KWAJ_OFFSET_SYMS, (uint)KWAJ_OFFSET_TBLSIZE, lzh.OFFSET_len, lzh.OFFSET_table) != 0) + if (!InternalStream.MakeDecodeTable(KWAJ_OFFSET_SYMS, KWAJ_OFFSET_TBLSIZE, lzh.OFFSET_len, lzh.OFFSET_table, msb: true)) return Error.MSPACK_ERR_DATAFORMAT; //BUILD_TREE(tbl, type) @@ -537,7 +499,7 @@ namespace LibMSPackSharp.KWAJ return err; lzh.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - if (InternalStream.MakeDecodeTable(KWAJ_LITERAL_SYMS, (uint)KWAJ_LITERAL_TBLSIZE, lzh.LITERAL_len, lzh.LITERAL_table) != 0) + if (!InternalStream.MakeDecodeTable(KWAJ_LITERAL_SYMS, KWAJ_LITERAL_TBLSIZE, lzh.LITERAL_len, lzh.LITERAL_table, msb: true)) return Error.MSPACK_ERR_DATAFORMAT; while (lzh.InputEnd == 0) @@ -545,14 +507,16 @@ namespace LibMSPackSharp.KWAJ if (lit_run) { //READ_HUFFSYM_SAFE(tbl, val) - lzh.READ_HUFFSYM(lzh.MATCHLEN2_table, ref len, KWAJ_MATCHLEN2_TBLSIZE, lzh.MATCHLEN2_len, KWAJ_MATCHLEN2_SYMS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + if (lzh.READ_HUFFSYM(lzh.MATCHLEN2_table, ref len, KWAJ_MATCHLEN2_TBLSIZE, lzh.MATCHLEN2_len, KWAJ_MATCHLEN2_SYMS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0) + return Error.MSPACK_ERR_DECRUNCH; if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd) return Error.MSPACK_ERR_OK; } else { //READ_HUFFSYM_SAFE(tbl, val) - lzh.READ_HUFFSYM(lzh.MATCHLEN1_table, ref len, KWAJ_MATCHLEN1_TBLSIZE, lzh.MATCHLEN1_len, KWAJ_MATCHLEN1_SYMS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + if (lzh.READ_HUFFSYM(lzh.MATCHLEN1_table, ref len, KWAJ_MATCHLEN1_TBLSIZE, lzh.MATCHLEN1_len, KWAJ_MATCHLEN1_SYMS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0) + return Error.MSPACK_ERR_DECRUNCH; if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd) return Error.MSPACK_ERR_OK; } @@ -563,7 +527,8 @@ namespace LibMSPackSharp.KWAJ lit_run = false; // Not the end of a literal run //READ_HUFFSYM_SAFE(tbl, val) - lzh.READ_HUFFSYM(lzh.OFFSET_table, ref j, KWAJ_OFFSET_TBLSIZE, lzh.OFFSET_len, KWAJ_OFFSET_SYMS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + if (lzh.READ_HUFFSYM(lzh.OFFSET_table, ref j, KWAJ_OFFSET_TBLSIZE, lzh.OFFSET_len, KWAJ_OFFSET_SYMS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0) + return Error.MSPACK_ERR_DECRUNCH; if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd) return Error.MSPACK_ERR_OK; @@ -571,7 +536,9 @@ namespace LibMSPackSharp.KWAJ //READ_BITS_SAFE(val, n) int tempj = (int)j; - lzh.READ_BITS(ref tempj, 6, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + lzh.READ_BITS(ref tempj, 6, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); + if (lzh.Error != Error.MSPACK_ERR_OK) + return lzh.Error; if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd) return Error.MSPACK_ERR_OK; @@ -591,7 +558,8 @@ namespace LibMSPackSharp.KWAJ else { //READ_HUFFSYM_SAFE(tbl, val) - lzh.READ_HUFFSYM(lzh.LITLEN_table, ref len, KWAJ_LITLEN_TBLSIZE, lzh.LITLEN_len, KWAJ_LITLEN_SYMS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + if (lzh.READ_HUFFSYM(lzh.LITLEN_table, ref len, KWAJ_LITLEN_TBLSIZE, lzh.LITLEN_len, KWAJ_LITLEN_SYMS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0) + return Error.MSPACK_ERR_DECRUNCH; if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd) return Error.MSPACK_ERR_OK; @@ -601,7 +569,8 @@ namespace LibMSPackSharp.KWAJ while (len-- > 0) { //READ_HUFFSYM_SAFE(tbl, val) - lzh.READ_HUFFSYM(lzh.LITERAL_table, ref j, KWAJ_LITERAL_TBLSIZE, lzh.LITERAL_len, KWAJ_LITERAL_SYMS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); + if (lzh.READ_HUFFSYM(lzh.LITERAL_table, ref j, KWAJ_LITERAL_TBLSIZE, lzh.LITERAL_len, KWAJ_LITERAL_SYMS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0) + return Error.MSPACK_ERR_DECRUNCH; if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd) return Error.MSPACK_ERR_OK; @@ -650,7 +619,7 @@ namespace LibMSPackSharp.KWAJ case 1: //READ_BITS_SAFE(val, n) - lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd) return Error.MSPACK_ERR_OK; @@ -658,7 +627,7 @@ namespace LibMSPackSharp.KWAJ for (i = 1; i < numsyms; i++) { //READ_BITS_SAFE(val, n) - lzh.READ_BITS(ref sel, 1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + lzh.READ_BITS(ref sel, 1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd) return Error.MSPACK_ERR_OK; @@ -669,7 +638,7 @@ namespace LibMSPackSharp.KWAJ else { //READ_BITS_SAFE(val, n) - lzh.READ_BITS(ref sel, 1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + lzh.READ_BITS(ref sel, 1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd) return Error.MSPACK_ERR_OK; @@ -680,7 +649,7 @@ namespace LibMSPackSharp.KWAJ else { //READ_BITS_SAFE(val, n) - lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd) return Error.MSPACK_ERR_OK; @@ -692,7 +661,7 @@ namespace LibMSPackSharp.KWAJ case 2: //READ_BITS_SAFE(val, n) - lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd) return Error.MSPACK_ERR_OK; @@ -700,14 +669,14 @@ namespace LibMSPackSharp.KWAJ for (i = 1; i < numsyms; i++) { //READ_BITS_SAFE(val, n) - lzh.READ_BITS(ref sel, 2, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + lzh.READ_BITS(ref sel, 2, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd) return Error.MSPACK_ERR_OK; if (sel == 3) { //READ_BITS_SAFE(val, n) - lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd) return Error.MSPACK_ERR_OK; } @@ -725,7 +694,7 @@ namespace LibMSPackSharp.KWAJ for (i = 0; i < numsyms; i++) { //READ_BITS_SAFE(val, n) - lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true); if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd) return Error.MSPACK_ERR_OK; diff --git a/BurnOutSharp/External/libmspack/KWAJ/InternalStream.cs b/BurnOutSharp/External/libmspack/KWAJ/InternalStream.cs index d934b924..027e2c34 100644 --- a/BurnOutSharp/External/libmspack/KWAJ/InternalStream.cs +++ b/BurnOutSharp/External/libmspack/KWAJ/InternalStream.cs @@ -33,20 +33,19 @@ namespace LibMSPackSharp.KWAJ public byte[] Window { get; set; } = new byte[LZSS.LZSS_WINDOW_SIZE]; - public override Error READ_BYTES(ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer) + public override void READ_BYTES(ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer, bool msb) { - Error error = Error.MSPACK_ERR_OK; if (i_ptr >= i_end) { - if ((error = Implementation.LZHReadInput(this)) != Error.MSPACK_ERR_OK) - return error; + if ((Error = Implementation.LZHReadInput(this)) != Error.MSPACK_ERR_OK) + return; i_ptr = InputPointer; i_end = InputLength; } - INJECT_BITS(InputBuffer[i_ptr++], 8, ref bitsLeft, ref bitBuffer); - return error; + INJECT_BITS(InputBuffer[i_ptr++], 8, ref bitsLeft, ref bitBuffer, msb); + Error = Error.MSPACK_ERR_OK; } public override int HUFF_ERROR() => (int)Error.MSPACK_ERR_DATAFORMAT; diff --git a/BurnOutSharp/External/libmspack/OAB/Implementation.cs b/BurnOutSharp/External/libmspack/OAB/Implementation.cs index b185bb4c..ce70c758 100644 --- a/BurnOutSharp/External/libmspack/OAB/Implementation.cs +++ b/BurnOutSharp/External/libmspack/OAB/Implementation.cs @@ -85,16 +85,21 @@ namespace LibMSPackSharp.OAB private static int SysWrite(object baseFile, byte[] buf, int pointer, int size) { - InternalFile file = baseFile as InternalFile; - if (file == null) - return 0; + if (baseFile is InternalFile file) + { + int bytes_written = file.OrigSys.Write(file.OrigFile, buf, pointer, size); + if (bytes_written > 0) + file.CRC = Checksum.CRC32(buf, 0, bytes_written, file.CRC); - int bytes_written = file.OrigSys.Write(file.OrigFile, buf, pointer, size); + return bytes_written; + } + else if (baseFile is DefaultFileImpl impl) + { + return SystemImpl.DefaultSystem.Write(impl, buf, pointer, size); + } - if (bytes_written > 0) - file.CRC = Checksum.CRC32(buf, 0, bytes_written, file.CRC); - - return bytes_written; + // Unknown file to write to + return 0; } #endregion