diff --git a/BurnOutSharp/External/libmspack/BaseDecompressState.cs b/BurnOutSharp/External/libmspack/BaseDecompressState.cs new file mode 100644 index 00000000..2cfc4c5e --- /dev/null +++ b/BurnOutSharp/External/libmspack/BaseDecompressState.cs @@ -0,0 +1,36 @@ +/* This file is part of libmspack. + * (C) 2003-2004 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.IO; + +namespace LibMSPackSharp +{ + public abstract class BaseDecompressState + { + /// + /// System wrapper for I/O operations + /// + public SystemImpl System { get; set; } + + /// + /// Persistent error state of the state + /// + public Error Error { get; set; } + + /// + /// Input file handle + /// + public FileStream InputFileHandle { get; set; } + + /// + /// Output file handle + /// + public FileStream OutputFileHandle { get; set; } + } +} diff --git a/BurnOutSharp/External/libmspack/BaseDecompressor.cs b/BurnOutSharp/External/libmspack/BaseDecompressor.cs new file mode 100644 index 00000000..42c7f477 --- /dev/null +++ b/BurnOutSharp/External/libmspack/BaseDecompressor.cs @@ -0,0 +1,32 @@ +/* This file is part of libmspack. + * (C) 2003-2004 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 +{ + /// + /// Set of common fields shared by all decompressors + /// + public abstract class BaseDecompressor + { + /// + /// System wrapper for I/O operations + /// + public SystemImpl System { get; set; } + + /// + /// Persistent error state of the decompressor + /// + public Error Error { get; set; } + + /// + /// Size of the internal buffer + /// + public int BufferSize { get; set; } + } +} diff --git a/BurnOutSharp/External/libmspack/HLP/Implementation.cs b/BurnOutSharp/External/libmspack/BaseHeader.cs similarity index 67% rename from BurnOutSharp/External/libmspack/HLP/Implementation.cs rename to BurnOutSharp/External/libmspack/BaseHeader.cs index 81d2717f..458d7540 100644 --- a/BurnOutSharp/External/libmspack/HLP/Implementation.cs +++ b/BurnOutSharp/External/libmspack/BaseHeader.cs @@ -7,9 +7,10 @@ * For further details, see the file COPYING.LIB distributed with libmspack */ -namespace LibMSPackSharp.HLP +namespace LibMSPackSharp { - public class Implementation - { - } + /// + /// Base class for decompressor-used objects + /// + public abstract class BaseHeader { } } diff --git a/BurnOutSharp/External/libmspack/CAB/Cabinet.cs b/BurnOutSharp/External/libmspack/CAB/Cabinet.cs index 7f4c42d1..d7c6a57a 100644 --- a/BurnOutSharp/External/libmspack/CAB/Cabinet.cs +++ b/BurnOutSharp/External/libmspack/CAB/Cabinet.cs @@ -72,7 +72,7 @@ namespace LibMSPackSharp.CAB /// /// /// - public class Cabinet + public class Cabinet : BaseHeader { #region Internal diff --git a/BurnOutSharp/External/libmspack/CAB/Constants.cs b/BurnOutSharp/External/libmspack/CAB/Constants.cs deleted file mode 100644 index 522c61f2..00000000 --- a/BurnOutSharp/External/libmspack/CAB/Constants.cs +++ /dev/null @@ -1,91 +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 - */ - -/* Cabinet (.CAB) files are a form of file archive. Each cabinet contains - * "folders", which are compressed spans of data. Each cabinet has - * "files", whose metadata is in the cabinet header, but whose actual data - * is stored compressed in one of the "folders". Cabinets can span more - * than one physical file on disk, in which case they are a "cabinet set", - * and usually the last folder of each cabinet extends into the next - * cabinet. - * - * For a complete description of the format, see the MSDN site: - * http://msdn.microsoft.com/en-us/library/bb267310.aspx - */ - -/* Notes on compliance with cabinet specification: - * - * One of the main changes between cabextract 0.6 and libmspack's cab - * decompressor is the move from block-oriented decompression to - * stream-oriented decompression. - * - * cabextract would read one data block from disk, decompress it with the - * appropriate method, then write the decompressed data. The CAB - * specification is specifically designed to work like this, as it ensures - * compression matches do not span the maximum decompressed block size - * limit of 32kb. - * - * However, the compression algorithms used are stream oriented, with - * specific hacks added to them to enforce the "individual 32kb blocks" - * rule in CABs. In other file formats, they do not have this limitation. - * - * In order to make more generalised decompressors, libmspack's CAB - * decompressor has moved from being block-oriented to more stream - * oriented. This also makes decompression slightly faster. - * - * However, this leads to incompliance with the CAB specification. The - * CAB controller can no longer ensure each block of input given to the - * decompressors is matched with their output. The "decompressed size" of - * each individual block is thrown away. - * - * Each CAB block is supposed to be seen as individually compressed. This - * means each consecutive data block can have completely different - * "uncompressed" sizes, ranging from 1 to 32768 bytes. However, in - * reality, all data blocks in a folder decompress to exactly 32768 bytes, - * excepting the final block. - * - * Given this situation, the decompression algorithms are designed to - * realign their input bitstreams on 32768 output-byte boundaries, and - * various other special cases have been made. libmspack will not - * correctly decompress LZX or Quantum compressed folders where the blocks - * do not follow this "32768 bytes until last block" pattern. It could be - * implemented if needed, but hopefully this is not necessary -- it has - * not been seen in over 3Gb of CAB archives. - */ - -namespace LibMSPackSharp.CAB -{ - public static class Constants - { - // CAB data blocks are <= 32768 bytes in uncompressed form.Uncompressed - // blocks have zero growth. MSZIP guarantees that it won't grow above - // uncompressed size by more than 12 bytes.LZX guarantees it won't grow - // more than 6144 bytes.Quantum has no documentation, but the largest - // block seen in the wild is 337 bytes above uncompressed size. - - public const int CAB_BLOCKMAX = 32768; - public const int CAB_INPUTMAX = CAB_BLOCKMAX + 6144; - - // input buffer needs to be CAB_INPUTMAX + 1 byte to allow for max-sized block - // plus 1 trailer byte added by cabd_sys_read_block() for Quantum alignment. - // - // When MSCABD_PARAM_SALVAGE is set, block size is not checked so can be - // up to 65535 bytes, so max input buffer size needed is 65535 + 1 - - public const int CAB_INPUTMAX_SALVAGE = 65535; - public const int CAB_INPUTBUF = CAB_INPUTMAX_SALVAGE + 1; - - // There are no more than 65535 data blocks per folder, so a folder cannot - // be more than 32768*65535 bytes in length.As files cannot span more than - // one folder, this is also their max offset, length and offset+length limit. - - public const int CAB_FOLDERMAX = 65535; - public const int CAB_LENGTHMAX = CAB_BLOCKMAX * CAB_FOLDERMAX; - } -} diff --git a/BurnOutSharp/External/libmspack/CAB/DecompressState.cs b/BurnOutSharp/External/libmspack/CAB/DecompressState.cs index 94cceab6..08b14cd7 100644 --- a/BurnOutSharp/External/libmspack/CAB/DecompressState.cs +++ b/BurnOutSharp/External/libmspack/CAB/DecompressState.cs @@ -8,11 +8,10 @@ */ using System; -using System.IO; namespace LibMSPackSharp.CAB { - public class DecompressState + public class DecompressState : BaseDecompressState { /// /// Current folder we're extracting from @@ -39,11 +38,6 @@ namespace LibMSPackSharp.CAB /// public long Outlen { get; set; } - /// - /// Special I/O code for decompressor - /// - public SystemImpl Sys { get; set; } - /// /// Type of compression used by folder /// @@ -57,23 +51,13 @@ namespace LibMSPackSharp.CAB /// /// Decompressor state /// - public object DecompressorState { get; set; } + public BaseDecompressState DecompressorState { get; set; } /// /// Cabinet where input data comes from /// public Cabinet InputCabinet { get; set; } - /// - /// Input file handle - /// - public FileStream InputFileHandle { get; set; } - - /// - /// Output file handle - /// - public FileStream OutputFileHandle { get; set; } - /// /// Input data consumed /// diff --git a/BurnOutSharp/External/libmspack/CAB/Decompressor.cs b/BurnOutSharp/External/libmspack/CAB/Decompressor.cs index 57e1492d..78665750 100644 --- a/BurnOutSharp/External/libmspack/CAB/Decompressor.cs +++ b/BurnOutSharp/External/libmspack/CAB/Decompressor.cs @@ -18,7 +18,7 @@ using System; using System.IO; using System.Text; using LibMSPackSharp.Compression; -using static LibMSPackSharp.CAB.Constants; +using static LibMSPackSharp.Constants; namespace LibMSPackSharp.CAB { @@ -29,24 +29,18 @@ namespace LibMSPackSharp.CAB /// /// /// - public class Decompressor + public class Decompressor : BaseDecompressor { #region Fields public DecompressState State { get; set; } - public SystemImpl System { get; set; } - - public int BufferSize { get; set; } - public int SearchBufferSize { get; set; } public bool FixMSZip { get; set; } public bool Salvage { get; set; } - public Error Error { get; set; } - public Error ReadError { get; set; } #endregion @@ -294,6 +288,7 @@ namespace LibMSPackSharp.CAB /// public Error Prepend(Cabinet cab, Cabinet prevcab) => Merge(prevcab, cab); + /// /// /// Extracts a file from a cabinet or cabinet set. /// @@ -367,7 +362,7 @@ namespace LibMSPackSharp.CAB Block = 0, Outlen = 0, - Sys = System, + System = System, InputCabinet = fol.Data.Cab, InputFileHandle = System.Open(fol.Data.Cab.Filename, OpenMode.MSPACK_SYS_OPEN_READ), @@ -376,8 +371,8 @@ namespace LibMSPackSharp.CAB InputEnd = 0, }; - State.Sys.Read = SysRead; - State.Sys.Write = SysWrite; + State.System.Read = SysRead; + State.System.Write = SysWrite; if (State.InputFileHandle == null) return Error = Error.MSPACK_ERR_OPEN; @@ -501,22 +496,22 @@ namespace LibMSPackSharp.CAB { case CompressionType.COMPTYPE_NONE: State.Decompress = None.Decompress; - State.DecompressorState = None.Init(State.Sys, State.InputFileHandle, State.OutputFileHandle, BufferSize); + State.DecompressorState = None.Init(State.System, State.InputFileHandle, State.OutputFileHandle, BufferSize); break; case CompressionType.COMPTYPE_MSZIP: State.Decompress = MSZIP.Decompress; - State.DecompressorState = MSZIP.Init(State.Sys, State.InputFileHandle, State.OutputFileHandle, BufferSize, FixMSZip); + State.DecompressorState = MSZIP.Init(State.System, State.InputFileHandle, State.OutputFileHandle, BufferSize, FixMSZip); break; case CompressionType.COMPTYPE_QUANTUM: State.Decompress = QTM.Decompress; - State.DecompressorState = QTM.Init(State.Sys, State.InputFileHandle, State.OutputFileHandle, ((ushort)ct >> 8) & 0x1f, BufferSize); + State.DecompressorState = QTM.Init(State.System, State.InputFileHandle, State.OutputFileHandle, ((ushort)ct >> 8) & 0x1f, BufferSize); break; case CompressionType.COMPTYPE_LZX: State.Decompress = LZX.Decompress; - State.DecompressorState = LZX.Init(State.Sys, State.InputFileHandle, State.OutputFileHandle, ((ushort)ct >> 8) & 0x1f, 0, BufferSize, 0, false); + State.DecompressorState = LZX.Init(State.System, State.InputFileHandle, State.OutputFileHandle, ((ushort)ct >> 8) & 0x1f, 0, BufferSize, 0, false); break; default: @@ -534,19 +529,10 @@ namespace LibMSPackSharp.CAB switch (State.CompressionType & CompressionType.COMPTYPE_MASK) { case CompressionType.COMPTYPE_NONE: - (State.DecompressorState as NoneState).Output = State.OutputFileHandle; - break; - case CompressionType.COMPTYPE_MSZIP: - (State.DecompressorState as MSZIPDStream).Output = State.OutputFileHandle; - break; - case CompressionType.COMPTYPE_QUANTUM: - (State.DecompressorState as QTMDStream).Output = State.OutputFileHandle; - break; - case CompressionType.COMPTYPE_LZX: - (State.DecompressorState as LZXDStream).Output = State.OutputFileHandle; + State.DecompressorState.OutputFileHandle = State.OutputFileHandle; break; default: diff --git a/BurnOutSharp/External/libmspack/CHM/CHM.cs b/BurnOutSharp/External/libmspack/CHM/CHM.cs index 6a0c33c2..50bf541a 100644 --- a/BurnOutSharp/External/libmspack/CHM/CHM.cs +++ b/BurnOutSharp/External/libmspack/CHM/CHM.cs @@ -21,7 +21,7 @@ namespace LibMSPackSharp.CHM /// /// All fields are READ ONLY. /// - public class CHM + public class CHM : BaseHeader { #region Internal diff --git a/BurnOutSharp/External/libmspack/CHM/Constants.cs b/BurnOutSharp/External/libmspack/CHM/Constants.cs deleted file mode 100644 index aeb7856a..00000000 --- a/BurnOutSharp/External/libmspack/CHM/Constants.cs +++ /dev/null @@ -1,53 +0,0 @@ -/* This file is part of libmspack. - * (C) 2003-2004 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.CHM -{ - public class Constants - { - // _PMGHeader - internal const int pmgl_Signature = 0x0000; - internal const int pmgl_QuickRefSize = 0x0004; - internal const int pmgl_PMGIEntries = 0x0008; // Unknown1 in PMGL - internal const int pmgl_PrevChunk = 0x000C; // Not in PMGI - internal const int pmgl_NextChunk = 0x0010; // Not in PMGI - internal const int pmgl_PMGLEntries = 0x0014; // Not in PMGI - internal const int pmgl_headerSIZEOF = 0x0014; - internal const int pmgi_headerSIZEOF = 0x000C; - - // _LZXControlData - internal const int lzxcd_Length = 0x0000; - internal const int lzxcd_Signature = 0x0004; - internal const int lzxcd_Version = 0x0008; - internal const int lzxcd_ResetInterval = 0x000C; - internal const int lzxcd_WindowSize = 0x0010; - internal const int lzxcd_CacheSize = 0x0014; - internal const int lzxcd_Unknown1 = 0x0018; - internal const int lzxcd_SIZEOF = 0x001C; - - // _LZXResetTable - internal const int lzxrt_Unknown1 = 0x0000; - internal const int lzxrt_NumEntries = 0x0004; - internal const int lzxrt_EntrySize = 0x0008; - internal const int lzxrt_TableOffset = 0x000C; - internal const int lzxrt_UncompLen = 0x0010; - internal const int lzxrt_CompLen = 0x0018; - internal const int lzxrt_FrameLen = 0x0020; - internal const int lzxrt_Entries = 0x0028; - internal const int lzxrt_headerSIZEOF = 0x0028; - - // Filenames of the system files used for decompression. - // - Content and ControlData are essential. - // - ResetTable is preferred, but SpanInfo can be used if not available - internal const string ContentName = "::DataSpace/Storage/MSCompressed/Content"; - internal const string ControlName = "::DataSpace/Storage/MSCompressed/ControlData"; - internal const string SpanInfoName = "::DataSpace/Storage/MSCompressed/SpanInfo"; - internal const string ResetTableName = "::DataSpace/Storage/MSCompressed/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTable"; - } -} diff --git a/BurnOutSharp/External/libmspack/CHM/DecompressState.cs b/BurnOutSharp/External/libmspack/CHM/DecompressState.cs index 7c916af2..ab76a42b 100644 --- a/BurnOutSharp/External/libmspack/CHM/DecompressState.cs +++ b/BurnOutSharp/External/libmspack/CHM/DecompressState.cs @@ -7,12 +7,11 @@ * For further details, see the file COPYING.LIB distributed with libmspack */ -using System.IO; using LibMSPackSharp.Compression; namespace LibMSPackSharp.CHM { - public class DecompressState + public class DecompressState : BaseDecompressState { /// /// CHM file being decompressed @@ -33,20 +32,5 @@ namespace LibMSPackSharp.CHM /// LZX decompressor state /// public LZXDStream State { get; set; } - - /// - /// Special I/O code for decompressor - /// - public SystemImpl Sys { get; set; } - - /// - /// Input file handle - /// - public FileStream InputFileHandle { get; set; } - - /// - /// Output file handle - /// - public FileStream OutputFileHandle { get; set; } } } diff --git a/BurnOutSharp/External/libmspack/CHM/Decompressor.cs b/BurnOutSharp/External/libmspack/CHM/Decompressor.cs index bd5a99b4..ce45be21 100644 --- a/BurnOutSharp/External/libmspack/CHM/Decompressor.cs +++ b/BurnOutSharp/External/libmspack/CHM/Decompressor.cs @@ -18,7 +18,7 @@ using System; using System.IO; using System.Text; using LibMSPackSharp.Compression; -using static LibMSPackSharp.CHM.Constants; +using static LibMSPackSharp.Constants; namespace LibMSPackSharp.CHM { @@ -29,16 +29,12 @@ namespace LibMSPackSharp.CHM /// /// /// - public class Decompressor + public class Decompressor : BaseDecompressor { #region Fields - public SystemImpl System { get; set; } - public DecompressState State { get; set; } - public Error Error { get; set; } - #endregion #region Public Functionality @@ -62,10 +58,7 @@ namespace LibMSPackSharp.CHM /// /// a pointer to a mschmd_header structure, or NULL on failure /// - public CHM Open(string filename) - { - return RealOpen(filename, true); - } + public CHM Open(string filename) => RealOpen(filename, true); /// /// Closes a previously opened CHM helpfile. @@ -137,8 +130,8 @@ namespace LibMSPackSharp.CHM State.Header = chm; State.Offset = 0; State.State = null; - State.Sys = System; - State.Sys.Write = SysWrite; + State.System = System; + State.System.Write = SysWrite; State.InputFileHandle = null; State.OutputFileHandle = null; } @@ -279,10 +272,7 @@ namespace LibMSPackSharp.CHM /// /// /// - public CHM FastOpen(string filename) - { - return RealOpen(filename, false); - } + public CHM FastOpen(string filename) => RealOpen(filename, false); /// /// Finds file details quickly. @@ -587,7 +577,7 @@ namespace LibMSPackSharp.CHM length -= State.Offset; // Initialise LZX stream - State.State = LZX.Init(State.Sys, State.InputFileHandle, State.OutputFileHandle, window_bits, reset_interval / LZX.LZX_FRAME_SIZE, 4096, length, false); + State.State = LZX.Init(State.System, State.InputFileHandle, State.OutputFileHandle, window_bits, reset_interval / LZX.LZX_FRAME_SIZE, 4096, length, false); if (State.State == null) Error = Error.MSPACK_ERR_NOMEMORY; diff --git a/BurnOutSharp/External/libmspack/Compression/CompressionStream.cs b/BurnOutSharp/External/libmspack/Compression/CompressionStream.cs index 75599476..fad21319 100644 --- a/BurnOutSharp/External/libmspack/Compression/CompressionStream.cs +++ b/BurnOutSharp/External/libmspack/Compression/CompressionStream.cs @@ -11,33 +11,15 @@ */ using System; -using System.IO; namespace LibMSPackSharp.Compression { - public abstract class CompressionStream + public abstract class CompressionStream : BaseDecompressState { private const int CHAR_BIT = 8; public const int BITBUF_WIDTH = 4 * CHAR_BIT; - /// - /// I/O routines - /// - public SystemImpl Sys { get; set; } - - /// - /// Input file handle - /// - public FileStream Input { get; set; } - - /// - /// Output file handle - /// - public FileStream Output { get; set; } - - public Error Error { get; set; } - #region I/O buffering public byte[] InputBuffer { get; set; } @@ -135,7 +117,7 @@ namespace LibMSPackSharp.Compression public Error ReadInput() { - int read = Sys.Read(Input, InputBuffer, 0, (int)InputBufferSize); + int read = System.Read(InputFileHandle, InputBuffer, 0, (int)InputBufferSize); if (read < 0) return Error = Error.MSPACK_ERR_READ; diff --git a/BurnOutSharp/External/libmspack/KWAJ/Implementation.cs b/BurnOutSharp/External/libmspack/Compression/LZHKWAJ.cs similarity index 71% rename from BurnOutSharp/External/libmspack/KWAJ/Implementation.cs rename to BurnOutSharp/External/libmspack/Compression/LZHKWAJ.cs index c07bd21d..b4c87fa3 100644 --- a/BurnOutSharp/External/libmspack/KWAJ/Implementation.cs +++ b/BurnOutSharp/External/libmspack/Compression/LZHKWAJ.cs @@ -7,415 +7,39 @@ * For further details, see the file COPYING.LIB distributed with libmspack */ -using System; using System.IO; -using System.Text; -using LibMSPackSharp.Compression; +using LibMSPackSharp.KWAJ; +using static LibMSPackSharp.Constants; -namespace LibMSPackSharp.KWAJ +namespace LibMSPackSharp.Compression { - public class Implementation + /// + /// In the KWAJ LZH format, there is no special 'eof' marker, it just + /// ends. Depending on how many bits are left in the final byte when + /// the stream ends, that might be enough to start another literal or + /// match. The only easy way to detect that we've come to an end is to + /// guard all bit-reading. We allow fake bits to be read once we reach + /// the end of the stream, but we check if we then consumed any of + /// those fake bits, after doing the READ_BITS / READ_HUFFSYM. This + /// isn't how the default ReadInput works (it simply lets + /// 2 fake bytes in then stops), so we implement our own. + /// + public class LZHKWAJ { - #region Generic KWAJ Definitions - - private const byte kwajh_Signature1 = 0x00; - private const byte kwajh_Signature2 = 0x04; - private const byte kwajh_CompMethod = 0x08; - private const byte kwajh_DataOffset = 0x0a; - private const byte kwajh_Flags = 0x0c; - private const byte kwajh_SIZEOF = 0x0e; - - #endregion - - #region KWAJ Decompression Definitions - - // Input buffer size during decompression - not worth parameterising IMHO - private const int KWAJ_INPUT_SIZE = (2048); - - // Huffman codes that are 9 bits or less are decoded immediately - public const int KWAJ_TABLEBITS = (9); - - // Number of codes in each huffman table - - public const int KWAJ_MATCHLEN1_SYMS = (16); - public const int KWAJ_MATCHLEN2_SYMS = (16); - public const int KWAJ_LITLEN_SYMS = (32); - public const int KWAJ_OFFSET_SYMS = (64); - public const int KWAJ_LITERAL_SYMS = (256); - - // Define decoding table sizes - - public const int KWAJ_TABLESIZE = (1 << KWAJ_TABLEBITS); - - //public const int KWAJ_MATCHLEN1_TBLSIZE = (KWAJ_MATCHLEN1_SYMS * 4); - public const int KWAJ_MATCHLEN1_TBLSIZE = (KWAJ_TABLESIZE + (KWAJ_MATCHLEN1_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 const int KWAJ_LITLEN_TBLSIZE = (KWAJ_LITLEN_SYMS * 4); - public const int KWAJ_LITLEN_TBLSIZE = (KWAJ_TABLESIZE + (KWAJ_LITLEN_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 - - #region KWAJD_OPEN - - /// - /// Opens a KWAJ file without decompressing, reads header - /// - public static Header Open(Decompressor d, string filename) - { - DecompressorImpl self = d as DecompressorImpl; - if (self == null) - return null; - - SystemImpl sys = self.System; - - FileStream fh = sys.Open(filename, OpenMode.MSPACK_SYS_OPEN_READ); - HeaderImpl hdr = new HeaderImpl(); - if (fh != null && hdr != null) - { - hdr.FileHandle = fh; - self.Error = ReadHeaders(sys, fh, hdr); - } - else - { - if (fh == null) - self.Error = Error.MSPACK_ERR_OPEN; - if (hdr == null) - self.Error = Error.MSPACK_ERR_NOMEMORY; - } - - if (self.Error != Error.MSPACK_ERR_OK) - { - if (fh != null) - sys.Close(fh); - - hdr = null; - } - - return hdr; - } - - #endregion - - #region KWAJD_CLOSE - - /// - /// Closes a KWAJ file - /// - public static void Close(Decompressor d, Header hdr) - { - DecompressorImpl self = d as DecompressorImpl; - HeaderImpl hdr_p = hdr as HeaderImpl; - - if (self?.System == null || hdr_p == null) - return; - - // Close the file handle associated - self.System.Close(hdr_p.FileHandle); - - self.Error = Error.MSPACK_ERR_OK; - } - - #endregion - - #region KWAJD_READ_HEADERS - - /// - /// Reads the headers of a KWAJ format file - /// - public static Error ReadHeaders(SystemImpl sys, FileStream fh, Header hdr) - { - int i; - - // Read in the header - byte[] buf = new byte[16]; - if (sys.Read(fh, buf, 0, kwajh_SIZEOF) != kwajh_SIZEOF) - { - return Error.MSPACK_ERR_READ; - } - - // Check for "KWAJ" signature - if ((BitConverter.ToUInt32(buf, kwajh_Signature1) != 0x4A41574B) || - (BitConverter.ToUInt32(buf, kwajh_Signature2) != 0xD127F088)) - { - return Error.MSPACK_ERR_SIGNATURE; - } - - // Basic header fields - hdr.CompressionType = (CompressionType)BitConverter.ToUInt16(buf, kwajh_CompMethod); - hdr.DataOffset = BitConverter.ToUInt16(buf, kwajh_DataOffset); - hdr.Headers = (OptionalHeaderFlag)BitConverter.ToUInt16(buf, kwajh_Flags); - hdr.Length = 0; - hdr.Filename = null; - hdr.Extra = null; - hdr.ExtraLength = 0; - - // Optional headers - - // 4 bytes: length of unpacked file - if (hdr.Headers.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASLENGTH)) - { - if (sys.Read(fh, buf, 0, 4) != 4) - return Error.MSPACK_ERR_READ; - - hdr.Length = BitConverter.ToUInt32(buf, 0); - } - - // 2 bytes: unknown purpose - if (hdr.Headers.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASUNKNOWN1)) - { - if (sys.Read(fh, buf, 0, 2) != 2) - return Error.MSPACK_ERR_READ; - } - - // 2 bytes: length of section, then [length] bytes: unknown purpose - if (hdr.Headers.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASUNKNOWN2)) - { - if (sys.Read(fh, buf, 0, 2) != 2) - return Error.MSPACK_ERR_READ; - - i = BitConverter.ToUInt16(buf, 0); - if (sys.Seek(fh, i, SeekMode.MSPACK_SYS_SEEK_CUR)) - return Error.MSPACK_ERR_SEEK; - } - - // Filename and extension - if (hdr.Headers.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASFILENAME) || hdr.Headers.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASFILEEXT)) - { - int len; - - // Allocate memory for maximum length filename - char[] fn = new char[13]; - int fnPtr = 0; - - // Copy filename if present - if (hdr.Headers.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASFILENAME)) - { - // Read and copy up to 9 bytes of a null terminated string - if ((len = sys.Read(fh, buf, 0, 9)) < 2) - return Error.MSPACK_ERR_READ; - - for (i = 0; i < len; i++) - { - if ((fn[fnPtr++] = (char)buf[i]) == '\0') - break; - } - - // If string was 9 bytes with no null terminator, reject it - if (i == 9 && buf[8] != '\0') - return Error.MSPACK_ERR_DATAFORMAT; - - // Seek to byte after string ended in file - if (sys.Seek(fh, i + 1 - len, SeekMode.MSPACK_SYS_SEEK_CUR)) - return Error.MSPACK_ERR_SEEK; - - fnPtr--; // Remove the null terminator - } - - // Copy extension if present - if (hdr.Headers.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASFILEEXT)) - { - fn[fnPtr++] = '.'; - - // Read and copy up to 4 bytes of a null terminated string - if ((len = sys.Read(fh, buf, 0, 4)) < 2) - return Error.MSPACK_ERR_READ; - - for (i = 0; i < len; i++) - { - if ((fn[fnPtr++] = (char)buf[i]) == '\0') - break; - } - - // If string was 4 bytes with no null terminator, reject it - if (i == 4 && buf[3] != '\0') - return Error.MSPACK_ERR_DATAFORMAT; - - // Seek to byte after string ended in file - if (sys.Seek(fh, i + 1 - len, SeekMode.MSPACK_SYS_SEEK_CUR)) - return Error.MSPACK_ERR_SEEK; - - fnPtr--; // Remove the null terminator - } - - fn[fnPtr] = '\0'; - } - - // 2 bytes: extra text length then [length] bytes of extra text data - if (hdr.Headers.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASEXTRATEXT)) - { - if (sys.Read(fh, buf, 0, 2) != 2) - return Error.MSPACK_ERR_READ; - - i = BitConverter.ToUInt16(buf, 0); - byte[] extra = new byte[i + 1]; - if (sys.Read(fh, extra, 0, i) != i) - return Error.MSPACK_ERR_READ; - - extra[i] = 0x00; - hdr.Extra = Encoding.ASCII.GetString(extra, 0, extra.Length); - hdr.ExtraLength = (ushort)i; - } - - return Error.MSPACK_ERR_OK; - } - - #endregion - - #region KWAJD_EXTRACT - - /// - /// Decompresses a KWAJ file - /// - public static Error Extract(Decompressor d, Header hdr, string filename) - { - DecompressorImpl self = d as DecompressorImpl; - if (self == null) - return Error.MSPACK_ERR_ARGS; - if (hdr == null) - return self.Error = Error.MSPACK_ERR_ARGS; - - SystemImpl sys = self.System; - FileStream fh = (hdr as HeaderImpl)?.FileHandle; - if (fh == null) - return Error.MSPACK_ERR_ARGS; - - // Seek to the compressed data - if (sys.Seek(fh, hdr.DataOffset, SeekMode.MSPACK_SYS_SEEK_START)) - return self.Error = Error.MSPACK_ERR_SEEK; - - // Open file for output - FileStream outfh; - if ((outfh = sys.Open(filename, OpenMode.MSPACK_SYS_OPEN_WRITE)) == null) - return self.Error = Error.MSPACK_ERR_OPEN; - - self.Error = Error.MSPACK_ERR_OK; - - // Decompress based on format - if (hdr.CompressionType == CompressionType.MSKWAJ_COMP_NONE || - hdr.CompressionType == CompressionType.MSKWAJ_COMP_XOR) - { - // NONE is a straight copy. XOR is a copy xored with 0xFF - byte[] buf = new byte[KWAJ_INPUT_SIZE]; - - int read, i; - while ((read = sys.Read(fh, buf, 0, KWAJ_INPUT_SIZE)) > 0) - { - if (hdr.CompressionType == CompressionType.MSKWAJ_COMP_XOR) - { - for (i = 0; i < read; i++) - { - buf[i] ^= 0xFF; - } - } - - if (sys.Write(outfh, buf, 0, read) != read) - { - self.Error = Error.MSPACK_ERR_WRITE; - break; - } - } - - if (read < 0) - self.Error = Error.MSPACK_ERR_READ; - } - else if (hdr.CompressionType == CompressionType.MSKWAJ_COMP_SZDD) - { - self.Error = LZSS.Decompress(sys, fh, outfh, KWAJ_INPUT_SIZE, LZSSMode.LZSS_MODE_EXPAND); - } - else if (hdr.CompressionType == CompressionType.MSKWAJ_COMP_LZH) - { - LZHKWAJStream lzh = LZHInit(sys, fh, outfh); - self.Error = (lzh != null) ? LZHDecompress(lzh) : Error.MSPACK_ERR_NOMEMORY; - } - else if (hdr.CompressionType == CompressionType.MSKWAJ_COMP_MSZIP) - { - MSZIPDStream zip = MSZIP.Init(sys, fh, outfh, KWAJ_INPUT_SIZE, false); - self.Error = (zip != null) ? MSZIP.DecompressKWAJ(zip) : Error.MSPACK_ERR_NOMEMORY; - } - else - { - self.Error = Error.MSPACK_ERR_DATAFORMAT; - } - - // Close output file - sys.Close(outfh); - - return self.Error; - } - - #endregion - - #region KWAJD_DECOMPRESS - - /// - /// Unpacks directly from input to output - /// - public static Error Decompress(Decompressor d, string input, string output) - { - DecompressorImpl self = d as DecompressorImpl; - if (self == null) - return Error.MSPACK_ERR_ARGS; - - Header hdr; - if ((hdr = Open(d, input)) == null) - return self.Error; - - Error error = Extract(d, hdr, output); - Close(d, hdr); - return self.Error = error; - } - - #endregion - - #region KWAJD_ERROR - - /// - /// Returns the last error that occurred - /// - public static Error LastError(Decompressor d) - { - DecompressorImpl self = d as DecompressorImpl; - return (self != null) ? self.Error : Error.MSPACK_ERR_ARGS; - } - - #endregion - - #region LZH_INIT, LZH_DECOMPRESS, LZH_FREE - - /* In the KWAJ LZH format, there is no special 'eof' marker, it just - * ends. Depending on how many bits are left in the final byte when - * the stream ends, that might be enough to start another literal or - * match. The only easy way to detect that we've come to an end is to - * guard all bit-reading. We allow fake bits to be read once we reach - * the end of the stream, but we check if we then consumed any of - * those fake bits, after doing the READ_BITS / READ_HUFFSYM. This - * isn't how the default readbits.h read_input() works (it simply lets - * 2 fake bytes in then stops), so we implement our own. - */ - - private static LZHKWAJStream LZHInit(SystemImpl sys, FileStream input, FileStream output) + public static LZHKWAJStream Init(SystemImpl sys, FileStream input, FileStream output) { if (sys == null || input == null || output == null) return null; return new LZHKWAJStream() { - Sys = sys, - Input = input, - Output = output, + System = sys, + InputFileHandle = input, + OutputFileHandle = output, }; } - private static Error LZHDecompress(LZHKWAJStream lzh) + public static Error Decompress(LZHKWAJStream lzh) { uint bit_buffer; int bits_left, i; @@ -464,7 +88,7 @@ namespace LibMSPackSharp.KWAJ { if (i_ptr >= i_end) { - if ((err = LZHReadInput(lzh)) != Error.MSPACK_ERR_OK) + if ((err = ReadInput(lzh)) != Error.MSPACK_ERR_OK) return err; i_ptr = lzh.InputPointer; @@ -506,7 +130,7 @@ namespace LibMSPackSharp.KWAJ lzh.BitsLeft = bits_left; } - err = LZHReadLens(lzh, types[0], KWAJ_MATCHLEN1_SYMS, lzh.MATCHLEN1_len); + err = ReadLens(lzh, types[0], KWAJ_MATCHLEN1_SYMS, lzh.MATCHLEN1_len); if (err != Error.MSPACK_ERR_OK) return err; @@ -532,7 +156,7 @@ namespace LibMSPackSharp.KWAJ lzh.BitsLeft = bits_left; } - err = LZHReadLens(lzh, types[1], KWAJ_MATCHLEN2_SYMS, lzh.MATCHLEN2_len); + err = ReadLens(lzh, types[1], KWAJ_MATCHLEN2_SYMS, lzh.MATCHLEN2_len); if (err != Error.MSPACK_ERR_OK) return err; @@ -558,7 +182,7 @@ namespace LibMSPackSharp.KWAJ lzh.BitsLeft = bits_left; } - err = LZHReadLens(lzh, types[2], KWAJ_LITLEN_SYMS, lzh.LITLEN_len); + err = ReadLens(lzh, types[2], KWAJ_LITLEN_SYMS, lzh.LITLEN_len); if (err != Error.MSPACK_ERR_OK) return err; @@ -584,7 +208,7 @@ namespace LibMSPackSharp.KWAJ lzh.BitsLeft = bits_left; } - err = LZHReadLens(lzh, types[3], KWAJ_OFFSET_SYMS, lzh.OFFSET_len); + err = ReadLens(lzh, types[3], KWAJ_OFFSET_SYMS, lzh.OFFSET_len); if (err != Error.MSPACK_ERR_OK) return err; @@ -610,7 +234,7 @@ namespace LibMSPackSharp.KWAJ lzh.BitsLeft = bits_left; } - err = LZHReadLens(lzh, types[4], KWAJ_LITERAL_SYMS, lzh.LITERAL_len); + err = ReadLens(lzh, types[4], KWAJ_LITERAL_SYMS, lzh.LITERAL_len); if (err != Error.MSPACK_ERR_OK) return err; @@ -642,7 +266,7 @@ namespace LibMSPackSharp.KWAJ { if (i_ptr >= i_end) { - if ((err = LZHReadInput(lzh)) != Error.MSPACK_ERR_OK) + if ((err = ReadInput(lzh)) != Error.MSPACK_ERR_OK) return err; i_ptr = lzh.InputPointer; @@ -702,7 +326,7 @@ namespace LibMSPackSharp.KWAJ { if (i_ptr >= i_end) { - if ((err = LZHReadInput(lzh)) != Error.MSPACK_ERR_OK) + if ((err = ReadInput(lzh)) != Error.MSPACK_ERR_OK) return err; i_ptr = lzh.InputPointer; @@ -766,7 +390,7 @@ namespace LibMSPackSharp.KWAJ { if (i_ptr >= i_end) { - if ((err = LZHReadInput(lzh)) != Error.MSPACK_ERR_OK) + if ((err = ReadInput(lzh)) != Error.MSPACK_ERR_OK) return err; i_ptr = lzh.InputPointer; @@ -826,7 +450,7 @@ namespace LibMSPackSharp.KWAJ { if (i_ptr >= i_end) { - if ((err = LZHReadInput(lzh)) != Error.MSPACK_ERR_OK) + if ((err = ReadInput(lzh)) != Error.MSPACK_ERR_OK) return err; i_ptr = lzh.InputPointer; @@ -864,7 +488,7 @@ namespace LibMSPackSharp.KWAJ //WRITE_BYTE { - if (lzh.Sys.Write(lzh.Output, lzh.Window, pos, 1) != 1) + if (lzh.System.Write(lzh.OutputFileHandle, lzh.Window, pos, 1) != 1) return Error.MSPACK_ERR_WRITE; } @@ -886,7 +510,7 @@ namespace LibMSPackSharp.KWAJ { if (i_ptr >= i_end) { - if ((err = LZHReadInput(lzh)) != Error.MSPACK_ERR_OK) + if ((err = ReadInput(lzh)) != Error.MSPACK_ERR_OK) return err; i_ptr = lzh.InputPointer; @@ -948,7 +572,7 @@ namespace LibMSPackSharp.KWAJ { if (i_ptr >= i_end) { - if ((err = LZHReadInput(lzh)) != Error.MSPACK_ERR_OK) + if ((err = ReadInput(lzh)) != Error.MSPACK_ERR_OK) return err; i_ptr = lzh.InputPointer; @@ -999,7 +623,7 @@ namespace LibMSPackSharp.KWAJ //WRITE_BYTE { - if (lzh.Sys.Write(lzh.Output, lzh.Window, pos, 1) != 1) + if (lzh.System.Write(lzh.OutputFileHandle, lzh.Window, pos, 1) != 1) return Error.MSPACK_ERR_WRITE; } @@ -1011,7 +635,7 @@ namespace LibMSPackSharp.KWAJ return Error.MSPACK_ERR_OK; } - public static Error LZHReadLens(LZHKWAJStream lzh, uint type, uint numsyms, byte[] lens) + private static Error ReadLens(LZHKWAJStream lzh, uint type, uint numsyms, byte[] lens) { uint bit_buffer; int bits_left; @@ -1052,7 +676,7 @@ namespace LibMSPackSharp.KWAJ { if (i_ptr >= i_end) { - if ((err = LZHReadInput(lzh)) != Error.MSPACK_ERR_OK) + if ((err = ReadInput(lzh)) != Error.MSPACK_ERR_OK) return err; i_ptr = lzh.InputPointer; @@ -1096,7 +720,7 @@ namespace LibMSPackSharp.KWAJ { if (i_ptr >= i_end) { - if ((err = LZHReadInput(lzh)) != Error.MSPACK_ERR_OK) + if ((err = ReadInput(lzh)) != Error.MSPACK_ERR_OK) return err; i_ptr = lzh.InputPointer; @@ -1143,7 +767,7 @@ namespace LibMSPackSharp.KWAJ { if (i_ptr >= i_end) { - if ((err = LZHReadInput(lzh)) != Error.MSPACK_ERR_OK) + if ((err = ReadInput(lzh)) != Error.MSPACK_ERR_OK) return err; i_ptr = lzh.InputPointer; @@ -1190,7 +814,7 @@ namespace LibMSPackSharp.KWAJ { if (i_ptr >= i_end) { - if ((err = LZHReadInput(lzh)) != Error.MSPACK_ERR_OK) + if ((err = ReadInput(lzh)) != Error.MSPACK_ERR_OK) return err; i_ptr = lzh.InputPointer; @@ -1239,7 +863,7 @@ namespace LibMSPackSharp.KWAJ { if (i_ptr >= i_end) { - if ((err = LZHReadInput(lzh)) != Error.MSPACK_ERR_OK) + if ((err = ReadInput(lzh)) != Error.MSPACK_ERR_OK) return err; i_ptr = lzh.InputPointer; @@ -1283,7 +907,7 @@ namespace LibMSPackSharp.KWAJ { if (i_ptr >= i_end) { - if ((err = LZHReadInput(lzh)) != Error.MSPACK_ERR_OK) + if ((err = ReadInput(lzh)) != Error.MSPACK_ERR_OK) return err; i_ptr = lzh.InputPointer; @@ -1326,7 +950,7 @@ namespace LibMSPackSharp.KWAJ { if (i_ptr >= i_end) { - if ((err = LZHReadInput(lzh)) != Error.MSPACK_ERR_OK) + if ((err = ReadInput(lzh)) != Error.MSPACK_ERR_OK) return err; i_ptr = lzh.InputPointer; @@ -1380,7 +1004,7 @@ namespace LibMSPackSharp.KWAJ { if (i_ptr >= i_end) { - if ((err = LZHReadInput(lzh)) != Error.MSPACK_ERR_OK) + if ((err = ReadInput(lzh)) != Error.MSPACK_ERR_OK) return err; i_ptr = lzh.InputPointer; @@ -1426,7 +1050,7 @@ namespace LibMSPackSharp.KWAJ return Error.MSPACK_ERR_OK; } - public static Error LZHReadInput(LZHKWAJStream lzh) + private static Error ReadInput(LZHKWAJStream lzh) { int read; if (lzh.InputEnd != 0) @@ -1437,7 +1061,7 @@ namespace LibMSPackSharp.KWAJ } else { - read = lzh.Sys.Read(lzh.Input, lzh.InputBuffer, 0, KWAJ_INPUT_SIZE); + read = lzh.System.Read(lzh.InputFileHandle, lzh.InputBuffer, 0, KWAJ_INPUT_SIZE); if (read < 0) return Error.MSPACK_ERR_READ; @@ -1454,7 +1078,5 @@ namespace LibMSPackSharp.KWAJ lzh.InputLength = read; return Error.MSPACK_ERR_OK; } - - #endregion } } diff --git a/BurnOutSharp/External/libmspack/KWAJ/LZHKWAJStream.cs b/BurnOutSharp/External/libmspack/Compression/LZHKWAJStream.cs similarity index 54% rename from BurnOutSharp/External/libmspack/KWAJ/LZHKWAJStream.cs rename to BurnOutSharp/External/libmspack/Compression/LZHKWAJStream.cs index 36442df1..c7bd28d1 100644 --- a/BurnOutSharp/External/libmspack/KWAJ/LZHKWAJStream.cs +++ b/BurnOutSharp/External/libmspack/Compression/LZHKWAJStream.cs @@ -7,27 +7,27 @@ * For further details, see the file COPYING.LIB distributed with libmspack */ -using LibMSPackSharp.Compression; +using static LibMSPackSharp.Constants; -namespace LibMSPackSharp.KWAJ +namespace LibMSPackSharp.Compression { public class LZHKWAJStream : CompressionStream { // Huffman code lengths - public byte[] MATCHLEN1_len { get; set; } = new byte[Implementation.KWAJ_MATCHLEN1_SYMS]; - public byte[] MATCHLEN2_len { get; set; } = new byte[Implementation.KWAJ_MATCHLEN2_SYMS]; - public byte[] LITLEN_len { get; set; } = new byte[Implementation.KWAJ_LITLEN_SYMS]; - public byte[] OFFSET_len { get; set; } = new byte[Implementation.KWAJ_OFFSET_SYMS]; - public byte[] LITERAL_len { get; set; } = new byte[Implementation.KWAJ_LITERAL_SYMS]; + public byte[] MATCHLEN1_len { get; set; } = new byte[KWAJ_MATCHLEN1_SYMS]; + public byte[] MATCHLEN2_len { get; set; } = new byte[KWAJ_MATCHLEN2_SYMS]; + public byte[] LITLEN_len { get; set; } = new byte[KWAJ_LITLEN_SYMS]; + public byte[] OFFSET_len { get; set; } = new byte[KWAJ_OFFSET_SYMS]; + public byte[] LITERAL_len { get; set; } = new byte[KWAJ_LITERAL_SYMS]; // Huffman decoding tables - public ushort[] MATCHLEN1_table { get; set; } = new ushort[Implementation.KWAJ_MATCHLEN1_TBLSIZE]; - public ushort[] MATCHLEN2_table { get; set; } = new ushort[Implementation.KWAJ_MATCHLEN2_TBLSIZE]; - public ushort[] LITLEN_table { get; set; } = new ushort[Implementation.KWAJ_LITLEN_TBLSIZE]; - public ushort[] OFFSET_table { get; set; } = new ushort[Implementation.KWAJ_OFFSET_TBLSIZE]; - public ushort[] LITERAL_table { get; set; } = new ushort[Implementation.KWAJ_LITERAL_TBLSIZE]; + public ushort[] MATCHLEN1_table { get; set; } = new ushort[KWAJ_MATCHLEN1_TBLSIZE]; + public ushort[] MATCHLEN2_table { get; set; } = new ushort[KWAJ_MATCHLEN2_TBLSIZE]; + public ushort[] LITLEN_table { get; set; } = new ushort[KWAJ_LITLEN_TBLSIZE]; + public ushort[] OFFSET_table { get; set; } = new ushort[KWAJ_OFFSET_TBLSIZE]; + public ushort[] LITERAL_table { get; set; } = new ushort[KWAJ_LITERAL_TBLSIZE]; // History window diff --git a/BurnOutSharp/External/libmspack/Compression/LZX.cs b/BurnOutSharp/External/libmspack/Compression/LZX.cs index 3c4e0633..9bb464a6 100644 --- a/BurnOutSharp/External/libmspack/Compression/LZX.cs +++ b/BurnOutSharp/External/libmspack/Compression/LZX.cs @@ -191,8 +191,6 @@ namespace LibMSPackSharp.Compression private static void ResetState(LZXDStream lzx) { - int i; - lzx.R0 = 1; lzx.R1 = 1; lzx.R2 = 1; @@ -201,12 +199,12 @@ namespace LibMSPackSharp.Compression lzx.BlockType = LZXBlockType.LZX_BLOCKTYPE_INVALID0; // Initialise tables to 0 (because deltas will be applied to them) - for (i = 0; i < LZX_MAINTREE_MAXSYMBOLS; i++) + for (int i = 0; i < LZX_MAINTREE_MAXSYMBOLS; i++) { lzx.MAINTREE_len[i] = 0; } - for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++) + for (int i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++) { lzx.LENGTH_len[i] = 0; } @@ -307,9 +305,9 @@ namespace LibMSPackSharp.Compression Window = new byte[window_size], InputBuffer = new byte[input_buffer_size], - Sys = system, - Input = input, - Output = output, + System = system, + InputFileHandle = input, + OutputFileHandle = output, Offset = 0, Length = output_length, @@ -472,7 +470,7 @@ namespace LibMSPackSharp.Compression if (i != 0) { - try { lzx.Sys.Write(lzx.Output, lzx.e8_buf, lzx.OutputPointer, i); } + try { lzx.System.Write(lzx.OutputFileHandle, lzx.e8_buf, lzx.OutputPointer, i); } catch { return lzx.Error = Error.MSPACK_ERR_WRITE; } lzx.OutputPointer += i; @@ -512,7 +510,7 @@ namespace LibMSPackSharp.Compression Console.WriteLine($"{lzx.BlockRemaining} bytes remaining at reset interval"); if (warned == 0) { - lzx.Sys.Message(null, "WARNING; invalid reset interval detected during LZX decompression"); + lzx.System.Message(null, "WARNING; invalid reset interval detected during LZX decompression"); warned++; } } @@ -577,182 +575,6 @@ namespace LibMSPackSharp.Compression } } - // Read header if necessary - if (lzx.HeaderRead == 0) - { - // Read 1 bit. if bit=0, intel_filesize = 0. - // if bit=1, read intel filesize (32 bits) - j = 0; - - //READ_BITS(i, 1) - { - //ENSURE_BITS(1) - { - while (bits_left < (1)) - { - //READ_BYTES - { - //READ_IF_NEEDED - { - if (i_ptr >= i_end) - { - if (lzx.ReadInput() != Error.MSPACK_ERR_OK) - return lzx.Error; - - i_ptr = lzx.InputPointer; - i_end = lzx.InputLength; - } - } - - byte b0 = lzx.InputBuffer[i_ptr++]; - - //READ_IF_NEEDED - { - if (i_ptr >= i_end) - { - if (lzx.ReadInput() != Error.MSPACK_ERR_OK) - return lzx.Error; - - i_ptr = lzx.InputPointer; - i_end = lzx.InputLength; - } - } - - byte b1 = lzx.InputBuffer[i_ptr++]; - - //INJECT_BITS((b1 << 8) | b0, 16) - { - bit_buffer |= (uint)((b1 << 8) | b0) << (CompressionStream.BITBUF_WIDTH - (16) - bits_left); - bits_left += (16); - } - } - } - } - - (i) = (int)(bit_buffer >> (CompressionStream.BITBUF_WIDTH - (1))); //PEEK_BITS(1) - - //REMOVE_BITS(1) - { - bit_buffer <<= (1); - bits_left -= (1); - } - } - - if (i != 0) - { - //READ_BITS(i, 16) - { - //ENSURE_BITS(16) - { - while (bits_left < (16)) - { - //READ_BYTES - { - //READ_IF_NEEDED - { - if (i_ptr >= i_end) - { - if (lzx.ReadInput() != Error.MSPACK_ERR_OK) - return lzx.Error; - - i_ptr = lzx.InputPointer; - i_end = lzx.InputLength; - } - } - - byte b0 = lzx.InputBuffer[i_ptr++]; - - //READ_IF_NEEDED - { - if (i_ptr >= i_end) - { - if (lzx.ReadInput() != Error.MSPACK_ERR_OK) - return lzx.Error; - - i_ptr = lzx.InputPointer; - i_end = lzx.InputLength; - } - } - - byte b1 = lzx.InputBuffer[i_ptr++]; - - //INJECT_BITS((b1 << 8) | b0, 16) - { - bit_buffer |= (uint)((b1 << 8) | b0) << (CompressionStream.BITBUF_WIDTH - (16) - bits_left); - bits_left += (16); - } - } - } - } - - (i) = (int)(bit_buffer >> (CompressionStream.BITBUF_WIDTH - (16))); //PEEK_BITS(16) - - //REMOVE_BITS(16) - { - bit_buffer <<= (16); - bits_left -= (16); - } - } - - //READ_BITS(j, 16) - { - //ENSURE_BITS(16) - { - while (bits_left < (16)) - { - //READ_BYTES - { - //READ_IF_NEEDED - { - if (i_ptr >= i_end) - { - if (lzx.ReadInput() != Error.MSPACK_ERR_OK) - return lzx.Error; - - i_ptr = lzx.InputPointer; - i_end = lzx.InputLength; - } - } - - byte b0 = lzx.InputBuffer[i_ptr++]; - - //READ_IF_NEEDED - { - if (i_ptr >= i_end) - { - if (lzx.ReadInput() != Error.MSPACK_ERR_OK) - return lzx.Error; - - i_ptr = lzx.InputPointer; - i_end = lzx.InputLength; - } - } - - byte b1 = lzx.InputBuffer[i_ptr++]; - - //INJECT_BITS((b1 << 8) | b0, 16) - { - bit_buffer |= (uint)((b1 << 8) | b0) << (CompressionStream.BITBUF_WIDTH - (16) - bits_left); - bits_left += (16); - } - } - } - } - - (j) = (int)(bit_buffer >> (CompressionStream.BITBUF_WIDTH - (16))); //PEEK_BITS(16) - - //REMOVE_BITS(16) - { - bit_buffer <<= (16); - bits_left -= (16); - } - } - } - - lzx.IntelFileSize = (i << 16) | j; - lzx.HeaderRead = 1; - } - // Calculate size of frame: all frames are 32k except the final frame // which is 32kb or less. this can only be calculated when lzx.Length // has been filled in. @@ -789,7 +611,7 @@ namespace LibMSPackSharp.Compression //READ_BITS(lzx.BlockType, 3) { - //ENSURE_BITS(3) + //ENSURE_BITS(3) // THIS IS NOT 3 BECAUSE OF OTHER CODE I FOUND { while (bits_left < (3)) { @@ -841,6 +663,182 @@ namespace LibMSPackSharp.Compression } } + // Read header if necessary + if (lzx.HeaderRead == 0) + { + // Read 1 bit. if bit=0, intel_filesize = 0. + // if bit=1, read intel filesize (32 bits) + j = 0; + + //READ_BITS(i, 1) + { + //ENSURE_BITS(1) + { + while (bits_left < (1)) + { + //READ_BYTES + { + //READ_IF_NEEDED + { + if (i_ptr >= i_end) + { + if (lzx.ReadInput() != Error.MSPACK_ERR_OK) + return lzx.Error; + + i_ptr = lzx.InputPointer; + i_end = lzx.InputLength; + } + } + + byte b0 = lzx.InputBuffer[i_ptr++]; + + //READ_IF_NEEDED + { + if (i_ptr >= i_end) + { + if (lzx.ReadInput() != Error.MSPACK_ERR_OK) + return lzx.Error; + + i_ptr = lzx.InputPointer; + i_end = lzx.InputLength; + } + } + + byte b1 = lzx.InputBuffer[i_ptr++]; + + //INJECT_BITS((b1 << 8) | b0, 16) + { + bit_buffer |= (uint)((b1 << 8) | b0) << (CompressionStream.BITBUF_WIDTH - (16) - bits_left); + bits_left += (16); + } + } + } + } + + (i) = (int)(bit_buffer >> (CompressionStream.BITBUF_WIDTH - (1))); //PEEK_BITS(1) + + //REMOVE_BITS(1) + { + bit_buffer <<= (1); + bits_left -= (1); + } + } + + if (i != 0) + { + //READ_BITS(i, 16) + { + //ENSURE_BITS(16) + { + while (bits_left < (16)) + { + //READ_BYTES + { + //READ_IF_NEEDED + { + if (i_ptr >= i_end) + { + if (lzx.ReadInput() != Error.MSPACK_ERR_OK) + return lzx.Error; + + i_ptr = lzx.InputPointer; + i_end = lzx.InputLength; + } + } + + byte b0 = lzx.InputBuffer[i_ptr++]; + + //READ_IF_NEEDED + { + if (i_ptr >= i_end) + { + if (lzx.ReadInput() != Error.MSPACK_ERR_OK) + return lzx.Error; + + i_ptr = lzx.InputPointer; + i_end = lzx.InputLength; + } + } + + byte b1 = lzx.InputBuffer[i_ptr++]; + + //INJECT_BITS((b1 << 8) | b0, 16) + { + bit_buffer |= (uint)((b1 << 8) | b0) << (CompressionStream.BITBUF_WIDTH - (16) - bits_left); + bits_left += (16); + } + } + } + } + + (i) = (int)(bit_buffer >> (CompressionStream.BITBUF_WIDTH - (16))); //PEEK_BITS(16) + + //REMOVE_BITS(16) + { + bit_buffer <<= (16); + bits_left -= (16); + } + } + + //READ_BITS(j, 16) + { + //ENSURE_BITS(16) + { + while (bits_left < (16)) + { + //READ_BYTES + { + //READ_IF_NEEDED + { + if (i_ptr >= i_end) + { + if (lzx.ReadInput() != Error.MSPACK_ERR_OK) + return lzx.Error; + + i_ptr = lzx.InputPointer; + i_end = lzx.InputLength; + } + } + + byte b0 = lzx.InputBuffer[i_ptr++]; + + //READ_IF_NEEDED + { + if (i_ptr >= i_end) + { + if (lzx.ReadInput() != Error.MSPACK_ERR_OK) + return lzx.Error; + + i_ptr = lzx.InputPointer; + i_end = lzx.InputLength; + } + } + + byte b1 = lzx.InputBuffer[i_ptr++]; + + //INJECT_BITS((b1 << 8) | b0, 16) + { + bit_buffer |= (uint)((b1 << 8) | b0) << (CompressionStream.BITBUF_WIDTH - (16) - bits_left); + bits_left += (16); + } + } + } + } + + (j) = (int)(bit_buffer >> (CompressionStream.BITBUF_WIDTH - (16))); //PEEK_BITS(16) + + //REMOVE_BITS(16) + { + bit_buffer <<= (16); + bits_left -= (16); + } + } + } + + lzx.IntelFileSize = (i << 16) | j; + lzx.HeaderRead = 1; + } + //READ_BITS(i, 16) { //ENSURE_BITS(16) @@ -2415,7 +2413,7 @@ namespace LibMSPackSharp.Compression // Write a frame i = (int)((out_bytes < frame_size) ? out_bytes : frame_size); - try { lzx.Output.Write(lzx.e8_buf, lzx.OutputPointer, i); } + try { lzx.System.Write(lzx.OutputFileHandle, lzx.e8_buf, lzx.OutputPointer, i); } catch { return lzx.Error = Error.MSPACK_ERR_WRITE; } } else @@ -2425,7 +2423,7 @@ namespace LibMSPackSharp.Compression // Write a frame i = (int)((out_bytes < frame_size) ? out_bytes : frame_size); - try { lzx.Output.Write(lzx.Window, lzx.OutputPointer, i); } + try { lzx.System.Write(lzx.OutputFileHandle, lzx.Window, lzx.OutputPointer, i); } catch { return lzx.Error = Error.MSPACK_ERR_WRITE; } } diff --git a/BurnOutSharp/External/libmspack/Compression/MSZIP.cs b/BurnOutSharp/External/libmspack/Compression/MSZIP.cs index 42e3827d..f6a160c0 100644 --- a/BurnOutSharp/External/libmspack/Compression/MSZIP.cs +++ b/BurnOutSharp/External/libmspack/Compression/MSZIP.cs @@ -112,9 +112,9 @@ namespace LibMSPackSharp.Compression InputBuffer = new byte[input_buffer_size], // Initialise decompression state - Sys = system, - Input = input, - Output = output, + System = system, + InputFileHandle = input, + OutputFileHandle = output, InputBufferSize = (uint)input_buffer_size, InputEnd = 0, Error = Error.MSPACK_ERR_OK, @@ -176,7 +176,7 @@ namespace LibMSPackSharp.Compression if (i != 0) { - if (zip.Sys.Write(zip.Output, zip.Window, zip.OutputPointer, i) != i) + if (zip.System.Write(zip.OutputFileHandle, zip.Window, zip.OutputPointer, i) != i) return zip.Error = Error.MSPACK_ERR_WRITE; zip.OutputPointer += i; @@ -279,7 +279,7 @@ namespace LibMSPackSharp.Compression if (zip.BytesOutput == 0 && zip.WindowPosition > 0) zip.FlushWindow(zip, zip.WindowPosition); - zip.Sys.Message(null, $"MSZIP error, {MSZIP_FRAME_SIZE - zip.BytesOutput} bytes of data lost."); + zip.System.Message(null, $"MSZIP error, {MSZIP_FRAME_SIZE - zip.BytesOutput} bytes of data lost."); for (i = zip.BytesOutput; i < MSZIP_FRAME_SIZE; i++) { zip.Window[i] = 0x00; @@ -298,7 +298,7 @@ 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) + if (zip.System.Write(zip.OutputFileHandle, 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 @@ -536,7 +536,7 @@ namespace LibMSPackSharp.Compression } // Write inflated block - try { zip.Sys.Write(zip.Output, zip.Window, 0, zip.BytesOutput); } + try { zip.System.Write(zip.OutputFileHandle, zip.Window, 0, zip.BytesOutput); } catch { return zip.Error = Error.MSPACK_ERR_WRITE; } } diff --git a/BurnOutSharp/External/libmspack/Compression/None.cs b/BurnOutSharp/External/libmspack/Compression/None.cs index 3d26968a..eacb7740 100644 --- a/BurnOutSharp/External/libmspack/Compression/None.cs +++ b/BurnOutSharp/External/libmspack/Compression/None.cs @@ -17,9 +17,9 @@ namespace LibMSPackSharp.Compression { return new NoneState() { - Sys = sys, - Input = input, - Output = output, + System = sys, + InputFileHandle = input, + OutputFileHandle = output, Buffer = new byte[bufsize], BufferSize = bufsize, }; @@ -36,10 +36,10 @@ namespace LibMSPackSharp.Compression { run = (bytes > state.BufferSize) ? state.BufferSize : (int)bytes; - if (state.Sys.Read(state.Input, state.Buffer, 0, run) != run) + if (state.System.Read(state.InputFileHandle, state.Buffer, 0, run) != run) return Error.MSPACK_ERR_READ; - if (state.Sys.Write(state.Output, state.Buffer, 0, run) != run) + if (state.System.Write(state.OutputFileHandle, state.Buffer, 0, run) != run) return Error.MSPACK_ERR_WRITE; bytes -= run; diff --git a/BurnOutSharp/External/libmspack/Compression/NoneState.cs b/BurnOutSharp/External/libmspack/Compression/NoneState.cs index ccbba111..b98ae342 100644 --- a/BurnOutSharp/External/libmspack/Compression/NoneState.cs +++ b/BurnOutSharp/External/libmspack/Compression/NoneState.cs @@ -7,21 +7,13 @@ * For further details, see the file COPYING.LIB distributed with libmspack */ -using System.IO; - namespace LibMSPackSharp.Compression { /// /// The "not compressed" method decompressor /// - public class NoneState + public class NoneState : BaseDecompressState { - public SystemImpl Sys { get; set; } - - public FileStream Input { get; set; } - - public FileStream Output { get; set; } - public byte[] Buffer { get; set; } public int BufferSize { get; set; } diff --git a/BurnOutSharp/External/libmspack/Compression/QTM.cs b/BurnOutSharp/External/libmspack/Compression/QTM.cs index 0a6ca78c..288347bf 100644 --- a/BurnOutSharp/External/libmspack/Compression/QTM.cs +++ b/BurnOutSharp/External/libmspack/Compression/QTM.cs @@ -116,9 +116,9 @@ namespace LibMSPackSharp.Compression InputBuffer = new byte[input_buffer_size], // Initialise decompression state - Sys = system, - Input = input, - Output = output, + System = system, + InputFileHandle = input, + OutputFileHandle = output, InputBufferSize = (uint)input_buffer_size, WindowSize = window_size, WindowPosition = 0, @@ -203,7 +203,7 @@ namespace LibMSPackSharp.Compression if (i != 0) { - if (qtm.Sys.Write(qtm.Output, qtm.Window, qtm.OutputPointer, i) != i) + if (qtm.System.Write(qtm.OutputFileHandle, qtm.Window, qtm.OutputPointer, i) != i) return qtm.Error = Error.MSPACK_ERR_WRITE; qtm.OutputPointer += i; @@ -1223,7 +1223,7 @@ namespace LibMSPackSharp.Compression return qtm.Error = Error.MSPACK_ERR_DECRUNCH; } - if (qtm.Sys.Write(qtm.Output, window, qtm.OutputPointer, i) != i) + if (qtm.System.Write(qtm.OutputFileHandle, window, qtm.OutputPointer, i) != i) return qtm.Error = Error.MSPACK_ERR_WRITE; out_bytes -= i; @@ -1388,7 +1388,7 @@ namespace LibMSPackSharp.Compression if (i >= out_bytes) break; - if (qtm.Sys.Write(qtm.Output, window, qtm.OutputPointer, i) != i) + if (qtm.System.Write(qtm.OutputFileHandle, window, qtm.OutputPointer, i) != i) return qtm.Error = Error.MSPACK_ERR_WRITE; out_bytes -= i; @@ -1403,7 +1403,7 @@ namespace LibMSPackSharp.Compression { i = (int)out_bytes; - if (qtm.Sys.Write(qtm.Output, window, qtm.OutputPointer, i) != i) + if (qtm.System.Write(qtm.OutputFileHandle, window, qtm.OutputPointer, i) != i) return qtm.Error = Error.MSPACK_ERR_WRITE; qtm.OutputPointer += i; diff --git a/BurnOutSharp/External/libmspack/Constants.cs b/BurnOutSharp/External/libmspack/Constants.cs new file mode 100644 index 00000000..eedc7346 --- /dev/null +++ b/BurnOutSharp/External/libmspack/Constants.cs @@ -0,0 +1,196 @@ +/* This file is part of libmspack. + * (C) 2003-2004 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 +{ + internal class Constants + { + #region CAB + + // CAB data blocks are <= 32768 bytes in uncompressed form.Uncompressed + // blocks have zero growth. MSZIP guarantees that it won't grow above + // uncompressed size by more than 12 bytes.LZX guarantees it won't grow + // more than 6144 bytes.Quantum has no documentation, but the largest + // block seen in the wild is 337 bytes above uncompressed size. + + public const int CAB_BLOCKMAX = 32768; + public const int CAB_INPUTMAX = CAB_BLOCKMAX + 6144; + + // input buffer needs to be CAB_INPUTMAX + 1 byte to allow for max-sized block + // plus 1 trailer byte added by cabd_sys_read_block() for Quantum alignment. + // + // When MSCABD_PARAM_SALVAGE is set, block size is not checked so can be + // up to 65535 bytes, so max input buffer size needed is 65535 + 1 + + public const int CAB_INPUTMAX_SALVAGE = 65535; + public const int CAB_INPUTBUF = CAB_INPUTMAX_SALVAGE + 1; + + // There are no more than 65535 data blocks per folder, so a folder cannot + // be more than 32768*65535 bytes in length.As files cannot span more than + // one folder, this is also their max offset, length and offset+length limit. + + public const int CAB_FOLDERMAX = 65535; + public const int CAB_LENGTHMAX = CAB_BLOCKMAX * CAB_FOLDERMAX; + + #endregion + + #region CHM + + // _PMGHeader + public const int pmgl_Signature = 0x0000; + public const int pmgl_QuickRefSize = 0x0004; + public const int pmgl_PMGIEntries = 0x0008; // Unknown1 in PMGL + public const int pmgl_PrevChunk = 0x000C; // Not in PMGI + public const int pmgl_NextChunk = 0x0010; // Not in PMGI + public const int pmgl_PMGLEntries = 0x0014; // Not in PMGI + public const int pmgl_headerSIZEOF = 0x0014; + public const int pmgi_headerSIZEOF = 0x000C; + + // _LZXControlData + public const int lzxcd_Length = 0x0000; + public const int lzxcd_Signature = 0x0004; + public const int lzxcd_Version = 0x0008; + public const int lzxcd_ResetInterval = 0x000C; + public const int lzxcd_WindowSize = 0x0010; + public const int lzxcd_CacheSize = 0x0014; + public const int lzxcd_Unknown1 = 0x0018; + public const int lzxcd_SIZEOF = 0x001C; + + // _LZXResetTable + public const int lzxrt_Unknown1 = 0x0000; + public const int lzxrt_NumEntries = 0x0004; + public const int lzxrt_EntrySize = 0x0008; + public const int lzxrt_TableOffset = 0x000C; + public const int lzxrt_UncompLen = 0x0010; + public const int lzxrt_CompLen = 0x0018; + public const int lzxrt_FrameLen = 0x0020; + public const int lzxrt_Entries = 0x0028; + public const int lzxrt_headerSIZEOF = 0x0028; + + // Filenames of the system files used for decompression. + // - Content and ControlData are essential. + // - ResetTable is preferred, but SpanInfo can be used if not available + public const string ContentName = "::DataSpace/Storage/MSCompressed/Content"; + public const string ControlName = "::DataSpace/Storage/MSCompressed/ControlData"; + public const string SpanInfoName = "::DataSpace/Storage/MSCompressed/SpanInfo"; + public const string ResetTableName = "::DataSpace/Storage/MSCompressed/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTable"; + + #endregion + + #region HLP + + // None currently + + #endregion + + #region KWAJ + + public const byte kwajh_Signature1 = 0x00; + public const byte kwajh_Signature2 = 0x04; + public const byte kwajh_CompMethod = 0x08; + public const byte kwajh_DataOffset = 0x0a; + public const byte kwajh_Flags = 0x0c; + public const byte kwajh_SIZEOF = 0x0e; + + // Input buffer size during decompression - not worth parameterising IMHO + public const int KWAJ_INPUT_SIZE = (2048); + + // Huffman codes that are 9 bits or less are decoded immediately + public const int KWAJ_TABLEBITS = (9); + + // Number of codes in each huffman table + + public const int KWAJ_MATCHLEN1_SYMS = (16); + public const int KWAJ_MATCHLEN2_SYMS = (16); + public const int KWAJ_LITLEN_SYMS = (32); + public const int KWAJ_OFFSET_SYMS = (64); + public const int KWAJ_LITERAL_SYMS = (256); + + // Define decoding table sizes + + public const int KWAJ_TABLESIZE = (1 << KWAJ_TABLEBITS); + + //public const int KWAJ_MATCHLEN1_TBLSIZE = (KWAJ_MATCHLEN1_SYMS * 4); + public const int KWAJ_MATCHLEN1_TBLSIZE = (KWAJ_TABLESIZE + (KWAJ_MATCHLEN1_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 const int KWAJ_LITLEN_TBLSIZE = (KWAJ_LITLEN_SYMS * 4); + public const int KWAJ_LITLEN_TBLSIZE = (KWAJ_TABLESIZE + (KWAJ_LITLEN_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 + + #region LIT + + // None currently + + #endregion + + #region OAB + + // _Header + public const int oabhead_VersionHi = 0x0000; + public const int oabhead_VersionLo = 0x0004; + public const int oabhead_BlockMax = 0x0008; + public const int oabhead_TargetSize = 0x000c; + public const int oabhead_SIZEOF = 0x0010; + + // _Block + public const int oabblk_Flags = 0x0000; + public const int oabblk_CompSize = 0x0004; + public const int oabblk_UncompSize = 0x0008; + public const int oabblk_CRC = 0x000c; + public const int oabblk_SIZEOF = 0x0010; + + // _PatchHeader + public const int patchhead_VersionHi = 0x0000; + public const int patchhead_VersionLo = 0x0004; + public const int patchhead_BlockMax = 0x0008; + public const int patchhead_SourceSize = 0x000c; + public const int patchhead_TargetSize = 0x0010; + public const int patchhead_SourceCRC = 0x0014; + public const int patchhead_TargetCRC = 0x0018; + public const int patchhead_SIZEOF = 0x001c; + + // _PatchBlock + public const int patchblk_PatchSize = 0x0000; + public const int patchblk_TargetSize = 0x0004; + public const int patchblk_SourceSize = 0x0008; + public const int patchblk_CRC = 0x000c; + public const int patchblk_SIZEOF = 0x0010; + + #endregion + + #region SZDD + + /// + /// Input buffer size during decompression - not worth parameterising IMHO + /// + public const int SZDD_INPUT_SIZE = 2048; + + public static readonly byte[] expandSignature = new byte[8] + { + 0x53, 0x5A, 0x44, 0x44, 0x88, 0xF0, 0x27, 0x33 + }; + + public static readonly byte[] qbasicSignature = new byte[8] + { + 0x53, 0x5A, 0x20, 0x88, 0xF0, 0x27, 0x33, 0xD1 + }; + + #endregion + } +} diff --git a/BurnOutSharp/External/libmspack/HLP/Compressor.cs b/BurnOutSharp/External/libmspack/HLP/Compressor.cs index 47ea0671..0f5efbb5 100644 --- a/BurnOutSharp/External/libmspack/HLP/Compressor.cs +++ b/BurnOutSharp/External/libmspack/HLP/Compressor.cs @@ -16,8 +16,11 @@ namespace LibMSPackSharp.HLP { + // TODO public class Compressor { + public SystemImpl System { get; set; } + public int Dummy { get; set; } } } diff --git a/BurnOutSharp/External/libmspack/HLP/CompressorImpl.cs b/BurnOutSharp/External/libmspack/HLP/CompressorImpl.cs deleted file mode 100644 index 9505c83a..00000000 --- a/BurnOutSharp/External/libmspack/HLP/CompressorImpl.cs +++ /dev/null @@ -1,18 +0,0 @@ -/* This file is part of libmspack. - * (C) 2003-2004 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.HLP -{ - public class CompressorImpl : Compressor - { - public SystemImpl System { get; set; } - - // TODO - } -} diff --git a/BurnOutSharp/External/libmspack/HLP/Decompressor.cs b/BurnOutSharp/External/libmspack/HLP/Decompressor.cs index 2b498d0b..82fa31c7 100644 --- a/BurnOutSharp/External/libmspack/HLP/Decompressor.cs +++ b/BurnOutSharp/External/libmspack/HLP/Decompressor.cs @@ -16,8 +16,8 @@ namespace LibMSPackSharp.HLP { - public class Decompressor + public class Decompressor : BaseDecompressor { - public int Dummy { get; set; } + // TODO } } diff --git a/BurnOutSharp/External/libmspack/HLP/DecompressorImpl.cs b/BurnOutSharp/External/libmspack/HLP/DecompressorImpl.cs deleted file mode 100644 index 534edc6d..00000000 --- a/BurnOutSharp/External/libmspack/HLP/DecompressorImpl.cs +++ /dev/null @@ -1,18 +0,0 @@ -/* This file is part of libmspack. - * (C) 2003-2004 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.HLP -{ - public class DecompressorImpl : Decompressor - { - public SystemImpl System { get; set; } - - // TODO - } -} diff --git a/BurnOutSharp/External/libmspack/KWAJ/Compressor.cs b/BurnOutSharp/External/libmspack/KWAJ/Compressor.cs index c86d55ff..16389d3d 100644 --- a/BurnOutSharp/External/libmspack/KWAJ/Compressor.cs +++ b/BurnOutSharp/External/libmspack/KWAJ/Compressor.cs @@ -27,6 +27,19 @@ namespace LibMSPackSharp.KWAJ /// public class Compressor { + #region Fields + + public SystemImpl System { get; set; } + + /// + /// !!! MATCH THIS TO NUM OF PARAMS IN MSPACK.H !!! + /// + public int[] Param { get; set; } = new int[2]; + + public Error Error { get; set; } + + #endregion + /// /// Reads an input file and creates a compressed output file in the /// KWAJ compressed file format.The KWAJ compression format is quick diff --git a/BurnOutSharp/External/libmspack/KWAJ/CompressorImpl.cs b/BurnOutSharp/External/libmspack/KWAJ/CompressorImpl.cs deleted file mode 100644 index 65f0eaa5..00000000 --- a/BurnOutSharp/External/libmspack/KWAJ/CompressorImpl.cs +++ /dev/null @@ -1,25 +0,0 @@ -/* This file is part of libmspack. - * (C) 2003-2010 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.KWAJ -{ - public class CompressorImpl : Compressor - { - public SystemImpl System { get; set; } - - // TODO - - /// - /// !!! MATCH THIS TO NUM OF PARAMS IN MSPACK.H !!! - /// - public int[] Param { get; set; } = new int[2]; - - public Error Error { get; set; } - } -} diff --git a/BurnOutSharp/External/libmspack/KWAJ/Decompressor.cs b/BurnOutSharp/External/libmspack/KWAJ/Decompressor.cs index 3ef07706..7cd37b67 100644 --- a/BurnOutSharp/External/libmspack/KWAJ/Decompressor.cs +++ b/BurnOutSharp/External/libmspack/KWAJ/Decompressor.cs @@ -15,6 +15,10 @@ */ using System; +using System.IO; +using System.Text; +using LibMSPackSharp.Compression; +using static LibMSPackSharp.Constants; namespace LibMSPackSharp.KWAJ { @@ -25,8 +29,10 @@ namespace LibMSPackSharp.KWAJ /// /// /// - public class Decompressor + public class Decompressor : BaseDecompressor { + #region Public Functionality + /// /// Opens a KWAJ file and reads the header. /// @@ -39,17 +45,37 @@ namespace LibMSPackSharp.KWAJ /// The filename pointer should be considered "in use" until close() is /// called on the KWAJ file. /// - /// - /// a self-referential pointer to the mskwaj_decompressor - /// instance being called - /// /// /// the filename of the KWAJ compressed file. This is /// passed directly to mspack_system::open(). /// - /// a pointer to a mskwajd_header structure, or NULL on failure - /// - public Func Open; + /// A pointer to a mskwajd_header structure, or NULL on failure + /// + public Header Open(string filename) + { + FileStream fh = System.Open(filename, OpenMode.MSPACK_SYS_OPEN_READ); + Header hdr = new Header(); + if (fh != null && hdr != null) + { + hdr.FileHandle = fh; + Error = ReadHeaders(fh, hdr); + } + else + { + if (fh == null) + Error = Error.MSPACK_ERR_OPEN; + if (hdr == null) + Error = Error.MSPACK_ERR_NOMEMORY; + } + + if (Error != Error.MSPACK_ERR_OK) + { + System.Close(fh); + hdr = null; + } + + return hdr; + } /// /// Closes a previously opened KWAJ file. @@ -58,13 +84,18 @@ namespace LibMSPackSharp.KWAJ /// with it. The KWAJ header pointer is now invalid and cannot be /// used again. /// - /// - /// a self-referential pointer to the mskwaj_decompressor - /// instance being called - /// - /// the KWAJ file to close - /// - public Action Close; + /// The KWAJ file to close + /// + public void Close(Header hdr) + { + if (System == null || hdr == null) + return; + + // Close the file handle associated + System.Close(hdr.FileHandle); + + Error = Error.MSPACK_ERR_OK; + } /// /// Extracts the compressed data from a KWAJ file. @@ -72,17 +103,81 @@ namespace LibMSPackSharp.KWAJ /// This decompresses the compressed KWAJ data stream and writes it to /// an output file. /// - /// - /// a self-referential pointer to the mskwaj_decompressor - /// instance being called - /// - /// the KWAJ file to extract data from + /// The KWAJ file to extract data from /// /// the filename to write the decompressed data to. This /// is passed directly to mspack_system::open(). /// /// an error code, or MSPACK_ERR_OK if successful - public Func Extract; + public Error Extract(Header hdr, string filename) + { + FileStream fh = hdr?.FileHandle; + if (fh == null) + return Error.MSPACK_ERR_ARGS; + + // Seek to the compressed data + if (System.Seek(fh, hdr.DataOffset, SeekMode.MSPACK_SYS_SEEK_START)) + return Error = Error.MSPACK_ERR_SEEK; + + // Open file for output + FileStream outfh; + if ((outfh = System.Open(filename, OpenMode.MSPACK_SYS_OPEN_WRITE)) == null) + return Error = Error.MSPACK_ERR_OPEN; + + Error = Error.MSPACK_ERR_OK; + + // Decompress based on format + if (hdr.CompressionType == CompressionType.MSKWAJ_COMP_NONE || + hdr.CompressionType == CompressionType.MSKWAJ_COMP_XOR) + { + // NONE is a straight copy. XOR is a copy xored with 0xFF + byte[] buf = new byte[KWAJ_INPUT_SIZE]; + + int read, i; + while ((read = System.Read(fh, buf, 0, KWAJ_INPUT_SIZE)) > 0) + { + if (hdr.CompressionType == CompressionType.MSKWAJ_COMP_XOR) + { + for (i = 0; i < read; i++) + { + buf[i] ^= 0xFF; + } + } + + if (System.Write(outfh, buf, 0, read) != read) + { + Error = Error.MSPACK_ERR_WRITE; + break; + } + } + + if (read < 0) + Error = Error.MSPACK_ERR_READ; + } + else if (hdr.CompressionType == CompressionType.MSKWAJ_COMP_SZDD) + { + Error = LZSS.Decompress(System, fh, outfh, KWAJ_INPUT_SIZE, LZSSMode.LZSS_MODE_EXPAND); + } + else if (hdr.CompressionType == CompressionType.MSKWAJ_COMP_LZH) + { + LZHKWAJStream lzh = LZHKWAJ.Init(System, fh, outfh); + Error = (lzh != null) ? LZHKWAJ.Decompress(lzh) : Error.MSPACK_ERR_NOMEMORY; + } + else if (hdr.CompressionType == CompressionType.MSKWAJ_COMP_MSZIP) + { + MSZIPDStream zip = MSZIP.Init(System, fh, outfh, KWAJ_INPUT_SIZE, false); + Error = (zip != null) ? MSZIP.DecompressKWAJ(zip) : Error.MSPACK_ERR_NOMEMORY; + } + else + { + Error = Error.MSPACK_ERR_DATAFORMAT; + } + + // Close output file + System.Close(outfh); + + return Error; + } /// /// Decompresses an KWAJ file to an output file in one step. @@ -106,21 +201,159 @@ namespace LibMSPackSharp.KWAJ /// is passed directly to mspack_system::open(). /// /// an error code, or MSPACK_ERR_OK if successful - public Func Decompress; + public Error Decompress(string input, string output) + { + Header hdr = Open(input) as Header; + if (hdr == null) + return Error; + + Error error = Extract(hdr, output); + Close(hdr); + return Error = error; + } + + #endregion + + #region Helpers /// - /// Returns the error code set by the most recently called method. - /// - /// This is useful for open() which does not return an - /// error code directly. + /// Reads the headers of a KWAJ format file /// - /// - /// a self-referential pointer to the mskwaj_decompressor - /// instance being called - /// - /// the most recent error code - /// - /// - public Func LastError; + private Error ReadHeaders(FileStream fh, Header hdr) + { + int i; + + // Read in the header + byte[] buf = new byte[16]; + if (System.Read(fh, buf, 0, kwajh_SIZEOF) != kwajh_SIZEOF) + return Error.MSPACK_ERR_READ; + + // Check for "KWAJ" signature + if ((BitConverter.ToUInt32(buf, kwajh_Signature1) != 0x4A41574B) || + (BitConverter.ToUInt32(buf, kwajh_Signature2) != 0xD127F088)) + { + return Error.MSPACK_ERR_SIGNATURE; + } + + // Basic header fields + hdr.CompressionType = (CompressionType)BitConverter.ToUInt16(buf, kwajh_CompMethod); + hdr.DataOffset = BitConverter.ToUInt16(buf, kwajh_DataOffset); + hdr.Headers = (OptionalHeaderFlag)BitConverter.ToUInt16(buf, kwajh_Flags); + hdr.Length = 0; + hdr.Filename = null; + hdr.Extra = null; + hdr.ExtraLength = 0; + + // Optional headers + + // 4 bytes: length of unpacked file + if (hdr.Headers.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASLENGTH)) + { + if (System.Read(fh, buf, 0, 4) != 4) + return Error.MSPACK_ERR_READ; + + hdr.Length = BitConverter.ToUInt32(buf, 0); + } + + // 2 bytes: unknown purpose + if (hdr.Headers.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASUNKNOWN1)) + { + if (System.Read(fh, buf, 0, 2) != 2) + return Error.MSPACK_ERR_READ; + } + + // 2 bytes: length of section, then [length] bytes: unknown purpose + if (hdr.Headers.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASUNKNOWN2)) + { + if (System.Read(fh, buf, 0, 2) != 2) + return Error.MSPACK_ERR_READ; + + i = BitConverter.ToUInt16(buf, 0); + if (System.Seek(fh, i, SeekMode.MSPACK_SYS_SEEK_CUR)) + return Error.MSPACK_ERR_SEEK; + } + + // Filename and extension + if (hdr.Headers.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASFILENAME) || hdr.Headers.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASFILEEXT)) + { + int len; + + // Allocate memory for maximum length filename + char[] fn = new char[13]; + int fnPtr = 0; + + // Copy filename if present + if (hdr.Headers.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASFILENAME)) + { + // Read and copy up to 9 bytes of a null terminated string + if ((len = System.Read(fh, buf, 0, 9)) < 2) + return Error.MSPACK_ERR_READ; + + for (i = 0; i < len; i++) + { + if ((fn[fnPtr++] = (char)buf[i]) == '\0') + break; + } + + // If string was 9 bytes with no null terminator, reject it + if (i == 9 && buf[8] != '\0') + return Error.MSPACK_ERR_DATAFORMAT; + + // Seek to byte after string ended in file + if (System.Seek(fh, i + 1 - len, SeekMode.MSPACK_SYS_SEEK_CUR)) + return Error.MSPACK_ERR_SEEK; + + fnPtr--; // Remove the null terminator + } + + // Copy extension if present + if (hdr.Headers.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASFILEEXT)) + { + fn[fnPtr++] = '.'; + + // Read and copy up to 4 bytes of a null terminated string + if ((len = System.Read(fh, buf, 0, 4)) < 2) + return Error.MSPACK_ERR_READ; + + for (i = 0; i < len; i++) + { + if ((fn[fnPtr++] = (char)buf[i]) == '\0') + break; + } + + // If string was 4 bytes with no null terminator, reject it + if (i == 4 && buf[3] != '\0') + return Error.MSPACK_ERR_DATAFORMAT; + + // Seek to byte after string ended in file + if (System.Seek(fh, i + 1 - len, SeekMode.MSPACK_SYS_SEEK_CUR)) + return Error.MSPACK_ERR_SEEK; + + fnPtr--; // Remove the null terminator + } + + fn[fnPtr] = '\0'; + } + + // 2 bytes: extra text length then [length] bytes of extra text data + if (hdr.Headers.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASEXTRATEXT)) + { + if (System.Read(fh, buf, 0, 2) != 2) + return Error.MSPACK_ERR_READ; + + i = BitConverter.ToUInt16(buf, 0); + byte[] extra = new byte[i + 1]; + if (System.Read(fh, extra, 0, i) != i) + return Error.MSPACK_ERR_READ; + + extra[i] = 0x00; + hdr.Extra = Encoding.ASCII.GetString(extra, 0, extra.Length); + hdr.ExtraLength = (ushort)i; + } + + return Error.MSPACK_ERR_OK; + } + + #endregion } } diff --git a/BurnOutSharp/External/libmspack/KWAJ/DecompressorImpl.cs b/BurnOutSharp/External/libmspack/KWAJ/DecompressorImpl.cs deleted file mode 100644 index 538cafa7..00000000 --- a/BurnOutSharp/External/libmspack/KWAJ/DecompressorImpl.cs +++ /dev/null @@ -1,18 +0,0 @@ -/* This file is part of libmspack. - * (C) 2003-2010 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.KWAJ -{ - public class DecompressorImpl : Decompressor - { - public SystemImpl System { get; set; } - - public Error Error { get; set; } - } -} diff --git a/BurnOutSharp/External/libmspack/KWAJ/Header.cs b/BurnOutSharp/External/libmspack/KWAJ/Header.cs index a762c615..ea43c0fe 100644 --- a/BurnOutSharp/External/libmspack/KWAJ/Header.cs +++ b/BurnOutSharp/External/libmspack/KWAJ/Header.cs @@ -14,6 +14,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +using System.IO; + namespace LibMSPackSharp.KWAJ { /// @@ -21,7 +23,7 @@ namespace LibMSPackSharp.KWAJ /// /// All fields are READ ONLY. /// - public class Header + public class Header : BaseHeader { /// /// The compression type @@ -58,5 +60,7 @@ namespace LibMSPackSharp.KWAJ /// Length of extra uncompressed data in the header /// public ushort ExtraLength { get; set; } + + public FileStream FileHandle { get; set; } } } diff --git a/BurnOutSharp/External/libmspack/KWAJ/HeaderImpl.cs b/BurnOutSharp/External/libmspack/KWAJ/HeaderImpl.cs deleted file mode 100644 index 77e1d5b0..00000000 --- a/BurnOutSharp/External/libmspack/KWAJ/HeaderImpl.cs +++ /dev/null @@ -1,18 +0,0 @@ -/* This file is part of libmspack. - * (C) 2003-2010 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.IO; - -namespace LibMSPackSharp.KWAJ -{ - public class HeaderImpl : Header - { - public FileStream FileHandle { get; set; } - } -} diff --git a/BurnOutSharp/External/libmspack/LIT/Compressor.cs b/BurnOutSharp/External/libmspack/LIT/Compressor.cs index 62ab902c..99ce6edb 100644 --- a/BurnOutSharp/External/libmspack/LIT/Compressor.cs +++ b/BurnOutSharp/External/libmspack/LIT/Compressor.cs @@ -19,6 +19,6 @@ namespace LibMSPackSharp.LIT // TODO public class Compressor { - public int Dummy { get; set; } + public SystemImpl System { get; set; } } } diff --git a/BurnOutSharp/External/libmspack/LIT/CompressorImpl.cs b/BurnOutSharp/External/libmspack/LIT/CompressorImpl.cs deleted file mode 100644 index 8eab67d0..00000000 --- a/BurnOutSharp/External/libmspack/LIT/CompressorImpl.cs +++ /dev/null @@ -1,18 +0,0 @@ -/* This file is part of libmspack. - * (C) 2003-2004 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.LIT -{ - public class CompressorImpl : Compressor - { - public SystemImpl System { get; set; } - - // TODO - } -} diff --git a/BurnOutSharp/External/libmspack/LIT/Decompressor.cs b/BurnOutSharp/External/libmspack/LIT/Decompressor.cs index 8c1b31e6..02ab30ba 100644 --- a/BurnOutSharp/External/libmspack/LIT/Decompressor.cs +++ b/BurnOutSharp/External/libmspack/LIT/Decompressor.cs @@ -16,9 +16,8 @@ namespace LibMSPackSharp.LIT { - // TODO - public class Decompressor + public class Decompressor : BaseDecompressor { - public int Dummy { get; set; } + // TODO } } diff --git a/BurnOutSharp/External/libmspack/LIT/DecompressorImpl.cs b/BurnOutSharp/External/libmspack/LIT/DecompressorImpl.cs deleted file mode 100644 index c8d5339a..00000000 --- a/BurnOutSharp/External/libmspack/LIT/DecompressorImpl.cs +++ /dev/null @@ -1,18 +0,0 @@ -/* This file is part of libmspack. - * (C) 2003-2004 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.LIT -{ - public class DecompressorImpl : Decompressor - { - public SystemImpl System { get; set; } - - // TODO - } -} diff --git a/BurnOutSharp/External/libmspack/LIT/Implementation.cs b/BurnOutSharp/External/libmspack/LIT/Implementation.cs deleted file mode 100644 index 06c384b7..00000000 --- a/BurnOutSharp/External/libmspack/LIT/Implementation.cs +++ /dev/null @@ -1,15 +0,0 @@ -/* This file is part of libmspack. - * (C) 2003-2004 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.LIT -{ - public class Implementation - { - } -} diff --git a/BurnOutSharp/External/libmspack/Library.cs b/BurnOutSharp/External/libmspack/Library.cs index 4295679a..d35a79d7 100644 --- a/BurnOutSharp/External/libmspack/Library.cs +++ b/BurnOutSharp/External/libmspack/Library.cs @@ -374,13 +374,8 @@ namespace LibMSPackSharp if (!SystemImpl.ValidSystem(sys)) return null; - return new SZDD.DecompressorImpl() + return new SZDD.Decompressor() { - Open = SZDD.Implementation.Open, - Close = SZDD.Implementation.Close, - Extract = SZDD.Implementation.Extract, - Decompress = SZDD.Implementation.Decompress, - LastError = SZDD.Implementation.LastError, System = sys, Error = Error.MSPACK_ERR_OK, }; @@ -428,13 +423,8 @@ namespace LibMSPackSharp if (!SystemImpl.ValidSystem(sys)) return null; - return new KWAJ.DecompressorImpl() + return new KWAJ.Decompressor() { - Open = KWAJ.Implementation.Open, - Close = KWAJ.Implementation.Close, - Extract = KWAJ.Implementation.Extract, - Decompress = KWAJ.Implementation.Decompress, - LastError = KWAJ.Implementation.LastError, System = sys, Error = Error.MSPACK_ERR_OK, }; @@ -482,11 +472,8 @@ namespace LibMSPackSharp if (!SystemImpl.ValidSystem(sys)) return null; - return new OAB.DecompressorImpl() + return new OAB.Decompressor() { - Decompress = OAB.Implementation.Decompress, - DecompressIncremental = OAB.Implementation.DecompressIncremental, - SetParam = OAB.Implementation.Param, System = sys, BufferSize = 4096, }; diff --git a/BurnOutSharp/External/libmspack/OAB/Compressor.cs b/BurnOutSharp/External/libmspack/OAB/Compressor.cs index 6aba61a0..3d7a80a4 100644 --- a/BurnOutSharp/External/libmspack/OAB/Compressor.cs +++ b/BurnOutSharp/External/libmspack/OAB/Compressor.cs @@ -27,6 +27,12 @@ namespace LibMSPackSharp.OAB /// public class Compressor { + #region Fields + + public SystemImpl System { get; set; } + + #endregion + /// /// Compress a full OAB file. /// diff --git a/BurnOutSharp/External/libmspack/OAB/CompressorImpl.cs b/BurnOutSharp/External/libmspack/OAB/CompressorImpl.cs deleted file mode 100644 index 8abb627a..00000000 --- a/BurnOutSharp/External/libmspack/OAB/CompressorImpl.cs +++ /dev/null @@ -1,16 +0,0 @@ -/* This file is part of libmspack. - * © 2013 Intel Corporation - * - * 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.OAB -{ - public class CompressorImpl : Compressor - { - public SystemImpl System { get; set; } - } -} diff --git a/BurnOutSharp/External/libmspack/OAB/Decompressor.cs b/BurnOutSharp/External/libmspack/OAB/Decompressor.cs index 03862a04..cde2dd4d 100644 --- a/BurnOutSharp/External/libmspack/OAB/Decompressor.cs +++ b/BurnOutSharp/External/libmspack/OAB/Decompressor.cs @@ -15,6 +15,9 @@ */ using System; +using System.IO; +using LibMSPackSharp.Compression; +using static LibMSPackSharp.Constants; namespace LibMSPackSharp.OAB { @@ -25,8 +28,10 @@ namespace LibMSPackSharp.OAB /// /// /// - public class Decompressor + public class Decompressor : BaseDecompressor { + #region Public Functionality + /// /// Decompresses a full Offline Address Book file. /// @@ -34,20 +39,170 @@ namespace LibMSPackSharp.OAB /// it will be read and the decompressed contents will be written to /// the output file. /// - /// - /// a self-referential pointer to the msoab_decompressor - /// instance being called - /// /// - /// the filename of the input file. This is passed + /// The filename of the input file. This is passed /// directly to mspack_system::open(). /// /// - /// the filename of the output file. This is passed + /// The filename of the output file. This is passed /// directly to mspack_system::open(). /// - /// an error code, or MSPACK_ERR_OK if successful - public Func Decompress; + /// An error code, or MSPACK_ERR_OK if successful + public Error Decompress(string input, string output) + { + byte[] hdrbuf = new byte[oabhead_SIZEOF]; + LZXDStream lzx = null; + Error ret = Error.MSPACK_ERR_OK; + + FileStream infh = System.Open(input, OpenMode.MSPACK_SYS_OPEN_READ); + if (infh == null) + { + ret = Error.MSPACK_ERR_OPEN; + System.Close(infh); + return ret; + } + + if (System.Read(infh, hdrbuf, 0, oabhead_SIZEOF) != oabhead_SIZEOF) + { + ret = Error.MSPACK_ERR_READ; + System.Close(infh); + return ret; + } + + if (BitConverter.ToUInt32(hdrbuf, oabhead_VersionHi) != 3 || + BitConverter.ToUInt32(hdrbuf, oabhead_VersionLo) != 1) + { + ret = Error.MSPACK_ERR_SIGNATURE; + System.Close(infh); + return ret; + } + + uint block_max = BitConverter.ToUInt32(hdrbuf, oabhead_BlockMax); + uint target_size = BitConverter.ToUInt32(hdrbuf, oabhead_TargetSize); + + FileStream outfh = System.Open(output, OpenMode.MSPACK_SYS_OPEN_WRITE); + if (outfh == null) + { + ret = Error.MSPACK_ERR_OPEN; + System.Close(outfh); + System.Close(infh); + return ret; + } + + byte[] buf = new byte[BufferSize]; + + SystemImpl oabd_sys = System; + oabd_sys.Read = SysRead; + oabd_sys.Write = SysWrite; + + InternalFile in_ofh = new InternalFile(); + in_ofh.OrigSys = System; + in_ofh.OrigFile = infh; + + InternalFile out_ofh = new InternalFile(); + out_ofh.OrigSys = System; + out_ofh.OrigFile = outfh; + + while (target_size != 0) + { + if (System.Read(infh, buf, 0, oabblk_SIZEOF) != oabblk_SIZEOF) + { + ret = Error.MSPACK_ERR_READ; + System.Close(outfh); + System.Close(infh); + return ret; + } + + uint blk_flags = BitConverter.ToUInt32(buf, oabblk_Flags); + uint blk_csize = BitConverter.ToUInt32(buf, oabblk_CompSize); + uint blk_dsize = BitConverter.ToUInt32(buf, oabblk_UncompSize); + uint blk_crc = BitConverter.ToUInt32(buf, oabblk_CRC); + + if (blk_dsize > block_max || blk_dsize > target_size || blk_flags > 1) + { + ret = Error.MSPACK_ERR_DATAFORMAT; + System.Close(outfh); + System.Close(infh); + return ret; + } + + if (blk_flags == 0) + { + // Uncompressed block + if (blk_dsize != blk_csize) + { + ret = Error.MSPACK_ERR_DATAFORMAT; + System.Close(outfh); + System.Close(infh); + return ret; + } + + ret = CopyFileHandle(infh, outfh, (int)blk_dsize, buf, BufferSize); + if (ret != Error.MSPACK_ERR_OK) + { + System.Close(outfh); + System.Close(infh); + return ret; + } + } + else + { + // LZX compressed block + int window_bits = 17; + + while (window_bits < 25 && (1U << window_bits) < blk_dsize) + { + window_bits++; + } + + in_ofh.Available = (int)blk_csize; + out_ofh.CRC = 0xffffffff; + + lzx = LZX.Init(oabd_sys, in_ofh.OrigFile, out_ofh.OrigFile, window_bits, 0, BufferSize, blk_dsize, true); + if (lzx == null) + { + ret = Error.MSPACK_ERR_NOMEMORY; + System.Close(outfh); + System.Close(infh); + return ret; + } + + ret = LZX.Decompress(lzx, blk_dsize); + if (ret != Error.MSPACK_ERR_OK) + { + System.Close(outfh); + System.Close(infh); + return ret; + } + + lzx = null; + + // Consume any trailing padding bytes before the next block + ret = CopyFileHandle(infh, null, in_ofh.Available, buf, BufferSize); + if (ret != Error.MSPACK_ERR_OK) + { + System.Close(outfh); + System.Close(infh); + return ret; + } + + if (out_ofh.CRC != blk_crc) + { + ret = Error.MSPACK_ERR_CHECKSUM; + System.Close(outfh); + System.Close(infh); + return ret; + } + } + + target_size -= blk_dsize; + } + + System.Close(outfh); + System.Close(infh); + + return ret; + } /// /// Decompresses an Offline Address Book with an incremental patch file. @@ -63,25 +218,184 @@ namespace LibMSPackSharp.OAB /// in incorrect data being decompressed, which will then fail a checksum /// test. /// - /// - /// a self-referential pointer to the msoab_decompressor - /// instance being called - /// /// - /// the filename of the input file. This is passed + /// The filename of the input file. This is passed /// directly to mspack_system::open(). /// - /// - /// the filename of the base file to which the + /// + /// The filename of the base file to which the /// incremental patch shall be applied. This is passed /// directly to mspack_system::open(). /// /// - /// the filename of the output file. This is passed + /// The filename of the output file. This is passed /// directly to mspack_system::open(). /// - /// an error code, or MSPACK_ERR_OK if successful - public Func DecompressIncremental; + /// An error code, or MSPACK_ERR_OK if successful + public Error DecompressIncremental(string input, string basePath, string output) + { + byte[] hdrbuf = new byte[patchhead_SIZEOF]; + LZXDStream lzx = null; + int window_bits; + uint window_size; + Error ret = Error.MSPACK_ERR_OK; + + FileStream infh = System.Open(input, OpenMode.MSPACK_SYS_OPEN_READ); + if (infh == null) + { + ret = Error.MSPACK_ERR_OPEN; + System.Close(infh); + return ret; + } + + if (System.Read(infh, hdrbuf, 0, patchhead_SIZEOF) != patchhead_SIZEOF) + { + ret = Error.MSPACK_ERR_READ; + System.Close(infh); + return ret; + } + + if (BitConverter.ToUInt32(hdrbuf, patchhead_VersionHi) != 3 || + BitConverter.ToUInt32(hdrbuf, patchhead_VersionLo) != 2) + { + ret = Error.MSPACK_ERR_SIGNATURE; + System.Close(infh); + return ret; + } + + uint block_max = BitConverter.ToUInt32(hdrbuf, patchhead_BlockMax); + uint target_size = BitConverter.ToUInt32(hdrbuf, patchhead_TargetSize); + + // We use it for reading block headers too + if (block_max < patchblk_SIZEOF) + block_max = patchblk_SIZEOF; + + FileStream basefh = System.Open(basePath, OpenMode.MSPACK_SYS_OPEN_READ); + if (basefh == null) + { + ret = Error.MSPACK_ERR_OPEN; + System.Close(basefh); + System.Close(infh); + return ret; + } + + FileStream outfh = System.Open(output, OpenMode.MSPACK_SYS_OPEN_WRITE); + if (outfh == null) + { + ret = Error.MSPACK_ERR_OPEN; + System.Close(outfh); + System.Close(basefh); + System.Close(infh); + return ret; + } + + byte[] buf = new byte[BufferSize]; + + SystemImpl oabd_sys = System; + oabd_sys.Read = SysRead; + oabd_sys.Write = SysWrite; + + InternalFile in_ofh = new InternalFile(); + in_ofh.OrigSys = System; + in_ofh.OrigFile = infh; + + InternalFile out_ofh = new InternalFile(); + out_ofh.OrigSys = System; + out_ofh.OrigFile = outfh; + + while (target_size != 0) + { + if (System.Read(infh, buf, 0, patchblk_SIZEOF) != patchblk_SIZEOF) + { + ret = Error.MSPACK_ERR_READ; + System.Close(outfh); + System.Close(basefh); + System.Close(infh); + return ret; + } + + uint blk_csize = BitConverter.ToUInt32(buf, patchblk_PatchSize); + uint blk_dsize = BitConverter.ToUInt32(buf, patchblk_TargetSize); + uint blk_ssize = BitConverter.ToUInt32(buf, patchblk_SourceSize); + uint blk_crc = BitConverter.ToUInt32(buf, patchblk_CRC); + + if (blk_dsize > block_max || blk_dsize > target_size || blk_ssize > block_max) + { + ret = Error.MSPACK_ERR_DATAFORMAT; + System.Close(outfh); + System.Close(basefh); + System.Close(infh); + return ret; + } + + window_size = (uint)((blk_ssize + 32767) & ~32767); + window_size += blk_dsize; + window_bits = 17; + + while (window_bits < 25 && (1U << window_bits) < window_size) + window_bits++; + + in_ofh.Available = (int)blk_csize; + out_ofh.CRC = 0xffffffff; + + lzx = LZX.Init(oabd_sys, in_ofh.OrigFile, out_ofh.OrigFile, window_bits, 0, 4096, blk_dsize, true); + if (lzx == null) + { + ret = Error.MSPACK_ERR_NOMEMORY; + System.Close(outfh); + System.Close(basefh); + System.Close(infh); + return ret; + } + + ret = LZX.SetReferenceData(lzx, System, basefh, blk_ssize); + if (ret != Error.MSPACK_ERR_OK) + { + System.Close(outfh); + System.Close(basefh); + System.Close(infh); + return ret; + } + + ret = LZX.Decompress(lzx, blk_dsize); + if (ret != Error.MSPACK_ERR_OK) + { + System.Close(outfh); + System.Close(basefh); + System.Close(infh); + return ret; + } + + lzx = null; + + // Consume any trailing padding bytes before the next block + ret = CopyFileHandle(infh, null, in_ofh.Available, buf, BufferSize); + if (ret != Error.MSPACK_ERR_OK) + { + System.Close(outfh); + System.Close(basefh); + System.Close(infh); + return ret; + } + + if (out_ofh.CRC != blk_crc) + { + ret = Error.MSPACK_ERR_CHECKSUM; + System.Close(outfh); + System.Close(basefh); + System.Close(infh); + return ret; + } + + target_size -= blk_dsize; + } + + System.Close(outfh); + System.Close(basefh); + System.Close(infh); + + return ret; + } /// /// Sets an OAB decompression engine parameter. Available only in OAB @@ -91,16 +405,95 @@ namespace LibMSPackSharp.OAB /// buffer by decompressors? The minimum value is 16. The default value /// is 4096. /// - /// - /// a self-referential pointer to the msoab_decompressor - /// instance being called - /// - /// the parameter to set - /// the value to set the parameter to + /// The parameter to set + /// The value to set the parameter to /// /// MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if there /// is a problem with either parameter or value. /// - public Func SetParam; + public Error SetParam(Parameters param, int value) + { + if (param == Parameters.MSOABD_PARAM_DECOMPBUF && value >= 16) + { + // Must be at least 16 bytes (patchblk_SIZEOF, oabblk_SIZEOF) + BufferSize = value; + return Error.MSPACK_ERR_OK; + } + + return Error.MSPACK_ERR_ARGS; + } + + #endregion + + #region I/O Methods + + private static int SysRead(object baseFile, byte[] buf, int pointer, int size) + { + InternalFile file = baseFile as InternalFile; + if (file == null) + return 0; + + int bytes_read; + + if (size > file.Available) + size = file.Available; + + bytes_read = file.OrigSys.Read(file.OrigFile, buf, pointer, size); + if (bytes_read < 0) + return bytes_read; + + file.Available -= bytes_read; + return bytes_read; + } + + private static int SysWrite(object baseFile, byte[] buf, int pointer, int size) + { + // Null output file means skip those bytes + if (baseFile == null) + { + return size; + } + else 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); + + return bytes_written; + } + else if (baseFile is FileStream impl) + { + return SystemImpl.DefaultSystem.Write(impl, buf, pointer, size); + } + + // Unknown file to write to + return -1; + } + + #endregion + + #region Helpers + + private Error CopyFileHandle(FileStream infh, FileStream outfh, int bytes_to_copy, byte[] buf, int buf_size) + { + while (bytes_to_copy != 0) + { + int run = buf_size; + if (run > bytes_to_copy) + run = bytes_to_copy; + + if (System.Read(infh, buf, 0, run) != run) + return Error.MSPACK_ERR_READ; + + if (outfh != null && System.Write(outfh, buf, 0, run) != run) + return Error.MSPACK_ERR_WRITE; + + bytes_to_copy -= run; + } + + return Error.MSPACK_ERR_OK; + } + + #endregion } } diff --git a/BurnOutSharp/External/libmspack/OAB/DecompressorImpl.cs b/BurnOutSharp/External/libmspack/OAB/DecompressorImpl.cs deleted file mode 100644 index 4309d503..00000000 --- a/BurnOutSharp/External/libmspack/OAB/DecompressorImpl.cs +++ /dev/null @@ -1,20 +0,0 @@ -/* This file is part of libmspack. - * © 2013 Intel Corporation - * - * 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.OAB -{ - public class DecompressorImpl : Decompressor - { - public SystemImpl System { get; set; } - - public int BufferSize { get; set; } - - // TODO - } -} diff --git a/BurnOutSharp/External/libmspack/OAB/Implementation.cs b/BurnOutSharp/External/libmspack/OAB/Implementation.cs deleted file mode 100644 index 828c20ee..00000000 --- a/BurnOutSharp/External/libmspack/OAB/Implementation.cs +++ /dev/null @@ -1,491 +0,0 @@ -/* This file is part of libmspack. - * © 2013 Intel Corporation - * - * 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 - */ - -/* The Exchange Online Addressbook (OAB or sometimes OAL) is distributed - * as a .LZX file in one of two forms. Either a "full download" containing - * the entire address list, or an incremental binary patch which should be - * applied to a previous version of the full decompressed data. - * - * The contents and format of the decompressed OAB are not handled here. - * - * For a complete description of the format, see the MSDN site: - * - * http://msdn.microsoft.com/en-us/library/cc463914 - [MS-OXOAB].pdf - * http://msdn.microsoft.com/en-us/library/cc483133 - [MS-PATCH].pdf - */ - -using System; -using System.IO; -using LibMSPackSharp.Compression; - -namespace LibMSPackSharp.OAB -{ - public class Implementation - { - #region OAB decompression definitions - - private const int oabhead_VersionHi = 0x0000; - private const int oabhead_VersionLo = 0x0004; - private const int oabhead_BlockMax = 0x0008; - private const int oabhead_TargetSize = 0x000c; - private const int oabhead_SIZEOF = 0x0010; - - private const int oabblk_Flags = 0x0000; - private const int oabblk_CompSize = 0x0004; - private const int oabblk_UncompSize = 0x0008; - private const int oabblk_CRC = 0x000c; - private const int oabblk_SIZEOF = 0x0010; - - private const int patchhead_VersionHi = 0x0000; - private const int patchhead_VersionLo = 0x0004; - private const int patchhead_BlockMax = 0x0008; - private const int patchhead_SourceSize = 0x000c; - private const int patchhead_TargetSize = 0x0010; - private const int patchhead_SourceCRC = 0x0014; - private const int patchhead_TargetCRC = 0x0018; - private const int patchhead_SIZEOF = 0x001c; - - private const int patchblk_PatchSize = 0x0000; - private const int patchblk_TargetSize = 0x0004; - private const int patchblk_SourceSize = 0x0008; - private const int patchblk_CRC = 0x000c; - private const int patchblk_SIZEOF = 0x0010; - - #endregion - - #region OABD_SYS_READ - - private static int SysRead(object baseFile, byte[] buf, int pointer, int size) - { - InternalFile file = baseFile as InternalFile; - if (file == null) - return 0; - - int bytes_read; - - if (size > file.Available) - size = file.Available; - - bytes_read = file.OrigSys.Read(file.OrigFile, buf, pointer, size); - if (bytes_read < 0) - return bytes_read; - - file.Available -= bytes_read; - return bytes_read; - } - - #endregion - - #region OABD_SYS_WRITE - - private static int SysWrite(object baseFile, byte[] buf, int pointer, int size) - { - // Null output file means skip those bytes - if (baseFile == null) - { - return size; - } - else 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); - - return bytes_written; - } - else if (baseFile is FileStream impl) - { - return SystemImpl.DefaultSystem.Write(impl, buf, pointer, size); - } - - // Unknown file to write to - return -1; - } - - #endregion - - #region OABD_DECOMPRESS - - public static Error Decompress(Decompressor d, string input, string output) - { - DecompressorImpl self = d as DecompressorImpl; - byte[] hdrbuf = new byte[oabhead_SIZEOF]; - LZXDStream lzx = null; - Error ret = Error.MSPACK_ERR_OK; - - if (self == null) - return Error.MSPACK_ERR_ARGS; - - SystemImpl sys = self.System; - - FileStream infh = sys.Open(input, OpenMode.MSPACK_SYS_OPEN_READ); - if (infh == null) - { - ret = Error.MSPACK_ERR_OPEN; - sys.Close(infh); - return ret; - } - - if (sys.Read(infh, hdrbuf, 0, oabhead_SIZEOF) != oabhead_SIZEOF) - { - ret = Error.MSPACK_ERR_READ; - sys.Close(infh); - return ret; - } - - if (BitConverter.ToUInt32(hdrbuf, oabhead_VersionHi) != 3 || - BitConverter.ToUInt32(hdrbuf, oabhead_VersionLo) != 1) - { - ret = Error.MSPACK_ERR_SIGNATURE; - sys.Close(infh); - return ret; - } - - uint block_max = BitConverter.ToUInt32(hdrbuf, oabhead_BlockMax); - uint target_size = BitConverter.ToUInt32(hdrbuf, oabhead_TargetSize); - - FileStream outfh = sys.Open(output, OpenMode.MSPACK_SYS_OPEN_WRITE); - if (outfh == null) - { - ret = Error.MSPACK_ERR_OPEN; - sys.Close(outfh); - sys.Close(infh); - return ret; - } - - byte[] buf = new byte[self.BufferSize]; - - SystemImpl oabd_sys = sys; - oabd_sys.Read = SysRead; - oabd_sys.Write = SysWrite; - - InternalFile in_ofh = new InternalFile(); - in_ofh.OrigSys = sys; - in_ofh.OrigFile = infh; - - InternalFile out_ofh = new InternalFile(); - out_ofh.OrigSys = sys; - out_ofh.OrigFile = outfh; - - while (target_size != 0) - { - if (sys.Read(infh, buf, 0, oabblk_SIZEOF) != oabblk_SIZEOF) - { - ret = Error.MSPACK_ERR_READ; - sys.Close(outfh); - sys.Close(infh); - return ret; - } - - uint blk_flags = BitConverter.ToUInt32(buf, oabblk_Flags); - uint blk_csize = BitConverter.ToUInt32(buf, oabblk_CompSize); - uint blk_dsize = BitConverter.ToUInt32(buf, oabblk_UncompSize); - uint blk_crc = BitConverter.ToUInt32(buf, oabblk_CRC); - - if (blk_dsize > block_max || blk_dsize > target_size || blk_flags > 1) - { - ret = Error.MSPACK_ERR_DATAFORMAT; - sys.Close(outfh); - sys.Close(infh); - return ret; - } - - if (blk_flags == 0) - { - // Uncompressed block - if (blk_dsize != blk_csize) - { - ret = Error.MSPACK_ERR_DATAFORMAT; - sys.Close(outfh); - sys.Close(infh); - return ret; - } - - ret = CopyFileHandle(sys, infh, outfh, (int)blk_dsize, buf, self.BufferSize); - if (ret != Error.MSPACK_ERR_OK) - { - sys.Close(outfh); - sys.Close(infh); - return ret; - } - } - else - { - // LZX compressed block - int window_bits = 17; - - while (window_bits < 25 && (1U << window_bits) < blk_dsize) - { - window_bits++; - } - - in_ofh.Available = (int)blk_csize; - out_ofh.CRC = 0xffffffff; - - lzx = LZX.Init(oabd_sys, in_ofh.OrigFile, out_ofh.OrigFile, window_bits, 0, self.BufferSize, blk_dsize, true); - if (lzx == null) - { - ret = Error.MSPACK_ERR_NOMEMORY; - sys.Close(outfh); - sys.Close(infh); - return ret; - } - - ret = LZX.Decompress(lzx, blk_dsize); - if (ret != Error.MSPACK_ERR_OK) - { - sys.Close(outfh); - sys.Close(infh); - return ret; - } - - lzx = null; - - // Consume any trailing padding bytes before the next block - ret = CopyFileHandle(sys, infh, null, in_ofh.Available, buf, self.BufferSize); - if (ret != Error.MSPACK_ERR_OK) - { - sys.Close(outfh); - sys.Close(infh); - return ret; - } - - if (out_ofh.CRC != blk_crc) - { - ret = Error.MSPACK_ERR_CHECKSUM; - sys.Close(outfh); - sys.Close(infh); - return ret; - } - } - - target_size -= blk_dsize; - } - - sys.Close(outfh); - sys.Close(infh); - - return ret; - } - - #endregion - - #region OABD_DECOMPRESS_INCREMENTAL - - public static Error DecompressIncremental(Decompressor d, string input, string basePath, string output) - { - DecompressorImpl self = d as DecompressorImpl; - byte[] hdrbuf = new byte[patchhead_SIZEOF]; - LZXDStream lzx = null; - int window_bits; - uint window_size; - Error ret = Error.MSPACK_ERR_OK; - - if (self == null) - return Error.MSPACK_ERR_ARGS; - - SystemImpl sys = self.System; - - FileStream infh = sys.Open(input, OpenMode.MSPACK_SYS_OPEN_READ); - if (infh == null) - { - ret = Error.MSPACK_ERR_OPEN; - sys.Close(infh); - return ret; - } - - if (sys.Read(infh, hdrbuf, 0, patchhead_SIZEOF) != patchhead_SIZEOF) - { - ret = Error.MSPACK_ERR_READ; - sys.Close(infh); - return ret; - } - - if (BitConverter.ToUInt32(hdrbuf, patchhead_VersionHi) != 3 || - BitConverter.ToUInt32(hdrbuf, patchhead_VersionLo) != 2) - { - ret = Error.MSPACK_ERR_SIGNATURE; - sys.Close(infh); - return ret; - } - - uint block_max = BitConverter.ToUInt32(hdrbuf, patchhead_BlockMax); - uint target_size = BitConverter.ToUInt32(hdrbuf, patchhead_TargetSize); - - // We use it for reading block headers too - if (block_max < patchblk_SIZEOF) - block_max = patchblk_SIZEOF; - - FileStream basefh = sys.Open(basePath, OpenMode.MSPACK_SYS_OPEN_READ); - if (basefh == null) - { - ret = Error.MSPACK_ERR_OPEN; - sys.Close(basefh); - sys.Close(infh); - return ret; - } - - FileStream outfh = sys.Open(output, OpenMode.MSPACK_SYS_OPEN_WRITE); - if (outfh == null) - { - ret = Error.MSPACK_ERR_OPEN; - sys.Close(outfh); - sys.Close(basefh); - sys.Close(infh); - return ret; - } - - byte[] buf = new byte[self.BufferSize]; - - SystemImpl oabd_sys = sys; - oabd_sys.Read = SysRead; - oabd_sys.Write = SysWrite; - - InternalFile in_ofh = new InternalFile(); - in_ofh.OrigSys = sys; - in_ofh.OrigFile = infh; - - InternalFile out_ofh = new InternalFile(); - out_ofh.OrigSys = sys; - out_ofh.OrigFile = outfh; - - while (target_size != 0) - { - if (sys.Read(infh, buf, 0, patchblk_SIZEOF) != patchblk_SIZEOF) - { - ret = Error.MSPACK_ERR_READ; - sys.Close(outfh); - sys.Close(basefh); - sys.Close(infh); - return ret; - } - - uint blk_csize = BitConverter.ToUInt32(buf, patchblk_PatchSize); - uint blk_dsize = BitConverter.ToUInt32(buf, patchblk_TargetSize); - uint blk_ssize = BitConverter.ToUInt32(buf, patchblk_SourceSize); - uint blk_crc = BitConverter.ToUInt32(buf, patchblk_CRC); - - if (blk_dsize > block_max || blk_dsize > target_size || blk_ssize > block_max) - { - ret = Error.MSPACK_ERR_DATAFORMAT; - sys.Close(outfh); - sys.Close(basefh); - sys.Close(infh); - return ret; - } - - window_size = (uint)((blk_ssize + 32767) & ~32767); - window_size += blk_dsize; - window_bits = 17; - - while (window_bits < 25 && (1U << window_bits) < window_size) - window_bits++; - - in_ofh.Available = (int)blk_csize; - out_ofh.CRC = 0xffffffff; - - lzx = LZX.Init(oabd_sys, in_ofh.OrigFile, out_ofh.OrigFile, window_bits, 0, 4096, blk_dsize, true); - if (lzx == null) - { - ret = Error.MSPACK_ERR_NOMEMORY; - sys.Close(outfh); - sys.Close(basefh); - sys.Close(infh); - return ret; - } - - ret = LZX.SetReferenceData(lzx, sys, basefh, blk_ssize); - if (ret != Error.MSPACK_ERR_OK) - { - sys.Close(outfh); - sys.Close(basefh); - sys.Close(infh); - return ret; - } - - ret = LZX.Decompress(lzx, blk_dsize); - if (ret != Error.MSPACK_ERR_OK) - { - sys.Close(outfh); - sys.Close(basefh); - sys.Close(infh); - return ret; - } - - lzx = null; - - // Consume any trailing padding bytes before the next block - ret = CopyFileHandle(sys, infh, null, in_ofh.Available, buf, self.BufferSize); - if (ret != Error.MSPACK_ERR_OK) - { - sys.Close(outfh); - sys.Close(basefh); - sys.Close(infh); - return ret; - } - - if (out_ofh.CRC != blk_crc) - { - ret = Error.MSPACK_ERR_CHECKSUM; - sys.Close(outfh); - sys.Close(basefh); - sys.Close(infh); - return ret; - } - - target_size -= blk_dsize; - } - - sys.Close(outfh); - sys.Close(basefh); - sys.Close(infh); - - return ret; - } - - private static Error CopyFileHandle(SystemImpl sys, FileStream infh, FileStream outfh, int bytes_to_copy, byte[] buf, int buf_size) - { - while (bytes_to_copy != 0) - { - int run = buf_size; - if (run > bytes_to_copy) - run = bytes_to_copy; - - if (sys.Read(infh, buf, 0, run) != run) - return Error.MSPACK_ERR_READ; - - if (outfh != null && sys.Write(outfh, buf, 0, run) != run) - return Error.MSPACK_ERR_WRITE; - - bytes_to_copy -= run; - } - - return Error.MSPACK_ERR_OK; - } - - #endregion - - #region OABD_PARAM - - public static Error Param(Decompressor d, Parameters param, int value) - { - DecompressorImpl self = d as DecompressorImpl; - if (self != null && param == Parameters.MSOABD_PARAM_DECOMPBUF && value >= 16) - { - // must be at least 16 bytes (patchblk_SIZEOF, oabblk_SIZEOF) - self.BufferSize = value; - return Error.MSPACK_ERR_OK; - } - - return Error.MSPACK_ERR_ARGS; - } - - #endregion - } -} diff --git a/BurnOutSharp/External/libmspack/SZDD/Compressor.cs b/BurnOutSharp/External/libmspack/SZDD/Compressor.cs index 18520701..f28b984b 100644 --- a/BurnOutSharp/External/libmspack/SZDD/Compressor.cs +++ b/BurnOutSharp/External/libmspack/SZDD/Compressor.cs @@ -27,6 +27,14 @@ namespace LibMSPackSharp.SZDD /// public class Compressor { + #region Fields + + public SystemImpl System { get; set; } + + public Error Error { get; set; } + + #endregion + /// /// Reads an input file and creates a compressed output file in the /// SZDD compressed file format. The SZDD compression format is quick diff --git a/BurnOutSharp/External/libmspack/SZDD/CompressorImpl.cs b/BurnOutSharp/External/libmspack/SZDD/CompressorImpl.cs deleted file mode 100644 index 60b2495f..00000000 --- a/BurnOutSharp/External/libmspack/SZDD/CompressorImpl.cs +++ /dev/null @@ -1,18 +0,0 @@ -/* This file is part of libmspack. - * (C) 2003-2004 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.SZDD -{ - public class CompressorImpl : Compressor - { - public SystemImpl System { get; set; } - - public Error Error { get; set; } - } -} diff --git a/BurnOutSharp/External/libmspack/SZDD/Decompressor.cs b/BurnOutSharp/External/libmspack/SZDD/Decompressor.cs index 537ae425..72bffb97 100644 --- a/BurnOutSharp/External/libmspack/SZDD/Decompressor.cs +++ b/BurnOutSharp/External/libmspack/SZDD/Decompressor.cs @@ -15,6 +15,10 @@ */ using System; +using System.IO; +using System.Linq; +using LibMSPackSharp.Compression; +using static LibMSPackSharp.Constants; namespace LibMSPackSharp.SZDD { @@ -25,8 +29,10 @@ namespace LibMSPackSharp.SZDD /// /// /// - public class Decompressor + public class Decompressor : BaseDecompressor { + #region Public Functionality + /// /// Opens a SZDD file and reads the header. /// @@ -39,17 +45,37 @@ namespace LibMSPackSharp.SZDD /// The filename pointer should be considered "in use" until close() is /// called on the SZDD file. /// - /// - /// a self-referential pointer to the msszdd_decompressor - /// instance being called - /// /// - /// the filename of the SZDD compressed file. This is + /// The filename of the SZDD compressed file. This is /// passed directly to mspack_system::open(). /// - /// a pointer to a msszddd_header structure, or NULL on failure - /// - public Func Open; + /// A pointer to a msszddd_header structure, or NULL on failure + /// + public Header Open(string filename) + { + FileStream fh = System.Open(filename, OpenMode.MSPACK_SYS_OPEN_READ); + Header hdr = new Header(); + if (fh != null && hdr != null) + { + hdr.FileHandle = fh; + Error = ReadHeaders(fh, hdr); + } + else + { + if (fh == null) + Error = Error.MSPACK_ERR_OPEN; + if (hdr == null) + Error = Error.MSPACK_ERR_NOMEMORY; + } + + if (Error != Error.MSPACK_ERR_OK) + { + System.Close(fh); + hdr = null; + } + + return hdr; + } /// /// Closes a previously opened SZDD file. @@ -59,13 +85,18 @@ namespace LibMSPackSharp.SZDD /// /// The SZDD header pointer is now invalid and cannot be used again. /// - /// - /// a self-referential pointer to the msszdd_decompressor - /// instance being called - /// - /// the SZDD file to close - /// - public Action Close; + /// The SZDD file to close + /// + public void Close(Header hdr) + { + if (System == null || hdr == null) + return; + + // Close the file handle associated + System.Close(hdr.FileHandle); + + Error = Error.MSPACK_ERR_OK; + } /// /// Extracts the compressed data from a SZDD file. @@ -73,17 +104,46 @@ namespace LibMSPackSharp.SZDD /// This decompresses the compressed SZDD data stream and writes it to /// an output file. /// - /// - /// a self-referential pointer to the msszdd_decompressor - /// instance being called - /// - /// the SZDD file to extract data from + /// The SZDD file to extract data from /// - /// filename the filename to write the decompressed data to. This + /// The filename to write the decompressed data to. This /// is passed directly to mspack_system::open(). /// - /// an error code, or MSPACK_ERR_OK if successful - public Func Extract; + /// An error code, or MSPACK_ERR_OK if successful + public Error Extract(Header hdr, string filename) + { + if (hdr == null) + return Error = Error.MSPACK_ERR_ARGS; + + FileStream fh = hdr.FileHandle; + if (fh == null) + return Error.MSPACK_ERR_ARGS; + + // Seek to the compressed data + long dataOffset = (hdr.Format == Format.MSSZDD_FMT_NORMAL) ? 14 : 12; + if (System.Seek(fh, dataOffset, SeekMode.MSPACK_SYS_SEEK_START)) + return Error = Error.MSPACK_ERR_SEEK; + + // Open file for output + FileStream outfh = System.Open(filename, OpenMode.MSPACK_SYS_OPEN_WRITE); + if (outfh == null) + return Error = Error.MSPACK_ERR_OPEN; + + // Decompress the data + Error = LZSS.Decompress( + System, + fh, + outfh, + SZDD_INPUT_SIZE, + hdr.Format == Format.MSSZDD_FMT_NORMAL + ? LZSSMode.LZSS_MODE_EXPAND + : LZSSMode.LZSS_MODE_QBASIC); + + // Close output file + System.Close(outfh); + + return Error; + } /// /// Decompresses an SZDD file to an output file in one step. @@ -94,35 +154,73 @@ namespace LibMSPackSharp.SZDD /// open() then extract() then close(), if you do not need to know the /// SZDD output size or missing character. /// - /// - /// a self-referential pointer to the msszdd_decompressor - /// instance being called - /// /// - /// the filename of the input SZDD file. This is passed + /// The filename of the input SZDD file. This is passed /// directly to mspack_system::open(). /// /// - /// the filename to write the decompressed data to. This + /// The filename to write the decompressed data to. This /// is passed directly to mspack_system::open(). /// - /// an error code, or MSPACK_ERR_OK if successful - public Func Decompress; + /// An error code, or MSPACK_ERR_OK if successful + public Error Decompress(string input, string output) + { + Header hdr = Open(input) as Header; + if (hdr == null) + return Error; + + Error error = Extract(hdr, output); + Close(hdr); + return Error = error; + } + + #endregion + + #region Helpers /// - /// Returns the error code set by the most recently called method. - /// - /// This is useful for open() which does not return an - /// error code directly. + /// Reads the headers of an SZDD format file /// - /// - /// a self-referential pointer to the msszdd_decompressor - /// instance being called - /// - /// the most recent error code - /// - /// - /// - public Func LastError; + private Error ReadHeaders(FileStream fh, Header hdr) + { + // Read and check signature + byte[] buf = new byte[8]; + if (System.Read(fh, buf, 0, 8) != 8) + return Error.MSPACK_ERR_READ; + + if (buf.SequenceEqual(expandSignature)) + { + // Common SZDD + hdr.Format = Format.MSSZDD_FMT_NORMAL; + + // Read the rest of the header + if (System.Read(fh, buf, 0, 6) != 6) + return Error.MSPACK_ERR_READ; + + if (buf[0] != 0x41) + return Error.MSPACK_ERR_DATAFORMAT; + + hdr.MissingChar = (char)buf[1]; + hdr.Length = BitConverter.ToUInt32(buf, 2); + } + if (buf.SequenceEqual(qbasicSignature)) + { + // Special QBasic SZDD + hdr.Format = Format.MSSZDD_FMT_QBASIC; + if (System.Read(fh, buf, 0, 4) != 4) + return Error.MSPACK_ERR_READ; + + hdr.MissingChar = '\0'; + hdr.Length = BitConverter.ToUInt32(buf, 0); + } + else + { + return Error.MSPACK_ERR_SIGNATURE; + } + + return Error.MSPACK_ERR_OK; + } + + #endregion } } diff --git a/BurnOutSharp/External/libmspack/SZDD/DecompressorImpl.cs b/BurnOutSharp/External/libmspack/SZDD/DecompressorImpl.cs deleted file mode 100644 index 161e8797..00000000 --- a/BurnOutSharp/External/libmspack/SZDD/DecompressorImpl.cs +++ /dev/null @@ -1,18 +0,0 @@ -/* This file is part of libmspack. - * (C) 2003-2004 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.SZDD -{ - public class DecompressorImpl : Decompressor - { - public SystemImpl System { get; set; } - - public Error Error { get; set; } - } -} diff --git a/BurnOutSharp/External/libmspack/SZDD/Header.cs b/BurnOutSharp/External/libmspack/SZDD/Header.cs index 96767497..6536e1e0 100644 --- a/BurnOutSharp/External/libmspack/SZDD/Header.cs +++ b/BurnOutSharp/External/libmspack/SZDD/Header.cs @@ -14,6 +14,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +using System.IO; + namespace LibMSPackSharp.SZDD { /// @@ -21,7 +23,7 @@ namespace LibMSPackSharp.SZDD /// /// All fields are READ ONLY. /// - public class Header + public class Header : BaseHeader { /// /// The file format @@ -41,5 +43,7 @@ namespace LibMSPackSharp.SZDD /// an MS-DOS filename (except ".") are valid. /// public char MissingChar { get; set; } + + public FileStream FileHandle { get; set; } } } diff --git a/BurnOutSharp/External/libmspack/SZDD/HeaderImpl.cs b/BurnOutSharp/External/libmspack/SZDD/HeaderImpl.cs deleted file mode 100644 index 57a4dee1..00000000 --- a/BurnOutSharp/External/libmspack/SZDD/HeaderImpl.cs +++ /dev/null @@ -1,18 +0,0 @@ -/* This file is part of libmspack. - * (C) 2003-2004 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.IO; - -namespace LibMSPackSharp.SZDD -{ - public class HeaderImpl : Header - { - public FileStream FileHandle { get; set; } - } -} diff --git a/BurnOutSharp/External/libmspack/SZDD/Implementation.cs b/BurnOutSharp/External/libmspack/SZDD/Implementation.cs deleted file mode 100644 index a2b1d138..00000000 --- a/BurnOutSharp/External/libmspack/SZDD/Implementation.cs +++ /dev/null @@ -1,223 +0,0 @@ -/* This file is part of libmspack. - * (C) 2003-2004 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; -using System.IO; -using System.Linq; -using LibMSPackSharp.Compression; - -namespace LibMSPackSharp.SZDD -{ - public class Implementation - { - /// - /// Input buffer size during decompression - not worth parameterising IMHO - /// - private const int SZDD_INPUT_SIZE = 2048; - - #region SZDDD_OPEN - - /// - /// Opens an SZDD file without decompressing, reads header - /// - public static Header Open(Decompressor d, string filename) - { - DecompressorImpl self = d as DecompressorImpl; - if (self == null) - return null; - - SystemImpl sys = self.System; - - FileStream fh = sys.Open(filename, OpenMode.MSPACK_SYS_OPEN_READ); - HeaderImpl hdr = new HeaderImpl(); - if (fh != null && hdr != null) - { - hdr.FileHandle = fh; - self.Error = ReadHeaders(sys, fh, hdr); - } - else - { - if (fh == null) - self.Error = Error.MSPACK_ERR_OPEN; - if (hdr == null) - self.Error = Error.MSPACK_ERR_NOMEMORY; - } - - if (self.Error != Error.MSPACK_ERR_OK) - { - sys.Close(fh); - hdr = null; - } - - return hdr; - } - - #endregion - - #region SZDDD_CLOSE - - /// - /// Closes an SZDD file - /// - public static void Close(Decompressor d, Header hdr) - { - DecompressorImpl self = d as DecompressorImpl; - HeaderImpl hdr_p = hdr as HeaderImpl; - - if (self?.System == null || hdr == null) - return; - - // Close the file handle associated - self.System.Close(hdr_p.FileHandle); - - self.Error = Error.MSPACK_ERR_OK; - } - - #endregion - - #region SZDDD_READ_HEADERS - - private static byte[] expandSignature = new byte[8] - { - 0x53, 0x5A, 0x44, 0x44, 0x88, 0xF0, 0x27, 0x33 - }; - - private static byte[] qbasicSignature = new byte[8] - { - 0x53, 0x5A, 0x20, 0x88, 0xF0, 0x27, 0x33, 0xD1 - }; - - /// - /// Reads the headers of an SZDD format file - /// - public static Error ReadHeaders(SystemImpl sys, FileStream fh, Header hdr) - { - // Read and check signature - byte[] buf = new byte[8]; - if (sys.Read(fh, buf, 0, 8) != 8) - return Error.MSPACK_ERR_READ; - - if (buf.SequenceEqual(expandSignature)) - { - // Common SZDD - hdr.Format = Format.MSSZDD_FMT_NORMAL; - - // Read the rest of the header - if (sys.Read(fh, buf, 0, 6) != 6) - return Error.MSPACK_ERR_READ; - - if (buf[0] != 0x41) - return Error.MSPACK_ERR_DATAFORMAT; - - hdr.MissingChar = (char)buf[1]; - hdr.Length = BitConverter.ToUInt32(buf, 2); - } - if (buf.SequenceEqual(qbasicSignature)) - { - // Special QBasic SZDD - hdr.Format = Format.MSSZDD_FMT_QBASIC; - if (sys.Read(fh, buf, 0, 4) != 4) - return Error.MSPACK_ERR_READ; - - hdr.MissingChar = '\0'; - hdr.Length = BitConverter.ToUInt32(buf, 0); - } - else - { - return Error.MSPACK_ERR_SIGNATURE; - } - - return Error.MSPACK_ERR_OK; - } - - #endregion - - #region SZDDD_EXTRACT - - /// - /// Decompresses an SZDD file - /// - public static Error Extract(Decompressor d, Header hdr, string filename) - { - DecompressorImpl self = d as DecompressorImpl; - if (self == null) - return Error.MSPACK_ERR_ARGS; - if (hdr == null) - return self.Error = Error.MSPACK_ERR_ARGS; - - SystemImpl sys = self.System; - - FileStream fh = (hdr as HeaderImpl)?.FileHandle; - if (fh == null) - return Error.MSPACK_ERR_ARGS; - - // Seek to the compressed data - long dataOffset = (hdr.Format == Format.MSSZDD_FMT_NORMAL) ? 14 : 12; - if (sys.Seek(fh, dataOffset, SeekMode.MSPACK_SYS_SEEK_START)) - return self.Error = Error.MSPACK_ERR_SEEK; - - // Open file for output - FileStream outfh; - if ((outfh = sys.Open(filename, OpenMode.MSPACK_SYS_OPEN_WRITE)) == null) - return self.Error = Error.MSPACK_ERR_OPEN; - - // Decompress the data - self.Error = LZSS.Decompress( - sys, - fh, - outfh, - SZDD_INPUT_SIZE, - hdr.Format == Format.MSSZDD_FMT_NORMAL - ? LZSSMode.LZSS_MODE_EXPAND - : LZSSMode.LZSS_MODE_QBASIC); - - // Close output file - sys.Close(outfh); - - return self.Error; - } - - #endregion - - #region SZDDD_DECOMPRESS - - /// - /// Unpacks directly from input to output - /// - public static Error Decompress(Decompressor d, string input, string output) - { - DecompressorImpl self = d as DecompressorImpl; - if (self == null) - return Error.MSPACK_ERR_ARGS; - - Header hdr; - if ((hdr = Open(d, input)) == null) - return self.Error; - - Error error = Extract(d, hdr, output); - Close(d, hdr); - return self.Error = error; - } - - #endregion - - #region SZDDD_ERROR - - /// - /// Returns the last error that occurred - /// - public static Error LastError(Decompressor d) - { - DecompressorImpl self = d as DecompressorImpl; - return (self != null) ? self.Error : Error.MSPACK_ERR_ARGS; - } - - #endregion - } -}