diff --git a/libmspack/CAB/Decompressor.cs b/libmspack/CAB/Decompressor.cs
index 8d32ee6..5a506e6 100644
--- a/libmspack/CAB/Decompressor.cs
+++ b/libmspack/CAB/Decompressor.cs
@@ -10,7 +10,7 @@ namespace SabreTools.Compression.libmspack.CAB
///
public unsafe class Decompressor : BaseDecompressor
{
- public mscabd_decompress_state d { get; private set; }
+ public mscabd_decompress_state d { get; set; }
public int buf_size { get; private set; }
@@ -1092,13 +1092,8 @@ namespace SabreTools.Compression.libmspack.CAB
// Allocate generic decompression state
if (this.d == null)
{
- this.d = new mscabd_decompress_state();
- this.d.folder = null;
- this.d.data = null;
+ this.d = new None.DecompressState();
this.d.sys = sys as CABSystem;
- this.d.state = null;
- this.d.infh = null;
- this.d.incab = null;
}
// Do we need to change folder or reset the current folder?
diff --git a/libmspack/kwaj.cs b/libmspack/KWAJ/Constants.cs
similarity index 94%
rename from libmspack/kwaj.cs
rename to libmspack/KWAJ/Constants.cs
index 39c4657..0dd210e 100644
--- a/libmspack/kwaj.cs
+++ b/libmspack/KWAJ/Constants.cs
@@ -1,6 +1,6 @@
-namespace SabreTools.Compression.libmspack
+namespace SabreTools.Compression.libmspack.KWAJ
{
- public static class kwaj
+ public static class Constants
{
public const byte kwajh_Signature1 = 0x00;
public const byte kwajh_Signature2 = 0x04;
diff --git a/libmspack/KWAJ/Decompressor.cs b/libmspack/KWAJ/Decompressor.cs
index 897fd59..7142daa 100644
--- a/libmspack/KWAJ/Decompressor.cs
+++ b/libmspack/KWAJ/Decompressor.cs
@@ -1,5 +1,4 @@
using System;
-using static SabreTools.Compression.libmspack.kwaj;
namespace SabreTools.Compression.libmspack.KWAJ
{
@@ -45,8 +44,8 @@ namespace SabreTools.Compression.libmspack.KWAJ
/// passed directly to mspack_system::open().
///
/// A pointer to a mskwajd_header structure, or null on failure
- ///
- public mskwajd_header open(in string filename)
+ ///
+ public mskwajd_header Open(in string filename)
{
mspack_system sys = this.system;
@@ -63,7 +62,7 @@ namespace SabreTools.Compression.libmspack.KWAJ
MSPACK_ERR err;
if ((err = ReadHeaders(sys, fh, hdr)) != MSPACK_ERR.MSPACK_ERR_OK)
{
- close(hdr);
+ Close(hdr);
this.error = err;
return null;
}
@@ -79,8 +78,8 @@ namespace SabreTools.Compression.libmspack.KWAJ
/// used again.
///
/// The KWAJ file to close
- ///
- public void close(mskwajd_header kwaj)
+ ///
+ public void Close(mskwajd_header kwaj)
{
if (this.system == null)
return;
@@ -150,7 +149,7 @@ namespace SabreTools.Compression.libmspack.KWAJ
if (sys.read(fh, &buf[0], 2) != 2)
return MSPACK_ERR.MSPACK_ERR_READ;
i = BitConverter.ToUInt16(buf, 0);
- if (sys.seek(fh, i, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_CUR))
+ if (sys.seek(fh, i, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_CUR) != 0)
return MSPACK_ERR.MSPACK_ERR_SEEK;
}
@@ -160,8 +159,8 @@ namespace SabreTools.Compression.libmspack.KWAJ
int len;
// Allocate memory for maximum length filename
- char* fn = (char*)sys.alloc(sys, 13);
- if (!(hdr.filename = fn))
+ char* fn = (char*)sys.alloc(13);
+ if ((hdr.extra = fn) == null)
return MSPACK_ERR.MSPACK_ERR_NOMEMORY;
// Copy filename if present
@@ -170,8 +169,9 @@ namespace SabreTools.Compression.libmspack.KWAJ
// Read and copy up to 9 bytes of a null terminated string
if ((len = sys.read(fh, &buf[0], 9)) < 2)
return MSPACK_ERR.MSPACK_ERR_READ;
+
for (i = 0; i < len; i++)
- if (!(*fn++ = buf[i]))
+ if ((*fn++ = (char)buf[i]) == '\0')
break;
// If string was 9 bytes with no null terminator, reject it
@@ -179,7 +179,7 @@ namespace SabreTools.Compression.libmspack.KWAJ
return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
// Seek to byte after string ended in file
- if (sys.seek(fh, i + 1 - len, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_CUR))
+ if (sys.seek(fh, i + 1 - len, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_CUR) != 0)
return MSPACK_ERR.MSPACK_ERR_SEEK;
fn--; // Remove the null terminator
@@ -195,7 +195,7 @@ namespace SabreTools.Compression.libmspack.KWAJ
return MSPACK_ERR.MSPACK_ERR_READ;
for (i = 0; i < len; i++)
- if (!(*fn++ = buf[i]))
+ if ((*fn++ = (char)buf[i]) == '\0')
break;
// If string was 4 bytes with no null terminator, reject it
@@ -203,7 +203,7 @@ namespace SabreTools.Compression.libmspack.KWAJ
return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
// Seek to byte after string ended in file
- if (sys.seek(fh, i + 1 - len, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_CUR))
+ if (sys.seek(fh, i + 1 - len, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_CUR) != 0)
return MSPACK_ERR.MSPACK_ERR_SEEK;
fn--; // Remove the null terminator
@@ -218,15 +218,15 @@ namespace SabreTools.Compression.libmspack.KWAJ
return MSPACK_ERR.MSPACK_ERR_READ;
i = BitConverter.ToUInt16(&buf[0]);
- hdr.extra = (char*)sys.alloc(sys, i + 1);
- if (!hdr.extra)
+ hdr.extra = (char*)sys.alloc(i + 1);
+ if (hdr.extra == null)
return MSPACK_ERR.MSPACK_ERR_NOMEMORY;
if (sys.read(fh, hdr.extra, i) != i)
return MSPACK_ERR.MSPACK_ERR_READ;
hdr.extra[i] = '\0';
- hdr.extra_length = i;
+ hdr.extra_length = (ushort)i;
}
return MSPACK_ERR.MSPACK_ERR_OK;
@@ -244,7 +244,88 @@ namespace SabreTools.Compression.libmspack.KWAJ
/// is passed directly to mspack_system::open().
///
/// An error code, or MSPACK_ERR_OK if successful
- public MSPACK_ERR extract(mskwajd_header kwaj, in string filename) => throw new NotImplementedException();
+ public MSPACK_ERR Extract(mskwajd_header kwaj, in string filename)
+ {
+ if (kwaj == null)
+ return this.error = MSPACK_ERR.MSPACK_ERR_ARGS;
+
+ mspack_system sys = this.system;
+ mspack_file fh = kwaj.fh;
+
+ // Seek to the compressed data
+ if (sys.seek(fh, kwaj.data_offset, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_START) != 0)
+ {
+ return this.error = MSPACK_ERR.MSPACK_ERR_SEEK;
+ }
+
+ // Open file for output
+ mspack_file outfh;
+ if ((outfh = sys.open(filename, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_WRITE)) == null)
+ {
+ return this.error = MSPACK_ERR.MSPACK_ERR_OPEN;
+ }
+
+ this.error = MSPACK_ERR.MSPACK_ERR_OK;
+
+ // Decompress based on format
+ if (kwaj.comp_type == MSKWAJ_COMP.MSKWAJ_COMP_NONE || kwaj.comp_type == MSKWAJ_COMP.MSKWAJ_COMP_XOR)
+ {
+ // NONE is a straight copy. XOR is a copy xored with 0xFF
+ byte* buf = (byte*)sys.alloc(KWAJ_INPUT_SIZE);
+ if (buf != null)
+ {
+ int read, i;
+ while ((read = sys.read(fh, buf, KWAJ_INPUT_SIZE)) > 0)
+ {
+ if (kwaj.comp_type == MSKWAJ_COMP.MSKWAJ_COMP_XOR)
+ {
+ for (i = 0; i < read; i++)
+ buf[i] ^= 0xFF;
+ }
+
+ if (sys.write(outfh, buf, read) != read)
+ {
+ this.error = MSPACK_ERR.MSPACK_ERR_WRITE;
+ break;
+ }
+ }
+
+ if (read < 0)
+ this.error = MSPACK_ERR.MSPACK_ERR_READ;
+
+ sys.free(buf);
+ }
+ else
+ {
+ this.error = MSPACK_ERR.MSPACK_ERR_NOMEMORY;
+ }
+ }
+ else if (kwaj.comp_type == MSKWAJ_COMP.MSKWAJ_COMP_SZDD)
+ {
+ this.error = lzss_decompress(sys, fh, outfh, KWAJ_INPUT_SIZE, LZSS_MODE.LZSS_MODE_QBASIC);
+ }
+ else if (kwaj.comp_type == MSKWAJ_COMP.MSKWAJ_COMP_LZH)
+ {
+ kwajd_stream lzh = lzh_init(sys, fh, outfh);
+ this.error = (lzh != null) ? lzh_decompress(lzh) : MSPACK_ERR.MSPACK_ERR_NOMEMORY;
+ lzh_free(lzh);
+ }
+ else if (kwaj.comp_type == MSKWAJ_COMP.MSKWAJ_COMP_MSZIP)
+ {
+ mszipd_stream zip = mszipd_init(sys, fh, outfh, KWAJ_INPUT_SIZE, 0);
+ this.error = (zip != null) ? mszipd_decompress_kwaj(zip) : MSPACK_ERR.MSPACK_ERR_NOMEMORY;
+ mszipd_free(zip);
+ }
+ else
+ {
+ this.error = MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
+ }
+
+ // Close output file
+ sys.close(outfh);
+
+ return this.error;
+ }
///
/// Decompresses an KWAJ file to an output file in one step.
@@ -264,7 +345,16 @@ namespace SabreTools.Compression.libmspack.KWAJ
/// is passed directly to mspack_system::open().
///
/// An error code, or MSPACK_ERR_OK if successful
- public MSPACK_ERR decompress(in string input, in string output) => throw new NotImplementedException();
+ public MSPACK_ERR Decompress(in string input, in string output)
+ {
+ mskwajd_header hdr;
+ if ((hdr = Open(input)) == null)
+ return this.error;
+
+ MSPACK_ERR error = Extract(hdr, output);
+ Close(hdr);
+ return this.error = error;
+ }
///
/// Returns the error code set by the most recently called method.
@@ -273,8 +363,11 @@ namespace SabreTools.Compression.libmspack.KWAJ
/// error code directly.
///
/// The most recent error code
- ///
+ ///
///
- public MSPACK_ERR last_error() => throw new NotImplementedException();
+ public MSPACK_ERR LastError()
+ {
+ return this.error;
+ }
}
}
\ No newline at end of file
diff --git a/libmspack/None/DecompressState.cs b/libmspack/None/DecompressState.cs
new file mode 100644
index 0000000..c429a99
--- /dev/null
+++ b/libmspack/None/DecompressState.cs
@@ -0,0 +1,47 @@
+namespace SabreTools.Compression.libmspack.None
+{
+ public unsafe class DecompressState : mscabd_decompress_state
+ {
+ public DecompressState()
+ {
+ this.comp_type = MSCAB_COMP.MSCAB_COMP_NONE;
+ this.state = null;
+ }
+
+ public DecompressState(mscabd_decompress_state oldstate)
+ {
+ this.comp_type = MSCAB_COMP.MSCAB_COMP_NONE;
+ this.state = null;
+ if (oldstate != null)
+ {
+ this.folder = oldstate.folder;
+ this.data = oldstate.data;
+ this.offset = oldstate.offset;
+ this.block = oldstate.block;
+ this.outlen = oldstate.outlen;
+ this.sys = oldstate.sys;
+ this.incab = oldstate.incab;
+ this.infh = oldstate.infh;
+ this.outfh = oldstate.outfh;
+ this.i_ptr = oldstate.i_ptr;
+ this.i_end = oldstate.i_end;
+ this.input = oldstate.input;
+ }
+ }
+
+ ///
+ public override unsafe MSPACK_ERR decompress(object data, long bytes)
+ {
+ State s = data as State;
+ while (bytes > 0)
+ {
+ int run = (bytes > s.BufferSize) ? s.BufferSize : (int)bytes;
+ if (s.InternalSystem.read(s.Input, &s.Buffer[0], run) != run) return MSPACK_ERR.MSPACK_ERR_READ;
+ if (s.InternalSystem.write(s.Output, &s.Buffer[0], run) != run) return MSPACK_ERR.MSPACK_ERR_WRITE;
+ bytes -= run;
+ }
+
+ return MSPACK_ERR.MSPACK_ERR_OK;
+ }
+ }
+}
\ No newline at end of file
diff --git a/libmspack/None/State.cs b/libmspack/None/State.cs
new file mode 100644
index 0000000..5e86557
--- /dev/null
+++ b/libmspack/None/State.cs
@@ -0,0 +1,34 @@
+namespace SabreTools.Compression.libmspack.None
+{
+ ///
+ /// The "not compressed" method decompressor
+ ///
+ public unsafe class State
+ {
+ public mspack_system InternalSystem { get; private set; }
+
+ public mspack_file Input { get; private set; }
+
+ public mspack_file Output { get; private set; }
+
+ public byte* Buffer { get; private set; }
+
+ public int BufferSize { get; private set; }
+
+ public State(mspack_system sys, mspack_file infh, mspack_file outfh, int bufsize)
+ {
+ this.InternalSystem = sys;
+ this.Input = infh;
+ this.Output = outfh;
+ this.Buffer = system.CreateArray(bufsize);
+ this.BufferSize = bufsize;
+ }
+
+ ~State()
+ {
+ mspack_system sys = this.InternalSystem;
+ sys.free(this.Buffer);
+ //sys.free(this);
+ }
+ }
+}
\ No newline at end of file
diff --git a/libmspack/szdd.cs b/libmspack/SZDD/Constants.cs
similarity index 85%
rename from libmspack/szdd.cs
rename to libmspack/SZDD/Constants.cs
index d416f90..5679b8c 100644
--- a/libmspack/szdd.cs
+++ b/libmspack/SZDD/Constants.cs
@@ -7,9 +7,9 @@
* For further details, see the file COPYING.LIB distributed with libmspack
*/
-namespace SabreTools.Compression.libmspack
+namespace SabreTools.Compression.libmspack.SZDD
{
- public static class szdd
+ public static class Constants
{
///
/// Input buffer size during decompression - not worth parameterising IMHO
diff --git a/libmspack/SZDD/Decompressor.cs b/libmspack/SZDD/Decompressor.cs
index 573915b..f323ab9 100644
--- a/libmspack/SZDD/Decompressor.cs
+++ b/libmspack/SZDD/Decompressor.cs
@@ -1,5 +1,5 @@
using System.Linq;
-using static SabreTools.Compression.libmspack.szdd;
+using static SabreTools.Compression.libmspack.SZDD.Constants;
namespace SabreTools.Compression.libmspack.SZDD
{
diff --git a/libmspack/cab.cs b/libmspack/cab.cs
index a41ede1..6a35523 100644
--- a/libmspack/cab.cs
+++ b/libmspack/cab.cs
@@ -19,8 +19,8 @@ namespace SabreTools.Compression.libmspack
switch ((MSCAB_COMP)((int)ct & cffoldCOMPTYPE_MASK))
{
case MSCAB_COMP.MSCAB_COMP_NONE:
- self.d = new mscabd_noned_decompress_state();
- self.d.state = noned_init(self.d.sys, fh, fh, self.buf_size);
+ self.d = new None.DecompressState(self.d);
+ self.d.state = new None.State(self.d.sys, fh, fh, self.buf_size);
break;
case MSCAB_COMP.MSCAB_COMP_MSZIP:
self.d = new mscabd_mszipd_decompress_state();
@@ -51,7 +51,6 @@ namespace SabreTools.Compression.libmspack
switch ((MSCAB_COMP)((int)self.d.comp_type & cffoldCOMPTYPE_MASK))
{
- case MSCAB_COMP.MSCAB_COMP_NONE: noned_free((noned_state)self.d.state); break;
case MSCAB_COMP.MSCAB_COMP_MSZIP: mszipd_free((mszipd_stream)self.d.state); break;
case MSCAB_COMP.MSCAB_COMP_QUANTUM: qtmd_free((qtmd_stream)self.d.state); break;
case MSCAB_COMP.MSCAB_COMP_LZX: lzxd_free((lzxd_stream)self.d.state); break;
@@ -62,32 +61,5 @@ namespace SabreTools.Compression.libmspack
}
#endregion
-
- #region noned_state
-
- public static noned_state noned_init(mspack_system sys, mspack_file @in, mspack_file @out, int bufsize)
- {
- noned_state state = new noned_state();
-
- state.sys = sys;
- state.i = @in;
- state.o = @out;
- state.buf = system.CreateArray(bufsize);
- state.bufsize = bufsize;
- return state;
- }
-
- public static void noned_free(noned_state state)
- {
- mspack_system sys;
- if (state != null)
- {
- sys = state.sys;
- sys.free(state.buf);
- //sys.free(state);
- }
- }
-
- #endregion
}
}
\ No newline at end of file
diff --git a/libmspack/kwajd_stream.cs b/libmspack/kwajd_stream.cs
index 71def9f..8bf8599 100644
--- a/libmspack/kwajd_stream.cs
+++ b/libmspack/kwajd_stream.cs
@@ -1,4 +1,4 @@
-using static SabreTools.Compression.libmspack.kwaj;
+using static SabreTools.Compression.libmspack.KWAJ.Constants;
using static SabreTools.Compression.libmspack.lzss;
namespace SabreTools.Compression.libmspack
diff --git a/libmspack/mscabd_decompress_state.cs b/libmspack/mscabd_decompress_state.cs
index 47badf8..bfc1143 100644
--- a/libmspack/mscabd_decompress_state.cs
+++ b/libmspack/mscabd_decompress_state.cs
@@ -3,7 +3,7 @@ using static SabreTools.Compression.libmspack.CAB.Constants;
namespace SabreTools.Compression.libmspack
{
- public unsafe class mscabd_decompress_state
+ public unsafe abstract class mscabd_decompress_state
{
///
/// Current folder we're extracting from
@@ -40,11 +40,6 @@ namespace SabreTools.Compression.libmspack
///
public MSCAB_COMP comp_type { get; set; }
- ///
- /// Decompressor code
- ///
- public virtual MSPACK_ERR decompress(object data, long offset) => MSPACK_ERR.MSPACK_ERR_NOMEMORY;
-
///
/// Decompressor state
///
@@ -79,26 +74,10 @@ namespace SabreTools.Compression.libmspack
/// One input block of data
///
public byte[] input { get; set; } = new byte[CAB_INPUTBUF];
- }
- public unsafe class mscabd_noned_decompress_state : mscabd_decompress_state
- {
- ///
- public override unsafe MSPACK_ERR decompress(object data, long bytes)
- {
- noned_state s = data as noned_state;
- while (bytes > 0)
- {
- int run = (bytes > s.bufsize) ? s.bufsize : (int)bytes;
- {
- if (s.sys.read(s.i, &s.buf[0], run) != run) return MSPACK_ERR.MSPACK_ERR_READ;
- if (s.sys.write(s.o, &s.buf[0], run) != run) return MSPACK_ERR.MSPACK_ERR_WRITE;
- bytes -= run;
- }
- return MSPACK_ERR.MSPACK_ERR_OK;
- }
-
- return MSPACK_ERR.MSPACK_ERR_DECRUNCH;
- }
+ ///
+ /// Decompressor code
+ ///
+ public abstract MSPACK_ERR decompress(object data, long offset);
}
}
\ No newline at end of file
diff --git a/libmspack/mskwajd_header.cs b/libmspack/mskwajd_header.cs
index 0740d3b..f87ffdf 100644
--- a/libmspack/mskwajd_header.cs
+++ b/libmspack/mskwajd_header.cs
@@ -5,7 +5,7 @@ namespace SabreTools.Compression.libmspack
///
/// All fields are READ ONLY.
///
- public class mskwajd_header
+ public unsafe class mskwajd_header
{
///
/// The compression type
@@ -30,13 +30,13 @@ namespace SabreTools.Compression.libmspack
///
/// Output filename, or null if not present
///
- public string filename { get; set; }
+ public char* filename { get; set; }
///
/// Extra uncompressed data (usually text) in the header.
/// This data can contain nulls so use extra_length to get the size.
///
- public string extra { get; set; }
+ public char* extra { get; set; }
///
/// Length of extra uncompressed data in the header
diff --git a/libmspack/noned_state.cs b/libmspack/noned_state.cs
deleted file mode 100644
index d946d7c..0000000
--- a/libmspack/noned_state.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- ///
- /// The "not compressed" method decompressor
- ///
- public unsafe class noned_state
- {
- public mspack_system sys { get; set; }
-
- public mspack_file i { get; set; }
-
- public mspack_file o { get; set; }
-
- public byte* buf { get; set; }
-
- public int bufsize { get; set; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/readhuff.cs b/libmspack/readhuff.cs
index 7d44321..fb2d027 100644
--- a/libmspack/readhuff.cs
+++ b/libmspack/readhuff.cs
@@ -1,7 +1,206 @@
namespace SabreTools.Compression.libmspack
{
- public unsafe abstract class readhuff
+ public unsafe static class readhuff
{
public const int HUFF_MAXBITS = 16;
+
+ #region MSB
+
+ ///
+ /// This function was originally coded by David Tritscher.
+ /// It builds a fast huffman decoding table from
+ /// 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 nsyms-1]
+ ///
+ /// The table to fill up with decoded symbols and pointers.
+ /// Should be ((1<
+ /// Returns 0 for OK or 1 for error
+ public static int make_decode_table_MSB(uint nsyms, uint nbits, byte* length, ushort* table)
+ {
+ ushort sym, next_symbol;
+ uint leaf, fill;
+ byte bit_num;
+ 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
+
+ // Fill entries for codes short enough for a direct mapping
+ for (bit_num = 1; bit_num <= nbits; bit_num++)
+ {
+ for (sym = 0; sym < nsyms; sym++)
+ {
+ if (length[sym] != bit_num) continue;
+ leaf = pos;
+
+ if ((pos += bit_mask) > table_mask) return 1; // Table overrun
+
+ // Fill all possible lookups of this symbol with the symbol itself
+ for (fill = bit_mask; fill-- > 0;) table[leaf++] = sym;
+ }
+ bit_mask >>= 1;
+ }
+
+ // Exit with success if table is now complete
+ if (pos == table_mask) return 0;
+
+ // Mark all remaining table entries as unused
+ for (sym = (ushort)pos; sym < table_mask; sym++)
+ {
+ table[sym] = 0xFFFF;
+ }
+
+ // next_symbol = base of allocation for long codes
+ next_symbol = (ushort)(((table_mask >> 1) < nsyms) ? nsyms : (table_mask >> 1));
+
+ // Give ourselves room for codes to grow by up to 16 more bits.
+ // codes now start at bit nbits+16 and end at (nbits+16-codelength)
+ pos <<= 16;
+ table_mask <<= 16;
+ bit_mask = 1 << 15;
+
+ for (bit_num = (byte)(nbits + 1); bit_num <= HUFF_MAXBITS; bit_num++)
+ {
+ for (sym = 0; sym < nsyms; sym++)
+ {
+ if (length[sym] != bit_num) continue;
+ if (pos >= table_mask) return 1; // Table overflow
+
+ 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] == 0xFFFF)
+ {
+ table[(next_symbol << 1)] = 0xFFFF;
+ table[(next_symbol << 1) + 1] = 0xFFFF;
+ table[leaf] = 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;
+ pos += bit_mask;
+ }
+ bit_mask >>= 1;
+ }
+
+ // Full table?
+ return (pos == table_mask) ? 0 : 1;
+ }
+
+ #endregion
+
+ #region LSB
+
+ ///
+ /// This function was originally coded by David Tritscher.
+ /// It builds a fast huffman decoding table from
+ /// 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 nsyms-1]
+ ///
+ /// The table to fill up with decoded symbols and pointers.
+ /// Should be ((1<
+ /// Returns 0 for OK or 1 for error
+ public static int make_decode_table_LSB(uint nsyms, uint nbits, byte* length, ushort* table)
+ {
+ ushort sym, next_symbol;
+ uint leaf, fill;
+ uint reverse;
+ byte bit_num;
+ 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
+
+ // Fill entries for codes short enough for a direct mapping
+ for (bit_num = 1; bit_num <= nbits; bit_num++)
+ {
+ for (sym = 0; sym < nsyms; sym++)
+ {
+ if (length[sym] != bit_num) continue;
+
+ // Reverse the significant bits
+ fill = length[sym]; reverse = pos >> (int)(nbits - fill); leaf = 0;
+ do { leaf <<= 1; leaf |= reverse & 1; reverse >>= 1; } while (--fill > 0);
+
+ if ((pos += bit_mask) > table_mask) return 1; // Table overrun
+
+ // Fill all possible lookups of this symbol with the symbol itself
+ fill = bit_mask; next_symbol = (ushort)(1 << bit_num);
+ do { table[leaf] = sym; leaf += next_symbol; } while (--fill > 0);
+ }
+ bit_mask >>= 1;
+ }
+
+ // Exit with success if table is now complete
+ if (pos == table_mask) return 0;
+
+ // Mark all remaining table entries as unused
+ for (sym = (ushort)pos; sym < table_mask; sym++)
+ {
+ reverse = sym; leaf = 0; fill = nbits;
+ do { leaf <<= 1; leaf |= reverse & 1; reverse >>= 1; } while (--fill > 0);
+ table[leaf] = 0xFFFF;
+ }
+
+ // next_symbol = base of allocation for long codes
+ next_symbol = (ushort)(((table_mask >> 1) < nsyms) ? nsyms : (table_mask >> 1));
+
+ // Give ourselves room for codes to grow by up to 16 more bits.
+ // codes now start at bit nbits+16 and end at (nbits+16-codelength)
+ pos <<= 16;
+ table_mask <<= 16;
+ bit_mask = 1 << 15;
+
+ for (bit_num = (byte)(nbits + 1); bit_num <= HUFF_MAXBITS; bit_num++)
+ {
+ for (sym = 0; sym < nsyms; sym++)
+ {
+ if (length[sym] != bit_num) continue;
+ if (pos >= table_mask) return 1; // Table overflow
+
+ // leaf = the first nbits of the code, reversed
+ reverse = pos >> 16; leaf = 0; fill = nbits;
+ do { leaf <<= 1; leaf |= reverse & 1; reverse >>= 1; } while (--fill > 0);
+ for (fill = 0; fill < (bit_num - nbits); fill++)
+ {
+ // If this path hasn't been taken yet, 'allocate' two entries
+ if (table[leaf] == 0xFFFF)
+ {
+ table[(next_symbol << 1)] = 0xFFFF;
+ table[(next_symbol << 1) + 1] = 0xFFFF;
+ table[leaf] = 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;
+ pos += bit_mask;
+ }
+ bit_mask >>= 1;
+ }
+
+ // Full table?
+ return (pos == table_mask) ? 0 : 1;
+ }
+
+ #endregion
}
}
\ No newline at end of file