Port LZX read lengths

This commit is contained in:
Matt Nadareski
2023-01-03 16:11:30 -08:00
parent bb6a045dd3
commit 1c78dac79f
3 changed files with 170 additions and 58 deletions

View File

@@ -7,6 +7,6 @@ namespace BurnOutSharp.Compression.LZX
public int BitsLeft;
public int InitialPosition; //byte*
public int InputPosition; //byte*
}
}

View File

@@ -19,11 +19,73 @@ namespace BurnOutSharp.Compression.LZX
/// <summary>
/// Read and build the Huffman tree from the lengths
/// </summary>
/// INCORRECT IMPLEMENTATION TO SATISFY COMPILER FOR NOW
private static int ReadLengths(byte[] lengths, uint first, uint last, Bits lb, State state, byte[] inbuf, ref int inpos, ref int bitsleft, ref uint bitbuf)
private static int ReadLengths(byte[] lengths, uint first, uint last, Bits lb, State state, byte[] inbuf)
{
uint i, j, x, y;
int z;
// TODO: Finish implementation
uint bitbuf = lb.BitBuffer;
int bitsleft = lb.BitsLeft;
int inpos = lb.InputPosition;
ushort[] hufftbl;
for (x = 0; x < 20; x++)
{
y = READ_BITS(4, inbuf, ref inpos, ref bitsleft, ref bitbuf);
state.tblPRETREE_len[x] = (byte)y;
}
make_decode_table(LZX_PRETREE_MAXSYMBOLS, LZX_PRETREE_TABLEBITS, state.tblPRETREE_len, state.tblPRETREE_table);
for (x = first; x < last;)
{
z = READ_HUFFSYM(state.tblPRETREE_table, state.tblPRETREE_len, LZX_PRETREE_TABLEBITS, LZX_PRETREE_MAXSYMBOLS, inbuf, ref inpos, ref bitsleft, ref bitbuf);
if (z == 17)
{
y = READ_BITS(4, inbuf, ref inpos, ref bitsleft, ref bitbuf);
y += 4;
while (y-- > 0)
{
lengths[x++] = 0;
}
}
else if (z == 18)
{
y = READ_BITS(5, inbuf, ref inpos, ref bitsleft, ref bitbuf);
y += 20;
while (y-- > 0)
{
lengths[x++] = 0;
}
}
else if (z == 19)
{
y = READ_BITS(1, inbuf, ref inpos, ref bitsleft, ref bitbuf);
y += 4;
z = READ_HUFFSYM(state.tblPRETREE_table, state.tblPRETREE_len, LZX_PRETREE_TABLEBITS, LZX_PRETREE_MAXSYMBOLS, inbuf, ref inpos, ref bitsleft, ref bitbuf);
z = lengths[x] - z;
if (z < 0)
z += 17;
while (y-- > 0)
{
lengths[x++] = (byte)z;
}
}
else
{
z = lengths[x] - z;
if (z < 0)
z += 17;
lengths[x++] = (byte)z;
}
}
lb.BitBuffer = bitbuf;
lb.BitsLeft = bitsleft;
lb.InputPosition = inpos;
return 0;
}
@@ -97,6 +159,105 @@ namespace BurnOutSharp.Compression.LZX
#endregion
#region Huffman Methods
/// <summary>
/// This function was coded by David Tritscher. It builds a fast huffman
/// decoding table out of just a canonical huffman code lengths table.
/// </summary>
/// <param name="nsyms">Total number of symbols in this huffman tree.</param>
/// <param name="nbits">
/// Any symbols with a code length of nbits or less can be decoded
/// in one lookup of the table.
/// </param>
/// <param name="length">A table to get code lengths from [0 to syms-1]</param>
/// <param name="table">The table to fill up with decoded symbols and pointers.</param>
/// <returns>
/// OK: 0
/// error: 1
/// </returns>
private static int make_decode_table(uint nsyms, uint nbits, byte[] length, ushort[] table)
{
ushort sym;
uint leaf;
byte bit_num = 1;
uint fill;
uint pos = 0; /* the current position in the decode table */
uint table_mask = (uint)(1 << (int)nbits);
uint bit_mask = table_mask >> 1; /* don't do 0 length codes */
uint next_symbol = bit_mask; /* base of allocation for long codes */
/* fill entries for codes short enough for a direct mapping */
while (bit_num <= nbits)
{
for (sym = 0; sym < nsyms; sym++)
{
if (length[sym] == bit_num)
{
leaf = pos;
if ((pos += bit_mask) > table_mask) return 1; /* table overrun */
/* fill all possible lookups of this symbol with the symbol itself */
fill = bit_mask;
while (fill-- > 0) table[leaf++] = sym;
}
}
bit_mask >>= 1;
bit_num++;
}
/* if there are any codes longer than nbits */
if (pos != table_mask)
{
/* clear the remainder of the table */
for (sym = (ushort)pos; sym < table_mask; sym++) table[sym] = 0;
/* give ourselves room for codes to grow by up to 16 more bits */
pos <<= 16;
table_mask <<= 16;
bit_mask = 1 << 15;
while (bit_num <= 16)
{
for (sym = 0; sym < nsyms; sym++)
{
if (length[sym] == bit_num)
{
leaf = pos >> 16;
for (fill = 0; fill < bit_num - nbits; fill++)
{
/* if this path hasn't been taken yet, 'allocate' two entries */
if (table[leaf] == 0)
{
table[(next_symbol << 1)] = 0;
table[(next_symbol << 1) + 1] = 0;
table[leaf] = (ushort)next_symbol++;
}
/* follow the path and select either left or right for next bit */
leaf = (uint)(table[leaf] << 1);
if (((pos >> (int)(15 - fill)) & 1) != 0) leaf++;
}
table[leaf] = sym;
if ((pos += bit_mask) > table_mask) return 1; /* table overflow */
}
}
bit_mask >>= 1;
bit_num++;
}
}
/* full table? */
if (pos == table_mask) return 0;
/* either erroneous table, or all elements are 0 - let's find out. */
for (sym = 0; sym < nsyms; sym++) if (length[sym] != 0) return 1;
return 0;
}
#endregion
// Huffman macros
#region Huffman Macros
@@ -104,7 +265,7 @@ namespace BurnOutSharp.Compression.LZX
/// Decodes one huffman symbol from the bitstream using the stated table and
/// puts it in v.
/// </summary>
private static int? READ_HUFFSYM(ushort[] hufftbl, byte[] lentable, int tablebits, int maxsymbols, byte[] inbuf, ref int inpos, ref int bitsleft, ref uint bitbuf)
private static int READ_HUFFSYM(ushort[] hufftbl, byte[] lentable, int tablebits, int maxsymbols, byte[] inbuf, ref int inpos, ref int bitsleft, ref uint bitbuf)
{
int v = 0, i, j = 0;
ENSURE_BITS(16, inbuf, ref inpos, ref bitsleft, ref bitbuf);
@@ -117,7 +278,7 @@ namespace BurnOutSharp.Compression.LZX
i <<= 1;
i |= (bitbuf & j) != 0 ? 1 : 0;
if (j == 0)
return null;
throw new System.Exception();
} while ((i = hufftbl[i]) >= maxsymbols);
}
@@ -134,14 +295,14 @@ namespace BurnOutSharp.Compression.LZX
{
lb.BitBuffer = bitbuf;
lb.BitsLeft = bitsleft;
lb.InitialPosition = inpos;
lb.InputPosition = inpos;
if (ReadLengths(lentable, first, last, lb, state, inbuf, ref inpos, ref bitsleft, ref bitbuf) != 0)
if (ReadLengths(lentable, first, last, lb, state, inbuf) != 0)
return false;
bitbuf = lb.BitBuffer;
bitsleft = lb.BitsLeft;
inpos = lb.InitialPosition;
inpos = lb.InputPosition;
return true;
}

View File

@@ -11,55 +11,6 @@
// {
// internal unsafe class LZXfdi
// {
// /************************************************************
// * fdi_lzx_read_lens (internal)
// */
// static int fdi_lzx_read_lens(cab_UBYTE* lens, cab_ULONG first, cab_ULONG last, struct lzx_bits *lb,
// fdi_decomp_state* decomp_state) {
// cab_ULONG i, j, x, y;
// int z;
// register cab_ULONG bitbuf = lb->bb;
// register int bitsleft = lb->bl;
// cab_UBYTE* inpos = lb->ip;
// cab_UWORD* hufftbl;
// for (x = 0; x< 20; x++) {
// READ_BITS(y, 4);
// LENTABLE(PRETREE)[x] = y;
// }
// BUILD_TABLE(PRETREE);
// for (x = first; x<last; ) {
// READ_HUFFSYM(PRETREE, z);
// if (z == 17) {
// READ_BITS(y, 4); y += 4;
// while (y--) lens[x++] = 0;
// }
// else if (z == 18)
// {
// READ_BITS(y, 5); y += 20;
// while (y--) lens[x++] = 0;
// }
// else if (z == 19)
// {
// READ_BITS(y, 1); y += 4;
// READ_HUFFSYM(PRETREE, z);
// z = lens[x] - z; if (z < 0) z += 17;
// while (y--) lens[x++] = z;
// }
// else
// {
// z = lens[x] - z; if (z < 0) z += 17;
// lens[x++] = z;
// }
// }
// lb->bb = bitbuf;
// lb->bl = bitsleft;
// lb->ip = inpos;
// return 0;
// }
// /*******************************************************
// * LZXfdi_decomp(internal)