mirror of
https://github.com/SabreTools/SabreTools.Compression.git
synced 2026-04-14 10:12:51 +00:00
Checkpoint (nw)
This commit is contained in:
10
libmspack/Compressor.cs
Normal file
10
libmspack/Compressor.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace SabreTools.Compression.libmspack
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all compressor implementations
|
||||
/// </summary>
|
||||
public abstract class Compressor
|
||||
{
|
||||
public mspack_system system { get; set; }
|
||||
}
|
||||
}
|
||||
10
libmspack/Decompressor.cs
Normal file
10
libmspack/Decompressor.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace SabreTools.Compression.libmspack
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all decompressor implementations
|
||||
/// </summary>
|
||||
public abstract class Decompressor
|
||||
{
|
||||
public mspack_system system { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Compression.libmspack
|
||||
{
|
||||
public static class cab
|
||||
public unsafe static class cab
|
||||
{
|
||||
/* structure offsets */
|
||||
public const byte cfhead_Signature = 0x00;
|
||||
@@ -36,13 +38,6 @@ namespace SabreTools.Compression.libmspack
|
||||
|
||||
/* flags */
|
||||
public const ushort cffoldCOMPTYPE_MASK = 0x000f;
|
||||
public const ushort cffoldCOMPTYPE_NONE = 0x0000;
|
||||
public const ushort cffoldCOMPTYPE_MSZIP = 0x0001;
|
||||
public const ushort cffoldCOMPTYPE_QUANTUM = 0x0002;
|
||||
public const ushort cffoldCOMPTYPE_LZX = 0x0003;
|
||||
public const ushort cfheadPREV_CABINET = 0x0001;
|
||||
public const ushort cfheadNEXT_CABINET = 0x0002;
|
||||
public const ushort cfheadRESERVE_PRESENT = 0x0004;
|
||||
public const ushort cffileCONTINUED_FROM_PREV = 0xFFFD;
|
||||
public const ushort cffileCONTINUED_TO_NEXT = 0xFFFE;
|
||||
public const ushort cffileCONTINUED_PREV_AND_NEXT = 0xFFFF;
|
||||
@@ -71,5 +66,91 @@ namespace SabreTools.Compression.libmspack
|
||||
*/
|
||||
public const int CAB_FOLDERMAX = 65535;
|
||||
public const int CAB_LENGTHMAX = CAB_BLOCKMAX * CAB_FOLDERMAX;
|
||||
|
||||
#region decomp
|
||||
|
||||
/// <summary>
|
||||
/// cabd_free_decomp frees decompression state, according to which method
|
||||
/// was used.
|
||||
/// </summary>
|
||||
public static MSPACK_ERR cabd_init_decomp(mscab_decompressor self, MSCAB_COMP ct)
|
||||
{
|
||||
mspack_file fh = self;
|
||||
|
||||
self.d.comp_type = ct;
|
||||
|
||||
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);
|
||||
break;
|
||||
case MSCAB_COMP.MSCAB_COMP_MSZIP:
|
||||
self.d = new mscabd_mszipd_decompress_state();
|
||||
self.d.state = mszipd_init(self.d.sys, fh, fh, self.buf_size, self.fix_mszip);
|
||||
break;
|
||||
case MSCAB_COMP.MSCAB_COMP_QUANTUM:
|
||||
self.d = new mscabd_qtmd_decompress_state();
|
||||
self.d.state = qtmd_init(self.d.sys, fh, fh, ((int)ct >> 8) & 0x1f, self.buf_size);
|
||||
break;
|
||||
case MSCAB_COMP.MSCAB_COMP_LZX:
|
||||
self.d = new mscabd_lzxd_decompress_state();
|
||||
self.d.state = lzxd_init(self.d.sys, fh, fh, ((int)ct >> 8) & 0x1f, 0, self.buf_size, 0, 0);
|
||||
break;
|
||||
default:
|
||||
return self.error = MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
|
||||
}
|
||||
return self.error = (self.d.state != null) ? MSPACK_ERR.MSPACK_ERR_OK : MSPACK_ERR.MSPACK_ERR_NOMEMORY;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// cabd_init_decomp initialises decompression state, according to which
|
||||
/// decompression method was used. relies on self.d.folder being the same
|
||||
/// as when initialised.
|
||||
/// </summary>
|
||||
public static void cabd_free_decomp(mscab_decompressor self)
|
||||
{
|
||||
if (self == null || self.d == null || self.d.state == null) return;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//self.d.decompress = null;
|
||||
self.d.state = null;
|
||||
}
|
||||
|
||||
#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
|
||||
}
|
||||
}
|
||||
@@ -3,28 +3,8 @@ using static SabreTools.Compression.libmspack.lzss;
|
||||
|
||||
namespace SabreTools.Compression.libmspack
|
||||
{
|
||||
public unsafe class kwajd_stream
|
||||
public unsafe class kwajd_stream : readbits
|
||||
{
|
||||
#region I/O buffering
|
||||
|
||||
public mspack_system sys { get; set; }
|
||||
|
||||
public mspack_file input { get; set; }
|
||||
|
||||
public mspack_file output { get; set; }
|
||||
|
||||
public byte* i_ptr { get; set; }
|
||||
|
||||
public byte* i_end { get; set; }
|
||||
|
||||
public uint bit_buffer { get; set; }
|
||||
|
||||
public uint bits_left { get; set; }
|
||||
|
||||
public int input_end { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Huffman code lengths
|
||||
|
||||
public byte[] MATCHLEN1_len { get; set; } = new byte[KWAJ_MATCHLEN1_SYMS];
|
||||
@@ -55,7 +35,7 @@ namespace SabreTools.Compression.libmspack
|
||||
|
||||
#region Input buffer
|
||||
|
||||
public byte[] inbuf { get; set; } = new byte[KWAJ_INPUT_SIZE];
|
||||
public new byte[] inbuf { get; set; } = new byte[KWAJ_INPUT_SIZE];
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -64,5 +44,17 @@ namespace SabreTools.Compression.libmspack
|
||||
public byte[] window { get; set; } = new byte[LZSS_WINDOW_SIZE];
|
||||
|
||||
#endregion
|
||||
|
||||
public override void READ_BYTES()
|
||||
{
|
||||
if (i_ptr >= i_end)
|
||||
{
|
||||
if ((err = lzh_read_input(lzh)))
|
||||
return err;
|
||||
i_ptr = lzh.i_ptr;
|
||||
i_end = lzh.i_end;
|
||||
}
|
||||
INJECT_BITS_MSB(*i_ptr++, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ namespace SabreTools.Compression.libmspack
|
||||
///
|
||||
/// This routine uses system->alloc() to allocate memory. If memory
|
||||
/// allocation fails, or the parameters to this function are invalid,
|
||||
/// NULL is returned.
|
||||
/// null is returned.
|
||||
/// </summary>
|
||||
/// <param name="system">
|
||||
/// An mspack_system structure used to read from
|
||||
@@ -77,7 +77,7 @@ namespace SabreTools.Compression.libmspack
|
||||
/// non-zero for LZX DELTA encoded data.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A pointer to an initialised lzxd_stream structure, or NULL if
|
||||
/// A pointer to an initialised lzxd_stream structure, or null if
|
||||
/// there was not enough memory or parameters to the function were wrong.
|
||||
/// </returns>
|
||||
public static lzxd_stream lzxd_init(mspack_system system, mspack_file input, mspack_file output, int window_bits, int reset_interval, int input_buffer_size, long output_length, char is_delta) => null;
|
||||
|
||||
@@ -2,23 +2,8 @@ using static SabreTools.Compression.libmspack.lzx;
|
||||
|
||||
namespace SabreTools.Compression.libmspack
|
||||
{
|
||||
public unsafe class lzxd_stream
|
||||
public unsafe class lzxd_stream : readbits
|
||||
{
|
||||
/// <summary>
|
||||
/// I/O routines
|
||||
/// </summary>
|
||||
public mspack_system sys { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Input file handle
|
||||
/// </summary>
|
||||
public mspack_file input { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Output file handle
|
||||
/// </summary>
|
||||
public mspack_file output { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of bytes actually output
|
||||
/// </summary>
|
||||
@@ -49,11 +34,6 @@ namespace SabreTools.Compression.libmspack
|
||||
/// </summary>
|
||||
public uint num_offsets { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Decompression offset within window
|
||||
/// </summary>
|
||||
public uint window_posn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current frame offset within in window
|
||||
/// </summary>
|
||||
@@ -117,35 +97,13 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <summary>
|
||||
/// Have we reached the end of input?
|
||||
/// </summary>
|
||||
public byte input_end { get; set; }
|
||||
public new byte input_end { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Does stream follow LZX DELTA spec?
|
||||
/// </summary>
|
||||
public byte is_delta { get; set; }
|
||||
|
||||
public MSPACK_ERR error { get; set; }
|
||||
|
||||
#region I/O buffering
|
||||
|
||||
public byte* inbuf { get; set; }
|
||||
|
||||
public byte* i_ptr { get; set; }
|
||||
|
||||
public byte* i_end { get; set; }
|
||||
|
||||
public byte* o_ptr { get; set; }
|
||||
|
||||
public byte* o_end { get; set; }
|
||||
|
||||
public uint bit_buffer { get; set; }
|
||||
|
||||
public uint bits_left { get; set; }
|
||||
|
||||
public uint inbuf_size { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Huffman code lengths
|
||||
|
||||
public byte[] PRETREE_len { get; set; } = new byte[LZX_PRETREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
|
||||
@@ -176,5 +134,15 @@ namespace SabreTools.Compression.libmspack
|
||||
/// This is used purely for doing the intel E8 transform
|
||||
/// </summary>
|
||||
public byte[] e8_buf { get; set; } = new byte[LZX_FRAME_SIZE];
|
||||
|
||||
public override void READ_BYTES()
|
||||
{
|
||||
byte b0, b1;
|
||||
READ_IF_NEEDED(ref i_ptr, ref i_end);
|
||||
b0 = *i_ptr++;
|
||||
READ_IF_NEEDED(ref i_ptr, ref i_end);
|
||||
b1 = *i_ptr++;
|
||||
INJECT_BITS_MSB((b1 << 8) | b0, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,8 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <summary>
|
||||
/// TODO
|
||||
/// </summary>
|
||||
public class mscab_compressor
|
||||
public class mscab_compressor : Compressor
|
||||
{
|
||||
public int dummy { get; set; }
|
||||
|
||||
public mspack_system system { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
using static SabreTools.Compression.libmspack.cab;
|
||||
|
||||
namespace SabreTools.Compression.libmspack
|
||||
{
|
||||
/// <summary>
|
||||
@@ -7,12 +9,10 @@ namespace SabreTools.Compression.libmspack
|
||||
/// </summary>
|
||||
/// <see cref="mspack_create_cab_decompressor()"/>
|
||||
/// <see cref="mspack_destroy_cab_decompressor()"/>
|
||||
public abstract class mscab_decompressor
|
||||
public unsafe class mscab_decompressor : Decompressor
|
||||
{
|
||||
public mscabd_decompress_state d { get; set; }
|
||||
|
||||
public mspack_system system { get; set; }
|
||||
|
||||
public int buf_size { get; set; }
|
||||
|
||||
public int searchbuf_size { get; set; }
|
||||
@@ -32,7 +32,7 @@ namespace SabreTools.Compression.libmspack
|
||||
/// and a mscabd_cabinet structure will be returned, with a full list of
|
||||
/// folders and files.
|
||||
///
|
||||
/// In the case of an error occuring, NULL is returned and the error code
|
||||
/// In the case of an error occuring, null is returned and the error code
|
||||
/// is available from last_error().
|
||||
///
|
||||
/// The filename pointer should be considered "in use" until close() is
|
||||
@@ -42,11 +42,37 @@ namespace SabreTools.Compression.libmspack
|
||||
/// The filename of the cabinet file. This is passed
|
||||
/// directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <returns>A pointer to a mscabd_cabinet structure, or NULL on failure</returns>
|
||||
/// <returns>A pointer to a mscabd_cabinet structure, or null on failure</returns>
|
||||
/// <see cref="close(mscabd_cabinet)"/>
|
||||
/// <see cref="search(in string)"/>
|
||||
/// <see cref="last_error()"/>
|
||||
public abstract mscabd_cabinet open(in string filename);
|
||||
public mscabd_cabinet open(in string filename)
|
||||
{
|
||||
mscabd_cabinet cab = null;
|
||||
mspack_file fh;
|
||||
MSPACK_ERR error;
|
||||
|
||||
mspack_system sys = this.system;
|
||||
if ((fh = sys.open(filename, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_READ)) != null)
|
||||
{
|
||||
cab = new mscabd_cabinet();
|
||||
cab.filename = filename;
|
||||
error = cabd_read_headers(sys, fh, cab, 0, this.salvage, 0);
|
||||
if (error != MSPACK_ERR.MSPACK_ERR_OK)
|
||||
{
|
||||
close(cab);
|
||||
cab = null;
|
||||
}
|
||||
this.error = error;
|
||||
sys.close(fh);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.error = MSPACK_ERR.MSPACK_ERR_OPEN;
|
||||
}
|
||||
|
||||
return cab;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes a previously opened cabinet or cabinet set.
|
||||
@@ -77,7 +103,374 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <see cref="search(in string)"/>
|
||||
/// <see cref="append(mscabd_cabinet, mscabd_cabinet)"/>
|
||||
/// <see cref="prepend(mscabd_cabinet, mscabd_cabinet)"/>
|
||||
public abstract void close(mscabd_cabinet cab);
|
||||
public void close(mscabd_cabinet origcab)
|
||||
{
|
||||
mscabd_folder_data dat, ndat;
|
||||
mscabd_cabinet cab, ncab;
|
||||
mscabd_folder fol, nfol;
|
||||
mscabd_file fi, nfi;
|
||||
|
||||
mspack_system sys = this.system;
|
||||
|
||||
this.error = MSPACK_ERR.MSPACK_ERR_OK;
|
||||
|
||||
while (origcab != null)
|
||||
{
|
||||
// Free files
|
||||
for (fi = origcab.files; fi != null; fi = nfi)
|
||||
{
|
||||
nfi = fi.next;
|
||||
//sys.free(fi.filename);
|
||||
//sys.free(fi);
|
||||
}
|
||||
|
||||
// Free folders
|
||||
for (fol = origcab.folders; fol != null; fol = nfol)
|
||||
{
|
||||
nfol = fol.next;
|
||||
|
||||
// Free folder decompression state if it has been decompressed
|
||||
if (this.d != null && (this.d.folder == fol))
|
||||
{
|
||||
if (this.d.infh != null) sys.close(this.d.infh);
|
||||
cabd_free_decomp();
|
||||
//sys.free(this.d);
|
||||
this.d = null;
|
||||
}
|
||||
|
||||
// Free folder data segments
|
||||
for (dat = fol.data.next; dat != null; dat = ndat)
|
||||
{
|
||||
ndat = dat.next;
|
||||
//sys.free(dat);
|
||||
}
|
||||
|
||||
//sys.free(fol);
|
||||
}
|
||||
|
||||
// Free predecessor cabinets (and the original cabinet's strings)
|
||||
for (cab = origcab; cab != null; cab = ncab)
|
||||
{
|
||||
ncab = cab.prevcab;
|
||||
//sys.free(cab.prevname);
|
||||
//sys.free(cab.nextname);
|
||||
//sys.free(cab.previnfo);
|
||||
//sys.free(cab.nextinfo);
|
||||
//if (cab != origcab) sys.free(cab);
|
||||
}
|
||||
|
||||
// Free successor cabinets
|
||||
for (cab = origcab.nextcab; cab != null; cab = ncab)
|
||||
{
|
||||
ncab = cab.nextcab;
|
||||
//sys.free(cab.prevname);
|
||||
//sys.free(cab.nextname);
|
||||
//sys.free(cab.previnfo);
|
||||
//sys.free(cab.nextinfo);
|
||||
//sys.free(cab);
|
||||
}
|
||||
|
||||
// Free actual cabinet structure
|
||||
cab = origcab.next;
|
||||
//sys.free(origcab);
|
||||
|
||||
// Repeat full procedure again with the cab.next pointer (if set)
|
||||
origcab = cab;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the cabinet file header, folder list and file list.
|
||||
/// Fills out a pre-existing mscabd_cabinet structure, allocates memory
|
||||
/// for folders and files as necessary
|
||||
/// </summary>
|
||||
private static MSPACK_ERR cabd_read_headers(mspack_system sys, mspack_file fh, mscabd_cabinet cab, long offset, int salvage, int quiet)
|
||||
{
|
||||
int num_folders, num_files, folder_resv, i, x, fidx;
|
||||
MSPACK_ERR err;
|
||||
mscabd_folder fol, linkfol = null;
|
||||
mscabd_file file, linkfile = null;
|
||||
byte[] buf = new byte[64];
|
||||
|
||||
// Initialise pointers
|
||||
cab.next = null;
|
||||
cab.files = null;
|
||||
cab.folders = null;
|
||||
cab.prevcab = cab.nextcab = null;
|
||||
cab.prevname = cab.nextname = null;
|
||||
cab.previnfo = cab.nextinfo = null;
|
||||
|
||||
cab.base_offset = offset;
|
||||
|
||||
// Seek to CFHEADER
|
||||
if (sys.seek(fh, offset, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_START) != 0)
|
||||
{
|
||||
return MSPACK_ERR.MSPACK_ERR_SEEK;
|
||||
}
|
||||
|
||||
// Read in the CFHEADER
|
||||
if (sys.read(fh, libmspack.system.GetArrayPointer(buf), cfhead_SIZEOF) != cfhead_SIZEOF)
|
||||
{
|
||||
return MSPACK_ERR.MSPACK_ERR_READ;
|
||||
}
|
||||
|
||||
// Check for "MSCF" signature
|
||||
if (EndGetI32((byte*)buf[cfhead_Signature]) != 0x4643534D)
|
||||
{
|
||||
return MSPACK_ERR.MSPACK_ERR_SIGNATURE;
|
||||
}
|
||||
|
||||
// Some basic header fields
|
||||
cab.length = EndGetI32((byte*)buf[cfhead_CabinetSize]);
|
||||
cab.set_id = EndGetI16((byte*)buf[cfhead_SetID]);
|
||||
cab.set_index = EndGetI16((byte*)buf[cfhead_CabinetIndex]);
|
||||
|
||||
// Get the number of folders
|
||||
num_folders = EndGetI16((byte*)buf[cfhead_NumFolders]);
|
||||
if (num_folders == 0)
|
||||
{
|
||||
if (quiet == 0) sys.message(fh, "No folders in cabinet.");
|
||||
return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
|
||||
}
|
||||
|
||||
// Get the number of files
|
||||
num_files = EndGetI16((byte*)buf[cfhead_NumFiles]);
|
||||
if (num_files == 0)
|
||||
{
|
||||
if (quiet == 0) sys.message(fh, "no files in cabinet.");
|
||||
return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
|
||||
}
|
||||
|
||||
// Check cabinet version
|
||||
if ((buf[cfhead_MajorVersion] != 1) && (buf[cfhead_MinorVersion] != 3))
|
||||
{
|
||||
if (quiet == 0) sys.message(fh, "WARNING; cabinet version is not 1.3");
|
||||
}
|
||||
|
||||
// Read the reserved-sizes part of header, if present
|
||||
cab.flags = EndGetI16((byte*)buf[cfhead_Flags]);
|
||||
|
||||
if (cab.flags.HasFlag(MSCAB_HDR.MSCAB_HDR_RESV))
|
||||
{
|
||||
if (sys.read(fh, libmspack.system.GetArrayPointer(buf), cfheadext_SIZEOF) != cfheadext_SIZEOF)
|
||||
{
|
||||
return MSPACK_ERR.MSPACK_ERR_READ;
|
||||
}
|
||||
cab.header_resv = EndGetI16((byte*)buf[cfheadext_HeaderReserved]);
|
||||
folder_resv = buf[cfheadext_FolderReserved];
|
||||
cab.block_resv = buf[cfheadext_DataReserved];
|
||||
|
||||
if (cab.header_resv > 60000)
|
||||
{
|
||||
if (quiet == 0) sys.message(fh, "WARNING; reserved header > 60000.");
|
||||
}
|
||||
|
||||
// Skip the reserved header
|
||||
if (cab.header_resv != 0)
|
||||
{
|
||||
if (sys.seek(fh, cab.header_resv, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_CUR) != 0)
|
||||
{
|
||||
return MSPACK_ERR.MSPACK_ERR_SEEK;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cab.header_resv = 0;
|
||||
folder_resv = 0;
|
||||
cab.block_resv = 0;
|
||||
}
|
||||
|
||||
// Read name and info of preceeding cabinet in set, if present
|
||||
if (cab.flags.HasFlag(MSCAB_HDR.MSCAB_HDR_PREVCAB))
|
||||
{
|
||||
cab.prevname = cabd_read_string(sys, fh, 0, out err);
|
||||
if (err != MSPACK_ERR.MSPACK_ERR_OK) return err;
|
||||
cab.previnfo = cabd_read_string(sys, fh, 1, out err);
|
||||
if (err != MSPACK_ERR.MSPACK_ERR_OK) return err;
|
||||
}
|
||||
|
||||
// Read name and info of next cabinet in set, if present
|
||||
if (cab.flags.HasFlag(MSCAB_HDR.MSCAB_HDR_NEXTCAB))
|
||||
{
|
||||
cab.nextname = cabd_read_string(sys, fh, 0, out err);
|
||||
if (err != MSPACK_ERR.MSPACK_ERR_OK) return err;
|
||||
cab.nextinfo = cabd_read_string(sys, fh, 1, out err);
|
||||
if (err != MSPACK_ERR.MSPACK_ERR_OK) return err;
|
||||
}
|
||||
|
||||
// Read folders
|
||||
for (i = 0; i < num_folders; i++)
|
||||
{
|
||||
if (sys.read(fh, libmspack.system.GetArrayPointer(buf), cffold_SIZEOF) != cffold_SIZEOF)
|
||||
{
|
||||
return MSPACK_ERR.MSPACK_ERR_READ;
|
||||
}
|
||||
if (folder_resv != 0)
|
||||
{
|
||||
if (sys.seek(fh, folder_resv, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_CUR) != 0)
|
||||
{
|
||||
return MSPACK_ERR.MSPACK_ERR_SEEK;
|
||||
}
|
||||
}
|
||||
|
||||
fol = new mscabd_folder();
|
||||
|
||||
fol.next = null;
|
||||
fol.comp_type = EndGetI16((byte*)buf[cffold_CompType]);
|
||||
fol.num_blocks = EndGetI16((byte*)buf[cffold_NumBlocks]);
|
||||
fol.data.next = null;
|
||||
fol.data.cab = cab;
|
||||
fol.data.offset = offset + (long)((uint)EndGetI32((byte*)buf[cffold_DataOffset]));
|
||||
fol.merge_prev = null;
|
||||
fol.merge_next = null;
|
||||
|
||||
// Link folder into list of folders
|
||||
if (linkfol == null) cab.folders = fol;
|
||||
else linkfol.next = fol;
|
||||
linkfol = fol;
|
||||
}
|
||||
|
||||
// Read files
|
||||
for (i = 0; i < num_files; i++)
|
||||
{
|
||||
if (sys.read(fh, libmspack.system.GetArrayPointer(buf), cffile_SIZEOF) != cffile_SIZEOF)
|
||||
{
|
||||
return MSPACK_ERR.MSPACK_ERR_READ;
|
||||
}
|
||||
|
||||
file = new mscabd_file();
|
||||
|
||||
file.next = null;
|
||||
file.length = EndGetI32((byte*)buf[cffile_UncompressedSize]);
|
||||
file.attribs = EndGetI16((byte*)buf[cffile_Attribs]);
|
||||
file.offset = EndGetI32((byte*)buf[cffile_FolderOffset]);
|
||||
|
||||
// Set folder pointer
|
||||
fidx = EndGetI16((byte*)buf[cffile_FolderIndex]);
|
||||
if (fidx < cffileCONTINUED_FROM_PREV)
|
||||
{
|
||||
/* normal folder index; count up to the correct folder */
|
||||
if (fidx < num_folders)
|
||||
{
|
||||
mscabd_folder ifol = cab.folders;
|
||||
while (fidx-- > 0) if (ifol != null) ifol = ifol.next;
|
||||
file.folder = ifol;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.Console.Error.WriteLine("Invalid folder index");
|
||||
file.folder = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// either CONTINUED_TO_NEXT, CONTINUED_FROM_PREV or CONTINUED_PREV_AND_NEXT
|
||||
if ((fidx == cffileCONTINUED_TO_NEXT) || (fidx == cffileCONTINUED_PREV_AND_NEXT))
|
||||
{
|
||||
// Get last folder
|
||||
mscabd_folder ifol = cab.folders;
|
||||
while (ifol.next != null) ifol = ifol.next;
|
||||
file.folder = ifol;
|
||||
|
||||
// Set "merge next" pointer
|
||||
fol = ifol;
|
||||
if (fol.merge_next == null) fol.merge_next = file;
|
||||
}
|
||||
|
||||
if ((fidx == cffileCONTINUED_FROM_PREV) || (fidx == cffileCONTINUED_PREV_AND_NEXT))
|
||||
{
|
||||
// Get first folder
|
||||
file.folder = cab.folders;
|
||||
|
||||
// Set "merge prev" pointer
|
||||
fol = file.folder;
|
||||
if (fol.merge_prev == null) fol.merge_prev = file;
|
||||
}
|
||||
}
|
||||
|
||||
// Get time
|
||||
x = EndGetI16((byte*)buf[cffile_Time]);
|
||||
file.time_h = (char)(x >> 11);
|
||||
file.time_m = (char)((x >> 5) & 0x3F);
|
||||
file.time_s = (char)((x << 1) & 0x3E);
|
||||
|
||||
// Get date
|
||||
x = EndGetI16((byte*)buf[cffile_Date]);
|
||||
file.date_d = (char)(x & 0x1F);
|
||||
file.date_m = (char)((x >> 5) & 0xF);
|
||||
file.date_y = (x >> 9) + 1980;
|
||||
|
||||
// Get filename
|
||||
file.filename = cabd_read_string(sys, fh, 0, out err);
|
||||
|
||||
// If folder index or filename are bad, either skip it or fail
|
||||
if (err != MSPACK_ERR.MSPACK_ERR_OK || file.folder == null)
|
||||
{
|
||||
//sys.free(file.filename);
|
||||
//sys.free(file);
|
||||
if (salvage != 0) continue;
|
||||
return err != MSPACK_ERR.MSPACK_ERR_OK ? err : MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
|
||||
}
|
||||
|
||||
// Link file entry into file list
|
||||
if (linkfile == null) cab.files = file;
|
||||
else linkfile.next = file;
|
||||
linkfile = file;
|
||||
}
|
||||
|
||||
if (cab.files == null)
|
||||
{
|
||||
// We never actually added any files to the file list. Something went wrong.
|
||||
// The file header may have been invalid
|
||||
|
||||
System.Console.Error.WriteLine($"No files found, even though header claimed to have {num_files} files");
|
||||
return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
|
||||
}
|
||||
|
||||
return MSPACK_ERR.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
private static string cabd_read_string(mspack_system sys, mspack_file fh, int permit_empty, out MSPACK_ERR error)
|
||||
{
|
||||
long @base = sys.tell(fh);
|
||||
byte[] buf = new byte[256];
|
||||
string str;
|
||||
int len, i, ok;
|
||||
|
||||
// Read up to 256 bytes */
|
||||
if ((len = sys.read(fh, libmspack.system.GetArrayPointer(buf), 256)) <= 0)
|
||||
{
|
||||
error = MSPACK_ERR.MSPACK_ERR_READ;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Search for a null terminator in the buffer
|
||||
for (i = 0, ok = 0; i < len; i++) if (buf[i] == 0) { ok = 1; break; }
|
||||
/* optionally reject empty strings */
|
||||
if (i == 0 && permit_empty == 0) ok = 0;
|
||||
|
||||
if (ok == 0)
|
||||
{
|
||||
error = MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
|
||||
return null;
|
||||
}
|
||||
|
||||
len = i + 1;
|
||||
|
||||
/* set the data stream to just after the string and return */
|
||||
if (sys.seek(fh, @base + len, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_START) != 0)
|
||||
{
|
||||
error = MSPACK_ERR.MSPACK_ERR_SEEK;
|
||||
return null;
|
||||
}
|
||||
|
||||
char[] strchr = new char[len];
|
||||
sys.copy(libmspack.system.GetArrayPointer(buf), libmspack.system.GetArrayPointer(strchr), len);
|
||||
str = new string(strchr);
|
||||
error = MSPACK_ERR.MSPACK_ERR_OK;
|
||||
return str;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches a regular file for embedded cabinets.
|
||||
@@ -94,11 +487,11 @@ namespace SabreTools.Compression.libmspack
|
||||
/// using the mscabd_cabinet::next field.
|
||||
///
|
||||
/// In the case of an error occuring anywhere other than the simulated
|
||||
/// open(), NULL is returned and the error code is available from
|
||||
/// open(), null is returned and the error code is available from
|
||||
/// last_error().
|
||||
///
|
||||
/// If no error occurs, but no cabinets can be found in the file, NULL is
|
||||
/// returned and last_error() returns MSPACK_ERR_OK.
|
||||
/// If no error occurs, but no cabinets can be found in the file, null is
|
||||
/// returned and last_error() returns MSPACK_ERR.MSPACK_ERR_OK.
|
||||
///
|
||||
/// The filename pointer should be considered in use until close() is
|
||||
/// called on the cabinet.
|
||||
@@ -110,7 +503,7 @@ namespace SabreTools.Compression.libmspack
|
||||
/// The filename of the file to search for cabinets. This
|
||||
/// is passed directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <returns>A pointer to a mscabd_cabinet structure, or NULL</returns>
|
||||
/// <returns>A pointer to a mscabd_cabinet structure, or null</returns>
|
||||
/// <see cref="close(mscabd_cabinet)"/>
|
||||
/// <see cref="open(in string)"/>
|
||||
/// <see cref="last_error()"/>
|
||||
@@ -121,7 +514,7 @@ namespace SabreTools.Compression.libmspack
|
||||
/// set.
|
||||
///
|
||||
/// This will attempt to append one cabinet to another such that
|
||||
/// <tt>(cab->nextcab == nextcab) && (nextcab->prevcab == cab)</tt> and
|
||||
/// <tt>(cab.nextcab == nextcab) && (nextcab.prevcab == cab)</tt> and
|
||||
/// any folders split between the two cabinets are merged.
|
||||
///
|
||||
/// The cabinets MUST be part of a cabinet set -- a cabinet set is a
|
||||
@@ -149,7 +542,7 @@ namespace SabreTools.Compression.libmspack
|
||||
/// </summary>
|
||||
/// <param name="cab">The cabinet which will be appended to, predecessor of nextcab</param>
|
||||
/// <param name="nextcab">The cabinet which will be appended, successor of cab</param>
|
||||
/// <returns>An error code, or MSPACK_ERR_OK if successful</returns>
|
||||
/// <returns>An error code, or MSPACK_ERR.MSPACK_ERR_OK if successful</returns>
|
||||
/// <see cref="prepend(mscabd_cabinet, mscabd_cabinet)"/>
|
||||
/// <see cref="open(in string)"/>
|
||||
/// <see cref="close(mscabd_cabinet)"/>
|
||||
@@ -160,13 +553,13 @@ namespace SabreTools.Compression.libmspack
|
||||
/// cabinet set.
|
||||
///
|
||||
/// This will attempt to prepend one cabinet to another, such that
|
||||
/// <tt>(cab->prevcab == prevcab) && (prevcab->nextcab == cab)</tt>. In
|
||||
/// <tt>(cab.prevcab == prevcab) && (prevcab.nextcab == cab)</tt>. In
|
||||
/// all other respects, it is identical to append(). See append() for the
|
||||
/// full documentation.
|
||||
/// </summary>
|
||||
/// <param name="cab">The cabinet which will be prepended to, successor of prevcab</param>
|
||||
/// <param name="prevcab">The cabinet which will be prepended, predecessor of cab</param>
|
||||
/// <returns>An error code, or MSPACK_ERR_OK if successful</returns>
|
||||
/// <returns>An error code, or MSPACK_ERR.MSPACK_ERR_OK if successful</returns>
|
||||
/// <see cref="append(mscabd_cabinet, mscabd_cabinet)"/>
|
||||
/// <see cref="open(in string)"/>
|
||||
/// <see cref="close(mscabd_cabinet)"/>
|
||||
@@ -190,7 +583,7 @@ namespace SabreTools.Compression.libmspack
|
||||
/// </summary>
|
||||
/// <param name="file">The file to be decompressed</param>
|
||||
/// <param name="filename">The filename of the file being written to</param>
|
||||
/// <returns>An error code, or MSPACK_ERR_OK if successful</returns>
|
||||
/// <returns>An error code, or MSPACK_ERR.MSPACK_ERR_OK if successful</returns>
|
||||
public abstract MSPACK_ERR extract(mscabd_file file, in string filename);
|
||||
|
||||
/// <summary>
|
||||
@@ -210,12 +603,35 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <param name="param">The parameter to set</param>
|
||||
/// <param name="value">The value to set the parameter to</param>
|
||||
/// <returns>
|
||||
/// MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if there
|
||||
/// MSPACK_ERR.MSPACK_ERR_OK if all is OK, or MSPACK_ERR.MSPACK_ERR_ARGS if there
|
||||
/// is a problem with either parameter or value.
|
||||
/// </returns>
|
||||
/// <see cref="search(in string)"/>
|
||||
/// <see cref="extract(mscabd_file, in string)"/>
|
||||
public abstract MSPACK_ERR set_param(MSCABD_PARAM param, int value);
|
||||
public MSPACK_ERR set_param(MSCABD_PARAM param, int value)
|
||||
{
|
||||
switch (param)
|
||||
{
|
||||
case MSCABD_PARAM.MSCABD_PARAM_SEARCHBUF:
|
||||
if (value < 4) return MSPACK_ERR.MSPACK_ERR_ARGS;
|
||||
this.searchbuf_size = value;
|
||||
break;
|
||||
case MSCABD_PARAM.MSCABD_PARAM_FIXMSZIP:
|
||||
this.fix_mszip = value;
|
||||
break;
|
||||
case MSCABD_PARAM.MSCABD_PARAM_DECOMPBUF:
|
||||
if (value < 4) return MSPACK_ERR.MSPACK_ERR_ARGS;
|
||||
this.buf_size = value;
|
||||
break;
|
||||
case MSCABD_PARAM.MSCABD_PARAM_SALVAGE:
|
||||
this.salvage = value;
|
||||
break;
|
||||
default:
|
||||
return MSPACK_ERR.MSPACK_ERR_ARGS;
|
||||
}
|
||||
|
||||
return MSPACK_ERR.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the error code set by the most recently called method.
|
||||
@@ -226,6 +642,9 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <returns>The most recent error code</returns>
|
||||
/// <see cref="open(in string)"/>
|
||||
/// <see cref="search(in string)"/>
|
||||
public abstract MSPACK_ERR last_error();
|
||||
public MSPACK_ERR last_error()
|
||||
{
|
||||
return this.error;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ namespace SabreTools.Compression.libmspack
|
||||
{
|
||||
/// <summary>
|
||||
/// The next cabinet in a chained list, if this cabinet was opened with
|
||||
/// mscab_decompressor::search(). May be NULL to mark the end of the
|
||||
/// mscab_decompressor::search(). May be null to mark the end of the
|
||||
/// list.
|
||||
/// </summary>
|
||||
public mscabd_cabinet next { get; set; }
|
||||
@@ -38,34 +38,34 @@ namespace SabreTools.Compression.libmspack
|
||||
public uint length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The previous cabinet in a cabinet set, or NULL.
|
||||
/// The previous cabinet in a cabinet set, or null.
|
||||
/// </summary>
|
||||
public mscabd_cabinet prevcab { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The next cabinet in a cabinet set, or NULL.
|
||||
/// The next cabinet in a cabinet set, or null.
|
||||
/// </summary>
|
||||
public mscabd_cabinet nextcab { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The filename of the previous cabinet in a cabinet set, or NULL.
|
||||
/// The filename of the previous cabinet in a cabinet set, or null.
|
||||
/// </summary>
|
||||
public string prevname { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The filename of the next cabinet in a cabinet set, or NULL.
|
||||
/// The filename of the next cabinet in a cabinet set, or null.
|
||||
/// </summary>
|
||||
public string nextname { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the disk containing the previous cabinet in a cabinet
|
||||
/// set, or NULL.
|
||||
/// set, or null.
|
||||
/// </summary>
|
||||
public string previnfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the disk containing the next cabinet in a cabinet set,
|
||||
/// or NULL.
|
||||
/// or null.
|
||||
/// </summary>
|
||||
public string nextinfo { get; set; }
|
||||
|
||||
|
||||
@@ -42,15 +42,12 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <summary>
|
||||
/// Decompressor code
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public abstract int decompress(void* data, long offset);
|
||||
public abstract MSPACK_ERR decompress(object data, long offset);
|
||||
|
||||
/// <summary>
|
||||
/// Decompressor state
|
||||
/// </summary>
|
||||
public void* state { get; set; }
|
||||
public object state { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cabinet where input data comes from
|
||||
@@ -82,4 +79,25 @@ namespace SabreTools.Compression.libmspack
|
||||
/// </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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ namespace SabreTools.Compression.libmspack
|
||||
public class mscabd_file
|
||||
{
|
||||
/// <summary>
|
||||
/// The next file in the cabinet or cabinet set, or NULL if this is the
|
||||
/// The next file in the cabinet or cabinet set, or null if this is the
|
||||
/// final file.
|
||||
/// </summary>
|
||||
public mscabd_file next { get; set; }
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace SabreTools.Compression.libmspack
|
||||
public class mscabd_folder
|
||||
{
|
||||
/// <summary>
|
||||
/// A pointer to the next folder in this cabinet or cabinet set, or NULL
|
||||
/// A pointer to the next folder in this cabinet or cabinet set, or null
|
||||
/// if this is the final folder.
|
||||
/// </summary>
|
||||
public mscabd_folder next { get; set; }
|
||||
|
||||
@@ -7,10 +7,8 @@ namespace SabreTools.Compression.libmspack
|
||||
/// </summary>
|
||||
/// <see cref="mspack_create_chm_compressor()"/>
|
||||
/// <see cref="mspack_destroy_chm_compressor()"/>
|
||||
public abstract class mschm_compressor
|
||||
public abstract class mschm_compressor : Compressor
|
||||
{
|
||||
public mspack_system system { get; set; }
|
||||
|
||||
public string temp_file { get; set; }
|
||||
|
||||
public int use_temp_file { get; set; }
|
||||
|
||||
@@ -7,10 +7,8 @@ namespace SabreTools.Compression.libmspack
|
||||
/// </summary>
|
||||
/// <see cref="mspack_create_chm_decompressor()"/>
|
||||
/// <see cref="mspack_destroy_chm_decompressor()"/>
|
||||
public abstract class mschm_decompressor
|
||||
public abstract class mschm_decompressor : Decompressor
|
||||
{
|
||||
public mspack_system system { get; set; }
|
||||
|
||||
public mschmd_decompress_state d { get; set; }
|
||||
|
||||
public MSPACK_ERR error { get; set; }
|
||||
@@ -22,7 +20,7 @@ namespace SabreTools.Compression.libmspack
|
||||
/// and a mschmd_header structure will be returned, with a full list of
|
||||
/// files.
|
||||
///
|
||||
/// In the case of an error occuring, NULL is returned and the error code
|
||||
/// In the case of an error occuring, null is returned and the error code
|
||||
/// is available from last_error().
|
||||
///
|
||||
/// The filename pointer should be considered "in use" until close() is
|
||||
@@ -32,7 +30,7 @@ namespace SabreTools.Compression.libmspack
|
||||
/// The filename of the CHM helpfile. This is passed
|
||||
/// directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <returns>A pointer to a mschmd_header structure, or NULL on failure</returns>
|
||||
/// <returns>A pointer to a mschmd_header structure, or null on failure</returns>
|
||||
/// <see cref="close(mschmd_header)"/>
|
||||
public abstract mschmd_header open(in string filename);
|
||||
|
||||
@@ -86,11 +84,11 @@ namespace SabreTools.Compression.libmspack
|
||||
///
|
||||
/// If the file opened is a valid CHM helpfile, only essential headers
|
||||
/// will be read. A mschmd_header structure will be still be returned, as
|
||||
/// with open(), but the mschmd_header::files field will be NULL. No
|
||||
/// with open(), but the mschmd_header::files field will be null. No
|
||||
/// files details will be automatically read. The fast_find() method
|
||||
/// must be used to obtain file details.
|
||||
///
|
||||
/// In the case of an error occuring, NULL is returned and the error code
|
||||
/// In the case of an error occuring, null is returned and the error code
|
||||
/// is available from last_error().
|
||||
///
|
||||
/// The filename pointer should be considered "in use" until close() is
|
||||
@@ -100,7 +98,7 @@ namespace SabreTools.Compression.libmspack
|
||||
/// The filename of the CHM helpfile. This is passed
|
||||
/// directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <returns>A pointer to a mschmd_header structure, or NULL on failure</returns>
|
||||
/// <returns>A pointer to a mschmd_header structure, or null on failure</returns>
|
||||
/// <see cref="open(in string)"/>
|
||||
/// <see cref="close(mschmd_header)"/>
|
||||
/// <see cref="fast_find(mschmd_header, in string, mschmd_file, int)"/>
|
||||
@@ -123,14 +121,14 @@ namespace SabreTools.Compression.libmspack
|
||||
/// - section: the correct value for the found file
|
||||
/// - offset: the correct value for the found file
|
||||
/// - length: the correct value for the found file
|
||||
/// - all other structure elements: NULL or 0
|
||||
/// - all other structure elements: null or 0
|
||||
///
|
||||
/// If the file was not found, MSPACK_ERR_OK will still be returned as the
|
||||
/// result, but the caller-provided structure will be filled out like so:
|
||||
/// - section: NULL
|
||||
/// - section: null
|
||||
/// - offset: 0
|
||||
/// - length: 0
|
||||
/// - all other structure elements: NULL or 0
|
||||
/// - all other structure elements: null or 0
|
||||
///
|
||||
/// This method is intended to be used in conjunction with CHM helpfiles
|
||||
/// opened with fast_open(), but it also works with helpfiles opened
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace SabreTools.Compression.libmspack
|
||||
public class mschmd_file
|
||||
{
|
||||
/// <summary>
|
||||
/// A pointer to the next file in the list, or NULL if this is the final
|
||||
/// A pointer to the next file in the list, or null if this is the final
|
||||
/// file.
|
||||
/// </summary>
|
||||
public mschmd_file next { get; set; }
|
||||
|
||||
@@ -3,10 +3,8 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <summary>
|
||||
/// TODO
|
||||
/// </summary>
|
||||
public class mshlp_compressor
|
||||
public class mshlp_compressor : Compressor
|
||||
{
|
||||
public int dummy { get; set; }
|
||||
|
||||
public mspack_system system { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,8 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <summary>
|
||||
/// TODO
|
||||
/// </summary>
|
||||
public class mshlp_decompressor
|
||||
public class mshlp_decompressor : Decompressor
|
||||
{
|
||||
public int dummy { get; set; }
|
||||
|
||||
public mspack_system system { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ namespace SabreTools.Compression.libmspack
|
||||
/// </summary>
|
||||
/// <see cref="mspack_create_kwaj_compressor()"/>
|
||||
/// <see cref="mspack_destroy_kwaj_compressor()"/>
|
||||
public unsafe abstract class mskwaj_compressor
|
||||
public unsafe abstract class mskwaj_compressor : Compressor
|
||||
{
|
||||
public mspack_system system { get; set; }
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace SabreTools.Compression.libmspack
|
||||
/// MS-DOS "8.3" type filename (up to 8 bytes for the filename, then
|
||||
/// optionally a "." and up to 3 bytes for a filename extension).
|
||||
///
|
||||
/// If NULL is passed as the filename, no filename is included in the
|
||||
/// If null is passed as the filename, no filename is included in the
|
||||
/// header. This is the default.
|
||||
/// </summary>
|
||||
/// <param name="filename">The original filename to use</param>
|
||||
@@ -86,7 +86,7 @@ namespace SabreTools.Compression.libmspack
|
||||
/// as the overall size of the header must not exceed 65535 bytes.
|
||||
/// The data can contain null bytes if desired.
|
||||
///
|
||||
/// If NULL is passed as the data pointer, or zero is passed as the
|
||||
/// If null is passed as the data pointer, or zero is passed as the
|
||||
/// length, no extra data is included in the header. This is the
|
||||
/// default.
|
||||
/// </summary>
|
||||
|
||||
@@ -7,10 +7,8 @@ namespace SabreTools.Compression.libmspack
|
||||
/// </summary>
|
||||
/// <see cref="mspack_create_kwaj_decompressor()"/>
|
||||
/// <see cref="mspack_destroy_kwaj_decompressor()"/>
|
||||
public abstract class mskwaj_decompressor
|
||||
public abstract class mskwaj_decompressor : Decompressor
|
||||
{
|
||||
public mspack_system system { get; set; }
|
||||
|
||||
public MSPACK_ERR error { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -19,7 +17,7 @@ namespace SabreTools.Compression.libmspack
|
||||
/// If the file opened is a valid KWAJ file, all headers will be read and
|
||||
/// a mskwajd_header structure will be returned.
|
||||
///
|
||||
/// In the case of an error occuring, NULL is returned and the error code
|
||||
/// In the case of an error occuring, null is returned and the error code
|
||||
/// is available from last_error().
|
||||
///
|
||||
/// The filename pointer should be considered "in use" until close() is
|
||||
@@ -29,7 +27,7 @@ namespace SabreTools.Compression.libmspack
|
||||
/// The filename of the KWAJ compressed file. This is
|
||||
/// passed directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <returns>A pointer to a mskwajd_header structure, or NULL on failure</returns>
|
||||
/// <returns>A pointer to a mskwajd_header structure, or null on failure</returns>
|
||||
/// <see cref="close(mskwajd_header)"/>
|
||||
public abstract mskwajd_header open(in string filename);
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace SabreTools.Compression.libmspack
|
||||
public long length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Output filename, or NULL if not present
|
||||
/// Output filename, or null if not present
|
||||
/// </summary>
|
||||
public string filename { get; set; }
|
||||
|
||||
|
||||
@@ -3,10 +3,8 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <summary>
|
||||
/// TODO
|
||||
/// </summary>
|
||||
public class mslit_compressor
|
||||
public class mslit_compressor : Compressor
|
||||
{
|
||||
public int dummy { get; set; }
|
||||
|
||||
public mspack_system system { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,8 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <summary>
|
||||
/// TODO
|
||||
/// </summary>
|
||||
public class mslit_decompressor
|
||||
public class mslit_decompressor : Decompressor
|
||||
{
|
||||
public int dummy { get; set; }
|
||||
|
||||
public mspack_system system { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,8 @@ namespace SabreTools.Compression.libmspack
|
||||
/// </summary>
|
||||
/// <see cref="mspack_create_oab_compressor()"/>
|
||||
/// <see cref="mspack_destroy_oab_compressor()"/>
|
||||
public abstract class msoab_compressor
|
||||
public abstract class msoab_compressor : Compressor
|
||||
{
|
||||
public mspack_system system { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Compress a full OAB file.
|
||||
///
|
||||
|
||||
@@ -9,10 +9,8 @@ namespace SabreTools.Compression.libmspack
|
||||
/// </summary>
|
||||
/// <see cref="mspack_create_oab_decompressor()"/>
|
||||
/// <see cref="mspack_destroy_oab_decompressor()"/>
|
||||
public unsafe class msoab_decompressor
|
||||
public unsafe class msoab_decompressor : Decompressor
|
||||
{
|
||||
public mspack_system system { get; set; }
|
||||
|
||||
public int buf_size { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -33,56 +31,54 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <returns>An error code, or MSPACK_ERR.MSPACK_ERR_OK if successful</returns>
|
||||
public MSPACK_ERR decompress(in string input, in string output)
|
||||
{
|
||||
msoab_decompressor_p* self = (msoab_decompressor_p*)_self;
|
||||
mspack_system* sys;
|
||||
mspack_file* infh = NULL;
|
||||
mspack_file* outfh = NULL;
|
||||
byte* buf = NULL;
|
||||
mspack_system sys;
|
||||
mspack_file infh = null;
|
||||
mspack_file outfh = null;
|
||||
byte* buf = null;
|
||||
byte[] hdrbuf = new byte[oabhead_SIZEOF];
|
||||
uint block_max, target_size;
|
||||
lzxd_stream* lzx = NULL;
|
||||
mspack_system oabd_sys;
|
||||
lzxd_stream lzx = null;
|
||||
mspack_oab_system oabd_sys;
|
||||
oabd_file in_ofh, out_ofh;
|
||||
uint window_bits;
|
||||
int ret = MSPACK_ERR_OK;
|
||||
MSPACK_ERR ret = MSPACK_ERR.MSPACK_ERR_OK;
|
||||
|
||||
if (!self) return MSPACK_ERR_ARGS;
|
||||
sys = self->system;
|
||||
sys = this.system;
|
||||
|
||||
infh = sys->open(sys, input, MSPACK_SYS_OPEN_READ);
|
||||
infh = sys.open(sys, input, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_READ);
|
||||
if (!infh)
|
||||
{
|
||||
ret = MSPACK_ERR_OPEN;
|
||||
ret = MSPACK_ERR.MSPACK_ERR_OPEN;
|
||||
goto outlbl;
|
||||
}
|
||||
|
||||
if (sys->read(infh, hdrbuf, oabhead_SIZEOF) != oabhead_SIZEOF)
|
||||
if (sys.read(infh, hdrbuf, oabhead_SIZEOF) != oabhead_SIZEOF)
|
||||
{
|
||||
ret = MSPACK_ERR_READ;
|
||||
ret = MSPACK_ERR.MSPACK_ERR_READ;
|
||||
goto outlbl;
|
||||
}
|
||||
|
||||
if (EndGetI32(&hdrbuf[oabhead_VersionHi]) != 3 ||
|
||||
EndGetI32(&hdrbuf[oabhead_VersionLo]) != 1)
|
||||
{
|
||||
ret = MSPACK_ERR_SIGNATURE;
|
||||
ret = MSPACK_ERR.MSPACK_ERR_SIGNATURE;
|
||||
goto outlbl;
|
||||
}
|
||||
|
||||
block_max = EndGetI32(&hdrbuf[oabhead_BlockMax]);
|
||||
target_size = EndGetI32(&hdrbuf[oabhead_TargetSize]);
|
||||
|
||||
outfh = sys->open(sys, output, MSPACK_SYS_OPEN_WRITE);
|
||||
outfh = sys.open(sys, output, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_WRITE);
|
||||
if (!outfh)
|
||||
{
|
||||
ret = MSPACK_ERR_OPEN;
|
||||
ret = MSPACK_ERR.MSPACK_ERR_OPEN;
|
||||
goto outlbl;
|
||||
}
|
||||
|
||||
buf = sys->alloc(sys, self->buf_size);
|
||||
buf = sys.alloc(sys, this.buf_size);
|
||||
if (!buf)
|
||||
{
|
||||
ret = MSPACK_ERR_NOMEMORY;
|
||||
ret = MSPACK_ERR.MSPACK_ERR_NOMEMORY;
|
||||
goto outlbl;
|
||||
}
|
||||
|
||||
@@ -100,9 +96,9 @@ namespace SabreTools.Compression.libmspack
|
||||
{
|
||||
uint blk_csize, blk_dsize, blk_crc, blk_flags;
|
||||
|
||||
if (sys->read(infh, buf, oabblk_SIZEOF) != oabblk_SIZEOF)
|
||||
if (sys.read(infh, buf, oabblk_SIZEOF) != oabblk_SIZEOF)
|
||||
{
|
||||
ret = MSPACK_ERR_READ;
|
||||
ret = MSPACK_ERR.MSPACK_ERR_READ;
|
||||
goto outlbl;
|
||||
}
|
||||
blk_flags = EndGetI32(&buf[oabblk_Flags]);
|
||||
@@ -112,7 +108,7 @@ namespace SabreTools.Compression.libmspack
|
||||
|
||||
if (blk_dsize > block_max || blk_dsize > target_size || blk_flags > 1)
|
||||
{
|
||||
ret = MSPACK_ERR_DATAFORMAT;
|
||||
ret = MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
|
||||
goto outlbl;
|
||||
}
|
||||
|
||||
@@ -121,10 +117,10 @@ namespace SabreTools.Compression.libmspack
|
||||
/* Uncompressed block */
|
||||
if (blk_dsize != blk_csize)
|
||||
{
|
||||
ret = MSPACK_ERR_DATAFORMAT;
|
||||
ret = MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
|
||||
goto outlbl;
|
||||
}
|
||||
ret = copy_fh(sys, infh, outfh, blk_dsize, buf, self->buf_size);
|
||||
ret = copy_fh(sys, infh, outfh, blk_dsize, buf, this.buf_size);
|
||||
if (ret) goto outlbl;
|
||||
}
|
||||
else
|
||||
@@ -139,27 +135,27 @@ namespace SabreTools.Compression.libmspack
|
||||
out_ofh.crc = 0xffffffff;
|
||||
|
||||
lzx = lzxd_init(&oabd_sys, (void*)&in_ofh, (void*)&out_ofh, window_bits,
|
||||
0, self->buf_size, blk_dsize, 1);
|
||||
0, this.buf_size, blk_dsize, 1);
|
||||
if (!lzx)
|
||||
{
|
||||
ret = MSPACK_ERR_NOMEMORY;
|
||||
ret = MSPACK_ERR.MSPACK_ERR_NOMEMORY;
|
||||
goto outlbl;
|
||||
}
|
||||
|
||||
ret = lzxd_decompress(lzx, blk_dsize);
|
||||
if (ret != MSPACK_ERR_OK)
|
||||
if (ret != MSPACK_ERR.MSPACK_ERR_OK)
|
||||
goto outlbl;
|
||||
|
||||
lzxd_free(lzx);
|
||||
lzx = NULL;
|
||||
lzx = null;
|
||||
|
||||
/* Consume any trailing padding bytes before the next block */
|
||||
ret = copy_fh(sys, infh, NULL, in_ofh.available, buf, self->buf_size);
|
||||
ret = copy_fh(sys, infh, null, in_ofh.available, buf, this.buf_size);
|
||||
if (ret) goto outlbl;
|
||||
|
||||
if (out_ofh.crc != blk_crc)
|
||||
{
|
||||
ret = MSPACK_ERR_CHECKSUM;
|
||||
ret = MSPACK_ERR.MSPACK_ERR_CHECKSUM;
|
||||
goto outlbl;
|
||||
}
|
||||
}
|
||||
@@ -168,9 +164,9 @@ namespace SabreTools.Compression.libmspack
|
||||
|
||||
outlbl:
|
||||
if (lzx) lzxd_free(lzx);
|
||||
if (outfh) sys->close(outfh);
|
||||
if (infh) sys->close(infh);
|
||||
sys->free(buf);
|
||||
if (outfh) sys.close(outfh);
|
||||
if (infh) sys.close(infh);
|
||||
sys.free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -8,19 +8,18 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <summary>
|
||||
/// Creates a new CAB compressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">A custom mspack_system structure, or NULL to use the default</param>
|
||||
/// <returns>A <see cref="mscab_compressor"/> or NULL</returns>
|
||||
/// <param name="sys">A custom mspack_system structure, or null to use the default</param>
|
||||
/// <returns>A <see cref="mscab_compressor"/> or null</returns>
|
||||
public static mscab_compressor mspack_create_cab_compressor(mspack_system sys) => null;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new CAB decompressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">A custom mspack_system structure, or NULL to use the default</param>
|
||||
/// <returns>A <see cref="mscab_decompressor"/> or NULL</returns>
|
||||
/// <param name="sys">A custom mspack_system structure, or null to use the default</param>
|
||||
/// <returns>A <see cref="mscab_decompressor"/> or null</returns>
|
||||
public static mscab_decompressor mspack_create_cab_decompressor(mspack_system sys)
|
||||
{
|
||||
if (sys == null)
|
||||
return null;
|
||||
if (sys == null) sys = new mspack_mscab_system();
|
||||
|
||||
var self = new mscab_decompressor
|
||||
{
|
||||
@@ -66,15 +65,15 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <summary>
|
||||
/// Creates a new CHM compressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">A custom mspack_system structure, or NULL to use the default</param>
|
||||
/// <returns>A <see cref="mschm_compressor"/> or NULL</returns>
|
||||
/// <param name="sys">A custom mspack_system structure, or null to use the default</param>
|
||||
/// <returns>A <see cref="mschm_compressor"/> or null</returns>
|
||||
public static mschm_compressor mspack_create_chm_compressor(mspack_system sys) => null;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new CHM decompressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">A custom mspack_system structure, or NULL to use the default</param>
|
||||
/// <returns>A <see cref="mschm_decompressor"/> or NULL</returns>
|
||||
/// <param name="sys">A custom mspack_system structure, or null to use the default</param>
|
||||
/// <returns>A <see cref="mschm_decompressor"/> or null</returns>
|
||||
public static mschm_decompressor mspack_create_chm_decompressor(mspack_system sys) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
@@ -92,15 +91,15 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <summary>
|
||||
/// Creates a new LIT compressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">A custom mspack_system structure, or NULL to use the default</param>
|
||||
/// <returns>A <see cref="mslit_compressor"/> or NULL</returns>
|
||||
/// <param name="sys">A custom mspack_system structure, or null to use the default</param>
|
||||
/// <returns>A <see cref="mslit_compressor"/> or null</returns>
|
||||
public static mslit_compressor mspack_create_lit_compressor(mspack_system sys) => null;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new LIT decompressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">A custom mspack_system structure, or NULL to use the default</param>
|
||||
/// <returns>A <see cref="mslit_decompressor"/> or NULL</returns>
|
||||
/// <param name="sys">A custom mspack_system structure, or null to use the default</param>
|
||||
/// <returns>A <see cref="mslit_decompressor"/> or null</returns>
|
||||
public static mslit_decompressor mspack_create_lit_decompressor(mspack_system sys) => null;
|
||||
|
||||
/// <summary>
|
||||
@@ -118,15 +117,15 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <summary>
|
||||
/// Creates a new HLP compressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">A custom mspack_system structure, or NULL to use the default</param>
|
||||
/// <returns>A <see cref="mshlp_compressor"/> or NULL</returns>
|
||||
/// <param name="sys">A custom mspack_system structure, or null to use the default</param>
|
||||
/// <returns>A <see cref="mshlp_compressor"/> or null</returns>
|
||||
public static mshlp_compressor mspack_create_hlp_compressor(mspack_system sys) => null;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new HLP decompressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">A custom mspack_system structure, or NULL to use the default</param>
|
||||
/// <returns>A <see cref="mshlp_decompressor"/> or NULL</returns>
|
||||
/// <param name="sys">A custom mspack_system structure, or null to use the default</param>
|
||||
/// <returns>A <see cref="mshlp_decompressor"/> or null</returns>
|
||||
public static mshlp_decompressor mspack_create_hlp_decompressor(mspack_system sys) => null;
|
||||
|
||||
/// <summary>
|
||||
@@ -144,15 +143,15 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <summary>
|
||||
/// Creates a new SZDD compressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">A custom mspack_system structure, or NULL to use the default</param>
|
||||
/// <returns>A <see cref="msszdd_compressor"/> or NULL</returns>
|
||||
/// <param name="sys">A custom mspack_system structure, or null to use the default</param>
|
||||
/// <returns>A <see cref="msszdd_compressor"/> or null</returns>
|
||||
public static msszdd_compressor mspack_create_szdd_compressor(mspack_system sys) => null;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new SZDD decompressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">A custom mspack_system structure, or NULL to use the default</param>
|
||||
/// <returns>A <see cref="msszdd_decompressor"/> or NULL</returns>
|
||||
/// <param name="sys">A custom mspack_system structure, or null to use the default</param>
|
||||
/// <returns>A <see cref="msszdd_decompressor"/> or null</returns>
|
||||
public static msszdd_decompressor mspack_create_szdd_decompressor(mspack_system sys)
|
||||
{
|
||||
msszdd_decompressor self = null;
|
||||
@@ -188,15 +187,15 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <summary>
|
||||
/// Creates a new KWAJ compressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">A custom mspack_system structure, or NULL to use the default</param>
|
||||
/// <returns>A <see cref="mskwaj_compressor"/> or NULL</returns>
|
||||
/// <param name="sys">A custom mspack_system structure, or null to use the default</param>
|
||||
/// <returns>A <see cref="mskwaj_compressor"/> or null</returns>
|
||||
public static mskwaj_compressor mspack_create_kwaj_compressor(mspack_system sys) => null;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new KWAJ decompressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">A custom mspack_system structure, or NULL to use the default</param>
|
||||
/// <returns>A <see cref="mskwaj_decompressor"/> or NULL</returns>
|
||||
/// <param name="sys">A custom mspack_system structure, or null to use the default</param>
|
||||
/// <returns>A <see cref="mskwaj_decompressor"/> or null</returns>
|
||||
public static mskwaj_decompressor mspack_create_kwaj_decompressor(mspack_system sys) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
@@ -214,22 +213,37 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <summary>
|
||||
/// Creates a new OAB compressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">A custom mspack_system structure, or NULL to use the default</param>
|
||||
/// <returns>A <see cref="msoab_compressor"/> or NULL</returns>
|
||||
public static msoab_compressor mspack_create_oab_compressor(mspack_system sys) => null;
|
||||
/// <param name="sys">A custom mspack_system structure, or null to use the default</param>
|
||||
/// <returns>A <see cref="msoab_compressor"/> or null</returns>
|
||||
public static msoab_compressor mspack_create_oab_compressor(mspack_system sys) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new OAB decompressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">A custom mspack_system structure, or NULL to use the default</param>
|
||||
/// <returns>A <see cref="msoab_decompressor"/> or NULL</returns>
|
||||
public static msoab_decompressor mspack_create_oab_decompressor(mspack_system sys) => throw new NotImplementedException();
|
||||
/// <param name="sys">A custom mspack_system structure, or null to use the default</param>
|
||||
/// <returns>A <see cref="msoab_decompressor"/> or null</returns>
|
||||
public static msoab_decompressor mspack_create_oab_decompressor(mspack_system sys)
|
||||
{
|
||||
if (sys == null) sys = new mspack_oab_system();
|
||||
|
||||
msoab_decompressor self = new msoab_decompressor();
|
||||
self.system = sys;
|
||||
self.buf_size = 4096;
|
||||
return self;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys an existing OAB compressor.
|
||||
/// </summary>
|
||||
/// <param name="self">The <see cref="msoab_compressor"/> to destroy</param>
|
||||
public static void mspack_destroy_oab_compressor(msoab_compressor self) { }
|
||||
public static void mspack_destroy_oab_compressor(msoab_compressor self)
|
||||
{
|
||||
if (self != null)
|
||||
{
|
||||
mspack_system sys = self.system;
|
||||
//sys.free(self);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys an existing OAB decompressor.
|
||||
|
||||
230
libmspack/mspack_mscab_system.cs
Normal file
230
libmspack/mspack_mscab_system.cs
Normal file
@@ -0,0 +1,230 @@
|
||||
using static SabreTools.Compression.libmspack.cab;
|
||||
|
||||
namespace SabreTools.Compression.libmspack
|
||||
{
|
||||
public unsafe class mspack_mscab_system : mspack_default_system
|
||||
{
|
||||
/// <summary>
|
||||
/// cabd_sys_read is the internal reader function which the decompressors
|
||||
/// use. will read data blocks (and merge split blocks) from the cabinet
|
||||
/// and serve the read bytes to the decompressors
|
||||
/// </summary>
|
||||
public override unsafe int read(mspack_file file, void* buffer, int bytes)
|
||||
{
|
||||
mscab_decompressor self = (mscab_decompressor)file;
|
||||
byte* buf = (byte*)buffer;
|
||||
mspack_system sys = self.system;
|
||||
int avail, todo, outlen, ignore_cksum, ignore_blocksize;
|
||||
|
||||
ignore_cksum = self.salvage != 0 || (self.fix_mszip != 0 && (((int)self.d.comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_MSZIP)) == true ? 1 : 0;
|
||||
ignore_blocksize = self.salvage;
|
||||
|
||||
todo = bytes;
|
||||
while (todo > 0)
|
||||
{
|
||||
avail = (int)(self.d.i_end - self.d.i_ptr);
|
||||
|
||||
// If out of input data, read a new block
|
||||
if (avail != 0)
|
||||
{
|
||||
// Copy as many input bytes available as possible
|
||||
if (avail > todo) avail = todo;
|
||||
sys.copy(self.d.i_ptr, buf, avail);
|
||||
self.d.i_ptr += avail;
|
||||
buf += avail;
|
||||
todo -= avail;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Out of data, read a new block
|
||||
|
||||
// Check if we're out of input blocks, advance block counter
|
||||
if (self.d.block++ >= self.d.folder.num_blocks)
|
||||
{
|
||||
if (self.salvage == 0)
|
||||
{
|
||||
self.read_error = MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.Console.Error.WriteLine("Ran out of CAB input blocks prematurely");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Read a block
|
||||
self.read_error = cabd_sys_read_block(sys, self.d, ref outlen, ignore_cksum, ignore_blocksize);
|
||||
if (self.read_error != MSPACK_ERR.MSPACK_ERR_OK) return -1;
|
||||
self.d.outlen += outlen;
|
||||
|
||||
// Special Quantum hack -- trailer byte to allow the decompressor
|
||||
// to realign itself. CAB Quantum blocks, unlike LZX blocks, can have
|
||||
// anything from 0 to 4 trailing null bytes.
|
||||
if (((int)self.d.comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_QUANTUM)
|
||||
{
|
||||
*self.d.i_end++ = 0xFF;
|
||||
}
|
||||
|
||||
// Is this the last block?
|
||||
if (self.d.block >= self.d.folder.num_blocks)
|
||||
{
|
||||
if (((int)self.d.comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_LZX)
|
||||
{
|
||||
/* special LZX hack -- on the last block, inform LZX of the
|
||||
* size of the output data stream. */
|
||||
lzxd_set_output_length((lzxd_stream)self.d.state, self.d.outlen);
|
||||
}
|
||||
}
|
||||
} /* if (avail) */
|
||||
} /* while (todo > 0) */
|
||||
return bytes - todo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// cabd_sys_write is the internal writer function which the decompressors
|
||||
/// use. it either writes data to disk (self.d.outfh) with the real
|
||||
/// sys.write() function, or does nothing with the data when
|
||||
/// self.d.outfh == null. advances self.d.offset
|
||||
/// </summary>
|
||||
public override unsafe int write(mspack_file file, void* buffer, int bytes)
|
||||
{
|
||||
mscab_decompressor self = (mscab_decompressor)file;
|
||||
self.d.offset += (uint)bytes;
|
||||
if (self.d.outfh != null)
|
||||
{
|
||||
return self.system.write(self.d.outfh, buffer, bytes);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a whole data block from a cab file. the block may span more than
|
||||
/// one cab file, if it does then the fragments will be reassembled
|
||||
/// </summary>
|
||||
private static MSPACK_ERR cabd_sys_read_block(mspack_system sys, mscabd_decompress_state d, ref int @out, int ignore_cksum, int ignore_blocksize)
|
||||
{
|
||||
byte[] hdr = new byte[cfdata_SIZEOF];
|
||||
uint cksum;
|
||||
int len, full_len;
|
||||
|
||||
// Reset the input block pointer and end of block pointer
|
||||
d.i_ptr = d.i_end = system.GetArrayPointer(d.input);
|
||||
|
||||
do
|
||||
{
|
||||
// Read the block header
|
||||
if (sys.read(d.infh, system.GetArrayPointer(hdr), cfdata_SIZEOF) != cfdata_SIZEOF)
|
||||
{
|
||||
return MSPACK_ERR.MSPACK_ERR_READ;
|
||||
}
|
||||
|
||||
// Skip any reserved block headers
|
||||
if (d.data.cab.block_resv != 0 &&
|
||||
sys.seek(d.infh, d.data.cab.block_resv, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_CUR) != 0)
|
||||
{
|
||||
return MSPACK_ERR.MSPACK_ERR_SEEK;
|
||||
}
|
||||
|
||||
// Blocks must not be over CAB_INPUTMAX in size
|
||||
len = EndGetI16(&hdr[cfdata_CompressedSize]);
|
||||
full_len = (int)(d.i_end - d.i_ptr + len); // Include cab-spanning blocks */
|
||||
if (full_len > CAB_INPUTMAX)
|
||||
{
|
||||
System.Console.Error.WriteLine($"Block size {full_len} > CAB_INPUTMAX");
|
||||
// In salvage mode, blocks can be 65535 bytes but no more than that
|
||||
if (ignore_blocksize == 0 || full_len > CAB_INPUTMAX_SALVAGE)
|
||||
{
|
||||
return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
|
||||
}
|
||||
}
|
||||
|
||||
// Blocks must not expand to more than CAB_BLOCKMAX
|
||||
if (EndGetI16(&hdr[cfdata_UncompressedSize]) > CAB_BLOCKMAX)
|
||||
{
|
||||
System.Console.Error.WriteLine("block size > CAB_BLOCKMAX");
|
||||
if (ignore_blocksize == 0) return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
|
||||
}
|
||||
|
||||
// Read the block data
|
||||
if (sys.read(d.infh, d.i_end, len) != len)
|
||||
{
|
||||
return MSPACK_ERR.MSPACK_ERR_READ;
|
||||
}
|
||||
|
||||
// Perform checksum test on the block (if one is stored)
|
||||
if ((cksum = EndGetI32(&hdr[cfdata_CheckSum])))
|
||||
{
|
||||
uint sum2 = cabd_checksum(d.i_end, (uint)len, 0);
|
||||
if (cabd_checksum(&hdr[4], 4, sum2) != cksum)
|
||||
{
|
||||
if (ignore_cksum == 0) return MSPACK_ERR.MSPACK_ERR_CHECKSUM;
|
||||
sys.message(d.infh, "WARNING; bad block checksum found");
|
||||
}
|
||||
}
|
||||
|
||||
// Advance end of block pointer to include newly read data
|
||||
d.i_end += len;
|
||||
|
||||
// Uncompressed size == 0 means this block was part of a split block
|
||||
// and it continues as the first block of the next cabinet in the set.
|
||||
// otherwise, this is the last part of the block, and no more block
|
||||
// reading needs to be done.
|
||||
|
||||
// EXIT POINT OF LOOP -- uncompressed size != 0
|
||||
if ((@out = EndGetI16(&hdr[cfdata_UncompressedSize])))
|
||||
{
|
||||
return MSPACK_ERR.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
// Otherwise, advance to next cabinet
|
||||
|
||||
// Close current file handle
|
||||
sys.close(d.infh);
|
||||
d.infh = null;
|
||||
|
||||
// Aadvance to next member in the cabinet set
|
||||
if ((d.data = d.data.next) == null)
|
||||
{
|
||||
sys.message(d.infh, "WARNING; ran out of cabinets in set. Are any missing?");
|
||||
return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
|
||||
}
|
||||
|
||||
// Open next cab file
|
||||
d.incab = d.data.cab;
|
||||
if ((d.infh = sys.open(d.incab.filename, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_READ)) == null)
|
||||
{
|
||||
return MSPACK_ERR.MSPACK_ERR_OPEN;
|
||||
}
|
||||
|
||||
// Seek to start of data blocks
|
||||
if (sys.seek(d.infh, d.data.offset, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_START) != 0)
|
||||
{
|
||||
return MSPACK_ERR.MSPACK_ERR_SEEK;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
// Not reached
|
||||
return MSPACK_ERR.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
private static uint cabd_checksum(byte* data, uint bytes, uint cksum)
|
||||
{
|
||||
uint len, ul = 0;
|
||||
|
||||
for (len = bytes >> 2; len-- > 0; data += 4)
|
||||
{
|
||||
cksum ^= EndGetI32(data);
|
||||
}
|
||||
|
||||
switch (bytes & 3)
|
||||
{
|
||||
case 3: ul |= (uint)(*data++ << 16); goto case 2;
|
||||
case 2: ul |= (uint)(*data++ << 8); goto case 1;
|
||||
case 1: ul |= *data; break;
|
||||
}
|
||||
cksum ^= ul;
|
||||
|
||||
return cksum;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ namespace SabreTools.Compression.libmspack
|
||||
/// with the file system and to allocate, free and copy all memory. It also
|
||||
/// uses it to send literal messages to the library user.
|
||||
///
|
||||
/// When the library is compiled normally, passing NULL to a compressor or
|
||||
/// When the library is compiled normally, passing null to a compressor or
|
||||
/// decompressor constructor will result in a default mspack_system being
|
||||
/// used, where all methods are implemented with the standard C library.
|
||||
///
|
||||
@@ -35,7 +35,7 @@ namespace SabreTools.Compression.libmspack
|
||||
/// A pointer to a mspack_file structure. This structure officially
|
||||
/// contains no members, its true contents are up to the
|
||||
/// mspack_system implementor. It should contain whatever is needed
|
||||
/// for other mspack_system methods to operate. Returning the NULL
|
||||
/// for other mspack_system methods to operate. Returning the null
|
||||
/// pointer indicates an error condition.
|
||||
/// </returns>
|
||||
/// <see cref="close(mspack_file)"/>
|
||||
@@ -127,7 +127,7 @@ namespace SabreTools.Compression.libmspack
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// May be a file handle returned from open() if this message
|
||||
/// pertains to a specific open file, or NULL if not related to
|
||||
/// pertains to a specific open file, or null if not related to
|
||||
/// a specific file.
|
||||
/// </param>
|
||||
/// <param name="format">
|
||||
@@ -141,7 +141,7 @@ namespace SabreTools.Compression.libmspack
|
||||
/// </summary>
|
||||
/// <param name="bytes">The number of bytes to allocate</param>
|
||||
/// <returns>
|
||||
/// A pointer to the requested number of bytes, or NULL if
|
||||
/// A pointer to the requested number of bytes, or null if
|
||||
/// not enough memory is available
|
||||
/// </returns>
|
||||
/// <see cref="free(void*)"/>
|
||||
@@ -150,7 +150,7 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <summary>
|
||||
/// Frees memory
|
||||
/// </summary>
|
||||
/// <param name="ptr">The memory to be freed. NULL is accepted and ignored.</param>
|
||||
/// <param name="ptr">The memory to be freed. null is accepted and ignored.</param>
|
||||
/// <see cref="alloc(int)"/>
|
||||
public abstract void free(void* ptr);
|
||||
|
||||
|
||||
@@ -7,10 +7,8 @@ namespace SabreTools.Compression.libmspack
|
||||
/// </summary>
|
||||
/// <see cref="mspack_create_szdd_compressor()"/>
|
||||
/// <see cref="mspack_destroy_szdd_compressor()"/>
|
||||
public abstract class msszdd_compressor
|
||||
public abstract class msszdd_compressor : Compressor
|
||||
{
|
||||
public mspack_system system { get; set; }
|
||||
|
||||
public MSPACK_ERR error { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -10,10 +10,8 @@ namespace SabreTools.Compression.libmspack
|
||||
/// </summary>
|
||||
/// <see cref="mspack_create_szdd_decompressor()"/>
|
||||
/// <see cref="mspack_destroy_szdd_decompressor()"/>
|
||||
public unsafe class msszdd_decompressor
|
||||
public unsafe class msszdd_decompressor : Decompressor
|
||||
{
|
||||
public mspack_system system { get; set; }
|
||||
|
||||
public MSPACK_ERR error { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace SabreTools.Compression.libmspack
|
||||
///
|
||||
/// - uses system->alloc() to allocate memory
|
||||
///
|
||||
/// - returns NULL if not enough memory
|
||||
/// - returns null if not enough memory
|
||||
///
|
||||
/// - input_buffer_size is how many bytes to use as an input bitstream buffer
|
||||
///
|
||||
|
||||
@@ -3,28 +3,8 @@ using static SabreTools.Compression.libmspack.mszip;
|
||||
|
||||
namespace SabreTools.Compression.libmspack
|
||||
{
|
||||
public unsafe class mszipd_stream
|
||||
public unsafe class mszipd_stream : readbits
|
||||
{
|
||||
/// <summary>
|
||||
/// I/O routines
|
||||
/// </summary>
|
||||
public mspack_system sys { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Input file handle
|
||||
/// </summary>
|
||||
public mspack_file input { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Output file handle
|
||||
/// </summary>
|
||||
public mspack_file output { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Offset within window
|
||||
/// </summary>
|
||||
public uint window_posn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// inflate() will call this whenever the window should be emptied.
|
||||
/// </summary>
|
||||
@@ -32,34 +12,10 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <returns></returns>
|
||||
public int flush_window(uint val) => 0;
|
||||
|
||||
public MSPACK_ERR error { get; set; }
|
||||
|
||||
public int repair_mode { get; set; }
|
||||
|
||||
public int bytes_output { get; set; }
|
||||
|
||||
#region I/O buffering
|
||||
|
||||
public byte* inbuf { get; set; }
|
||||
|
||||
public byte* i_ptr { get; set; }
|
||||
|
||||
public byte* i_end { get; set; }
|
||||
|
||||
public byte* o_ptr { get; set; }
|
||||
|
||||
public byte* o_end { get; set; }
|
||||
|
||||
public byte input_end { get; set; }
|
||||
|
||||
public uint bit_buffer { get; set; }
|
||||
|
||||
public uint bits_left { get; set; }
|
||||
|
||||
public uint inbuf_size { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Huffman code lengths
|
||||
|
||||
public byte[] LITERAL_len { get; set; } = new byte[MSZIP_LITERAL_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
|
||||
@@ -80,5 +36,11 @@ namespace SabreTools.Compression.libmspack
|
||||
/// 32kb history window
|
||||
/// </summary>
|
||||
public byte[] window { get; set; } = new byte[MSZIP_FRAME_SIZE];
|
||||
|
||||
public override void READ_BYTES()
|
||||
{
|
||||
READ_IF_NEEDED;
|
||||
INJECT_BITS_LSB(*i_ptr++, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
18
libmspack/noned_state.cs
Normal file
18
libmspack/noned_state.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
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; }
|
||||
}
|
||||
}
|
||||
221
libmspack/qtm.cs
221
libmspack/qtm.cs
@@ -1,17 +1,142 @@
|
||||
namespace SabreTools.Compression.libmspack
|
||||
{
|
||||
public static class qtm
|
||||
public unsafe static class qtm
|
||||
{
|
||||
public const int QTM_FRAME_SIZE = 32768;
|
||||
|
||||
#region Quantum static data tables
|
||||
|
||||
/*
|
||||
* Quantum uses 'position slots' to represent match offsets. For every
|
||||
* match, a small 'position slot' number and a small offset from that slot
|
||||
* are encoded instead of one large offset.
|
||||
*
|
||||
* position_base[] is an index to the position slot bases
|
||||
*
|
||||
* extra_bits[] states how many bits of offset-from-base data is needed.
|
||||
*
|
||||
* length_base[] and length_extra[] are equivalent in function, but are
|
||||
* used for encoding selector 6 (variable length match) match lengths,
|
||||
* instead of match offsets.
|
||||
*
|
||||
* They are generated with the following code:
|
||||
* unsigned int i, offset;
|
||||
* for (i = 0, offset = 0; i < 42; i++) {
|
||||
* position_base[i] = offset;
|
||||
* extra_bits[i] = ((i < 2) ? 0 : (i - 2)) >> 1;
|
||||
* offset += 1 << extra_bits[i];
|
||||
* }
|
||||
* for (i = 0, offset = 0; i < 26; i++) {
|
||||
* length_base[i] = offset;
|
||||
* length_extra[i] = (i < 2 ? 0 : i - 2) >> 2;
|
||||
* offset += 1 << length_extra[i];
|
||||
* }
|
||||
* length_base[26] = 254; length_extra[26] = 0;
|
||||
*/
|
||||
|
||||
private static readonly uint[] position_base = new uint[42]
|
||||
{
|
||||
0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
|
||||
1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152,
|
||||
65536, 98304, 131072, 196608, 262144, 393216, 524288, 786432, 1048576, 1572864
|
||||
};
|
||||
private static readonly byte[] extra_bits = new byte[42]
|
||||
{
|
||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
|
||||
11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19
|
||||
};
|
||||
|
||||
private static readonly byte[] length_base = new byte[27]
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 14, 18, 22, 26,
|
||||
30, 38, 46, 54, 62, 78, 94, 110, 126, 158, 190, 222, 254
|
||||
};
|
||||
|
||||
private static readonly byte[] length_extra = new byte[27]
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
private static void qtmd_update_model(qtmd_model model)
|
||||
{
|
||||
qtmd_modelsym tmp;
|
||||
int i, j;
|
||||
|
||||
if (--model.shiftsleft > 0)
|
||||
{
|
||||
for (i = model.entries - 1; i >= 0; i--)
|
||||
{
|
||||
/* -1, not -2; the 0 entry saves this */
|
||||
model.syms[i].cumfreq >>= 1;
|
||||
if (model.syms[i].cumfreq <= model.syms[i + 1].cumfreq)
|
||||
{
|
||||
model.syms[i].cumfreq = (ushort)(model.syms[i + 1].cumfreq + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
model.shiftsleft = 50;
|
||||
for (i = 0; i < model.entries; i++)
|
||||
{
|
||||
/* no -1, want to include the 0 entry */
|
||||
/* this converts cumfreqs into frequencies, then shifts right */
|
||||
model.syms[i].cumfreq -= model.syms[i + 1].cumfreq;
|
||||
model.syms[i].cumfreq++; /* avoid losing things entirely */
|
||||
model.syms[i].cumfreq >>= 1;
|
||||
}
|
||||
|
||||
/* now sort by frequencies, decreasing order -- this must be an
|
||||
* inplace selection sort, or a sort with the same (in)stability
|
||||
* characteristics */
|
||||
for (i = 0; i < model.entries - 1; i++)
|
||||
{
|
||||
for (j = i + 1; j < model.entries; j++)
|
||||
{
|
||||
if (model.syms[i].cumfreq < model.syms[j].cumfreq)
|
||||
{
|
||||
tmp = model.syms[i];
|
||||
model.syms[i] = model.syms[j];
|
||||
model.syms[j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* then convert frequencies back to cumfreq */
|
||||
for (i = model.entries - 1; i >= 0; i--)
|
||||
{
|
||||
model.syms[i].cumfreq += model.syms[i + 1].cumfreq;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialises a model to decode symbols from [start] to [start]+[len]-1
|
||||
/// </summary>
|
||||
private static void qtmd_init_model(qtmd_model model, qtmd_modelsym* syms, int start, int len)
|
||||
{
|
||||
model.shiftsleft = 4;
|
||||
model.entries = len;
|
||||
model.syms = syms;
|
||||
|
||||
for (int i = 0; i <= len; i++)
|
||||
{
|
||||
syms[i].sym = (ushort)(start + i); // Actual symbol
|
||||
syms[i].cumfreq = (ushort)(len - i); // Current frequency of that symbol
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allocates Quantum decompression state for decoding the given stream.
|
||||
///
|
||||
/// - returns NULL if window_bits is outwith the range 10 to 21 (inclusive).
|
||||
/// - returns null if window_bits is outwith the range 10 to 21 (inclusive).
|
||||
///
|
||||
/// - uses system->alloc() to allocate memory
|
||||
/// - uses system.alloc() to allocate memory
|
||||
///
|
||||
/// - returns NULL if not enough memory
|
||||
/// - returns null if not enough memory
|
||||
///
|
||||
/// - window_bits is the size of the Quantum window, from 1Kb (10) to 2Mb (21).
|
||||
///
|
||||
@@ -23,8 +148,70 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <param name="window_bits"></param>
|
||||
/// <param name="input_buffer_size"></param>
|
||||
/// <returns></returns>
|
||||
public static qtmd_stream qtmd_init(mspack_system system, mspack_file input, mspack_file output, int window_bits, int input_buffer_size) => null;
|
||||
|
||||
public static qtmd_stream qtmd_init(mspack_system system, mspack_file input, mspack_file output, int window_bits, int input_buffer_size)
|
||||
{
|
||||
uint window_size = (uint)(1 << window_bits);
|
||||
int i;
|
||||
|
||||
if (system == null) return null;
|
||||
|
||||
// Quantum supports window sizes of 2^10 (1Kb) through 2^21 (2Mb)
|
||||
if (window_bits < 10 || window_bits > 21) return null;
|
||||
|
||||
// Round up input buffer size to multiple of two
|
||||
input_buffer_size = (input_buffer_size + 1) & -2;
|
||||
if (input_buffer_size < 2) return null;
|
||||
|
||||
// Allocate decompression state
|
||||
qtmd_stream qtm = new qtmd_stream();
|
||||
|
||||
// Allocate decompression window and input buffer
|
||||
qtm.window = (byte*)system.alloc((int)window_size);
|
||||
qtm.inbuf = (byte*)system.alloc((int)input_buffer_size);
|
||||
if (qtm.window == null || qtm.inbuf == null)
|
||||
{
|
||||
system.free(qtm.window);
|
||||
system.free(qtm.inbuf);
|
||||
//system.free(qtm);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Initialise decompression state
|
||||
qtm.sys = system;
|
||||
qtm.input = input;
|
||||
qtm.output = output;
|
||||
qtm.inbuf_size = (uint)input_buffer_size;
|
||||
qtm.window_size = window_size;
|
||||
qtm.window_posn = 0;
|
||||
qtm.frame_todo = QTM_FRAME_SIZE;
|
||||
qtm.header_read = 0;
|
||||
qtm.error = MSPACK_ERR.MSPACK_ERR_OK;
|
||||
|
||||
qtm.i_ptr = qtm.i_end = &qtm.inbuf[0];
|
||||
qtm.o_ptr = qtm.o_end = &qtm.window[0];
|
||||
qtm.input_end = 0;
|
||||
qtm.bits_left = 0;
|
||||
qtm.bit_buffer = 0;
|
||||
|
||||
// Initialise arithmetic coding models
|
||||
// - model 4 depends on window size, ranges from 20 to 24
|
||||
// - model 5 depends on window size, ranges from 20 to 36
|
||||
// - model 6pos depends on window size, ranges from 20 to 42
|
||||
i = window_bits * 2;
|
||||
qtmd_init_model(qtm.model0, qtm.m0sym, 0, 64);
|
||||
qtmd_init_model(qtm.model1, qtm.m1sym, 64, 64);
|
||||
qtmd_init_model(qtm.model2, qtm.m2sym, 128, 64);
|
||||
qtmd_init_model(qtm.model3, qtm.m3sym, 192, 64);
|
||||
qtmd_init_model(qtm.model4, qtm.m4sym, 0, (i > 24) ? 24 : i);
|
||||
qtmd_init_model(qtm.model5, qtm.m5sym, 0, (i > 36) ? 36 : i);
|
||||
qtmd_init_model(qtm.model6, qtm.m6sym, 0, i);
|
||||
qtmd_init_model(qtm.model6len, qtm.m6lsym, 0, 27);
|
||||
qtmd_init_model(qtm.model7, qtm.m7sym, 0, 7);
|
||||
|
||||
// All ok
|
||||
return qtm;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decompresses, or decompresses more of, a Quantum stream.
|
||||
///
|
||||
@@ -35,13 +222,13 @@ namespace SabreTools.Compression.libmspack
|
||||
/// amount of bytes decoded spills over that amount, they will be kept for
|
||||
/// a later invocation of qtmd_decompress().
|
||||
///
|
||||
/// - the output bytes will be passed to the system->write() function given in
|
||||
/// - the output bytes will be passed to the system.write() function given in
|
||||
/// qtmd_init(), using the output file handle given in qtmd_init(). More
|
||||
/// than one call may be made to system->write()
|
||||
/// than one call may be made to system.write()
|
||||
///
|
||||
/// - Quantum will read input bytes as necessary using the system->read()
|
||||
/// - Quantum will read input bytes as necessary using the system.read()
|
||||
/// function given in qtmd_init(), using the input file handle given in
|
||||
/// qtmd_init(). This will continue until system->read() returns 0 bytes,
|
||||
/// qtmd_init(). This will continue until system.read() returns 0 bytes,
|
||||
/// or an error.
|
||||
/// </summary>
|
||||
/// <param name="qtm"></param>
|
||||
@@ -52,9 +239,19 @@ namespace SabreTools.Compression.libmspack
|
||||
/// <summary>
|
||||
/// Frees all state associated with a Quantum data stream
|
||||
///
|
||||
/// - calls system->free() using the system pointer given in qtmd_init()
|
||||
/// - calls system.free() using the system pointer given in qtmd_init()
|
||||
/// </summary>
|
||||
/// <param name="qtm"></param>
|
||||
public static void qtmd_free(qtmd_stream qtm) { }
|
||||
public static void qtmd_free(qtmd_stream qtm)
|
||||
{
|
||||
mspack_system sys;
|
||||
if (qtm != null)
|
||||
{
|
||||
sys = qtm.sys;
|
||||
//sys.free(qtm.window);
|
||||
//sys.free(qtm.inbuf);
|
||||
//sys.free(qtm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,6 @@ namespace SabreTools.Compression.libmspack
|
||||
|
||||
public int entries { get; set; }
|
||||
|
||||
public qtmd_modelsym** syms { get; set; }
|
||||
public qtmd_modelsym* syms { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,7 @@
|
||||
namespace SabreTools.Compression.libmspack
|
||||
{
|
||||
public unsafe class qtmd_stream
|
||||
public unsafe class qtmd_stream : readbits
|
||||
{
|
||||
/// <summary>
|
||||
/// I/O routines
|
||||
/// </summary>
|
||||
public mspack_system sys { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Input file handle
|
||||
/// </summary>
|
||||
public mspack_file input { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Output file handle
|
||||
/// </summary>
|
||||
public mspack_file output { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Decoding window
|
||||
/// </summary>
|
||||
@@ -27,11 +12,6 @@ namespace SabreTools.Compression.libmspack
|
||||
/// </summary>
|
||||
public uint window_size { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Decompression offset within window
|
||||
/// </summary>
|
||||
public uint window_posn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Bytes remaining for current frame
|
||||
/// </summary>
|
||||
@@ -57,30 +37,6 @@ namespace SabreTools.Compression.libmspack
|
||||
/// </summary>
|
||||
public byte header_read { get; set; }
|
||||
|
||||
public MSPACK_ERR error { get; set; }
|
||||
|
||||
#region I/O buffering
|
||||
|
||||
public byte* inbuf { get; set; }
|
||||
|
||||
public byte* i_ptr { get; set; }
|
||||
|
||||
public byte* i_end { get; set; }
|
||||
|
||||
public byte* o_ptr { get; set; }
|
||||
|
||||
public byte* o_end { get; set; }
|
||||
|
||||
public uint bit_buffer { get; set; }
|
||||
|
||||
public uint inbuf_size { get; set; }
|
||||
|
||||
public byte bits_left { get; set; }
|
||||
|
||||
public byte input_end { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Models
|
||||
|
||||
#region Four literal models, each representing 64 symbols
|
||||
@@ -156,5 +112,15 @@ namespace SabreTools.Compression.libmspack
|
||||
public qtmd_modelsym[] m7sym { get; set; } = new qtmd_modelsym[7 + 1];
|
||||
|
||||
#endregion
|
||||
|
||||
public override void READ_BYTES()
|
||||
{
|
||||
byte b0, b1;
|
||||
READ_IF_NEEDED;
|
||||
b0 = *i_ptr++;
|
||||
READ_IF_NEEDED;
|
||||
b1 = *i_ptr++;
|
||||
INJECT_BITS_MSB((b0 << 8) | b1, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
245
libmspack/readbits.cs
Normal file
245
libmspack/readbits.cs
Normal file
@@ -0,0 +1,245 @@
|
||||
namespace SabreTools.Compression.libmspack
|
||||
{
|
||||
public unsafe abstract class readbits
|
||||
{
|
||||
/// <summary>
|
||||
/// I/O routines
|
||||
/// </summary>
|
||||
public mspack_system sys { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Input file handle
|
||||
/// </summary>
|
||||
public mspack_file input { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Output file handle
|
||||
/// </summary>
|
||||
public mspack_file output { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Decompression offset within window
|
||||
/// </summary>
|
||||
public uint window_posn { get; set; }
|
||||
|
||||
#region I/O buffering
|
||||
|
||||
public byte* inbuf { get; set; }
|
||||
|
||||
public byte* i_ptr { get; set; }
|
||||
|
||||
public byte* i_end { get; set; }
|
||||
|
||||
public byte* o_ptr { get; set; }
|
||||
|
||||
public byte* o_end { get; set; }
|
||||
|
||||
public int input_end { get; set; }
|
||||
|
||||
public uint bit_buffer { get; set; }
|
||||
|
||||
public uint bits_left { get; set; }
|
||||
|
||||
public uint inbuf_size { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
public MSPACK_ERR error { get; set; }
|
||||
|
||||
/// <see href="https://github.com/kyz/libmspack/blob/master/libmspack/mspack/readbits.h"/>
|
||||
#region readbits.h
|
||||
|
||||
private const int BITBUF_WIDTH = 64;
|
||||
|
||||
private static readonly ushort[] lsb_bit_mask = new ushort[17]
|
||||
{
|
||||
0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
|
||||
0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
|
||||
};
|
||||
|
||||
public void INIT_BITS()
|
||||
{
|
||||
this.i_ptr = inbuf;
|
||||
this.i_end = inbuf;
|
||||
this.bit_buffer = 0;
|
||||
this.bits_left = 0;
|
||||
this.input_end = 0;
|
||||
}
|
||||
|
||||
public void STORE_BITS(byte* i_ptr, byte* i_end, uint bit_buffer, uint bits_left)
|
||||
{
|
||||
this.i_ptr = i_ptr;
|
||||
this.i_end = i_end;
|
||||
this.bit_buffer = bit_buffer;
|
||||
this.bits_left = bits_left;
|
||||
}
|
||||
|
||||
public void RESTORE_BITS(out byte* i_ptr, out byte* i_end, out uint bit_buffer, out uint bits_left)
|
||||
{
|
||||
i_ptr = this.i_ptr;
|
||||
i_end = this.i_end;
|
||||
bit_buffer = this.bit_buffer;
|
||||
bits_left = this.bits_left;
|
||||
}
|
||||
|
||||
public void ENSURE_BITS(byte nbits, ref uint bits_left)
|
||||
{
|
||||
while (bits_left < nbits)
|
||||
{
|
||||
this.READ_BYTES();
|
||||
}
|
||||
}
|
||||
|
||||
#region MSB
|
||||
|
||||
public void READ_BITS_MSB(out int val, byte nbits, ref uint bit_buffer, ref uint bits_left)
|
||||
{
|
||||
this.ENSURE_BITS(nbits, ref bits_left);
|
||||
val = PEEK_BITS_MSB(nbits, bit_buffer);
|
||||
REMOVE_BITS_MSB(nbits, ref bit_buffer, ref bits_left);
|
||||
}
|
||||
|
||||
public void READ_MANY_BITS_MSB(out int val, byte bits, ref uint bit_buffer, ref uint bits_left)
|
||||
{
|
||||
byte needed = bits;
|
||||
byte bitrun;
|
||||
val = 0;
|
||||
while (needed > 0)
|
||||
{
|
||||
if (bits_left < (int)(BITBUF_WIDTH - 16))
|
||||
this.READ_BYTES();
|
||||
|
||||
bitrun = (bits_left < needed) ? (byte)bits_left : needed;
|
||||
val = (val << bitrun) | PEEK_BITS_MSB(bitrun, bit_buffer);
|
||||
REMOVE_BITS_MSB(bitrun, ref bit_buffer, ref bits_left);
|
||||
needed -= bitrun;
|
||||
}
|
||||
}
|
||||
|
||||
public int PEEK_BITS_MSB(byte nbits, uint bit_buffer)
|
||||
{
|
||||
return (int)(bit_buffer >> (BITBUF_WIDTH - nbits));
|
||||
}
|
||||
|
||||
public void REMOVE_BITS_MSB(byte nbits, ref uint bit_buffer, ref uint bits_left)
|
||||
{
|
||||
bit_buffer <<= nbits;
|
||||
bits_left -= nbits;
|
||||
}
|
||||
|
||||
public void INJECT_BITS_MSB(uint bitdata, byte nbits, ref uint bit_buffer, ref uint bits_left)
|
||||
{
|
||||
bit_buffer |= (uint)(int)(bitdata << (int)(BITBUF_WIDTH - nbits - bits_left));
|
||||
bits_left += nbits;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LSB
|
||||
|
||||
public void READ_BITS_LSB(out int val, byte nbits, ref uint bit_buffer, ref uint bits_left)
|
||||
{
|
||||
this.ENSURE_BITS(nbits, ref bits_left);
|
||||
val = PEEK_BITS_LSB(nbits, bit_buffer);
|
||||
REMOVE_BITS_LSB(nbits, ref bit_buffer, ref bits_left);
|
||||
}
|
||||
|
||||
public void READ_MANY_BITS_LSB(out int val, byte bits, ref uint bit_buffer, ref uint bits_left)
|
||||
{
|
||||
byte needed = bits;
|
||||
byte bitrun;
|
||||
val = 0;
|
||||
while (needed > 0)
|
||||
{
|
||||
if (bits_left < (int)(BITBUF_WIDTH - 16))
|
||||
this.READ_BYTES();
|
||||
|
||||
bitrun = (bits_left < needed) ? (byte)bits_left : needed;
|
||||
val = (val << bitrun) | PEEK_BITS_LSB(bitrun, bit_buffer);
|
||||
REMOVE_BITS_LSB(bitrun, ref bit_buffer, ref bits_left);
|
||||
needed -= bitrun;
|
||||
}
|
||||
}
|
||||
|
||||
public int PEEK_BITS_LSB(byte nbits, uint bit_buffer)
|
||||
{
|
||||
return (int)(bit_buffer & ((uint)(1 << nbits) - 1));
|
||||
}
|
||||
|
||||
public void REMOVE_BITS_LSB(byte nbits, ref uint bit_buffer, ref uint bits_left)
|
||||
{
|
||||
bit_buffer >>= nbits;
|
||||
bits_left -= nbits;
|
||||
}
|
||||
|
||||
public void INJECT_BITS_LSB(uint bitdata, byte nbits, ref uint bit_buffer, ref uint bits_left)
|
||||
{
|
||||
bit_buffer |= bitdata << (int)bits_left;
|
||||
bits_left += nbits;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LSB_T
|
||||
|
||||
public int PEEK_BITS_LSB_T(byte nbits, uint bit_buffer)
|
||||
{
|
||||
return (int)(bit_buffer & lsb_bit_mask[nbits]);
|
||||
}
|
||||
|
||||
public void READ_BITS_LSB_T(out int val, byte nbits, ref uint bit_buffer, ref uint bits_left)
|
||||
{
|
||||
this.ENSURE_BITS(nbits, ref bits_left);
|
||||
val = PEEK_BITS_LSB_T(nbits, bit_buffer);
|
||||
REMOVE_BITS_LSB(nbits, ref bit_buffer, ref bits_left);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public abstract void READ_BYTES();
|
||||
|
||||
public MSPACK_ERR READ_IF_NEEDED(ref byte* i_ptr, ref byte* i_end)
|
||||
{
|
||||
if (i_ptr >= i_end)
|
||||
{
|
||||
if (read_input() != MSPACK_ERR.MSPACK_ERR_OK)
|
||||
return this.error;
|
||||
|
||||
i_ptr = this.i_ptr;
|
||||
i_end = this.i_end;
|
||||
}
|
||||
|
||||
return MSPACK_ERR.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
private MSPACK_ERR read_input()
|
||||
{
|
||||
int read = this.sys.read(this.input, this.inbuf, (int)this.inbuf_size);
|
||||
if (read < 0) return this.error = MSPACK_ERR.MSPACK_ERR_READ;
|
||||
|
||||
/* we might overrun the input stream by asking for bits we don't use,
|
||||
* so fake 2 more bytes at the end of input */
|
||||
if (read == 0)
|
||||
{
|
||||
if (this.input_end != 0)
|
||||
{
|
||||
System.Console.Error.WriteLine("Out of input bytes");
|
||||
return this.error = MSPACK_ERR.MSPACK_ERR_READ;
|
||||
}
|
||||
else
|
||||
{
|
||||
read = 2;
|
||||
this.inbuf[0] = this.inbuf[1] = 0;
|
||||
this.input_end = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Update i_ptr and i_end
|
||||
this.i_ptr = this.inbuf;
|
||||
this.i_end = this.inbuf + read;
|
||||
return MSPACK_ERR.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
7
libmspack/readhuff.cs
Normal file
7
libmspack/readhuff.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace SabreTools.Compression.libmspack
|
||||
{
|
||||
public unsafe abstract class readhuff
|
||||
{
|
||||
public const int HUFF_MAXBITS = 16;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user