diff --git a/BurnOutSharp/External/libmspack/Compression/LZX.cs b/BurnOutSharp/External/libmspack/Compression/LZX.cs index 05e54e96..fe0e8516 100644 --- a/BurnOutSharp/External/libmspack/Compression/LZX.cs +++ b/BurnOutSharp/External/libmspack/Compression/LZX.cs @@ -439,7 +439,6 @@ namespace LibMSPackSharp.Compression /// LZX decompression state, as allocated by lzxd_init(). /// the number of bytes of data to decompress. /// an error code, or MSPACK_ERR_OK if successful - // TODO: Huffman tree implementation public static Error Decompress(object o, long out_bytes) { LZXDStream lzx = o as LZXDStream; @@ -1017,36 +1016,221 @@ namespace LibMSPackSharp.Compression lzx.ALIGNED_len[i] = (byte)j; } - BUILD_TABLE(ALIGNED); + //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; + } + } // Read lengths of and build main huffman decoding tree - READ_LENGTHS(MAINTREE, 0, 256); - READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + lzx.NumOffsets); - BUILD_TABLE(MAINTREE); + + //READ_LENGTHS(MAINTREE, 0, 256) + { + //STORE_BITS + { + lzx.InputPointer = i_ptr; + lzx.InputLength = i_end; + lzx.BitBuffer = bit_buffer; + lzx.BitsLeft = bits_left; + } + + if (ReadLens(lzx, lzx.MAINTREE_len, (0), (uint)(256)) != Error.MSPACK_ERR_OK) + return lzx.Error; + + //RESTORE_BITS + { + i_ptr = lzx.InputPointer; + i_end = lzx.InputLength; + bit_buffer = lzx.BitBuffer; + bits_left = lzx.BitsLeft; + } + } + + //READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + lzx.NumOffsets) + { + //STORE_BITS + { + lzx.InputPointer = i_ptr; + lzx.InputLength = i_end; + lzx.BitBuffer = bit_buffer; + lzx.BitsLeft = bits_left; + } + + if (ReadLens(lzx, lzx.MAINTREE_len, (256), (uint)(LZX_NUM_CHARS + lzx.NumOffsets)) != Error.MSPACK_ERR_OK) + return lzx.Error; + + //RESTORE_BITS + { + i_ptr = lzx.InputPointer; + i_end = lzx.InputLength; + bit_buffer = lzx.BitBuffer; + bits_left = lzx.BitsLeft; + } + } + + //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; + } + } // 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(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS); - BUILD_TABLE_MAYBE_EMPTY(LENGTH); + + //READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS) + { + //STORE_BITS + { + lzx.InputPointer = i_ptr; + lzx.InputLength = i_end; + lzx.BitBuffer = bit_buffer; + lzx.BitsLeft = bits_left; + } + + if (ReadLens(lzx, lzx.LENGTH_len, (0), (uint)(LZX_NUM_SECONDARY_LENGTHS)) != Error.MSPACK_ERR_OK) + return lzx.Error; + + //RESTORE_BITS + { + i_ptr = lzx.InputPointer; + i_end = lzx.InputLength; + bit_buffer = lzx.BitBuffer; + bits_left = lzx.BitsLeft; + } + } + + //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; + } + } break; case LZXBlockType.LZX_BLOCKTYPE_VERBATIM: // Read lengths of and build main huffman decoding tree - READ_LENGTHS(MAINTREE, 0, 256); - READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + lzx.NumOffsets); - BUILD_TABLE(MAINTREE); + + //READ_LENGTHS(MAINTREE, 0, 256) + { + //STORE_BITS + { + lzx.InputPointer = i_ptr; + lzx.InputLength = i_end; + lzx.BitBuffer = bit_buffer; + lzx.BitsLeft = bits_left; + } + + if (ReadLens(lzx, lzx.MAINTREE_len, (0), (uint)(256)) != Error.MSPACK_ERR_OK) + return lzx.Error; + + //RESTORE_BITS + { + i_ptr = lzx.InputPointer; + i_end = lzx.InputLength; + bit_buffer = lzx.BitBuffer; + bits_left = lzx.BitsLeft; + } + } + + //READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + lzx.NumOffsets) + { + //STORE_BITS + { + lzx.InputPointer = i_ptr; + lzx.InputLength = i_end; + lzx.BitBuffer = bit_buffer; + lzx.BitsLeft = bits_left; + } + + if (ReadLens(lzx, lzx.MAINTREE_len, (256), (uint)(LZX_NUM_CHARS + lzx.NumOffsets)) != Error.MSPACK_ERR_OK) + return lzx.Error; + + //RESTORE_BITS + { + i_ptr = lzx.InputPointer; + i_end = lzx.InputLength; + bit_buffer = lzx.BitBuffer; + bits_left = lzx.BitsLeft; + } + } + + //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; + } + } // 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(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS); - BUILD_TABLE_MAYBE_EMPTY(LENGTH); + + //READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS) + { + //STORE_BITS + { + lzx.InputPointer = i_ptr; + lzx.InputLength = i_end; + lzx.BitBuffer = bit_buffer; + lzx.BitsLeft = bits_left; + } + + if (ReadLens(lzx, lzx.LENGTH_len, (0), (uint)(LZX_NUM_SECONDARY_LENGTHS)) != Error.MSPACK_ERR_OK) + return lzx.Error; + + //RESTORE_BITS + { + i_ptr = lzx.InputPointer; + i_end = lzx.InputLength; + bit_buffer = lzx.BitBuffer; + bits_left = lzx.BitsLeft; + } + } + + //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; + } + } break; @@ -1150,7 +1334,76 @@ namespace LibMSPackSharp.Compression case LZXBlockType.LZX_BLOCKTYPE_VERBATIM: while (this_run > 0) { - READ_HUFFSYM(MAINTREE, main_element); + //READ_HUFFSYM(MAINTREE, main_element) + { + //ENSURE_BITS(CompressionStream.HUFF_MAXBITS) + { + while (bits_left < (CompressionStream.HUFF_MAXBITS)) + { + //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(bitdata, 16) + { + bit_buffer |= (uint)((b1 << 8) | b0) << (CompressionStream.BITBUF_WIDTH - (16) - bits_left); + bits_left += (16); + } + } + } + } + + sym = lzx.MAINTREE_table[(bit_buffer >> (CompressionStream.BITBUF_WIDTH - (LZX_MAINTREE_TABLEBITS)))]; //PEEK_BITS(TABLEBITS(MAINTREE)) + if (sym >= LZX_MAINTREE_MAXSYMBOLS) + { + //HUFF_TRAVERSE(tbl) + { + 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]; + + //REMOVE_BITS(i) + { + bit_buffer <<= (i); + bits_left -= (i); + } + } if (main_element < LZX_NUM_CHARS) { @@ -1173,7 +1426,76 @@ namespace LibMSPackSharp.Compression return lzx.Error = Error.MSPACK_ERR_DECRUNCH; } - READ_HUFFSYM(LENGTH, length_footer); + //READ_HUFFSYM(LENGTH, length_footer) + { + //ENSURE_BITS(CompressionStream.HUFF_MAXBITS) + { + while (bits_left < (CompressionStream.HUFF_MAXBITS)) + { + //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(bitdata, 16) + { + bit_buffer |= (uint)((b1 << 8) | b0) << (CompressionStream.BITBUF_WIDTH - (16) - bits_left); + bits_left += (16); + } + } + } + } + + sym = lzx.LENGTH_table[(bit_buffer >> (CompressionStream.BITBUF_WIDTH - (LZX_LENGTH_TABLEBITS)))]; //PEEK_BITS(TABLEBITS(LENGTH)) + 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]; + + //REMOVE_BITS(i) + { + bit_buffer <<= (i); + bits_left -= (i); + } + } match_length += length_footer; } @@ -1335,7 +1657,76 @@ namespace LibMSPackSharp.Compression match_offset += (uint)(verbatim_bits << 3); - READ_HUFFSYM(ALIGNED, aligned_bits); + //READ_HUFFSYM(ALIGNED, aligned_bits) + { + //ENSURE_BITS(CompressionStream.HUFF_MAXBITS) + { + while (bits_left < (CompressionStream.HUFF_MAXBITS)) + { + //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(bitdata, 16) + { + bit_buffer |= (uint)((b1 << 8) | b0) << (CompressionStream.BITBUF_WIDTH - (16) - bits_left); + bits_left += (16); + } + } + } + } + + sym = lzx.ALIGNED_table[(bit_buffer >> (CompressionStream.BITBUF_WIDTH - (LZX_ALIGNED_TABLEBITS)))]; //PEEK_BITS(TABLEBITS(ALIGNED)) + 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]; + + //REMOVE_BITS(i) + { + bit_buffer <<= (i); + bits_left -= (i); + } + } match_offset += (uint)aligned_bits; } @@ -1343,7 +1734,76 @@ namespace LibMSPackSharp.Compression // 3: aligned bits only else if (extra == 3) { - READ_HUFFSYM(ALIGNED, aligned_bits); + //READ_HUFFSYM(ALIGNED, aligned_bits) + { + //ENSURE_BITS(CompressionStream.HUFF_MAXBITS) + { + while (bits_left < (CompressionStream.HUFF_MAXBITS)) + { + //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(bitdata, 16) + { + bit_buffer |= (uint)((b1 << 8) | b0) << (CompressionStream.BITBUF_WIDTH - (16) - bits_left); + bits_left += (16); + } + } + } + } + + sym = lzx.ALIGNED_table[(bit_buffer >> (CompressionStream.BITBUF_WIDTH - (LZX_ALIGNED_TABLEBITS)))]; //PEEK_BITS(TABLEBITS(ALIGNED)) + 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]; + + //REMOVE_BITS(i) + { + bit_buffer <<= (i); + bits_left -= (i); + } + } match_offset += (uint)aligned_bits; } @@ -2009,7 +2469,6 @@ namespace LibMSPackSharp.Compression return Error.MSPACK_ERR_OK; } - // TODO: Huffman tree implementation private static Error ReadLens(LZXDStream lzx, byte[] lens, uint first, uint last) { // Bit buffer and huffman symbol decode variables @@ -2089,11 +2548,87 @@ namespace LibMSPackSharp.Compression lzx.PRETREE_len[x] = (byte)y; } - BUILD_TABLE(PRETREE); + //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; + } + } for (x = first; x < last;) { - READ_HUFFSYM(PRETREE, z); + //READ_HUFFSYM(PRETREE, z) + { + //ENSURE_BITS(CompressionStream.HUFF_MAXBITS) + { + while (bits_left < (CompressionStream.HUFF_MAXBITS)) + { + //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(bitdata, 16) + { + bit_buffer |= (uint)((b1 << 8) | b0) << (CompressionStream.BITBUF_WIDTH - (16) - bits_left); + bits_left += (16); + } + } + } + } + + sym = lzx.PRETREE_table[(bit_buffer >> (CompressionStream.BITBUF_WIDTH - (LZX_PRETREE_TABLEBITS)))]; //PEEK_BITS(TABLEBITS(PRETREE)) + 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]; + + //REMOVE_BITS(i) + { + bit_buffer <<= (i); + bits_left -= (i); + } + } // Code = 17, run of ([read 4 bits]+4) zeros if (z == 17) @@ -2282,7 +2817,76 @@ namespace LibMSPackSharp.Compression y += 4; - READ_HUFFSYM(PRETREE, z); + //READ_HUFFSYM(PRETREE, z) + { + //ENSURE_BITS(CompressionStream.HUFF_MAXBITS) + { + while (bits_left < (CompressionStream.HUFF_MAXBITS)) + { + //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(bitdata, 16) + { + bit_buffer |= (uint)((b1 << 8) | b0) << (CompressionStream.BITBUF_WIDTH - (16) - bits_left); + bits_left += (16); + } + } + } + } + + sym = lzx.PRETREE_table[(bit_buffer >> (CompressionStream.BITBUF_WIDTH - (LZX_PRETREE_TABLEBITS)))]; //PEEK_BITS(TABLEBITS(PRETREE)) + 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]; + + //REMOVE_BITS(i) + { + bit_buffer <<= (i); + bits_left -= (i); + } + } z = lens[x] - z; if (z < 0)