diff --git a/BurnOutSharp.Compression/MSZIP.cs b/BurnOutSharp.Compression/MSZIP.cs
deleted file mode 100644
index be76177e..00000000
--- a/BurnOutSharp.Compression/MSZIP.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using System;
-using ICSharpCode.SharpZipLib.Zip.Compression;
-
-namespace BurnOutSharp.Compression
-{
- public class MSZIP_zlib
- {
- #region Instance Variables
-
- ///
- /// Inflater to be shared between blocks
- ///
- private readonly Inflater _inflater = new Inflater(noHeader: true);
-
- #endregion
-
- #region Decompressiom
-
- ///
- /// Decompress MSZIP data block
- ///
- public byte[] DecompressMSZIPData(byte[] data, bool previousBlock = false)
- {
- if (previousBlock)
- _inflater.Reset();
-
- _inflater.SetInput(buffer: data, 2, data.Length - 2);
- byte[] outputData = new byte[128 * 1024];
- int read = _inflater.Inflate(outputData);
- return outputData.AsSpan(0, read).ToArray();
- }
-
- #endregion
- }
-}
\ No newline at end of file
diff --git a/BurnOutSharp.Compression/MSZIP/Decompressor.cs b/BurnOutSharp.Compression/MSZIP/Decompressor.cs
index 742b547d..5673f01f 100644
--- a/BurnOutSharp.Compression/MSZIP/Decompressor.cs
+++ b/BurnOutSharp.Compression/MSZIP/Decompressor.cs
@@ -1,63 +1,69 @@
+using System;
+using System.Runtime.InteropServices;
using BurnOutSharp.Models.Compression.MSZIP;
using static BurnOutSharp.Models.Compression.MSZIP.Constants;
namespace BurnOutSharp.Compression.MSZIP
{
///
- public class Decompressor
+ public unsafe class Decompressor
{
///
/// Decompress a byte array using a given State
///
public static bool Decompress(State state, int inlen, byte[] inbuf, int outlen, byte[] outbuf)
{
- state.InputPosition = 0; // inbuf[0];
- state.BitBuffer = state.BitCount = state.WindowPosition = 0;
- if (outlen > ZIPWSIZE)
- return false;
-
- // CK = Chris Kirmse, official Microsoft purloiner
- if (inbuf[state.InputPosition + 0] != 0x43 || inbuf[state.InputPosition + 1] != 0x48)
- return false;
-
- state.InputPosition += 2;
-
- int lastBlockFlag = 0;
- do
+ fixed (byte* inpos = inbuf)
{
- if (InflateBlock(ref lastBlockFlag, state, inbuf, outbuf) != 0)
+ state.inpos = inpos;
+ state.bb = state.bk = state.window_posn = 0;
+ if (outlen > ZIPWSIZE)
return false;
- } while (lastBlockFlag == 0);
- // Return success
- return true;
+ // CK = Chris Kirmse, official Microsoft purloiner
+ if (state.inpos[0] != 0x43 || state.inpos[1] != 0x48)
+ return false;
+
+ state.inpos += 2;
+
+ int lastBlockFlag = 0;
+ do
+ {
+ if (InflateBlock(&lastBlockFlag, state, inbuf, outbuf) != 0)
+ return false;
+ } while (lastBlockFlag == 0);
+
+ // Return success
+ return true;
+ }
+
}
///
/// Decompress a deflated block
///
- private static uint InflateBlock(ref int e, State state, byte[] inbuf, byte[] outbuf)
+ private static uint InflateBlock(int* e, State state, byte[] inbuf, byte[] outbuf)
{
// Make local bit buffer
- uint bitBuffer = state.BitBuffer;
- uint bitCount = state.BitCount;
+ uint b = state.bb;
+ uint k = state.bk;
// Read the deflate block header
var header = new DeflateBlockHeader();
// Read in last block bit
- ZIPNEEDBITS(1, state, inbuf, ref bitBuffer, ref bitCount);
- header.BFINAL = (e = (int)(bitBuffer & 1)) != 0;
- ZIPDUMPBITS(1, ref bitBuffer, ref bitCount);
+ ZIPNEEDBITS(1, state, ref b, ref k);
+ header.BFINAL = (*e = (int)b & 1) != 0;
+ ZIPDUMPBITS(1, ref b, ref k);
// Read in block type
- ZIPNEEDBITS(2, state, inbuf, ref bitBuffer, ref bitCount);
- header.BTYPE = (CompressionType)(bitBuffer & 3);
- ZIPDUMPBITS(2, ref bitBuffer, ref bitCount);
+ ZIPNEEDBITS(2, state, ref b, ref k);
+ header.BTYPE = (CompressionType)(b & 3);
+ ZIPDUMPBITS(2, ref b, ref k);
// Restore the global bit buffer
- state.BitBuffer = bitBuffer;
- state.BitCount = bitCount;
+ state.bb = b;
+ state.bk = k;
// Inflate that block type
switch (header.BTYPE)
@@ -82,42 +88,42 @@ namespace BurnOutSharp.Compression.MSZIP
private static int DecompressStored(State state, byte[] inbuf, byte[] outbuf)
{
// Make local copies of globals
- uint bitBuffer = state.BitBuffer;
- uint bitCount = state.BitCount;
- uint windowPosition = state.WindowPosition;
+ uint b = state.bb;
+ uint k = state.bk;
+ uint w = state.window_posn;
// Go to byte boundary
- int n = (int)(bitCount & 7);
- ZIPDUMPBITS(n, ref bitBuffer, ref bitCount);
+ int n = (int)(k & 7);
+ ZIPDUMPBITS(n, ref b, ref k);
// Read the stored block header
var header = new NonCompressedBlockHeader();
// Get the length and its compliment
- ZIPNEEDBITS(16, state, inbuf, ref bitBuffer, ref bitCount);
- header.LEN = (ushort)(bitBuffer & 0xffff);
- ZIPDUMPBITS(16, ref bitBuffer, ref bitCount);
+ ZIPNEEDBITS(16, state, ref b, ref k);
+ header.LEN = (ushort)(b & 0xffff);
+ ZIPDUMPBITS(16, ref b, ref k);
- ZIPNEEDBITS(16, state, inbuf, ref bitBuffer, ref bitCount);
- header.NLEN = (ushort)(bitBuffer & 0xffff);
+ ZIPNEEDBITS(16, state, ref b, ref k);
+ header.NLEN = (ushort)(b & 0xffff);
if (header.LEN != (~header.NLEN & 0xffff))
return 1; // Error in compressed data
- ZIPDUMPBITS(16, ref bitBuffer, ref bitCount);
+ ZIPDUMPBITS(16, ref b, ref k);
// Read and output the compressed data
while (n-- > 0)
{
- ZIPNEEDBITS(8, state, inbuf, ref bitBuffer, ref bitCount);
- outbuf[windowPosition++] = (byte)bitBuffer;
- ZIPDUMPBITS(8, ref bitBuffer, ref bitCount);
+ ZIPNEEDBITS(8, state, ref b, ref k);
+ outbuf[w++] = (byte)b;
+ ZIPDUMPBITS(8, ref b, ref k);
}
// Restore the globals from the locals
- state.WindowPosition = windowPosition;
- state.BitBuffer = bitBuffer;
- state.BitCount = bitCount;
+ state.window_posn = w;
+ state.bb = b;
+ state.bk = k;
return 0;
}
@@ -128,78 +134,492 @@ namespace BurnOutSharp.Compression.MSZIP
private static int DecompressFixed(State state, byte[] inbuf, byte[] outbuf)
{
// Create the block header
- var header = new FixedHuffmanCompressedBlockHeader();
+ FixedHuffmanCompressedBlockHeader header = new FixedHuffmanCompressedBlockHeader();
- // Assign the literal lengths
- state.Lengths = header.LiteralLengths;
- var literalLengthTable = new HuffmanNode[30];
- int literalLengthBitCount = 7;
+ fixed (uint* l = state.ll)
+ fixed (ushort* Zipcplens = CopyLengths)
+ fixed (ushort* Zipcplext = LiteralExtraBits)
+ fixed (ushort* Zipcpdist = CopyOffsets)
+ fixed (ushort* Zipcpdext = DistanceExtraBits)
+ {
+ // Assign the literal lengths
+ state.ll = header.LiteralLengths;
+ HuffmanNode* fixed_tl;
+ int fixed_bl = 7;
- // Build the literal length tree
- int i = BuildHuffmanTree(state.Lengths, 0, 30, 0, CopyOffsets, LiteralExtraBits, ref literalLengthTable, ref literalLengthBitCount, state);
- if (i != 0)
- return i;
+ // Build the literal length tree
+ int i = BuildHuffmanTree(l, 288, 257, Zipcplens, Zipcplext, &fixed_tl, &fixed_bl, state);
+ if (i != 0)
+ return i;
- // Assign the distance codes
- state.Lengths = header.DistanceCodes;
- var distanceCodeTable = new HuffmanNode[30];
- int distanceCodeBitCount = 5;
+ // Assign the distance codes
+ state.ll = header.DistanceCodes;
+ HuffmanNode* fixed_td;
+ int fixed_bd = 5;
- // Build the distance code tree
- i = BuildHuffmanTree(state.Lengths, 0, 30, 0, CopyOffsets, DistanceExtraBits, ref distanceCodeTable, ref distanceCodeBitCount, state);
- if (i != 0)
- return i;
+ // Build the distance code tree
+ i = BuildHuffmanTree(l, 30, 0, Zipcpdist, Zipcpdext, &fixed_td, &fixed_bd, state);
+ if (i != 0)
+ return i;
- // Decompress until an end-of-block code
- return InflateCodes(literalLengthTable, distanceCodeTable, literalLengthBitCount, distanceCodeBitCount, state, inbuf, outbuf);
+ // Decompress until an end-of-block code
+ return InflateCodes(fixed_tl, fixed_td, fixed_bl, fixed_bd, state, inbuf, outbuf);
+ }
}
///
/// Decompress a block originally compressed with dynamic Huffman codes
///
- /// INCORRECT IMPLEMENTATION TO SATISFY COMPILER FOR NOW
private static int DecompressDynamic(State state, byte[] inbuf, byte[] outbuf)
{
+ int i; /* temporary variables */
+ uint j;
+ uint l; /* last length */
+ uint m; /* mask for bit lengths table */
+ uint n; /* number of lengths to get */
+ HuffmanNode* tl; /* literal/length code table */
+ HuffmanNode* td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ uint nb; /* number of bit length codes */
+ uint nl; /* number of literal/length codes */
+ uint nd; /* number of distance codes */
+ uint b; /* bit buffer */
+ uint k; /* number of bits in bit buffer */
- // TODO: Finish implementation
- return 0;
+ /* make local bit buffer */
+ b = state.bb;
+ k = state.bk;
+
+ fixed (uint* ll = state.ll)
+ {
+ /* read in table lengths */
+ ZIPNEEDBITS(5, state, ref b, ref k);
+ nl = 257 + (b & 0x1f); /* number of literal/length codes */
+ ZIPDUMPBITS(5, ref b, ref k);
+
+ ZIPNEEDBITS(5, state, ref b, ref k);
+ nd = 1 + (b & 0x1f); /* number of distance codes */
+ ZIPDUMPBITS(5, ref b, ref k);
+
+ ZIPNEEDBITS(4, state, ref b, ref k);
+ nb = 4 + (b & 0xf); /* number of bit length codes */
+ ZIPDUMPBITS(4, ref b, ref k);
+ if (nl > 288 || nd > 32)
+ return 1; /* bad lengths */
+
+ /* read in bit-length-code lengths */
+ for (j = 0; j < nb; j++)
+ {
+ ZIPNEEDBITS(3, state, ref b, ref k);
+ state.ll[BitLengthOrder[j]] = b & 7;
+ ZIPDUMPBITS(3, ref b, ref k);
+ }
+ for (; j < 19; j++)
+ state.ll[BitLengthOrder[j]] = 0;
+
+ /* build decoding table for trees--single level, 7 bit lookup */
+ bl = 7;
+ if ((i = BuildHuffmanTree(ll, 19, 19, null, null, &tl, &bl, state)) != 0)
+ return i; /* incomplete code set */
+
+ /* read in literal and distance code lengths */
+ n = nl + nd;
+ m = BitMasks[bl];
+ i = (int)(l = 0);
+ while ((uint)i < n)
+ {
+ ZIPNEEDBITS(bl, state, ref b, ref k);
+ j = (td = tl + (b & m))->b;
+ ZIPDUMPBITS((int)j, ref b, ref k);
+ j = td->n;
+ if (j < 16) /* length of code in bits (0..15) */
+ {
+ state.ll[i++] = l = j; /* save last length in l */
+ }
+ else if (j == 16) /* repeat last length 3 to 6 times */
+ {
+ ZIPNEEDBITS(2, state, ref b, ref k);
+ j = 3 + (b & 3);
+ ZIPDUMPBITS(2, ref b, ref k);
+ if ((uint)i + j > n)
+ return 1;
+ while (j-- > 0)
+ {
+ state.ll[i++] = l;
+ }
+ }
+ else if (j == 17) /* 3 to 10 zero length codes */
+ {
+ ZIPNEEDBITS(3, state, ref b, ref k);
+ j = 3 + (b & 7);
+ ZIPDUMPBITS(3, ref b, ref k);
+ if ((uint)i + j > n)
+ return 1;
+ while (j-- > 0)
+ state.ll[i++] = 0;
+ l = 0;
+ }
+ else /* j == 18: 11 to 138 zero length codes */
+ {
+ ZIPNEEDBITS(7, state, ref b, ref k);
+ j = 11 + (b & 0x7f);
+ ZIPDUMPBITS(7, ref b, ref k);
+ if ((uint)i + j > n)
+ return 1;
+ while (j-- > 0)
+ state.ll[i++] = 0;
+ l = 0;
+ }
+ }
+
+ /* restore the global bit buffer */
+ state.bb = b;
+ state.bk = k;
+
+ fixed (ushort* Zipcplens = CopyLengths)
+ fixed (ushort* Zipcplext = LiteralExtraBits)
+ fixed (ushort* Zipcpdist = CopyOffsets)
+ fixed (ushort* Zipcpdext = DistanceExtraBits)
+ {
+ /* build the decoding tables for literal/length and distance codes */
+ bl = ZIPLBITS;
+ if ((i = BuildHuffmanTree(ll, nl, 257, Zipcplens, Zipcplext, &tl, &bl, state)) != 0)
+ {
+ return i; /* incomplete code set */
+ }
+ bd = ZIPDBITS;
+ BuildHuffmanTree(ll + nl, nd, 0, Zipcpdist, Zipcpdext, &td, &bd, state);
+
+ /* decompress until an end-of-block code */
+ if (InflateCodes(tl, td, bl, bd, state, inbuf, outbuf) != 0)
+ return 1;
+
+ return 0;
+ }
+ }
}
///
/// Build a Huffman tree from a set of lengths
///
- /// INCORRECT IMPLEMENTATION TO SATISFY COMPILER FOR NOW
- private static int BuildHuffmanTree(uint[] b, int bi, uint n, uint s, ushort[] d, ushort[] e, ref HuffmanNode[] t, ref int m, State state)
+ private static int BuildHuffmanTree(uint* b, uint n, uint s, ushort* d, ushort* e, HuffmanNode** t, int* m, State state)
{
-
- // TODO: Finish implementation
- return 0;
+ uint a; /* counter for codes of length k */
+ uint el; /* length of EOB code (value 256) */
+ uint f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ uint i; /* counter, current code */
+ uint j; /* counter */
+ int k; /* number of bits in current code */
+ int* l; /* stack of bits per table */
+ uint* p; /* pointer into state.c[],state.b[],state.v[] */
+ HuffmanNode* q; /* points to current table */
+ HuffmanNode r = new HuffmanNode(); /* table entry for structure assignment */
+ int w; /* bits before this table == (l * h) */
+ uint* xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ uint z; /* number of entries in current table */
+
+ fixed (int* state_lx_ptr = state.lx)
+ {
+ l = state_lx_ptr + 1;
+
+ /* Generate counts for each bit length */
+ el = n > 256 ? b[256] : ZIPBMAX; /* set length of EOB code, if any */
+
+ for (i = 0; i < ZIPBMAX + 1; ++i)
+ state.c[i] = 0;
+ p = b; i = n;
+ do
+ {
+ state.c[*p]++; p++; /* assume all entries <= ZIPBMAX */
+ } while (--i > 0);
+
+ if (state.c[0] == n) /* null input--all zero length codes */
+ {
+ *t = null;
+ *m = 0;
+ return 0;
+ }
+
+ /* Find minimum and maximum length, bound *m by those */
+ for (j = 1; j <= ZIPBMAX; j++)
+ {
+ if (state.c[j] > 0)
+ break;
+ }
+
+ k = (int)j; /* minimum code length */
+ if ((uint)*m < j)
+ *m = (int)j;
+
+ for (i = ZIPBMAX; i > 0; i--)
+ {
+ if (state.c[i] > 0)
+ break;
+ }
+
+ g = (int)i; /* maximum code length */
+ if ((uint)*m > i)
+ *m = (int)i;
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << (int)j; j < i; j++, y <<= 1)
+ {
+ if ((y -= (int)state.c[j]) < 0)
+ return 2; /* bad input: more codes than bits */
+ }
+
+ if ((y -= (int)state.c[i]) < 0)
+ return 2;
+
+ state.c[i] += (uint)y;
+
+ /* Generate starting offsets LONGo the value table for each length */
+ state.x[1] = j = 0;
+
+ fixed (uint* state_c_ptr = state.c)
+ fixed (uint* state_x_ptr = state.x)
+ {
+ p = state_c_ptr + 1;
+ xp = state_x_ptr + 2;
+ while (--i > 0)
+ {
+ /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+ }
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do
+ {
+ if ((j = *p++) != 0)
+ state.v[state.x[j]++] = i;
+ } while (++i < n);
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ state.x[0] = i = 0; /* first Huffman code is zero */
+
+ fixed (uint* state_v_ptr = state.v)
+ {
+ p = state_v_ptr; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = l[-1] = 0; /* no bits decoded yet */
+ state.u[0] = default; /* just to keep compilers happy */
+ q = null; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+ a = state.c[k];
+ while (a-- > 0)
+ {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l[h])
+ {
+ w += l[h++]; /* add bits already decoded */
+
+ /* compute minimum size table less than or equal to *m bits */
+ if ((z = (uint)(g - w)) > (uint)*m) /* upper limit */
+ z = (uint)*m;
+
+ if ((f = (uint)(1 << (int)(j = (uint)(k - w)))) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ fixed (uint* state_c_ptr = state.c)
+ {
+ xp = state_c_ptr + k;
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ }
+
+ if ((uint)w + j > el && (uint)w < el)
+ j = (uint)(el - w); /* make EOB code end at table */
+
+ z = (uint)(1 << (int)j); /* table entries for j-bit table */
+ l[h] = (int)j; /* set table size in stack */
+
+ /* allocate and link in new table */
+ q = (HuffmanNode*)Marshal.AllocHGlobal((int)((z + 1) * sizeof(HuffmanNode)));
+ *t = q + 1; /* link to list for HuffmanNode_free() */
+ *(t = &(*q).t) = null;
+ state.u[h] = ++q; /* table starts after link */
+
+ /* connect to last table, if there is one */
+ if (h > 0)
+ {
+ state.x[h] = i; /* save pattern for backing up */
+ r.b = (byte)l[h - 1]; /* bits to dump before this table */
+ r.e = (byte)(16 + j); /* bits in this table */
+ r.t = q; /* pointer to this table */
+ j = (uint)((i & ((1 << w) - 1)) >> (w - l[h - 1]));
+ state.u[h - 1][j] = r; /* connect to last table */
+ }
+ }
+
+ /* set up table entry in r */
+ r.b = (byte)(k - w);
+
+ fixed (uint* state_v_ptr_comp = state.v)
+ {
+ if (p >= state_v_ptr_comp + n)
+ {
+ r.e = 99; /* out of values--invalid code */
+ }
+ else if (*p < s)
+ {
+ r.e = (byte)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */
+ r.n = (ushort)*p++; /* simple code is just the value */
+ }
+ else
+ {
+ r.e = (byte)e[*p - s]; /* non-simple--look up in lists */
+ r.n = d[*p++ - s];
+ }
+ }
+
+ /* fill code-like entries with r */
+ f = (uint)(1 << (k - w));
+ for (j = i >> w; j < z; j += f)
+ {
+ q[j] = r;
+ }
+
+ /* backwards increment the k-bit code i */
+ for (j = (uint)(1 << (k - 1)); (i & j) != 0; j >>= 1)
+ {
+ i ^= j;
+ }
+
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != state.x[h])
+ w -= l[--h]; /* don't need to update q */
+ }
+ }
+ }
+
+ /* return actual size of base table */
+ *m = l[0];
+ }
+
+ /* Return true (1) if we were given an incomplete table */
+ return y != 0 && g != 1 ? 1 : 0;
}
///
/// Inflate codes into Huffman trees
///
- /// INCORRECT IMPLEMENTATION TO SATISFY COMPILER FOR NOW
- private static int InflateCodes(HuffmanNode[] tl, HuffmanNode[] td, int bl, int bd, State state, byte[] inbuf, byte[] outbuf)
+ private static int InflateCodes(HuffmanNode* tl, HuffmanNode* td, int bl, int bd, State state, byte[] inbuf, byte[] outbuf)
{
+ uint e; /* table entry flag/number of extra bits */
+ uint n, d; /* length and index for copy */
+ uint w; /* current window position */
+ HuffmanNode* t; /* pointer to table entry */
+ uint ml, md; /* masks for bl and bd bits */
+ uint b; /* bit buffer */
+ uint k; /* number of bits in bit buffer */
- // TODO: Finish implementation
+ /* make local copies of globals */
+ b = state.bb; /* initialize bit buffer */
+ k = state.bk;
+ w = state.window_posn; /* initialize window position */
+
+ /* inflate the coded data */
+ ml = BitMasks[bl]; /* precompute masks for speed */
+ md = BitMasks[bd];
+
+ for (; ; )
+ {
+ ZIPNEEDBITS(bl, state, ref b, ref k);
+ if ((e = (t = tl + (b & ml))->e) > 16)
+ {
+ do
+ {
+ if (e == 99)
+ return 1;
+ ZIPDUMPBITS(t->b, ref b, ref k);
+ e -= 16;
+ ZIPNEEDBITS((int)e, state, ref b, ref k);
+ } while ((e = (*(t = t->t + (b & BitMasks[e]))).e) > 16);
+ }
+
+ ZIPDUMPBITS(t->b, ref b, ref k);
+ if (e == 16) /* then it's a literal */
+ {
+ outbuf[w++] = (byte)t->n;
+ }
+ else /* it's an EOB or a length */
+ {
+ /* exit if end of block */
+ if (e == 15)
+ break;
+
+ /* get length of block to copy */
+ ZIPNEEDBITS((int)e, state, ref b, ref k);
+ n = t->n + (b & BitMasks[e]);
+ ZIPDUMPBITS((int)e, ref b, ref k);
+
+ /* decode distance of block to copy */
+ ZIPNEEDBITS(bd, state, ref b, ref k);
+
+ if ((e = (*(t = td + (b & md))).e) > 16)
+ do
+ {
+ if (e == 99)
+ return 1;
+ ZIPDUMPBITS(t->b, ref b, ref k);
+ e -= 16;
+ ZIPNEEDBITS((int)e, state, ref b, ref k);
+ } while ((e = (*(t = t->t + (b & BitMasks[e]))).e) > 16);
+
+ ZIPDUMPBITS(t->b, ref b, ref k);
+
+ ZIPNEEDBITS((int)e, state, ref b, ref k);
+ d = w - t->n - (b & BitMasks[e]);
+ ZIPDUMPBITS((int)e, ref b, ref k);
+
+ do
+ {
+ d &= ZIPWSIZE - 1;
+ e = ZIPWSIZE - Math.Max(d, w);
+ e = Math.Min(e, n);
+ n -= e;
+ do
+ {
+ outbuf[w++] = outbuf[d++];
+ } while (--e > 0);
+ } while (n > 0);
+ }
+ }
+
+ /* restore the globals from the locals */
+ state.window_posn = w; /* restore global window pointer */
+ state.bb = b; /* restore global bit buffer */
+ state.bk = k;
+
+ /* done */
return 0;
}
- ///
- /// Free a single huffman node
- ///
- /// No-op because of garbage collection
- private static void Free(HuffmanNode node) { }
-
#region Macros
- private static void ZIPNEEDBITS(int n, State state, byte[] inbuf, ref uint bitBuffer, ref uint bitCount)
+ private static void ZIPNEEDBITS(int n, State state, ref uint bitBuffer, ref uint bitCount)
{
while (bitCount < n)
{
- int c = inbuf[state.InputPosition++];
+ int c = *state.inpos++;
bitBuffer |= (uint)(c << (int)bitCount);
bitCount += 8;
}
diff --git a/BurnOutSharp.Compression/MSZIP/HuffmanNode.cs b/BurnOutSharp.Compression/MSZIP/HuffmanNode.cs
index 475a9a6c..ebb42a52 100644
--- a/BurnOutSharp.Compression/MSZIP/HuffmanNode.cs
+++ b/BurnOutSharp.Compression/MSZIP/HuffmanNode.cs
@@ -1,28 +1,28 @@
namespace BurnOutSharp.Compression.MSZIP
{
- public class HuffmanNode
+ public unsafe struct HuffmanNode
{
///
/// Number of extra bits or operation
///
- public byte ExtraBits;
+ public byte e;
///
/// Number of bits in this code or subcode
///
- public byte BitLength;
+ public byte b;
#region v
///
/// Literal, length base, or distance base
///
- public ushort Base;
+ public ushort n;
///
/// Pointer to next level of table
///
- public HuffmanNode[] NextLevel;
+ public HuffmanNode* t;
#endregion
}
diff --git a/BurnOutSharp.Compression/MSZIP/State.cs b/BurnOutSharp.Compression/MSZIP/State.cs
index 57bcd237..022ba9df 100644
--- a/BurnOutSharp.Compression/MSZIP/State.cs
+++ b/BurnOutSharp.Compression/MSZIP/State.cs
@@ -3,54 +3,54 @@ using static BurnOutSharp.Models.Compression.MSZIP.Constants;
namespace BurnOutSharp.Compression.MSZIP
{
///
- public class State
+ public unsafe class State
{
///
/// Current offset within the window
///
- public uint WindowPosition;
+ public uint window_posn;
///
/// Bit buffer
///
- public uint BitBuffer;
+ public uint bb;
///
/// Bits in bit buffer
///
- public uint BitCount;
+ public uint bk;
///
/// Literal/length and distance code lengths
///
- public uint[] Lengths = new uint[288 + 32];
+ public uint[] ll = new uint[288 + 32];
///
/// Bit length count table
///
- public uint[] Counts = new uint[ZIPBMAX + 1];
+ public uint[] c = new uint[ZIPBMAX + 1];
///
/// Memory for l[-1..ZIPBMAX-1]
///
- public int[] LengthMemory = new int[ZIPBMAX + 1];
+ public int[] lx = new int[ZIPBMAX + 1];
///
/// Table stack
///
- public HuffmanNode[] TableStack = new HuffmanNode[ZIPBMAX];
+ public HuffmanNode*[] u = new HuffmanNode*[ZIPBMAX];
///
/// Values in order of bit length
///
- public uint[] Values = new uint[ZIPN_MAX];
+ public uint[] v = new uint[ZIPN_MAX];
///
/// Bit offsets, then code stack
///
- public uint[] BitOffsets = new uint[ZIPBMAX + 1];
+ public uint[] x = new uint[ZIPBMAX + 1];
/// byte*
- public int InputPosition;
+ public byte* inpos;
}
}
\ No newline at end of file
diff --git a/BurnOutSharp.Wrappers/MicrosoftCabinet.cs b/BurnOutSharp.Wrappers/MicrosoftCabinet.cs
index 84630cb9..347b1126 100644
--- a/BurnOutSharp.Wrappers/MicrosoftCabinet.cs
+++ b/BurnOutSharp.Wrappers/MicrosoftCabinet.cs
@@ -218,11 +218,9 @@ namespace BurnOutSharp.Wrappers
// Setup LZX decompression
var lzx = new Compression.LZX.State();
Compression.LZX.Decompressor.Init(((ushort)folder.CompressionType >> 8) & 0x1f, lzx);
- // TODO: Use this area for LZX
// Setup MS-ZIP decompression
- Compression.MSZIP_zlib mszip = new Compression.MSZIP_zlib();
- bool hasLastBlock = false;
+ Compression.MSZIP.State mszip = new Compression.MSZIP.State();
// Setup Quantum decompression
var qtm = new Compression.Quantum.State();
@@ -238,7 +236,7 @@ namespace BurnOutSharp.Wrappers
decompressed = dataBlock.CompressedData;
break;
case Models.MicrosoftCabinet.CompressionType.TYPE_MSZIP:
- decompressed = mszip.DecompressMSZIPData(dataBlock.CompressedData, hasLastBlock);
+ Compression.MSZIP.Decompressor.Decompress(mszip, dataBlock.CompressedSize, dataBlock.CompressedData, dataBlock.UncompressedSize, decompressed);
break;
case Models.MicrosoftCabinet.CompressionType.TYPE_QUANTUM:
Compression.Quantum.Decompressor.Decompress(qtm, dataBlock.CompressedSize, dataBlock.CompressedData, dataBlock.UncompressedSize, decompressed);
@@ -250,7 +248,6 @@ namespace BurnOutSharp.Wrappers
return null;
}
- hasLastBlock = true;
data.AddRange(decompressed ?? new byte[0]);
}
diff --git a/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.MSZIP.cs b/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.MSZIP.cs
deleted file mode 100644
index 656ae0de..00000000
--- a/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.MSZIP.cs
+++ /dev/null
@@ -1,444 +0,0 @@
-// using static BurnOutSharp.Wrappers.CabinetConstants;
-// using static BurnOutSharp.Wrappers.FDIcConstants;
-// using static BurnOutSharp.Wrappers.FDIConstants;
-// using static BurnOutSharp.Models.Compression.MSZIP.Constants;
-// using cab_LONG = System.Int32;
-// using cab_off_t = System.UInt32;
-// using cab_UBYTE = System.Byte;
-// using uint = System.UInt32;
-// using cab_UWORD = System.UInt16;
-
-// namespace BurnOutSharp.Wrappers
-// {
-// internal unsafe class MSZIPfdi
-// {
-// ///
-// /// BuildHuffmanTree (internal)
-// ///
-// static cab_LONG BuildHuffmanTree(uint* b, uint n, uint s, cab_UWORD* d, cab_UWORD* e, ref Ziphuft[] t, cab_LONG* m, fdi_decomp_state decomp_state)
-// {
-// uint a; /* counter for codes of length k */
-// uint el; /* length of EOB code (value 256) */
-// uint f; /* i repeats in table every f entries */
-// cab_LONG g; /* maximum code length */
-// cab_LONG h; /* table level */
-// uint i; /* counter, current code */
-// uint j; /* counter */
-// cab_LONG k; /* number of bits in current code */
-// cab_LONG* l; /* stack of bits per table */
-// uint* p; /* pointer into decomp_state.zip.c[],decomp_state.zip.b[],decomp_state.zip.v[] */
-// Ziphuft* q; /* points to current table */
-// Ziphuft r; /* table entry for structure assignment */
-// cab_LONG w; /* bits before this table == (l * h) */
-// uint* xp; /* pointer into x */
-// cab_LONG y; /* number of dummy codes added */
-// uint z; /* number of entries in current table */
-
-// l = decomp_state.zip.lx + 1;
-
-// // Generate counts for each bit length
-// // set length of EOB code, if any
-// el = n > 256 ? b[256] : ZIPBMAX;
-
-// for (i = 0; i < ZIPBMAX + 1; ++i)
-// {
-// decomp_state.zip.c[i] = 0;
-// }
-
-// p = b; i = n;
-
-// // assume all entries <= ZIPBMAX
-// do
-// {
-// decomp_state.zip.c[*p]++; p++;
-// } while (--i != 0);
-
-// // null input--all zero length codes
-// if (decomp_state.zip.c[0] == n)
-// {
-// t = null;
-// *m = 0;
-// return 0;
-// }
-
-// // Find minimum and maximum length, bound *m by those
-// for (j = 1; j <= ZIPBMAX; j++)
-// {
-// if (decomp_state.zip.c[j] != 0)
-// break;
-// }
-
-// // minimum code length
-// k = (int)j;
-// if (*m < j)
-// *m = (int)j;
-
-// for (i = ZIPBMAX; i != 0; i--)
-// {
-// if (decomp_state.zip.c[i] != 0)
-// break;
-// }
-
-// // maximum code length
-// g = (int)i;
-// if (*m > i)
-// *m = (int)i;
-
-// // Adjust last length count to fill out codes, if needed */
-// for (y = 1 << (int)j; j < i; j++, y <<= 1)
-// {
-// // bad input: more codes than bits
-// if ((y -= (int)decomp_state.zip.c[j]) < 0)
-// return 2;
-// }
-
-// if ((y -= (int)decomp_state.zip.c[i]) < 0)
-// return 2;
-
-// decomp_state.zip.c[i] += (uint)y;
-
-// // Generate starting offsets LONGo the value table for each length
-// decomp_state.zip.x[1] = j = 0;
-// p = decomp_state.zip.c + 1; xp = decomp_state.zip.x + 2;
-// while (--i != 0)
-// {
-// // note that i == g from above
-// *xp++ = (j += *p++);
-// }
-
-// /* Make a table of values in order of bit lengths */
-// p = b; i = 0;
-// do
-// {
-// if ((j = *p++) != 0)
-// decomp_state.zip.v[decomp_state.zip.x[j]++] = i;
-// } while (++i < n);
-
-// // Generate the Huffman codes and for each, make the table entries
-// decomp_state.zip.x[0] = i = 0; /* first Huffman code is zero */
-// p = decomp_state.zip.v; /* grab values in bit order */
-// h = -1; /* no tables yet--level -1 */
-// w = l[-1] = 0; /* no bits decoded yet */
-// decomp_state.zip.u[0] = null; /* just to keep compilers happy */
-// q = null; /* ditto */
-// z = 0; /* ditto */
-
-// /* go through the bit lengths (k already is bits in shortest code) */
-// for (; k <= g; k++)
-// {
-// a = decomp_state.zip.c[k];
-// while (a-- != 0)
-// {
-// // here i is the Huffman code of length k bits for value *p
-// // make tables up to required level
-// while (k > w + l[h])
-// {
-// // add bits already decoded
-// w += l[h++];
-
-// // compute minimum size table less than or equal to *m bits
-// if ((z = (uint)(g - w)) > *m) /* upper limit */
-// z = (uint)*m;
-
-// // try a k-w bit table
-// if ((f = (uint)(1 << (int)(j = (uint)(k - w)))) > a + 1)
-// { /* too few codes for k-w bit table */
-// f -= a + 1; /* deduct codes from patterns left */
-// xp = decomp_state.zip.c + k;
-// while (++j < z) /* try smaller tables up to z bits */
-// {
-// if ((f <<= 1) <= *++xp)
-// break; /* enough codes to use up j bits */
-// f -= *xp; /* else deduct codes from patterns */
-// }
-// }
-
-// if ((uint)w + j > el && (uint)w < el)
-// j = el - w; /* make EOB code end at table */
-
-// z = 1 << j; /* table entries for j-bit table */
-// l[h] = j; /* set table size in stack */
-
-// /* allocate and link in new table */
-// if (!(q = decomp_state.fdi.alloc((z + 1) * sizeof(Ziphuft))))
-// {
-// if (h)
-// Free(decomp_state.fdi, decomp_state.zip.u[0]);
-// return 3; /* not enough memory */
-// }
-
-// *t = q + 1; /* link to list for Ziphuft_free() */
-// *(t = &(q.v.t)) = null;
-// decomp_state.zip.u[h] = ++q; /* table starts after link */
-
-// // connect to last table, if there is one
-// if (h != 0)
-// {
-// decomp_state.zip.x[h] = i; /* save pattern for backing up */
-// r.b = (cab_UBYTE)l[h - 1]; /* bits to dump before this table */
-// r.e = (cab_UBYTE)(16 + j); /* bits in this table */
-// r.t = q; /* pointer to this table */
-// j = (i & ((1 << w) - 1)) >> (w - l[h - 1]);
-// decomp_state.zip.u[h - 1][j] = r; /* connect to last table */
-// }
-// }
-
-// /* set up table entry in r */
-// r.b = (cab_UBYTE)(k - w);
-// if (p >= decomp_state.zip.v + n)
-// {
-// r.e = 99; /* out of values--invalid code */
-// }
-// else if (*p < s)
-// {
-// r.e = (cab_UBYTE)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */
-// r.n = *p++; /* simple code is just the value */
-// }
-// else
-// {
-// r.e = (cab_UBYTE)e[*p - s]; /* non-simple--look up in lists */
-// r.n = d[*p++ - s];
-// }
-
-// /* fill code-like entries with r */
-// f = 1 << (k - w);
-// for (j = i >> w; j < z; j += f)
-// q[j] = r;
-
-// /* backwards increment the k-bit code i */
-// for (j = 1 << (k - 1); i & j; j >>= 1)
-// i ^= j;
-// i ^= j;
-
-// /* backup over finished tables */
-// while ((i & ((1 << w) - 1)) != decomp_state.zip.x[h])
-// w -= l[--h]; /* don't need to update q */
-// }
-// }
-
-// /* return actual size of base table */
-// *m = l[0];
-
-// /* Return true (1) if we were given an incomplete table */
-// return y != 0 && g != 1;
-// }
-
-// ///
-// /// fdi_Zipinflate_codes (internal)
-// ///
-// static cab_LONG fdi_Zipinflate_codes(in Ziphuft tl, in Ziphuft td, cab_LONG bl, cab_LONG bd, fdi_decomp_state decomp_state)
-// {
-// uint e; /* table entry flag/number of extra bits */
-// uint n, d; /* length and index for copy */
-// uint w; /* current window position */
-// Ziphuft t; /* pointer to table entry */
-// uint ml, md; /* masks for bl and bd bits */
-// uint b; /* bit buffer */
-// uint k; /* number of bits in bit buffer */
-
-// /* make local copies of globals */
-// b = decomp_state.zip.bb; /* initialize bit buffer */
-// k = decomp_state.zip.bk;
-// w = decomp_state.zip.window_posn; /* initialize window position */
-
-// /* inflate the coded data */
-// ml = BitMasks[bl]; /* precompute masks for speed */
-// md = BitMasks[bd];
-
-// for (; ; )
-// {
-// ZIPNEEDBITS((uint)bl)
-// if ((e = (t = tl + (b & ml)).e) > 16)
-// do
-// {
-// if (e == 99)
-// return 1;
-// ZIPDUMPBITS(t.b)
-// e -= 16;
-// ZIPNEEDBITS(e)
-// } while ((e = (t = t.v.t + (b & BitMasks[e])).e) > 16);
-// ZIPDUMPBITS(t.b)
-// if (e == 16) /* then it's a literal */
-// decomp_state.outbuf[w++] = (cab_UBYTE)t.v.n;
-// else /* it's an EOB or a length */
-// {
-// /* exit if end of block */
-// if (e == 15)
-// break;
-
-// /* get length of block to copy */
-// ZIPNEEDBITS(e)
-// n = t.v.n + (b & BitMasks[e]);
-// ZIPDUMPBITS(e);
-
-// /* decode distance of block to copy */
-// ZIPNEEDBITS((uint)bd)
-// if ((e = (t = td + (b & md)).e) > 16)
-// do
-// {
-// if (e == 99)
-// return 1;
-// ZIPDUMPBITS(t.b)
-// e -= 16;
-// ZIPNEEDBITS(e)
-// } while ((e = (t = t.v.t + (b & BitMasks[e])).e) > 16);
-// ZIPDUMPBITS(t.b)
-// ZIPNEEDBITS(e)
-// d = w - t.v.n - (b & BitMasks[e]);
-// ZIPDUMPBITS(e)
-// do
-// {
-// d &= ZIPWSIZE - 1;
-// e = ZIPWSIZE - max(d, w);
-// e = min(e, n);
-// n -= e;
-// do
-// {
-// decomp_state.outbuf[w++] = decomp_state.outbuf[d++];
-// } while (--e);
-// } while (n);
-// }
-// }
-
-// /* restore the globals from the locals */
-// decomp_state.zip.window_posn = w; /* restore global window pointer */
-// decomp_state.zip.bb = b; /* restore global bit buffer */
-// decomp_state.zip.bk = k;
-
-// /* done */
-// return 0;
-// }
-
-// ///
-// /// fdi_Zipinflate_dynamic (internal)
-// ///
-// /// decompress an inflated type 2 (dynamic Huffman codes) block.
-// ///
-// static cab_LONG fdi_Zipinflate_dynamic(fdi_decomp_state decomp_state)
-// {
-// cab_LONG i; /* temporary variables */
-// uint j;
-// uint l; /* last length */
-// uint m; /* mask for bit lengths table */
-// uint n; /* number of lengths to get */
-// Ziphuft tl; /* literal/length code table */
-// Ziphuft td; /* distance code table */
-// cab_LONG bl; /* lookup bits for tl */
-// cab_LONG bd; /* lookup bits for td */
-// uint nb; /* number of bit length codes */
-// uint nl; /* number of literal/length codes */
-// uint nd; /* number of distance codes */
-// uint bitBuffer; /* bit buffer */
-// uint bitCount; /* number of bits in bit buffer */
-
-// /* make local bit buffer */
-// bitBuffer = decomp_state.zip.bb;
-// bitCount = decomp_state.zip.bk;
-
-// /* read in table lengths */
-// ZIPNEEDBITS(5)
-// nl = 257 + (bitBuffer & 0x1f); /* number of literal/length codes */
-// ZIPDUMPBITS(5)
-// ZIPNEEDBITS(5)
-// nd = 1 + (bitBuffer & 0x1f); /* number of distance codes */
-// ZIPDUMPBITS(5)
-// ZIPNEEDBITS(4)
-// nb = 4 + (bitBuffer & 0xf); /* number of bit length codes */
-// ZIPDUMPBITS(4)
-// if (nl > 288 || nd > 32)
-// return 1; /* bad lengths */
-
-// /* read in bit-length-code lengths */
-// for (j = 0; j < nb; j++)
-// {
-// ZIPNEEDBITS(3)
-// state.Lengths[BitLengthOrder[j]] = bitBuffer & 7;
-// ZIPDUMPBITS(3)
-// }
-// for (; j < 19; j++)
-// state.Lengths[BitLengthOrder[j]] = 0;
-
-// /* build decoding table for trees--single level, 7 bit lookup */
-// bl = 7;
-// if ((i = BuildHuffmanTree(state.Lengths, 19, 19, null, null, &tl, &bl, decomp_state)) != 0)
-// {
-// if (i == 1)
-// Free(decomp_state.fdi, tl);
-// return i; /* incomplete code set */
-// }
-
-// /* read in literal and distance code lengths */
-// n = nl + nd;
-// m = BitMasks[bl];
-// i = l = 0;
-// while ((uint)i < n)
-// {
-// ZIPNEEDBITS((uint)bl)
-// j = (td = tl + (bitBuffer & m)).b;
-// ZIPDUMPBITS(j)
-// j = td.v.n;
-// if (j < 16) /* length of code in bits (0..15) */
-// state.Lengths[i++] = l = j; /* save last length in l */
-// else if (j == 16) /* repeat last length 3 to 6 times */
-// {
-// ZIPNEEDBITS(2)
-// j = 3 + (bitBuffer & 3);
-// ZIPDUMPBITS(2)
-// if ((uint)i + j > n)
-// return 1;
-// while (j--)
-// state.Lengths[i++] = l;
-// }
-// else if (j == 17) /* 3 to 10 zero length codes */
-// {
-// ZIPNEEDBITS(3)
-// j = 3 + (bitBuffer & 7);
-// ZIPDUMPBITS(3)
-// if ((uint)i + j > n)
-// return 1;
-// while (j--)
-// state.Lengths[i++] = 0;
-// l = 0;
-// }
-// else /* j == 18: 11 to 138 zero length codes */
-// {
-// ZIPNEEDBITS(7)
-// j = 11 + (bitBuffer & 0x7f);
-// ZIPDUMPBITS(7)
-// if ((uint)i + j > n)
-// return 1;
-// while (j--)
-// state.Lengths[i++] = 0;
-// l = 0;
-// }
-// }
-
-// /* free decoding table for trees */
-// Free(decomp_state.fdi, tl);
-
-// /* restore the global bit buffer */
-// decomp_state.zip.bb = bitBuffer;
-// decomp_state.zip.bk = bitCount;
-
-// /* build the decoding tables for literal/length and distance codes */
-// bl = ZIPLBITS;
-// if ((i = BuildHuffmanTree(state.Lengths, nl, 257, CopyLengths, LiteralExtraBits, &tl, &bl, decomp_state)) != 0)
-// {
-// if (i == 1)
-// Free(decomp_state.fdi, tl);
-// return i; /* incomplete code set */
-// }
-// bd = ZIPDBITS;
-// BuildHuffmanTree(state.Lengths + nl, nd, 0, CopyOffsets, DistanceExtraBits, &td, &bd, decomp_state);
-
-// /* decompress until an end-of-block code */
-// if (fdi_Zipinflate_codes(tl, td, bl, bd, decomp_state))
-// return 1;
-
-// /* free the decoding tables, return */
-// Free(decomp_state.fdi, tl);
-// Free(decomp_state.fdi, td);
-// return 0;
-// }
-// }
-// }
\ No newline at end of file
diff --git a/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.cs b/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.cs
deleted file mode 100644
index 1c57ad2d..00000000
--- a/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.cs
+++ /dev/null
@@ -1,1561 +0,0 @@
-// using System;
-// using System.Collections.Generic;
-// using System.IO;
-// using System.Linq;
-// using BurnOutSharp.Compression;
-// using BurnOutSharp.Compression.MSZIP;
-// using static BurnOutSharp.Wrappers.CabinetConstants;
-// using static BurnOutSharp.Wrappers.FDIcConstants;
-// using static BurnOutSharp.Wrappers.FDIConstants;
-
-// namespace BurnOutSharp.Wrappers
-// {
-// public partial class MicrosoftCabinet
-// {
-// // TEMP AREA TO MAKE BUILDS WORK
-
-// private static void SetLastError(int error) { }
-// private class HFDI : FDI_Int { }
-// private const int ERROR_INVALID_HANDLE = 0;
-// private const int FDIERROR_NONE = 0;
-// private const int ERROR_BAD_ARGUMENTS = 0;
-// private const int FDIERROR_ALLOC_FAIL = 0;
-// private static void ERR(object o) { }
-
-// // END TEMP AREA
-
-// static void set_error(FDI_Int fdi, int oper, int err)
-// {
-// fdi.perf.erfOper = oper;
-// fdi.perf.erfType = err;
-// fdi.perf.fError = true;
-// if (err != 0) SetLastError(err);
-// }
-
-// static FDI_Int get_fdi_ptr(HFDI hfdi)
-// {
-// FDI_Int fdi = hfdi as FDI_Int;
-
-// if (fdi == null || fdi.magic != FDI_INT_MAGIC)
-// {
-// SetLastError(ERROR_INVALID_HANDLE);
-// return null;
-// }
-// return fdi;
-// }
-
-// /*************************************************************************
-// * make_decode_table (internal)
-// *
-// * This function was coded by David Tritscher. It builds a fast huffman
-// * decoding table out of just a canonical huffman code lengths table.
-// *
-// * PARAMS
-// * nsyms: total number of symbols in this huffman tree.
-// * nbits: any symbols with a code length of nbits or less can be decoded
-// * in one lookup of the table.
-// * length: A table to get code lengths from [0 to syms-1]
-// * table: The table to fill up with decoded symbols and pointers.
-// *
-// * RETURNS
-// * OK: 0
-// * error: 1
-// */
-// 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;
-// }
-
-// /*************************************************************************
-// * checksum (internal)
-// */
-// static uint checksum(byte[] data, ushort bytes, uint csum)
-// {
-// int dataPtr = 0; // TODO: Confirm that it's always starting at the beginning of data
-
-// int len;
-// uint ul = 0;
-
-// for (len = bytes >> 2; len-- > 0; dataPtr += 4)
-// {
-// csum ^= (uint)((data[dataPtr + 0]) | (data[dataPtr + 1] << 8) | (data[dataPtr + 2] << 16) | (data[dataPtr + 3] << 24));
-// }
-
-// switch (bytes & 3)
-// {
-// case 3: ul |= (uint)(data[dataPtr++] << 16); goto case 2;
-// /* fall through */
-// case 2: ul |= (uint)(data[dataPtr++] << 8); goto case 1;
-// /* fall through */
-// case 1: ul |= data[dataPtr]; break;
-// }
-// csum ^= ul;
-
-// return csum;
-// }
-
-// /***********************************************************************
-// * FDICreate (CABINET.20)
-// *
-// * Provided with several callbacks (all of them are mandatory),
-// * returns a handle which can be used to perform operations
-// * on cabinet files.
-// *
-// * PARAMS
-// * pfnalloc [I] A pointer to a function which allocates ram. Uses
-// * the same interface as malloc.
-// * pfnfree [I] A pointer to a function which frees ram. Uses the
-// * same interface as free.
-// * pfnopen [I] A pointer to a function which opens a file. Uses
-// * the same interface as _open.
-// * pfnread [I] A pointer to a function which reads from a file into
-// * a caller-provided buffer. Uses the same interface
-// * as _read
-// * pfnwrite [I] A pointer to a function which writes to a file from
-// * a caller-provided buffer. Uses the same interface
-// * as _write.
-// * pfnclose [I] A pointer to a function which closes a file handle.
-// * Uses the same interface as _close.
-// * pfnseek [I] A pointer to a function which seeks in a file.
-// * Uses the same interface as _lseek.
-// * cpuType [I] The type of CPU; ignored in wine (recommended value:
-// * cpuUNKNOWN, aka -1).
-// * perf [IO] A pointer to an ERF structure. When FDICreate
-// * returns an error condition, error information may
-// * be found here as well as from GetLastError.
-// *
-// * RETURNS
-// * On success, returns an FDI handle of type HFDI.
-// * On failure, the null file handle is returned. Error
-// * info can be retrieved from perf.
-// *
-// * INCLUDES
-// * fdi.h
-// *
-// */
-// HFDI FDICreate(
-// Action pfnalloc,
-// Action