diff --git a/BurnOutSharp.Compression/LZX/Bits.cs b/BurnOutSharp.Compression/LZX/Bits.cs
index b5bfe65a..aac72c7a 100644
--- a/BurnOutSharp.Compression/LZX/Bits.cs
+++ b/BurnOutSharp.Compression/LZX/Bits.cs
@@ -7,6 +7,6 @@ namespace BurnOutSharp.Compression.LZX
public int BitsLeft;
- public int InitialPosition; //byte*
+ public int InputPosition; //byte*
}
}
\ No newline at end of file
diff --git a/BurnOutSharp.Compression/LZX/Decompressor.cs b/BurnOutSharp.Compression/LZX/Decompressor.cs
index 5c061736..b89dad11 100644
--- a/BurnOutSharp.Compression/LZX/Decompressor.cs
+++ b/BurnOutSharp.Compression/LZX/Decompressor.cs
@@ -19,11 +19,73 @@ namespace BurnOutSharp.Compression.LZX
///
/// Read and build the Huffman tree from the lengths
///
- /// 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
+
+ ///
+ /// This function was coded by David Tritscher. It builds a fast huffman
+ /// decoding table out of just a canonical huffman code lengths table.
+ ///
+ /// Total number of symbols in this huffman tree.
+ ///
+ /// Any symbols with a code length of nbits or less can be decoded
+ /// in one lookup of the table.
+ ///
+ /// A table to get code lengths from [0 to syms-1]
+ /// The table to fill up with decoded symbols and pointers.
+ ///
+ /// OK: 0
+ /// error: 1
+ ///
+ 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.
///
- 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;
}
diff --git a/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.LZX.cs b/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.LZX.cs
index 4757bef4..f2d0a772 100644
--- a/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.LZX.cs
+++ b/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.LZX.cs
@@ -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; xbb = bitbuf;
-// lb->bl = bitsleft;
-// lb->ip = inpos;
-// return 0;
-// }
// /*******************************************************
// * LZXfdi_decomp(internal)