mirror of
https://github.com/SabreTools/SabreTools.Compression.git
synced 2026-09-21 14:24:55 +00:00
Checkpoint (nw)
This commit is contained in:
@@ -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?
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
47
libmspack/None/DecompressState.cs
Normal file
47
libmspack/None/DecompressState.cs
Normal 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
34
libmspack/None/State.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user