diff --git a/libmspack/mspack.cs b/libmspack/mspack.cs
index 318a26f..d45839a 100644
--- a/libmspack/mspack.cs
+++ b/libmspack/mspack.cs
@@ -1,4 +1,5 @@
using System;
+using System.Runtime.Serialization;
namespace SabreTools.Compression.libmspack
{
@@ -16,7 +17,25 @@ namespace SabreTools.Compression.libmspack
///
/// A custom mspack_system structure, or NULL to use the default
/// A or NULL
- public static mscab_decompressor mspack_create_cab_decompressor(mspack_system sys) => throw new NotImplementedException();
+ public static mscab_decompressor mspack_create_cab_decompressor(mspack_system sys)
+ {
+ if (sys == null)
+ return null;
+
+ var self = new mscab_decompressor
+ {
+ system = sys,
+ d = null,
+ error = MSPACK_ERR.MSPACK_ERR_OK,
+
+ searchbuf_size = 32768,
+ fix_mszip = 0,
+ buf_size = 4096,
+ salvage = 0,
+ };
+
+ return self;
+ }
///
/// Destroys an existing CAB compressor.
@@ -28,7 +47,21 @@ namespace SabreTools.Compression.libmspack
/// Destroys an existing CAB decompressor.
///
/// The to destroy
- public static void mspack_destroy_cab_decompressor(mscab_decompressor self) => throw new NotImplementedException();
+ public static void mspack_destroy_cab_decompressor(mscab_decompressor self)
+ {
+ if (self != null)
+ {
+ mspack_system sys = self.system;
+ if (self.d != null)
+ {
+ if (self.d.infh != null) sys.close(self.d.infh);
+ cabd_free_decomp(self);
+ //sys.free(self.d);
+ }
+
+ //sys.free(self);
+ }
+ }
///
/// Creates a new CHM compressor.
@@ -120,7 +153,18 @@ namespace SabreTools.Compression.libmspack
///
/// A custom mspack_system structure, or NULL to use the default
/// A or NULL
- public static msszdd_decompressor mspack_create_szdd_decompressor(mspack_system sys) => throw new NotImplementedException();
+ public static msszdd_decompressor mspack_create_szdd_decompressor(mspack_system sys)
+ {
+ msszdd_decompressor self = null;
+
+ if (sys == null) sys = new mspack_default_system();
+
+ self = new msszdd_decompressor();
+ self.system = sys;
+ self.error = MSPACK_ERR.MSPACK_ERR_OK;
+
+ return self;
+ }
///
/// Destroys an existing SZDD compressor.
@@ -132,7 +176,14 @@ namespace SabreTools.Compression.libmspack
/// Destroys an existing SZDD decompressor.
///
/// The to destroy
- public static void mspack_destroy_szdd_decompressor(msszdd_decompressor self) => throw new NotImplementedException();
+ public static void mspack_destroy_szdd_decompressor(msszdd_decompressor self)
+ {
+ if (self != null)
+ {
+ mspack_system sys = self.system;
+ //sys.free(self);
+ }
+ }
///
/// Creates a new KWAJ compressor.
diff --git a/libmspack/msszdd_decompressor.cs b/libmspack/msszdd_decompressor.cs
index de22af0..10d377a 100644
--- a/libmspack/msszdd_decompressor.cs
+++ b/libmspack/msszdd_decompressor.cs
@@ -1,3 +1,6 @@
+using System.Linq;
+using static SabreTools.Compression.libmspack.szdd;
+
namespace SabreTools.Compression.libmspack
{
///
@@ -7,7 +10,7 @@ namespace SabreTools.Compression.libmspack
///
///
///
- public abstract class msszdd_decompressor
+ public unsafe class msszdd_decompressor
{
public mspack_system system { get; set; }
@@ -19,7 +22,7 @@ namespace SabreTools.Compression.libmspack
/// If the file opened is a valid SZDD file, all headers will be read and
/// a msszddd_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,9 +32,26 @@ namespace SabreTools.Compression.libmspack
/// The filename of the SZDD compressed file. This is
/// passed directly to mspack_system::open().
///
- /// A pointer to a msszddd_header structure, or NULL on failure
+ /// A pointer to a msszddd_header structure, or null on failure
///
- public abstract msszddd_header open(in string filename);
+ public msszddd_header open(in string filename)
+ {
+ mspack_system sys = this.system;
+
+ mspack_file fh = sys.open(filename, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_READ);
+ msszddd_header hdr = new msszddd_header();
+ hdr.fh = fh;
+ this.error = szddd_read_headers(sys, fh, hdr);
+
+ if (this.error != MSPACK_ERR.MSPACK_ERR_OK)
+ {
+ if (fh != null) sys.close(fh);
+ //sys.free(hdr);
+ hdr = null;
+ }
+
+ return hdr;
+ }
///
/// Closes a previously opened SZDD file.
@@ -42,7 +62,69 @@ namespace SabreTools.Compression.libmspack
/// The SZDD header pointer is now invalid and cannot be used again.
///
/// The SZDD file to close
- public abstract void close(msszddd_header szdd);
+ public void close(msszddd_header szdd)
+ {
+ if (this.system == null) return;
+
+ // Close the file handle associated
+ this.system.close(szdd.fh);
+
+ // Free the memory associated
+ //this.system.free(hdr);
+
+ this.error = MSPACK_ERR.MSPACK_ERR_OK;
+ }
+
+ private static readonly byte[] szdd_signature_expand = new byte[8]
+ {
+ 0x53, 0x5A, 0x44, 0x44, 0x88, 0xF0, 0x27, 0x33
+ };
+
+ private static readonly byte[] szdd_signature_qbasic = new byte[8]
+ {
+ 0x53, 0x5A, 0x20, 0x88, 0xF0, 0x27, 0x33, 0xD1
+ };
+
+ ///
+ /// Reads the headers of an SZDD format file
+ ///
+ ///
+ ///
+ ///
+ ///
+ private static MSPACK_ERR szddd_read_headers(mspack_system sys, mspack_file fh, msszddd_header hdr)
+ {
+ byte[] buf = new byte[8];
+ byte* bufPtr = libmspack.system.GetArrayPointer(buf);
+
+ // Read and check signature
+ if (sys.read(fh, buffer: bufPtr, 8) != 8) return MSPACK_ERR.MSPACK_ERR_READ;
+
+ if (buf.SequenceEqual(szdd_signature_expand))
+ {
+ // Common SZDD
+ hdr.format = MSSZDD_FMT.MSSZDD_FMT_NORMAL;
+
+ // Read the rest of the header
+ if (sys.read(fh, bufPtr, 6) != 6) return MSPACK_ERR.MSPACK_ERR_READ;
+ if (buf[0] != 0x41) return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
+ hdr.missing_char = (char)buf[1];
+ hdr.length = EndGetI32(&buf[2]);
+ }
+ else if (buf.SequenceEqual(szdd_signature_qbasic))
+ {
+ // Special QBasic SZDD
+ hdr.format = MSSZDD_FMT.MSSZDD_FMT_QBASIC;
+ if (sys.read(fh, bufPtr, 4) != 4) return MSPACK_ERR.MSPACK_ERR_READ;
+ hdr.missing_char = '\0';
+ hdr.length = EndGetI32(buf);
+ }
+ else
+ {
+ return MSPACK_ERR.MSPACK_ERR_SIGNATURE;
+ }
+ return MSPACK_ERR.MSPACK_ERR_OK;
+ }
///
/// Extracts the compressed data from a SZDD file.
@@ -56,7 +138,38 @@ namespace SabreTools.Compression.libmspack
/// is passed directly to mspack_system::open().
///
/// An error code, or MSPACK_ERR_OK if successful
- public abstract MSPACK_ERR extract(msszddd_header szdd, in string filename);
+ public MSPACK_ERR extract(msszddd_header szdd, in string filename)
+ {
+ if (szdd == null) return this.error = MSPACK_ERR.MSPACK_ERR_ARGS;
+ mspack_system sys = this.system;
+
+ mspack_file fh = szdd.fh;
+
+ // Seek to the compressed data
+ long data_offset = (szdd.format == MSSZDD_FMT.MSSZDD_FMT_NORMAL) ? 14 : 12;
+ if (sys.seek(fh, data_offset, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_START) != 0)
+ {
+ return this.error = MSPACK_ERR.MSPACK_ERR_SEEK;
+ }
+
+ // Open file for output
+ mspack_file outfh;
+ if ((outfh = sys.open(filename, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_WRITE)) == null)
+ {
+ return this.error = MSPACK_ERR.MSPACK_ERR_OPEN;
+ }
+
+ // Decompress the data
+ this.error = lzss_decompress(sys, fh, outfh, SZDD_INPUT_SIZE,
+ szdd.format == MSSZDD_FMT.MSSZDD_FMT_NORMAL
+ ? LZSS_MODE.LZSS_MODE_EXPAND
+ : LZSS_MODE.LZSS_MODE_QBASIC);
+
+ // Close output file
+ sys.close(outfh);
+
+ return this.error;
+ }
///
/// Decompresses an SZDD file to an output file in one step.
@@ -76,7 +189,15 @@ namespace SabreTools.Compression.libmspack
/// is passed directly to mspack_system::open().
///
/// An error code, or MSPACK_ERR_OK if successful
- public abstract MSPACK_ERR decompress(in string input, in string output);
+ public MSPACK_ERR decompress(in string input, in string output)
+ {
+ msszddd_header hdr;
+
+ if ((hdr = open(input)) == null) return this.error;
+ MSPACK_ERR error = extract(hdr, output);
+ close(hdr);
+ return this.error = error;
+ }
///
/// Returns the error code set by the most recently called method.
@@ -88,6 +209,9 @@ namespace SabreTools.Compression.libmspack
///
///
///
- public abstract MSPACK_ERR last_error();
+ public MSPACK_ERR last_error()
+ {
+ return this.error;
+ }
}
}
\ No newline at end of file
diff --git a/libmspack/system.cs b/libmspack/system.cs
index a8bbffe..0cb029a 100644
--- a/libmspack/system.cs
+++ b/libmspack/system.cs
@@ -9,12 +9,12 @@
namespace SabreTools.Compression.libmspack
{
- public static class system
+ public unsafe static class system
{
///
/// Returns the length of a file opened for reading
///
- public unsafe static MSPACK_ERR mspack_sys_filelen(mspack_system system, mspack_file file, long* length)
+ public static MSPACK_ERR mspack_sys_filelen(mspack_system system, mspack_file file, long* length)
{
if (system == null || file == null || length == null) return MSPACK_ERR.MSPACK_ERR_OPEN;
@@ -38,5 +38,18 @@ namespace SabreTools.Compression.libmspack
return MSPACK_ERR.MSPACK_ERR_OK;
}
+
+ public static T* CreateArray(int length)
+ {
+ T[] buf = new T[length];
+ return GetArrayPointer(buf);
+ }
+
+ public static T* GetArrayPointer(T[] arr)
+ {
+ var bufRef = __makeref(arr);
+ var bufPtr = **(System.IntPtr**)&bufRef;
+ return (T*)bufPtr.ToPointer();
+ }
}
}
\ No newline at end of file
diff --git a/libmspack/szdd.cs b/libmspack/szdd.cs
index 73f8861..d416f90 100644
--- a/libmspack/szdd.cs
+++ b/libmspack/szdd.cs
@@ -9,7 +9,7 @@
namespace SabreTools.Compression.libmspack
{
- public static class SZDD
+ public static class szdd
{
///
/// Input buffer size during decompression - not worth parameterising IMHO