From 4316427980a517faf2e999828dcc083bb4dc09ea Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Tue, 24 May 2022 00:47:09 -0700 Subject: [PATCH] Nearly finish demacroificiation --- .../Compression/CompressionStream.cs | 93 ++++- .../External/libmspack/Compression/LZHKWAJ.cs | 369 ++++------------- .../libmspack/Compression/LZHKWAJStream.cs | 55 +++ .../External/libmspack/Compression/LZX.cs | 372 +++++------------ .../libmspack/Compression/LZXDStream.cs | 3 + .../External/libmspack/Compression/MSZIP.cs | 118 ++---- .../libmspack/Compression/MSZIPDStream.cs | 3 + .../External/libmspack/Compression/QTM.cs | 373 +++--------------- .../libmspack/Compression/QTMDStream.cs | 5 + 9 files changed, 409 insertions(+), 982 deletions(-) diff --git a/BurnOutSharp/External/libmspack/Compression/CompressionStream.cs b/BurnOutSharp/External/libmspack/Compression/CompressionStream.cs index 6ae59ec9..b54a0910 100644 --- a/BurnOutSharp/External/libmspack/Compression/CompressionStream.cs +++ b/BurnOutSharp/External/libmspack/Compression/CompressionStream.cs @@ -17,6 +17,8 @@ namespace LibMSPackSharp.Compression { public abstract class CompressionStream : BaseDecompressState { + #region Constants + /// /// Number of bits in a character /// @@ -27,6 +29,13 @@ namespace LibMSPackSharp.Compression /// public const int BITBUF_WIDTH = 4 * CHAR_BIT; + /// + /// Maximum bits in a Huffman code + /// + public const int HUFF_MAXBITS = 16; + + #endregion + #region I/O buffering public byte[] InputBuffer { get; set; } @@ -363,7 +372,7 @@ namespace LibMSPackSharp.Compression // TODO: These should be in a separate file #region ReadHuff Methods - public const int HUFF_MAXBITS = 16; + #region Common /// /// This function was originally coded by David Tritscher. @@ -379,6 +388,7 @@ namespace LibMSPackSharp.Compression /// Should be ((1< /// true for OK or false for error + /// TODO: Split into MSB and LSB variants public static bool MakeDecodeTable(int nsyms, int nbits, byte[] length, ushort[] table, bool msb) { ushort sym, next_symbol; @@ -535,6 +545,87 @@ namespace LibMSPackSharp.Compression return pos == table_mask; } + /// + /// Per compression error code for decoding failure + /// + public abstract Error HUFF_ERROR(); + + #endregion + + #region MSB + + /// + /// Decodes the next huffman symbol from the input bitstream into var. + /// Do not use this macro on a table unless build_decode_table() succeeded. + /// + public long READ_HUFFSYM_MSB(ushort[] table, byte[] lengths, int tablebits, int maxsymbols, ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left) + { + ENSURE_BITS(HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + ushort sym = table[PEEK_BITS_MSB(tablebits, bit_buffer)]; + if (sym >= maxsymbols) + HUFF_TRAVERSE_MSB(ref sym, table, tablebits, maxsymbols, bit_buffer); + + REMOVE_BITS_MSB(lengths[sym], ref bit_buffer, ref bits_left); + return sym; + } + + /// + /// Traverse for a single symbol + /// + private void HUFF_TRAVERSE_MSB(ref ushort sym, ushort[] table, int tablebits, int maxsymbols, uint bit_buffer) + { + int i = 1 << (BITBUF_WIDTH - tablebits); + do + { + if ((i >>= 1) == 0) + { + Error = HUFF_ERROR(); + return; + } + + sym = table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)]; + } while (sym >= maxsymbols); + } + + #endregion + + #region LSB + + /// + /// Decodes the next huffman symbol from the input bitstream into var. + /// Do not use this macro on a table unless build_decode_table() succeeded. + /// + public long READ_HUFFSYM_LSB(ushort[] table, byte[] lengths, int tablebits, int maxsymbols, ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left) + { + ENSURE_BITS(HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + ushort sym = table[PEEK_BITS_LSB(tablebits, bit_buffer)]; + if (sym >= maxsymbols) + HUFF_TRAVERSE_LSB(ref sym, table, tablebits, maxsymbols, bit_buffer); + + REMOVE_BITS_LSB(lengths[sym], ref bit_buffer, ref bits_left); + return sym; + } + + /// + /// Traverse for a single symbol + /// + private void HUFF_TRAVERSE_LSB(ref ushort sym, ushort[] table, int tablebits, int maxsymbols, uint bit_buffer) + { + int i = tablebits - 1; + do + { + if (i++ > HUFF_MAXBITS) + { + Error = HUFF_ERROR(); + return; + } + + sym = table[(sym << 1) | ((bit_buffer >> i) & 1)]; + } while (sym >= maxsymbols); + } + + #endregion + #endregion } } diff --git a/BurnOutSharp/External/libmspack/Compression/LZHKWAJ.cs b/BurnOutSharp/External/libmspack/Compression/LZHKWAJ.cs index 64bcec2c..7efac2fc 100644 --- a/BurnOutSharp/External/libmspack/Compression/LZHKWAJ.cs +++ b/BurnOutSharp/External/libmspack/Compression/LZHKWAJ.cs @@ -8,7 +8,6 @@ */ using System.IO; -using LibMSPackSharp.KWAJ; using static LibMSPackSharp.Constants; namespace LibMSPackSharp.Compression @@ -42,10 +41,8 @@ namespace LibMSPackSharp.Compression public static Error Decompress(LZHKWAJStream lzh) { int i; - ushort sym; int lit_run = 0; int j, pos = 0, len, offset; - Error err; uint[] types = new uint[6]; // Reset global state @@ -60,151 +57,31 @@ namespace LibMSPackSharp.Compression // Read 6 encoding types (for byte alignment) but only 5 are needed for (i = 0; i < 6; i++) { - //READ_BITS_SAFE(types[i], 4) - { - types[i] = (uint)lzh.READ_BITS_MSB(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput) - return Error.MSPACK_ERR_OK; - } + types[i] = (uint)lzh.READ_BITS_SAFE(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzh.Error == Error.MSPACK_ERR_NOMEMORY) + return Error.MSPACK_ERR_OK; } // Read huffman table symbol lengths and build huffman trees - - //BUILD_TREE(MATCHLEN1, types[0]) - { - lzh.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left); - - err = ReadLens(lzh, types[0], KWAJ_MATCHLEN1_SYMS, lzh.MATCHLEN1_len); - if (err != Error.MSPACK_ERR_OK) - return err; - - lzh.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left); - - if (!CompressionStream.MakeDecodeTable(KWAJ_MATCHLEN1_SYMS, KWAJ_TABLEBITS, lzh.MATCHLEN1_len, lzh.MATCHLEN1_table, msb: true)) - return Error.MSPACK_ERR_DATAFORMAT; - } - - //BUILD_TREE(MATCHLEN2, types[1]) - { - lzh.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left); - - err = ReadLens(lzh, types[1], KWAJ_MATCHLEN2_SYMS, lzh.MATCHLEN2_len); - if (err != Error.MSPACK_ERR_OK) - return err; - - lzh.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left); - - if (!CompressionStream.MakeDecodeTable(KWAJ_MATCHLEN2_SYMS, KWAJ_TABLEBITS, lzh.MATCHLEN2_len, lzh.MATCHLEN2_table, msb: true)) - return Error.MSPACK_ERR_DATAFORMAT; - } - - //BUILD_TREE(LITLEN, types[2]) - { - lzh.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left); - - err = ReadLens(lzh, types[2], KWAJ_LITLEN_SYMS, lzh.LITLEN_len); - if (err != Error.MSPACK_ERR_OK) - return err; - - lzh.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left); - - if (!CompressionStream.MakeDecodeTable(KWAJ_LITLEN_SYMS, KWAJ_TABLEBITS, lzh.LITLEN_len, lzh.LITLEN_table, msb: true)) - return Error.MSPACK_ERR_DATAFORMAT; - } - - //BUILD_TREE(OFFSET, types[3]) - { - lzh.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left); - - err = ReadLens(lzh, types[3], KWAJ_OFFSET_SYMS, lzh.OFFSET_len); - if (err != Error.MSPACK_ERR_OK) - return err; - - lzh.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left); - - if (!CompressionStream.MakeDecodeTable(KWAJ_OFFSET_SYMS, KWAJ_TABLEBITS, lzh.OFFSET_len, lzh.OFFSET_table, msb: true)) - return Error.MSPACK_ERR_DATAFORMAT; - } - - //BUILD_TREE(LITERAL, types[4]) - { - lzh.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left); - - err = ReadLens(lzh, types[4], KWAJ_LITERAL_SYMS, lzh.LITERAL_len); - if (err != Error.MSPACK_ERR_OK) - return err; - - lzh.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left); - - if (!CompressionStream.MakeDecodeTable(KWAJ_LITERAL_SYMS, KWAJ_TABLEBITS, lzh.LITERAL_len, lzh.LITERAL_table, msb: true)) - return Error.MSPACK_ERR_DATAFORMAT; - } + BUILD_TREE(lzh, types[0], lzh.MATCHLEN1_table, lzh.MATCHLEN1_len, KWAJ_TABLEBITS, KWAJ_MATCHLEN1_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + BUILD_TREE(lzh, types[1], lzh.MATCHLEN2_table, lzh.MATCHLEN2_len, KWAJ_TABLEBITS, KWAJ_MATCHLEN2_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + BUILD_TREE(lzh, types[2], lzh.LITLEN_table, lzh.LITLEN_len, KWAJ_TABLEBITS, KWAJ_LITLEN_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + BUILD_TREE(lzh, types[3], lzh.OFFSET_table, lzh.OFFSET_len, KWAJ_TABLEBITS, KWAJ_OFFSET_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + BUILD_TREE(lzh, types[4], lzh.LITERAL_table, lzh.LITERAL_len, KWAJ_TABLEBITS, KWAJ_LITERAL_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); while (lzh.EndOfInput == 0) { if (lit_run != 0) { - //READ_HUFFSYM_SAFE(MATCHLEN2, len) - { - //READ_HUFFSYM(MATCHLEN2, len) - { - lzh.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - sym = lzh.MATCHLEN2_table[lzh.PEEK_BITS_MSB(KWAJ_TABLEBITS, bit_buffer)]; - if (sym >= KWAJ_MATCHLEN2_SYMS) - { - //HUFF_TRAVERSE(MATCHLEN2) - { - i = 1 << (CompressionStream.BITBUF_WIDTH - KWAJ_TABLEBITS); - do - { - if ((i >>= 1) == 0) - return Error.MSPACK_ERR_DATAFORMAT; - - sym = lzh.MATCHLEN2_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)]; - } while (sym >= KWAJ_MATCHLEN2_SYMS); - } - } - - (len) = sym; - i = lzh.MATCHLEN2_len[sym]; - lzh.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left); - } - - if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput) - return Error.MSPACK_ERR_OK; - } + len = (int)lzh.READ_HUFFSYM_SAFE(lzh.MATCHLEN2_table, lzh.MATCHLEN2_len, KWAJ_MATCHLEN2_TBLSIZE, KWAJ_MATCHLEN2_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzh.Error == Error.MSPACK_ERR_NOMEMORY) + return Error.MSPACK_ERR_OK; } else { - //READ_HUFFSYM_SAFE(MATCHLEN1, len) - { - //READ_HUFFSYM(MATCHLEN1, len) - { - lzh.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - sym = lzh.MATCHLEN1_table[lzh.PEEK_BITS_MSB(KWAJ_TABLEBITS, bit_buffer)]; - if (sym >= KWAJ_MATCHLEN1_SYMS) - { - //HUFF_TRAVERSE(MATCHLEN1) - { - i = 1 << (CompressionStream.BITBUF_WIDTH - KWAJ_TABLEBITS); - do - { - if ((i >>= 1) == 0) - return Error.MSPACK_ERR_DATAFORMAT; - - sym = lzh.MATCHLEN1_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)]; - } while (sym >= KWAJ_MATCHLEN1_SYMS); - } - } - - (len) = sym; - i = lzh.MATCHLEN1_len[sym]; - lzh.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left); - } - - if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput) - return Error.MSPACK_ERR_OK; - } + len = (int)lzh.READ_HUFFSYM_SAFE(lzh.MATCHLEN1_table, lzh.MATCHLEN1_len, KWAJ_MATCHLEN1_TBLSIZE, KWAJ_MATCHLEN1_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzh.Error == Error.MSPACK_ERR_NOMEMORY) + return Error.MSPACK_ERR_OK; } if (len > 0) @@ -212,44 +89,15 @@ namespace LibMSPackSharp.Compression len += 2; lit_run = 0; // Not the end of a literal run - //READ_HUFFSYM_SAFE(OFFSET, j) - { - //READ_HUFFSYM(OFFSET, j) - { - lzh.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - sym = lzh.OFFSET_table[lzh.PEEK_BITS_MSB(KWAJ_TABLEBITS, bit_buffer)]; - if (sym >= KWAJ_OFFSET_SYMS) - { - //HUFF_TRAVERSE(OFFSET) - { - i = 1 << (CompressionStream.BITBUF_WIDTH - KWAJ_TABLEBITS); - do - { - if ((i >>= 1) == 0) - return Error.MSPACK_ERR_DATAFORMAT; - - sym = lzh.OFFSET_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)]; - } while (sym >= KWAJ_OFFSET_SYMS); - } - } - - (j) = sym; - i = lzh.OFFSET_len[sym]; - lzh.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left); - } - - if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput) - return Error.MSPACK_ERR_OK; - } + j = (int)lzh.READ_HUFFSYM_SAFE(lzh.OFFSET_table, lzh.OFFSET_len, KWAJ_OFFSET_TBLSIZE, KWAJ_OFFSET_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzh.Error == Error.MSPACK_ERR_NOMEMORY) + return Error.MSPACK_ERR_OK; offset = j << 6; - //READ_BITS_SAFE(j, 6) - { - j = (int)lzh.READ_BITS_MSB(6, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput) - return Error.MSPACK_ERR_OK; - } + j = (int)lzh.READ_BITS_SAFE(6, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzh.Error == Error.MSPACK_ERR_NOMEMORY) + return Error.MSPACK_ERR_OK; offset |= j; @@ -257,12 +105,9 @@ namespace LibMSPackSharp.Compression while (len-- > 0) { lzh.Window[pos] = lzh.Window[(pos + 4096 - offset) & 4095]; - - //WRITE_BYTE - { - if (lzh.System.Write(lzh.OutputFileHandle, lzh.Window, pos, 1) != 1) - return Error.MSPACK_ERR_WRITE; - } + lzh.WRITE_BYTE(pos); + if (lzh.Error != Error.MSPACK_ERR_OK) + return lzh.Error; pos++; pos &= 4095; @@ -270,78 +115,24 @@ namespace LibMSPackSharp.Compression } else { - //READ_HUFFSYM_SAFE(LITLEN, len) - { - //READ_HUFFSYM(LITLEN, len) - { - lzh.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - sym = lzh.LITLEN_table[lzh.PEEK_BITS_MSB(KWAJ_TABLEBITS, bit_buffer)]; - if (sym >= KWAJ_LITLEN_SYMS) - { - //HUFF_TRAVERSE(tbl) - { - i = 1 << (CompressionStream.BITBUF_WIDTH - KWAJ_TABLEBITS); - do - { - if ((i >>= 1) == 0) - return Error.MSPACK_ERR_DATAFORMAT; - - sym = lzh.LITLEN_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)]; - } while (sym >= KWAJ_LITLEN_SYMS); - } - } - - (len) = sym; - i = lzh.LITLEN_len[sym]; - lzh.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left); - } - - if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput) - return Error.MSPACK_ERR_OK; - } + len = (int)lzh.READ_HUFFSYM_SAFE(lzh.LITLEN_table, lzh.LITLEN_len, KWAJ_LITLEN_TBLSIZE, KWAJ_LITLEN_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzh.Error == Error.MSPACK_ERR_NOMEMORY) + return Error.MSPACK_ERR_OK; len++; lit_run = (len == 32) ? 0 : 1; // End of a literal run? while (len-- > 0) { - //READ_HUFFSYM_SAFE(LITERAL, j) - { - //READ_HUFFSYM(LITERAL, j) - { - lzh.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - sym = lzh.LITERAL_table[lzh.PEEK_BITS_MSB(KWAJ_TABLEBITS, bit_buffer)]; - if (sym >= KWAJ_LITERAL_SYMS) - { - //HUFF_TRAVERSE(LITERAL) - { - i = 1 << (CompressionStream.BITBUF_WIDTH - KWAJ_TABLEBITS); - do - { - if ((i >>= 1) == 0) - return Error.MSPACK_ERR_DATAFORMAT; - - sym = lzh.LITERAL_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)]; - } while (sym >= KWAJ_LITERAL_SYMS); - } - } - - (j) = sym; - i = lzh.LITERAL_len[sym]; - lzh.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left); - } - - if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput) - return Error.MSPACK_ERR_OK; - } + j = (int)lzh.READ_HUFFSYM_SAFE(lzh.LITERAL_table, lzh.LITERAL_len, KWAJ_LITERAL_TBLSIZE, KWAJ_LITERAL_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzh.Error == Error.MSPACK_ERR_NOMEMORY) + return Error.MSPACK_ERR_OK; // Copy as output and into the ring buffer lzh.Window[pos] = (byte)j; - //WRITE_BYTE - { - if (lzh.System.Write(lzh.OutputFileHandle, lzh.Window, pos, 1) != 1) - return Error.MSPACK_ERR_WRITE; - } + lzh.WRITE_BYTE(pos); + if (lzh.Error != Error.MSPACK_ERR_OK) + return lzh.Error; pos++; pos &= 4095; } @@ -351,16 +142,28 @@ namespace LibMSPackSharp.Compression return Error.MSPACK_ERR_OK; } - private static Error ReadLens(LZHKWAJStream lzh, uint type, uint numsyms, byte[] lens) + private static Error BUILD_TREE(LZHKWAJStream lzh, uint type, ushort[] table, byte[] lengths, int tablebits, int maxsymbols, ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left) { - uint bit_buffer; - int bits_left; - int i_ptr, i_end; - uint i, c, sel; - Error err; + lzh.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left); + + Error err = ReadLens(lzh, type, (uint)maxsymbols, lzh.MATCHLEN1_len); + if (err != Error.MSPACK_ERR_OK) + return err; lzh.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left); + if (!CompressionStream.MakeDecodeTable(maxsymbols, tablebits, lengths, table, msb: true)) + return Error.MSPACK_ERR_DATAFORMAT; + + return Error.MSPACK_ERR_OK; + } + + private static Error ReadLens(LZHKWAJStream lzh, uint type, uint numsyms, byte[] lens) + { + uint i, c, sel; + + lzh.RESTORE_BITS(out int i_ptr, out int i_end, out uint bit_buffer, out int bits_left); + switch (type) { case 0: @@ -374,22 +177,16 @@ namespace LibMSPackSharp.Compression break; case 1: - //READ_BITS_SAFE(c, 4) - { - c = (uint)lzh.READ_BITS_MSB(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput) - return Error.MSPACK_ERR_OK; - } + c = (uint)lzh.READ_BITS_SAFE(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzh.Error == Error.MSPACK_ERR_NOMEMORY) + return Error.MSPACK_ERR_OK; lens[0] = (byte)c; for (i = 1; i < numsyms; i++) { - //READ_BITS_SAFE(sel, 1) - { - sel = (uint)lzh.READ_BITS_MSB(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput) - return Error.MSPACK_ERR_OK; - } + sel = (uint)lzh.READ_BITS_SAFE(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzh.Error == Error.MSPACK_ERR_NOMEMORY) + return Error.MSPACK_ERR_OK; if (sel == 0) { @@ -397,12 +194,9 @@ namespace LibMSPackSharp.Compression } else { - //READ_BITS_SAFE(sel, 1) - { - sel = (uint)lzh.READ_BITS_MSB(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput) - return Error.MSPACK_ERR_OK; - } + sel = (uint)lzh.READ_BITS_SAFE(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzh.Error == Error.MSPACK_ERR_NOMEMORY) + return Error.MSPACK_ERR_OK; if (sel == 0) { @@ -410,12 +204,9 @@ namespace LibMSPackSharp.Compression } else { - //READ_BITS_SAFE(c, 4) - { - c = (uint)lzh.READ_BITS_MSB(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput) - return Error.MSPACK_ERR_OK; - } + c = (uint)lzh.READ_BITS_SAFE(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzh.Error == Error.MSPACK_ERR_NOMEMORY) + return Error.MSPACK_ERR_OK; lens[i] = (byte)c; } @@ -425,31 +216,22 @@ namespace LibMSPackSharp.Compression break; case 2: - //READ_BITS_SAFE(c, 4) - { - c = (uint)lzh.READ_BITS_MSB(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput) - return Error.MSPACK_ERR_OK; - } + c = (uint)lzh.READ_BITS_SAFE(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzh.Error == Error.MSPACK_ERR_NOMEMORY) + return Error.MSPACK_ERR_OK; lens[0] = (byte)c; for (i = 1; i < numsyms; i++) { - //READ_BITS_SAFE(sel, 2) - { - sel = (uint)lzh.READ_BITS_MSB(2, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput) - return Error.MSPACK_ERR_OK; - } + sel = (uint)lzh.READ_BITS_SAFE(2, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzh.Error == Error.MSPACK_ERR_NOMEMORY) + return Error.MSPACK_ERR_OK; if (sel == 3) { - //READ_BITS_SAFE(c, 4) - { - c = (uint)lzh.READ_BITS_MSB(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput) - return Error.MSPACK_ERR_OK; - } + c = (uint)lzh.READ_BITS_SAFE(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzh.Error == Error.MSPACK_ERR_NOMEMORY) + return Error.MSPACK_ERR_OK; } else { @@ -464,12 +246,9 @@ namespace LibMSPackSharp.Compression case 3: for (i = 0; i < numsyms; i++) { - //READ_BITS_SAFE(c, 4) - { - c = (uint)lzh.READ_BITS_MSB(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput) - return Error.MSPACK_ERR_OK; - } + c = (uint)lzh.READ_BITS_SAFE(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzh.Error == Error.MSPACK_ERR_NOMEMORY) + return Error.MSPACK_ERR_OK; lens[i] = (byte)c; } diff --git a/BurnOutSharp/External/libmspack/Compression/LZHKWAJStream.cs b/BurnOutSharp/External/libmspack/Compression/LZHKWAJStream.cs index 4ea428d4..4f84eb4e 100644 --- a/BurnOutSharp/External/libmspack/Compression/LZHKWAJStream.cs +++ b/BurnOutSharp/External/libmspack/Compression/LZHKWAJStream.cs @@ -37,6 +37,61 @@ namespace LibMSPackSharp.Compression #endregion + #region Specialty Methods + + /* 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. + */ + + /// + /// Safely read bits from the buffer + /// + public long READ_BITS_SAFE(int nbits, ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left) + { + long val = READ_BITS_MSB(nbits, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (EndOfInput != 0 && BitsLeft < EndOfInput) + Error = Error.MSPACK_ERR_NOMEMORY; + else + Error = Error.MSPACK_ERR_OK; + + return val; + } + + /// + /// Safely read a symbol from a Huffman tree + /// + public long READ_HUFFSYM_SAFE(ushort[] table, byte[] lengths, int tablebits, int maxsymbols, ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left) + { + long val = READ_HUFFSYM_MSB(table, lengths, tablebits, maxsymbols, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (EndOfInput != 0 && BitsLeft < EndOfInput) + Error = Error.MSPACK_ERR_NOMEMORY; + else + Error = Error.MSPACK_ERR_OK; + + return val; + } + + /// + /// Write a single byte to the output stream + /// + public void WRITE_BYTE(int pos) + { + if (System.Write(OutputFileHandle, Window, pos, 1) != 1) + Error = Error.MSPACK_ERR_WRITE; + } + + #endregion + + /// + public override Error HUFF_ERROR() => Error.MSPACK_ERR_DATAFORMAT; + /// public override void READ_BYTES(ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left) { diff --git a/BurnOutSharp/External/libmspack/Compression/LZX.cs b/BurnOutSharp/External/libmspack/Compression/LZX.cs index dff107f5..c5bd6e33 100644 --- a/BurnOutSharp/External/libmspack/Compression/LZX.cs +++ b/BurnOutSharp/External/libmspack/Compression/LZX.cs @@ -435,12 +435,6 @@ namespace LibMSPackSharp.Compression if (lzx == null) return Error.MSPACK_ERR_ARGS; - // Bitstream and huffman reading variables - uint bit_buffer; - int bits_left, i; - int i_ptr, i_end; - ushort sym; - int match_length, length_footer, extra, verbatim_bits, bytes_todo; int this_run, main_element, aligned_bits, j, warned = 0; byte[] window, buf = new byte[12]; @@ -456,7 +450,7 @@ namespace LibMSPackSharp.Compression return lzx.Error; // Flush out any stored-up bytes before we begin - i = lzx.OutputEnd - lzx.OutputPointer; + int i = lzx.OutputEnd - lzx.OutputPointer; if (i > out_bytes) i = (int)out_bytes; @@ -474,7 +468,7 @@ namespace LibMSPackSharp.Compression return Error.MSPACK_ERR_OK; // Restore local state - lzx.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left); + lzx.RESTORE_BITS(out int i_ptr, out int i_end, out uint bit_buffer, out int bits_left); window = lzx.Window; window_posn = lzx.WindowPosition; R0 = lzx.R0; @@ -577,149 +571,64 @@ namespace LibMSPackSharp.Compression lzx.ALIGNED_len[i] = (byte)j; } - //BUILD_TABLE(ALIGNED) - { - if (!CompressionStream.MakeDecodeTable(LZX_ALIGNED_MAXSYMBOLS, LZX_ALIGNED_TABLEBITS, lzx.ALIGNED_len, lzx.ALIGNED_table, msb: true)) - { - Console.WriteLine($"Failed to build ALIGNED table"); - return lzx.Error = Error.MSPACK_ERR_DECRUNCH; - } - } + BUILD_TABLE(lzx, lzx.ALIGNED_table, lzx.ALIGNED_len, LZX_ALIGNED_TABLEBITS, LZX_ALIGNED_MAXSYMBOLS); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; // Read lengths of and build main huffman decoding tree + READ_LENGTHS(lzx, lzx.MAINTREE_len, 0, 256, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; - //READ_LENGTHS(MAINTREE, 0, 256) - { - lzx.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left); + READ_LENGTHS(lzx, lzx.MAINTREE_len, 256, LZX_NUM_CHARS + lzx.NumOffsets, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; - if (ReadLens(lzx, lzx.MAINTREE_len, (0), (uint)(256)) != Error.MSPACK_ERR_OK) - return lzx.Error; - - lzx.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left); - } - - //READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + lzx.NumOffsets) - { - lzx.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left); - - if (ReadLens(lzx, lzx.MAINTREE_len, (256), (uint)(LZX_NUM_CHARS + lzx.NumOffsets)) != Error.MSPACK_ERR_OK) - return lzx.Error; - - lzx.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left); - } - - //BUILD_TABLE(MAINTREE) - { - if (!CompressionStream.MakeDecodeTable(LZX_MAINTREE_MAXSYMBOLS, LZX_MAINTREE_TABLEBITS, lzx.MAINTREE_len, lzx.MAINTREE_table, msb: true)) - { - Console.WriteLine($"Failed to build MAINTREE table"); - return lzx.Error = Error.MSPACK_ERR_DECRUNCH; - } - } + BUILD_TABLE(lzx, lzx.MAINTREE_table, lzx.MAINTREE_len, LZX_MAINTREE_TABLEBITS, LZX_MAINTREE_MAXSYMBOLS); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; // If the literal 0xE8 is anywhere in the block... if (lzx.MAINTREE_len[0xE8] != 0) lzx.IntelStarted = true; // Read lengths of and build lengths huffman decoding tree + READ_LENGTHS(lzx, lzx.LENGTH_len, 0, LZX_NUM_SECONDARY_LENGTHS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; - //READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS) - { - lzx.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left); - - if (ReadLens(lzx, lzx.LENGTH_len, (0), (uint)(LZX_NUM_SECONDARY_LENGTHS)) != Error.MSPACK_ERR_OK) - return lzx.Error; - - lzx.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left); - } - - //BUILD_TABLE_MAYBE_EMPTY(LENGTH) - { - lzx.LENGTH_empty = 0; - if (!CompressionStream.MakeDecodeTable(LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS, lzx.LENGTH_len, lzx.LENGTH_table, msb: true)) - { - for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++) - { - if (lzx.LENGTH_len[i] > 0) - { - Console.WriteLine("Failed to build TBL table"); - return lzx.Error = Error.MSPACK_ERR_DECRUNCH; - } - } - - // Empty tree - allow it, but don't decode symbols with it - lzx.LENGTH_empty = 1; - } - } + BUILD_TABLE_MAYBE_EMPTY(lzx); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; break; case LZXBlockType.LZX_BLOCKTYPE_VERBATIM: // Read lengths of and build main huffman decoding tree + READ_LENGTHS(lzx, lzx.MAINTREE_len, 0, 256, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; - //READ_LENGTHS(MAINTREE, 0, 256) - { - lzx.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left); + READ_LENGTHS(lzx, lzx.MAINTREE_len, 256, LZX_NUM_CHARS + lzx.NumOffsets, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; - if (ReadLens(lzx, lzx.MAINTREE_len, (0), (uint)(256)) != Error.MSPACK_ERR_OK) - return lzx.Error; - - lzx.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left); - } - - //READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + lzx.NumOffsets) - { - lzx.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left); - - if (ReadLens(lzx, lzx.MAINTREE_len, (256), (uint)(LZX_NUM_CHARS + lzx.NumOffsets)) != Error.MSPACK_ERR_OK) - return lzx.Error; - - lzx.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left); - } - - //BUILD_TABLE(MAINTREE) - { - if (!CompressionStream.MakeDecodeTable(LZX_MAINTREE_MAXSYMBOLS, LZX_MAINTREE_TABLEBITS, lzx.MAINTREE_len, lzx.MAINTREE_table, msb: true)) - { - Console.WriteLine($"Failed to build MAINTREE table"); - return lzx.Error = Error.MSPACK_ERR_DECRUNCH; - } - } + BUILD_TABLE(lzx, lzx.MAINTREE_table, lzx.MAINTREE_len, LZX_MAINTREE_TABLEBITS, LZX_MAINTREE_MAXSYMBOLS); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; // If the literal 0xE8 is anywhere in the block... if (lzx.MAINTREE_len[0xE8] != 0) lzx.IntelStarted = true; // Read lengths of and build lengths huffman decoding tree + READ_LENGTHS(lzx, lzx.LENGTH_len, 0, LZX_NUM_SECONDARY_LENGTHS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; - //READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS) - { - lzx.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left); - - if (ReadLens(lzx, lzx.LENGTH_len, (0), (uint)(LZX_NUM_SECONDARY_LENGTHS)) != Error.MSPACK_ERR_OK) - return lzx.Error; - - lzx.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left); - } - - //BUILD_TABLE_MAYBE_EMPTY(LENGTH) - { - lzx.LENGTH_empty = 0; - if (!CompressionStream.MakeDecodeTable(LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS, lzx.LENGTH_len, lzx.LENGTH_table, msb: true)) - { - for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++) - { - if (lzx.LENGTH_len[i] > 0) - { - Console.WriteLine("Failed to build TBL table"); - return lzx.Error = Error.MSPACK_ERR_DECRUNCH; - } - } - - // Empty tree - allow it, but don't decode symbols with it - lzx.LENGTH_empty = 1; - } - } + BUILD_TABLE_MAYBE_EMPTY(lzx); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; break; @@ -772,30 +681,7 @@ namespace LibMSPackSharp.Compression case LZXBlockType.LZX_BLOCKTYPE_VERBATIM: while (this_run > 0) { - //READ_HUFFSYM(MAINTREE, main_element) - { - lzx.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - sym = lzx.MAINTREE_table[lzx.PEEK_BITS_MSB(LZX_MAINTREE_TABLEBITS, bit_buffer)]; - if (sym >= LZX_MAINTREE_MAXSYMBOLS) - { - //HUFF_TRAVERSE(MAINTREE) - { - i = 1 << (CompressionStream.BITBUF_WIDTH - LZX_MAINTREE_TABLEBITS); - do - { - if ((i >>= 1) == 0) - return lzx.Error = Error.MSPACK_ERR_DECRUNCH; - - sym = lzx.MAINTREE_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)]; - } while (sym >= LZX_MAINTREE_MAXSYMBOLS); - } - } - - (main_element) = sym; - i = lzx.MAINTREE_len[sym]; - lzx.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left); - } - + main_element = (int)lzx.READ_HUFFSYM_MSB(lzx.MAINTREE_table, lzx.MAINTREE_len, LZX_MAINTREE_TABLEBITS, LZX_MAINTREE_MAXSYMBOLS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); if (main_element < LZX_NUM_CHARS) { // Literal: 0 to LZX_NUM_CHARS-1 @@ -817,30 +703,7 @@ namespace LibMSPackSharp.Compression return lzx.Error = Error.MSPACK_ERR_DECRUNCH; } - //READ_HUFFSYM(LENGTH, length_footer) - { - lzx.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - sym = lzx.LENGTH_table[lzx.PEEK_BITS_MSB(LZX_LENGTH_TABLEBITS, bit_buffer)]; - if (sym >= LZX_LENGTH_MAXSYMBOLS) - { - //HUFF_TRAVERSE(LENGTH) - { - i = 1 << (CompressionStream.BITBUF_WIDTH - LZX_LENGTH_TABLEBITS); - do - { - if ((i >>= 1) == 0) - return lzx.Error = Error.MSPACK_ERR_DECRUNCH; - - sym = lzx.LENGTH_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)]; - } while (sym >= LZX_LENGTH_MAXSYMBOLS); - } - } - - (length_footer) = sym; - i = lzx.LENGTH_len[sym]; - lzx.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left); - } - + length_footer = (int)lzx.READ_HUFFSYM_MSB(lzx.LENGTH_table, lzx.LENGTH_len, LZX_LENGTH_TABLEBITS, LZX_LENGTH_MAXSYMBOLS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); match_length += length_footer; } @@ -893,60 +756,14 @@ namespace LibMSPackSharp.Compression verbatim_bits = (int)lzx.READ_BITS_MSB(extra, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); match_offset += (uint)(verbatim_bits << 3); - //READ_HUFFSYM(ALIGNED, aligned_bits) - { - lzx.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - sym = lzx.ALIGNED_table[lzx.PEEK_BITS_MSB(LZX_ALIGNED_TABLEBITS, bit_buffer)]; - if (sym >= LZX_ALIGNED_MAXSYMBOLS) - { - //HUFF_TRAVERSE(ALIGNED) - { - i = 1 << (CompressionStream.BITBUF_WIDTH - LZX_ALIGNED_TABLEBITS); - do - { - if ((i >>= 1) == 0) - return lzx.Error = Error.MSPACK_ERR_DECRUNCH; - - sym = lzx.ALIGNED_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)]; - } while (sym >= LZX_ALIGNED_MAXSYMBOLS); - } - } - - (aligned_bits) = sym; - i = lzx.ALIGNED_len[sym]; - lzx.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left); - } - + aligned_bits = (int)lzx.READ_HUFFSYM_MSB(lzx.ALIGNED_table, lzx.ALIGNED_len, LZX_ALIGNED_TABLEBITS, LZX_ALIGNED_MAXSYMBOLS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); match_offset += (uint)aligned_bits; } // 3: aligned bits only else if (extra == 3) { - //READ_HUFFSYM(ALIGNED, aligned_bits) - { - lzx.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - sym = lzx.ALIGNED_table[lzx.PEEK_BITS_MSB(LZX_ALIGNED_TABLEBITS, bit_buffer)]; - if (sym >= LZX_ALIGNED_MAXSYMBOLS) - { - //HUFF_TRAVERSE(ALIGNED) - { - i = 1 << (CompressionStream.BITBUF_WIDTH - LZX_ALIGNED_TABLEBITS); - do - { - if ((i >>= 1) == 0) - return lzx.Error = Error.MSPACK_ERR_DECRUNCH; - - sym = lzx.ALIGNED_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)]; - } while (sym >= LZX_ALIGNED_MAXSYMBOLS); - } - } - - (aligned_bits) = sym; - i = lzx.ALIGNED_len[sym]; - lzx.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left); - } - + aligned_bits = (int)lzx.READ_HUFFSYM_MSB(lzx.ALIGNED_table, lzx.ALIGNED_len, LZX_ALIGNED_TABLEBITS, LZX_ALIGNED_MAXSYMBOLS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); match_offset += (uint)aligned_bits; } @@ -1220,18 +1037,55 @@ namespace LibMSPackSharp.Compression return Error.MSPACK_ERR_OK; } + private static Error BUILD_TABLE(LZXDStream lzx, ushort[] table, byte[] lengths, int tablebits, int maxsymbols) + { + if (!CompressionStream.MakeDecodeTable(maxsymbols, tablebits, lengths, table, msb: true)) + { + Console.WriteLine($"Failed to build table"); + return lzx.Error = Error.MSPACK_ERR_DECRUNCH; + } + + return lzx.Error = Error.MSPACK_ERR_OK; + } + + private static Error BUILD_TABLE_MAYBE_EMPTY(LZXDStream lzx) + { + lzx.LENGTH_empty = 0; + if (!CompressionStream.MakeDecodeTable(LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS, lzx.LENGTH_len, lzx.LENGTH_table, msb: true)) + { + for (int i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++) + { + if (lzx.LENGTH_len[i] > 0) + { + Console.WriteLine("Failed to build table"); + return lzx.Error = Error.MSPACK_ERR_DECRUNCH; + } + } + + // Empty tree - allow it, but don't decode symbols with it + lzx.LENGTH_empty = 1; + } + + return lzx.Error = Error.MSPACK_ERR_OK; + } + + private static Error READ_LENGTHS(LZXDStream lzx, byte[] lengths, uint first, uint last, ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left) + { + lzx.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left); + + if (ReadLens(lzx, lengths, first, last) != Error.MSPACK_ERR_OK) + return lzx.Error; + + lzx.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left); + return lzx.Error = Error.MSPACK_ERR_OK; + } + private static Error ReadLens(LZXDStream lzx, byte[] lens, uint first, uint last) { - // Bit buffer and huffman symbol decode variables - uint bit_buffer; - int bits_left, i; - ushort sym; - int i_ptr, i_end; - uint x, y; int z; - lzx.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left); + lzx.RESTORE_BITS(out int i_ptr, out int i_end, out uint bit_buffer, out int bits_left); // Read lengths for pretree (20 symbols, lengths stored in fixed 4 bits) for (x = 0; x < 20; x++) @@ -1240,40 +1094,13 @@ namespace LibMSPackSharp.Compression lzx.PRETREE_len[x] = (byte)y; } - //BUILD_TABLE(PRETREE) - { - if (!CompressionStream.MakeDecodeTable(LZX_PRETREE_MAXSYMBOLS, LZX_PRETREE_TABLEBITS, lzx.PRETREE_len, lzx.PRETREE_table, msb: true)) - { - Console.WriteLine($"failed to build PRETREE table"); - return lzx.Error = Error.MSPACK_ERR_DECRUNCH; - } - } + BUILD_TABLE(lzx, lzx.PRETREE_table, lzx.PRETREE_len, LZX_PRETREE_TABLEBITS, LZX_PRETREE_MAXSYMBOLS); + if (lzx.Error != Error.MSPACK_ERR_OK) + return lzx.Error; for (x = first; x < last;) { - //READ_HUFFSYM(PRETREE, z) - { - lzx.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - sym = lzx.PRETREE_table[lzx.PEEK_BITS_MSB(LZX_PRETREE_TABLEBITS, bit_buffer)]; - if (sym >= LZX_PRETREE_MAXSYMBOLS) - { - //HUFF_TRAVERSE(PRETREE) - { - i = 1 << (CompressionStream.BITBUF_WIDTH - LZX_PRETREE_TABLEBITS); - do - { - if ((i >>= 1) == 0) - return lzx.Error = Error.MSPACK_ERR_DECRUNCH; - - sym = lzx.PRETREE_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)]; - } while (sym >= LZX_PRETREE_MAXSYMBOLS); - } - } - - (z) = sym; - i = lzx.PRETREE_len[sym]; - lzx.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left); - } + z = (int)lzx.READ_HUFFSYM_MSB(lzx.PRETREE_table, lzx.PRETREE_len, LZX_PRETREE_TABLEBITS, LZX_PRETREE_MAXSYMBOLS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); // Code = 17, run of ([read 4 bits]+4) zeros if (z == 17) @@ -1302,30 +1129,7 @@ namespace LibMSPackSharp.Compression { y = (uint)lzx.READ_BITS_MSB(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); y += 4; - - //READ_HUFFSYM(PRETREE, z) - { - lzx.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - sym = lzx.PRETREE_table[lzx.PEEK_BITS_MSB(LZX_PRETREE_TABLEBITS, bit_buffer)]; - if (sym >= LZX_PRETREE_MAXSYMBOLS) - { - //HUFF_TRAVERSE(PRETREE) - { - i = 1 << (CompressionStream.BITBUF_WIDTH - LZX_PRETREE_TABLEBITS); - do - { - if ((i >>= 1) == 0) - return lzx.Error = Error.MSPACK_ERR_DECRUNCH; - - sym = lzx.PRETREE_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)]; - } while (sym >= LZX_PRETREE_MAXSYMBOLS); - } - } - - (z) = sym; - i = lzx.PRETREE_len[sym]; - lzx.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left); - } + z = (int)lzx.READ_HUFFSYM_MSB(lzx.PRETREE_table, lzx.PRETREE_len, LZX_PRETREE_TABLEBITS, LZX_PRETREE_MAXSYMBOLS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); z = lens[x] - z; if (z < 0) diff --git a/BurnOutSharp/External/libmspack/Compression/LZXDStream.cs b/BurnOutSharp/External/libmspack/Compression/LZXDStream.cs index bd94147b..3cb656cf 100644 --- a/BurnOutSharp/External/libmspack/Compression/LZXDStream.cs +++ b/BurnOutSharp/External/libmspack/Compression/LZXDStream.cs @@ -141,6 +141,9 @@ namespace LibMSPackSharp.Compression #endregion + /// + public override Error HUFF_ERROR() => Error.MSPACK_ERR_DECRUNCH; + /// public override void READ_BYTES(ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left) { diff --git a/BurnOutSharp/External/libmspack/Compression/MSZIP.cs b/BurnOutSharp/External/libmspack/Compression/MSZIP.cs index f3fef598..5ef4e4ec 100644 --- a/BurnOutSharp/External/libmspack/Compression/MSZIP.cs +++ b/BurnOutSharp/External/libmspack/Compression/MSZIP.cs @@ -12,7 +12,6 @@ using System; using System.IO; -using static LibMSPackSharp.Compression.Constants; namespace LibMSPackSharp.Compression { @@ -289,7 +288,7 @@ namespace LibMSPackSharp.Compression block_len = (int)zip.READ_BITS_LSB(8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); i = (int)zip.READ_BITS_LSB(8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - + block_len |= i << 8; if (block_len == 0) break; @@ -514,16 +513,9 @@ namespace LibMSPackSharp.Compression i_ptr += (int)this_run; length -= this_run; - //FLUSH_IF_NEEDED - { - if (zip.WindowPosition == MSZIP_FRAME_SIZE) - { - if (zip.FlushWindow(zip, MSZIP_FRAME_SIZE) != Error.MSPACK_ERR_OK) - return Error.INF_ERR_FLUSH; - - zip.WindowPosition = 0; - } - } + err = FLUSH_IF_NEEDED(zip); + if (err != Error.MSPACK_ERR_OK) + return err; } } else if ((block_type == 1) || (block_type == 2)) @@ -582,44 +574,14 @@ namespace LibMSPackSharp.Compression // Decode forever until end of block code for (; ; ) { - //READ_HUFFSYM(LITERAL, code) - { - zip.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - sym = zip.LITERAL_table[zip.PEEK_BITS_LSB(MSZIP_LITERAL_TABLEBITS, bit_buffer)]; - if (sym >= MSZIP_LITERAL_MAXSYMBOLS) - { - //HUFF_TRAVERSE(LITERAL) - { - i = MSZIP_LITERAL_TABLEBITS - 1; - do - { - if (i++ > CompressionStream.HUFF_MAXBITS) - return Error.INF_ERR_HUFFSYM; - - sym = zip.LITERAL_table[(sym << 1) | ((bit_buffer >> (int)i) & 1)]; - } while (sym >= MSZIP_LITERAL_MAXSYMBOLS); - } - } - - (code) = sym; - i = zip.LITERAL_len[sym]; - zip.REMOVE_BITS_LSB((int)i, ref bit_buffer, ref bits_left); - } + code = (uint)zip.READ_HUFFSYM_LSB(zip.LITERAL_table, zip.LITERAL_len, MSZIP_LITERAL_TABLEBITS, MSZIP_LITERAL_MAXSYMBOLS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); if (code < 256) { zip.Window[zip.WindowPosition++] = (byte)code; - - //FLUSH_IF_NEEDED - { - if (zip.WindowPosition == MSZIP_FRAME_SIZE) - { - if (zip.FlushWindow(zip, MSZIP_FRAME_SIZE) != Error.MSPACK_ERR_OK) - return Error.INF_ERR_FLUSH; - - zip.WindowPosition = 0; - } - } + err = FLUSH_IF_NEEDED(zip); + if (err != Error.MSPACK_ERR_OK) + return err; } else if (code == 256) { @@ -635,29 +597,7 @@ namespace LibMSPackSharp.Compression length = (uint)zip.READ_BITS_T_LSB(lit_extrabits[code], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); length += lit_lengths[code]; - //READ_HUFFSYM(DISTANCE, code) - { - zip.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - sym = zip.DISTANCE_table[zip.PEEK_BITS_LSB(MSZIP_DISTANCE_TABLEBITS, bit_buffer)]; - if (sym >= MSZIP_DISTANCE_MAXSYMBOLS) - { - //HUFF_TRAVERSE(DISTANCE) - { - i = MSZIP_DISTANCE_TABLEBITS - 1; - do - { - if (i++ > CompressionStream.HUFF_MAXBITS) - return Error.INF_ERR_HUFFSYM; - - sym = zip.DISTANCE_table[(sym << 1) | ((bit_buffer >> (int)i) & 1)]; - } while (sym >= MSZIP_DISTANCE_MAXSYMBOLS); - } - } - - (code) = sym; - i = zip.DISTANCE_len[sym]; - zip.REMOVE_BITS_LSB((int)i, ref bit_buffer, ref bits_left); - } + code = (uint)zip.READ_HUFFSYM_LSB(zip.DISTANCE_table, zip.DISTANCE_len, MSZIP_DISTANCE_TABLEBITS, MSZIP_DISTANCE_MAXSYMBOLS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); if (code >= 30) return Error.INF_ERR_DISTCODE; @@ -678,17 +618,9 @@ namespace LibMSPackSharp.Compression { zip.Window[zip.WindowPosition++] = zip.Window[match_posn++]; match_posn &= MSZIP_FRAME_SIZE - 1; - - //FLUSH_IF_NEEDED - { - if (zip.WindowPosition == MSZIP_FRAME_SIZE) - { - if (zip.FlushWindow(zip, MSZIP_FRAME_SIZE) != Error.MSPACK_ERR_OK) - return Error.INF_ERR_FLUSH; - - zip.WindowPosition = 0; - } - } + err = FLUSH_IF_NEEDED(zip); + if (err != Error.MSPACK_ERR_OK) + return err; } } else @@ -716,16 +648,9 @@ namespace LibMSPackSharp.Compression if (match_posn == MSZIP_FRAME_SIZE) match_posn = 0; - //FLUSH_IF_NEEDED - { - if (zip.WindowPosition == MSZIP_FRAME_SIZE) - { - if (zip.FlushWindow(zip, MSZIP_FRAME_SIZE) != Error.MSPACK_ERR_OK) - return Error.INF_ERR_FLUSH; - - zip.WindowPosition = 0; - } - } + err = FLUSH_IF_NEEDED(zip); + if (err != Error.MSPACK_ERR_OK) + return err; } while (length > 0); } @@ -753,6 +678,19 @@ namespace LibMSPackSharp.Compression return Error.MSPACK_ERR_OK; } + private static Error FLUSH_IF_NEEDED(MSZIPDStream zip) + { + if (zip.WindowPosition == MSZIP_FRAME_SIZE) + { + if (zip.FlushWindow(zip, MSZIP_FRAME_SIZE) != Error.MSPACK_ERR_OK) + return Error.INF_ERR_FLUSH; + + zip.WindowPosition = 0; + } + + return Error.MSPACK_ERR_OK; + } + /// /// inflate() calls this whenever the window should be flushed. As /// MSZIP only expands to the size of the window, the implementation used diff --git a/BurnOutSharp/External/libmspack/Compression/MSZIPDStream.cs b/BurnOutSharp/External/libmspack/Compression/MSZIPDStream.cs index e0c5d12d..52f9b7b9 100644 --- a/BurnOutSharp/External/libmspack/Compression/MSZIPDStream.cs +++ b/BurnOutSharp/External/libmspack/Compression/MSZIPDStream.cs @@ -53,6 +53,9 @@ namespace LibMSPackSharp.Compression #endregion + /// + public override Error HUFF_ERROR() => Error.INF_ERR_HUFFSYM; + /// public override void READ_BYTES(ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left) { diff --git a/BurnOutSharp/External/libmspack/Compression/QTM.cs b/BurnOutSharp/External/libmspack/Compression/QTM.cs index f83ad717..7f1ba42b 100644 --- a/BurnOutSharp/External/libmspack/Compression/QTM.cs +++ b/BurnOutSharp/External/libmspack/Compression/QTM.cs @@ -244,58 +244,7 @@ namespace LibMSPackSharp.Compression while (window_posn < frame_end) { - //GET_SYMBOL(qtm.Model7, var) - { - range = (uint)((H - L) & 0xFFFF) + 1; - symf = (ushort)(((((C - L + 1) * qtm.Model7.Syms[0].CumulativeFrequency) - 1) / range) & 0xFFFF); - - for (i = 1; i < qtm.Model7.Entries; i++) - { - if (qtm.Model7.Syms[i].CumulativeFrequency <= symf) - break; - } - - (selector) = qtm.Model7.Syms[i - 1].Sym; - - range = (uint)(H - L) + 1; - symf = qtm.Model7.Syms[0].CumulativeFrequency; - H = (ushort)(L + ((qtm.Model7.Syms[i - 1].CumulativeFrequency * range) / symf) - 1); - L = (ushort)(L + ((qtm.Model7.Syms[i].CumulativeFrequency * range) / symf)); - - do - { - qtm.Model7.Syms[--i].CumulativeFrequency += 8; - } while (i > 0); - - if (qtm.Model7.Syms[0].CumulativeFrequency > 3800) - UpdateModel(qtm.Model7); - - while (true) - { - if ((L & 0x8000) != (H & 0x8000)) - { - if ((L & 0x4000) != 0 && (H & 0x4000) == 0) - { - // Underflow case - C ^= 0x4000; - L &= 0x3FFF; - H |= 0x4000; - } - else - { - break; - } - } - - L <<= 1; - H = (ushort)((H << 1) | 1); - - qtm.ENSURE_BITS(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - C = (ushort)((C << 1) | (qtm.PEEK_BITS_MSB(1, bit_buffer))); - qtm.REMOVE_BITS_MSB(1, ref bit_buffer, ref bits_left); - } - } - + selector = GET_SYMBOL(qtm, qtm.Model7, ref H, ref L, ref C, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); if (selector < 4) { // Literal byte @@ -320,58 +269,7 @@ namespace LibMSPackSharp.Compression break; } - //GET_SYMBOL(mdl, sym) - { - range = (uint)((H - L) & 0xFFFF) + 1; - symf = (ushort)(((((C - L + 1) * mdl.Syms[0].CumulativeFrequency) - 1) / range) & 0xFFFF); - - for (i = 1; i < mdl.Entries; i++) - { - if (mdl.Syms[i].CumulativeFrequency <= symf) - break; - } - - (sym) = mdl.Syms[i - 1].Sym; - - range = (uint)(H - L) + 1; - symf = mdl.Syms[0].CumulativeFrequency; - H = (ushort)(L + ((mdl.Syms[i - 1].CumulativeFrequency * range) / symf) - 1); - L = (ushort)(L + ((mdl.Syms[i].CumulativeFrequency * range) / symf)); - - do - { - mdl.Syms[--i].CumulativeFrequency += 8; - } while (i > 0); - - if (mdl.Syms[0].CumulativeFrequency > 3800) - UpdateModel(mdl); - - while (true) - { - if ((L & 0x8000) != (H & 0x8000)) - { - if ((L & 0x4000) != 0 && (H & 0x4000) == 0) - { - // Underflow case - C ^= 0x4000; - L &= 0x3FFF; - H |= 0x4000; - } - else - { - break; - } - } - - L <<= 1; - H = (ushort)((H << 1) | 1); - - qtm.ENSURE_BITS(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - C = (ushort)((C << 1) | (qtm.PEEK_BITS_MSB(1, bit_buffer))); - qtm.REMOVE_BITS_MSB(1, ref bit_buffer, ref bits_left); - } - } - + sym = GET_SYMBOL(qtm, mdl, ref H, ref L, ref C, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); window[window_posn++] = (byte)sym; frame_todo--; } @@ -382,58 +280,7 @@ namespace LibMSPackSharp.Compression { // Selector 4 = fixed length match (3 bytes) case 4: - //GET_SYMBOL(qtm.Model4, sym) - { - range = (uint)((H - L) & 0xFFFF) + 1; - symf = (ushort)(((((C - L + 1) * qtm.Model4.Syms[0].CumulativeFrequency) - 1) / range) & 0xFFFF); - - for (i = 1; i < qtm.Model4.Entries; i++) - { - if (qtm.Model4.Syms[i].CumulativeFrequency <= symf) - break; - } - - (sym) = qtm.Model4.Syms[i - 1].Sym; - - range = (uint)(H - L) + 1; - symf = qtm.Model4.Syms[0].CumulativeFrequency; - H = (ushort)(L + ((qtm.Model4.Syms[i - 1].CumulativeFrequency * range) / symf) - 1); - L = (ushort)(L + ((qtm.Model4.Syms[i].CumulativeFrequency * range) / symf)); - - do - { - qtm.Model4.Syms[--i].CumulativeFrequency += 8; - } while (i > 0); - - if (qtm.Model4.Syms[0].CumulativeFrequency > 3800) - UpdateModel(qtm.Model4); - - while (true) - { - if ((L & 0x8000) != (H & 0x8000)) - { - if ((L & 0x4000) != 0 && (H & 0x4000) == 0) - { - // Underflow case - C ^= 0x4000; - L &= 0x3FFF; - H |= 0x4000; - } - else - { - break; - } - } - - L <<= 1; - H = (ushort)((H << 1) | 1); - - qtm.ENSURE_BITS(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - C = (ushort)((C << 1) | (qtm.PEEK_BITS_MSB(1, bit_buffer))); - qtm.REMOVE_BITS_MSB(1, ref bit_buffer, ref bits_left); - } - } - + sym = GET_SYMBOL(qtm, qtm.Model4, ref H, ref L, ref C, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); extra = (int)qtm.READ_MANY_BITS_MSB(extra_bits[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); match_offset = (uint)(position_base[sym] + extra + 1); match_length = 3; @@ -441,58 +288,7 @@ namespace LibMSPackSharp.Compression // Selector 5 = fixed length match (4 bytes) case 5: - //GET_SYMBOL(qtm.Model5, sym) - { - range = (uint)((H - L) & 0xFFFF) + 1; - symf = (ushort)(((((C - L + 1) * qtm.Model5.Syms[0].CumulativeFrequency) - 1) / range) & 0xFFFF); - - for (i = 1; i < qtm.Model5.Entries; i++) - { - if (qtm.Model5.Syms[i].CumulativeFrequency <= symf) - break; - } - - (sym) = qtm.Model5.Syms[i - 1].Sym; - - range = (uint)(H - L) + 1; - symf = qtm.Model5.Syms[0].CumulativeFrequency; - H = (ushort)(L + ((qtm.Model5.Syms[i - 1].CumulativeFrequency * range) / symf) - 1); - L = (ushort)(L + ((qtm.Model5.Syms[i].CumulativeFrequency * range) / symf)); - - do - { - qtm.Model5.Syms[--i].CumulativeFrequency += 8; - } while (i > 0); - - if (qtm.Model5.Syms[0].CumulativeFrequency > 3800) - UpdateModel(qtm.Model5); - - while (true) - { - if ((L & 0x8000) != (H & 0x8000)) - { - if ((L & 0x4000) != 0 && (H & 0x4000) == 0) - { - // Underflow case - C ^= 0x4000; - L &= 0x3FFF; - H |= 0x4000; - } - else - { - break; - } - } - - L <<= 1; - H = (ushort)((H << 1) | 1); - - qtm.ENSURE_BITS(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - C = (ushort)((C << 1) | (qtm.PEEK_BITS_MSB(1, bit_buffer))); - qtm.REMOVE_BITS_MSB(1, ref bit_buffer, ref bits_left); - } - } - + sym = GET_SYMBOL(qtm, qtm.Model5, ref H, ref L, ref C, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); extra = (int)qtm.READ_MANY_BITS_MSB(extra_bits[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); match_offset = (uint)(position_base[sym] + extra + 1); match_length = 4; @@ -500,113 +296,11 @@ namespace LibMSPackSharp.Compression // Selector 6 = variable length match case 6: - //GET_SYMBOL(qtm.Model6Len, sym) - { - range = (uint)((H - L) & 0xFFFF) + 1; - symf = (ushort)(((((C - L + 1) * qtm.Model6Len.Syms[0].CumulativeFrequency) - 1) / range) & 0xFFFF); - - for (i = 1; i < qtm.Model6Len.Entries; i++) - { - if (qtm.Model6Len.Syms[i].CumulativeFrequency <= symf) - break; - } - - (sym) = qtm.Model6Len.Syms[i - 1].Sym; - - range = (uint)(H - L) + 1; - symf = qtm.Model6Len.Syms[0].CumulativeFrequency; - H = (ushort)(L + ((qtm.Model6Len.Syms[i - 1].CumulativeFrequency * range) / symf) - 1); - L = (ushort)(L + ((qtm.Model6Len.Syms[i].CumulativeFrequency * range) / symf)); - - do - { - qtm.Model6Len.Syms[--i].CumulativeFrequency += 8; - } while (i > 0); - - if (qtm.Model6Len.Syms[0].CumulativeFrequency > 3800) - UpdateModel(qtm.Model6Len); - - while (true) - { - if ((L & 0x8000) != (H & 0x8000)) - { - if ((L & 0x4000) != 0 && (H & 0x4000) == 0) - { - // Underflow case - C ^= 0x4000; - L &= 0x3FFF; - H |= 0x4000; - } - else - { - break; - } - } - - L <<= 1; - H = (ushort)((H << 1) | 1); - - qtm.ENSURE_BITS(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - C = (ushort)((C << 1) | (qtm.PEEK_BITS_MSB(1, bit_buffer))); - qtm.REMOVE_BITS_MSB(1, ref bit_buffer, ref bits_left); - } - } - + sym = GET_SYMBOL(qtm, qtm.Model6Len, ref H, ref L, ref C, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); extra = (int)qtm.READ_MANY_BITS_MSB(length_extra[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); match_length = length_base[sym] + extra + 5; - //GET_SYMBOL(qtm.Model6, sym) - { - range = (uint)((H - L) & 0xFFFF) + 1; - symf = (ushort)(((((C - L + 1) * qtm.Model6.Syms[0].CumulativeFrequency) - 1) / range) & 0xFFFF); - - for (i = 1; i < qtm.Model6.Entries; i++) - { - if (qtm.Model6.Syms[i].CumulativeFrequency <= symf) - break; - } - - (sym) = qtm.Model6.Syms[i - 1].Sym; - - range = (uint)(H - L) + 1; - symf = qtm.Model6.Syms[0].CumulativeFrequency; - H = (ushort)(L + ((qtm.Model6.Syms[i - 1].CumulativeFrequency * range) / symf) - 1); - L = (ushort)(L + ((qtm.Model6.Syms[i].CumulativeFrequency * range) / symf)); - - do - { - qtm.Model6.Syms[--i].CumulativeFrequency += 8; - } while (i > 0); - - if (qtm.Model6.Syms[0].CumulativeFrequency > 3800) - UpdateModel(qtm.Model6); - - while (true) - { - if ((L & 0x8000) != (H & 0x8000)) - { - if ((L & 0x4000) != 0 && (H & 0x4000) == 0) - { - // Underflow case - C ^= 0x4000; - L &= 0x3FFF; - H |= 0x4000; - } - else - { - break; - } - } - - L <<= 1; - H = (ushort)((H << 1) | 1); - - qtm.ENSURE_BITS(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); - C = (ushort)((C << 1) | (qtm.PEEK_BITS_MSB(1, bit_buffer))); - qtm.REMOVE_BITS_MSB(1, ref bit_buffer, ref bits_left); - } - } - + sym = GET_SYMBOL(qtm, qtm.Model6, ref H, ref L, ref C, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); extra = (int)qtm.READ_MANY_BITS_MSB(extra_bits[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); match_offset = (uint)(position_base[sym] + extra + 1); break; @@ -786,6 +480,61 @@ namespace LibMSPackSharp.Compression return Error.MSPACK_ERR_OK; } + private static ushort GET_SYMBOL(QTMDStream qtm, QTMDModel model, ref ushort H, ref ushort L, ref ushort C, ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left) + { + uint range = (uint)((H - L) & 0xFFFF) + 1; + ushort symf = (ushort)(((((C - L + 1) * model.Syms[0].CumulativeFrequency) - 1) / range) & 0xFFFF); + + int i = 1; + for (; i < model.Entries; i++) + { + if (model.Syms[i].CumulativeFrequency <= symf) + break; + } + + ushort temp = model.Syms[i - 1].Sym; + + range = (uint)(H - L) + 1; + symf = model.Syms[0].CumulativeFrequency; + H = (ushort)(L + ((model.Syms[i - 1].CumulativeFrequency * range) / symf) - 1); + L = (ushort)(L + ((model.Syms[i].CumulativeFrequency * range) / symf)); + + do + { + model.Syms[--i].CumulativeFrequency += 8; + } while (i > 0); + + if (model.Syms[0].CumulativeFrequency > 3800) + UpdateModel(model); + + while (true) + { + if ((L & 0x8000) != (H & 0x8000)) + { + if ((L & 0x4000) != 0 && (H & 0x4000) == 0) + { + // Underflow case + C ^= 0x4000; + L &= 0x3FFF; + H |= 0x4000; + } + else + { + break; + } + } + + L <<= 1; + H = (ushort)((H << 1) | 1); + + qtm.ENSURE_BITS(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); + C = (ushort)((C << 1) | (qtm.PEEK_BITS_MSB(1, bit_buffer))); + qtm.REMOVE_BITS_MSB(1, ref bit_buffer, ref bits_left); + } + + return temp; + } + private static void UpdateModel(QTMDModel model) { QTMDModelSym tmp; diff --git a/BurnOutSharp/External/libmspack/Compression/QTMDStream.cs b/BurnOutSharp/External/libmspack/Compression/QTMDStream.cs index ca8d6e89..dd73b778 100644 --- a/BurnOutSharp/External/libmspack/Compression/QTMDStream.cs +++ b/BurnOutSharp/External/libmspack/Compression/QTMDStream.cs @@ -10,6 +10,8 @@ * For further details, see the file COPYING.LIB distributed with libmspack */ +using System; + namespace LibMSPackSharp.Compression { public class QTMDStream : CompressionStream @@ -124,6 +126,9 @@ namespace LibMSPackSharp.Compression #endregion + /// + public override Error HUFF_ERROR() => throw new NotImplementedException(); + /// public override void READ_BYTES(ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left) {