Checkpoint (nw)

This commit is contained in:
Matt Nadareski
2023-09-20 10:55:16 -04:00
parent d014d57750
commit 568d6f9e72
13 changed files with 412 additions and 111 deletions

View File

@@ -10,7 +10,7 @@ namespace SabreTools.Compression.libmspack.CAB
/// </summary>
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?

View File

@@ -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;

View File

@@ -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().
/// </param>
/// <returns>A pointer to a mskwajd_header structure, or null on failure</returns>
/// <see cref="close(mskwajd_header)"/>
public mskwajd_header open(in string filename)
/// <see cref="Close(mskwajd_header)"/>
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.
/// </summary>
/// <param name="kwaj">The KWAJ file to close</param>
/// <see cref="open(in string)"/>
public void close(mskwajd_header kwaj)
/// <see cref="Open(in string)"/>
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().
/// </param>
/// <returns>An error code, or MSPACK_ERR_OK if successful</returns>
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;
}
/// <summary>
/// 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().
/// </param>
/// <returns>An error code, or MSPACK_ERR_OK if successful</returns>
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;
}
/// <summary>
/// Returns the error code set by the most recently called method.
@@ -273,8 +363,11 @@ namespace SabreTools.Compression.libmspack.KWAJ
/// error code directly.
/// </summary>
/// <returns>The most recent error code</returns>
/// <see cref="open(in string)"/>
/// <see cref="Open(in string)"/>
/// <see cref="search()"/>
public MSPACK_ERR last_error() => throw new NotImplementedException();
public MSPACK_ERR LastError()
{
return this.error;
}
}
}

View File

@@ -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;
}
}
/// <inheritdoc/>
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;
}
}
}

34
libmspack/None/State.cs Normal file
View File

@@ -0,0 +1,34 @@
namespace SabreTools.Compression.libmspack.None
{
/// <summary>
/// The "not compressed" method decompressor
/// </summary>
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<byte>(bufsize);
this.BufferSize = bufsize;
}
~State()
{
mspack_system sys = this.InternalSystem;
sys.free(this.Buffer);
//sys.free(this);
}
}
}

View File

@@ -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
{
/// <summary>
/// Input buffer size during decompression - not worth parameterising IMHO

View File

@@ -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
{

View File

@@ -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<byte>(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
}
}

View File

@@ -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

View File

@@ -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
{
/// <summary>
/// Current folder we're extracting from
@@ -40,11 +40,6 @@ namespace SabreTools.Compression.libmspack
/// </summary>
public MSCAB_COMP comp_type { get; set; }
/// <summary>
/// Decompressor code
/// </summary>
public virtual MSPACK_ERR decompress(object data, long offset) => MSPACK_ERR.MSPACK_ERR_NOMEMORY;
/// <summary>
/// Decompressor state
/// </summary>
@@ -79,26 +74,10 @@ namespace SabreTools.Compression.libmspack
/// One input block of data
/// </summary>
public byte[] input { get; set; } = new byte[CAB_INPUTBUF];
}
public unsafe class mscabd_noned_decompress_state : mscabd_decompress_state
{
/// <inheritdoc/>
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;
}
/// <summary>
/// Decompressor code
/// </summary>
public abstract MSPACK_ERR decompress(object data, long offset);
}
}

View File

@@ -5,7 +5,7 @@ namespace SabreTools.Compression.libmspack
///
/// All fields are READ ONLY.
/// </summary>
public class mskwajd_header
public unsafe class mskwajd_header
{
/// <summary>
/// The compression type
@@ -30,13 +30,13 @@ namespace SabreTools.Compression.libmspack
/// <summary>
/// Output filename, or null if not present
/// </summary>
public string filename { get; set; }
public char* filename { get; set; }
/// <summary>
/// Extra uncompressed data (usually text) in the header.
/// This data can contain nulls so use extra_length to get the size.
/// </summary>
public string extra { get; set; }
public char* extra { get; set; }
/// <summary>
/// Length of extra uncompressed data in the header

View File

@@ -1,18 +0,0 @@
namespace SabreTools.Compression.libmspack
{
/// <summary>
/// The "not compressed" method decompressor
/// </summary>
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; }
}
}

View File

@@ -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
/// <summary>
/// This function was originally coded by David Tritscher.
/// It builds a fast huffman decoding table from
/// 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 nsyms-1]</param>
/// <param name="table">
/// The table to fill up with decoded symbols and pointers.
/// Should be ((1<<nbits) + (nsyms*2)) in length.
/// </param>
/// <returns>Returns 0 for OK or 1 for error</returns>
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
/// <summary>
/// This function was originally coded by David Tritscher.
/// It builds a fast huffman decoding table from
/// 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 nsyms-1]</param>
/// <param name="table">
/// The table to fill up with decoded symbols and pointers.
/// Should be ((1<<nbits) + (nsyms*2)) in length.
/// </param>
/// <returns>Returns 0 for OK or 1 for error</returns>
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
}
}