diff --git a/libmspack/BaseCompressor.cs b/libmspack/BaseCompressor.cs
deleted file mode 100644
index 42ea3b7..0000000
--- a/libmspack/BaseCompressor.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- ///
- /// Base class for all compressor implementations
- ///
- public abstract class BaseCompressor : mspack_file
- {
-#if NET48
- public mspack_system system { get; set; }
-#else
- public mspack_system? system { get; set; }
-#endif
-
- public MSPACK_ERR error { get; set; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/BaseDecompressor.cs b/libmspack/BaseDecompressor.cs
deleted file mode 100644
index 1de341a..0000000
--- a/libmspack/BaseDecompressor.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- ///
- /// Base class for all decompressor implementations
- ///
- public abstract class BaseDecompressor : mspack_file
- {
-#if NET48
- public mspack_system system { get; set; }
-#else
- public mspack_system? system { get; set; }
-#endif
-
- public MSPACK_ERR error { get; set; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/BitStream.cs b/libmspack/BitStream.cs
deleted file mode 100644
index 962ef18..0000000
--- a/libmspack/BitStream.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- public unsafe abstract class BitStream
- {
- ///
- /// I/O routines
- ///
- public mspack_system sys { get; set; }
-
- ///
- /// Input file handle
- ///
- public mspack_file input { get; set; }
-
- ///
- /// Output file handle
- ///
- public mspack_file output { get; set; }
-
- ///
- /// Decompression offset within window
- ///
- 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; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/CAB/CABSystem.cs b/libmspack/CAB/CABSystem.cs
deleted file mode 100644
index 9442bb2..0000000
--- a/libmspack/CAB/CABSystem.cs
+++ /dev/null
@@ -1,231 +0,0 @@
-using static SabreTools.Compression.libmspack.macros;
-using static SabreTools.Compression.libmspack.CAB.Constants;
-
-namespace SabreTools.Compression.libmspack.CAB
-{
- public unsafe class CABSystem : mspack_default_system
- {
- ///
- /// 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
- ///
- public override int read(mspack_file file, void* buffer, int bytes)
- {
- Decompressor self = (Decompressor)file;
- byte* buf = (byte*)buffer;
- mspack_system sys = self.system;
- int avail, todo, outlen = 0, ignore_cksum, ignore_blocksize;
-
- ignore_cksum = self.salvage != 0 || (self.fix_mszip != 0 && ((MSCAB_COMP)((int)self.d.comp_type & cffoldCOMPTYPE_MASK) == MSCAB_COMP.MSCAB_COMP_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 = ReadBlock(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 ((MSCAB_COMP)((int)self.d.comp_type & cffoldCOMPTYPE_MASK) == MSCAB_COMP.MSCAB_COMP_QUANTUM)
- {
- *self.d.i_end++ = 0xFF;
- }
-
- // Is this the last block?
- if (self.d.block >= self.d.folder.num_blocks)
- {
- if ((MSCAB_COMP)((int)self.d.comp_type & cffoldCOMPTYPE_MASK) == MSCAB_COMP.MSCAB_COMP_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;
- }
-
- ///
- /// 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
- ///
- public override int write(mspack_file file, void* buffer, int bytes)
- {
- Decompressor self = (Decompressor)file;
- self.d.offset += (uint)bytes;
- if (self.d.outfh != null)
- {
- return self.system.write(self.d.outfh, buffer, bytes);
- }
- return bytes;
- }
-
- ///
- /// 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
- ///
- private static MSPACK_ERR ReadBlock(mspack_system sys, mscabd_decompress_state d, ref int @out, int ignore_cksum, int ignore_blocksize)
- {
- FixedArray hdr = new FixedArray(cfdata_SIZEOF);
- uint cksum;
- int len, full_len;
-
- // Reset the input block pointer and end of block pointer
- d.i_ptr = d.i_end = d.input;
-
- do
- {
- // Read the block header
- if (sys.read(d.infh, 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)) != 0)
- {
- uint sum2 = Checksum(d.i_end, (uint)len, 0);
- if (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)) != 0)
- {
- 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 Checksum(FixedArray data, int ptr, uint bytes, uint cksum)
- {
- uint len, ul = 0;
-
- for (len = bytes >> 2; len-- > 0; ptr += 4)
- {
- cksum ^= EndGetI32(data, ptr);
- }
-
- switch (bytes & 3)
- {
- case 3: ul |= (uint)(data[ptr++] << 16); goto case 2;
- case 2: ul |= (uint)(data[ptr++] << 8); goto case 1;
- case 1: ul |= data[ptr]; break;
- }
- cksum ^= ul;
-
- return cksum;
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/CAB/Compressor.cs b/libmspack/CAB/Compressor.cs
deleted file mode 100644
index 0fdaadc..0000000
--- a/libmspack/CAB/Compressor.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace SabreTools.Compression.libmspack.CAB
-{
- ///
- /// TODO
- ///
- public class Compressor : BaseCompressor
- {
- ///
- /// Creates a new CAB compressor
- ///
- public Compressor()
- {
- this.system = new CABSystem();
- this.error = MSPACK_ERR.MSPACK_ERR_OK;
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/CAB/Constants.cs b/libmspack/CAB/Constants.cs
deleted file mode 100644
index 2ea4b30..0000000
--- a/libmspack/CAB/Constants.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-namespace SabreTools.Compression.libmspack.CAB
-{
- public static class Constants
- {
- /* structure offsets */
- public const byte cfhead_Signature = 0x00;
- public const byte cfhead_CabinetSize = 0x08;
- public const byte cfhead_FileOffset = 0x10;
- public const byte cfhead_MinorVersion = 0x18;
- public const byte cfhead_MajorVersion = 0x19;
- public const byte cfhead_NumFolders = 0x1A;
- public const byte cfhead_NumFiles = 0x1C;
- public const byte cfhead_Flags = 0x1E;
- public const byte cfhead_SetID = 0x20;
- public const byte cfhead_CabinetIndex = 0x22;
- public const byte cfhead_SIZEOF = 0x24;
- public const byte cfheadext_HeaderReserved = 0x00;
- public const byte cfheadext_FolderReserved = 0x02;
- public const byte cfheadext_DataReserved = 0x03;
- public const byte cfheadext_SIZEOF = 0x04;
- public const byte cffold_DataOffset = 0x00;
- public const byte cffold_NumBlocks = 0x04;
- public const byte cffold_CompType = 0x06;
- public const byte cffold_SIZEOF = 0x08;
- public const byte cffile_UncompressedSize = 0x00;
- public const byte cffile_FolderOffset = 0x04;
- public const byte cffile_FolderIndex = 0x08;
- public const byte cffile_Date = 0x0A;
- public const byte cffile_Time = 0x0C;
- public const byte cffile_Attribs = 0x0E;
- public const byte cffile_SIZEOF = 0x10;
- public const byte cfdata_CheckSum = 0x00;
- public const byte cfdata_CompressedSize = 0x04;
- public const byte cfdata_UncompressedSize = 0x06;
- public const byte cfdata_SIZEOF = 0x08;
-
- /* flags */
- public const ushort cffoldCOMPTYPE_MASK = 0x000f;
- public const ushort cffileCONTINUED_FROM_PREV = 0xFFFD;
- public const ushort cffileCONTINUED_TO_NEXT = 0xFFFE;
- public const ushort cffileCONTINUED_PREV_AND_NEXT = 0xFFFF;
-
- /* CAB data blocks are <= 32768 bytes in uncompressed form. Uncompressed
- * blocks have zero growth. MSZIP guarantees that it won't grow above
- * uncompressed size by more than 12 bytes. LZX guarantees it won't grow
- * more than 6144 bytes. Quantum has no documentation, but the largest
- * block seen in the wild is 337 bytes above uncompressed size.
- */
- public const int CAB_BLOCKMAX = 32768;
- public const int CAB_INPUTMAX = CAB_BLOCKMAX + 6144;
-
- /* input buffer needs to be CAB_INPUTMAX + 1 byte to allow for max-sized block
- * plus 1 trailer byte added by cabd_sys_read_block() for Quantum alignment.
- *
- * When MSCABD_PARAM_SALVAGE is set, block size is not checked so can be
- * up to 65535 bytes, so max input buffer size needed is 65535 + 1
- */
- public const int CAB_INPUTMAX_SALVAGE = 65535;
- public const int CAB_INPUTBUF = CAB_INPUTMAX_SALVAGE + 1;
-
- /* There are no more than 65535 data blocks per folder, so a folder cannot
- * be more than 32768*65535 bytes in length. As files cannot span more than
- * one folder, this is also their max offset, length and offset+length limit.
- */
- public const int CAB_FOLDERMAX = 65535;
- public const int CAB_LENGTHMAX = CAB_BLOCKMAX * CAB_FOLDERMAX;
- }
-}
\ No newline at end of file
diff --git a/libmspack/CAB/Decompressor.cs b/libmspack/CAB/Decompressor.cs
deleted file mode 100644
index 6688a7e..0000000
--- a/libmspack/CAB/Decompressor.cs
+++ /dev/null
@@ -1,1242 +0,0 @@
-using static SabreTools.Compression.libmspack.cab;
-using static SabreTools.Compression.libmspack.macros;
-using static SabreTools.Compression.libmspack.CAB.Constants;
-
-namespace SabreTools.Compression.libmspack.CAB
-{
- ///
- /// A decompressor for .CAB (Microsoft Cabinet) files
- ///
- /// All fields are READ ONLY.
- ///
- public unsafe class Decompressor : BaseDecompressor
- {
- public mscabd_decompress_state d { get; set; }
-
- public int buf_size { get; private set; }
-
- public int searchbuf_size { get; private set; }
-
- public int fix_mszip { get; private set; }
-
- public int salvage { get; private set; }
-
- public MSPACK_ERR read_error { get; set; }
-
- ///
- /// Creates a new CAB decompressor
- ///
- public Decompressor()
- {
- this.system = new CABSystem();
- this.d = null;
- this.error = MSPACK_ERR.MSPACK_ERR_OK;
-
- this.searchbuf_size = 32768;
- this.fix_mszip = 0;
- this.buf_size = 4096;
- this.salvage = 0;
- }
-
- ///
- /// Destroys an existing CAB decompressor.
- ///
- ~Decompressor()
- {
- mspack_system sys = this.system;
- if (this.d != null)
- {
- if (this.d.infh != null) sys.close(this.d.infh);
- cab.cabd_free_decomp(this);
- //sys.free(this.d);
- }
-
- //sys.free(this);
- }
-
- ///
- /// Opens a cabinet file and reads its contents.
- ///
- /// If the file opened is a valid cabinet file, all headers will be read
- /// 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
- /// is available from last_error().
- ///
- /// The filename pointer should be considered "in use" until close() is
- /// called on the cabinet.
- ///
- ///
- /// The filename of the cabinet file. This is passed
- /// directly to mspack_system::open().
- ///
- /// A pointer to a mscabd_cabinet structure, or null on failure
- ///
- ///
- ///
- public mscabd_cabinet open(in string filename)
- {
- mscabd_cabinet cab = null;
- mspack_file fh;
-
- if ((fh = this.system.open(filename, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_READ)) != null)
- {
- cab = new mscabd_cabinet();
- cab.filename = filename;
- MSPACK_ERR error = ReadHeaders(this.system, fh, cab, 0, this.salvage, 0);
- if (error != MSPACK_ERR.MSPACK_ERR_OK)
- {
- close(cab);
- cab = null;
- }
- this.error = error;
- this.system.close(fh);
- }
- else
- {
- this.error = MSPACK_ERR.MSPACK_ERR_OPEN;
- }
-
- return cab;
- }
-
- ///
- /// Closes a previously opened cabinet or cabinet set.
- ///
- /// This closes a cabinet, all cabinets associated with it via the
- /// mscabd_cabinet::next, mscabd_cabinet::prevcab and
- /// mscabd_cabinet::nextcab pointers, and all folders and files. All
- /// memory used by these entities is freed.
- ///
- /// The cabinet pointer is now invalid and cannot be used again. All
- /// mscabd_folder and mscabd_file pointers from that cabinet or cabinet
- /// set are also now invalid, and cannot be used again.
- ///
- /// If the cabinet pointer given was created using search(), it MUST be
- /// the cabinet pointer returned by search() and not one of the later
- /// cabinet pointers further along the mscabd_cabinet::next chain.
- ///
- /// If extra cabinets have been added using append() or prepend(), these
- /// will all be freed, even if the cabinet pointer given is not the first
- /// cabinet in the set. Do NOT close() more than one cabinet in the set.
- ///
- /// The mscabd_cabinet::filename is not freed by the library, as it is
- /// not allocated by the library. The caller should free this itself if
- /// necessary, before it is lost forever.
- ///
- /// The cabinet to close
- ///
- ///
- ///
- ///
- 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(this);
- //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;
- }
- }
-
- ///
- /// 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
- ///
- private static MSPACK_ERR ReadHeaders(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;
- FixedArray buf = new FixedArray(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, buf, cfhead_SIZEOF) != cfhead_SIZEOF)
- {
- return MSPACK_ERR.MSPACK_ERR_READ;
- }
-
- // Check for "MSCF" signature
- if (EndGetI32(buf, cfhead_Signature) != 0x4643534D)
- {
- return MSPACK_ERR.MSPACK_ERR_SIGNATURE;
- }
-
- // Some basic header fields
- cab.length = EndGetI32(buf, cfhead_CabinetSize);
- cab.set_id = EndGetI16(buf, cfhead_SetID);
- cab.set_index = EndGetI16(buf, cfhead_CabinetIndex);
-
- // Get the number of folders
- num_folders = EndGetI16(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(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 = (MSCAB_HDR)EndGetI16(buf, cfhead_Flags);
-
- if (cab.flags.HasFlag(MSCAB_HDR.MSCAB_HDR_RESV))
- {
- if (sys.read(fh, buf, cfheadext_SIZEOF) != cfheadext_SIZEOF)
- {
- return MSPACK_ERR.MSPACK_ERR_READ;
- }
- cab.header_resv = EndGetI16(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 = ReadString(sys, fh, 0, out err);
- if (err != MSPACK_ERR.MSPACK_ERR_OK) return err;
- cab.previnfo = ReadString(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 = ReadString(sys, fh, 0, out err);
- if (err != MSPACK_ERR.MSPACK_ERR_OK) return err;
- cab.nextinfo = ReadString(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, 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 = (MSCAB_COMP)EndGetI16(buf, cffold_CompType);
- fol.num_blocks = (uint)EndGetI16(buf, cffold_NumBlocks);
- fol.data.next = null;
- fol.data.cab = cab;
- fol.data.offset = offset + (long)((uint)EndGetI32(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, buf, cffile_SIZEOF) != cffile_SIZEOF)
- {
- return MSPACK_ERR.MSPACK_ERR_READ;
- }
-
- file = new mscabd_file();
-
- file.next = null;
- file.length = EndGetI32(buf, cffile_UncompressedSize);
- file.attribs = (MSCAB_ATTRIB)EndGetI16(buf, cffile_Attribs);
- file.offset = EndGetI32(buf, cffile_FolderOffset);
-
- // Set folder pointer
- fidx = EndGetI16(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(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(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 = ReadString(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 ReadString(mspack_system sys, mspack_file fh, int permit_empty, out MSPACK_ERR error)
- {
- long @base = sys.tell(fh);
- FixedArray buf = new FixedArray(256);
- string str;
- int len, i, ok;
-
- // Read up to 256 bytes
- if ((len = sys.read(fh, 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;
- }
-
- FixedArray strchr = new FixedArray(len);
- sys.copy(buf, (void*)strchr, len);
- str = new string(strchr.ToArray());
- error = MSPACK_ERR.MSPACK_ERR_OK;
- return str;
- }
-
- ///
- /// Searches a regular file for embedded cabinets.
- ///
- /// This opens a normal file with the given filename and will search the
- /// entire file for embedded cabinet files
- ///
- /// If any cabinets are found, the equivalent of open() is called on each
- /// potential cabinet file at the offset it was found. All successfully
- /// open()ed cabinets are kept in a list.
- ///
- /// The first cabinet found will be returned directly as the result of
- /// this method. Any further cabinets found will be chained in a list
- /// 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
- /// last_error().
- ///
- /// 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.
- ///
- /// close() should only be called on the result of search(), not on any
- /// subsequent cabinets in the mscabd_cabinet::next chain.
- ///
- ///
- /// The filename of the file to search for cabinets. This
- /// is passed directly to mspack_system::open().
- ///
- /// A pointer to a mscabd_cabinet structure, or null
- ///
- ///
- ///
- public mscabd_cabinet search(in string filename)
- {
- mscabd_cabinet cab = null;
- mspack_system sys;
- FixedArray search_buf;
- mspack_file fh;
- long filelen, firstlen = 0;
-
- sys = this.system;
-
- // Allocate a search buffer
- search_buf = new FixedArray(this.searchbuf_size);
- if (search_buf == null)
- {
- this.error = MSPACK_ERR.MSPACK_ERR_NOMEMORY;
- return null;
- }
-
- // Open file and get its full file length
- if ((fh = sys.open(filename, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_READ)) != null)
- {
- if ((this.error = libmspack.system.mspack_sys_filelen(sys, fh, &filelen)) == MSPACK_ERR.MSPACK_ERR_OK)
- {
- this.error = Find(search_buf, fh, filename, filelen, ref firstlen, cab);
- }
-
- // Truncated / extraneous data warning:
- if (firstlen != 0 && (firstlen != filelen) && cab == null || (cab.base_offset == 0))
- {
- if (firstlen < filelen)
- {
- sys.message(fh, $"WARNING; possible {filelen - firstlen} extra bytes at end of file");
- }
- else
- {
- sys.message(fh, $"WARNING; file possibly truncated by {firstlen - filelen} bytes.");
- }
- }
-
- sys.close(fh);
- }
- else
- {
- this.error = MSPACK_ERR.MSPACK_ERR_OPEN;
- }
-
- // Free the search buffer
- sys.free(search_buf);
-
- return cab;
- }
-
- ///
- /// Find is the inner loop of , to make it easier to
- /// break out of the loop and be sure that all resources are freed
- ///
- private MSPACK_ERR Find(FixedArray buf, mspack_file fh, in string filename, long flen, ref long firstlen, mscabd_cabinet firstcab)
- {
- mscabd_cabinet cab, link = null;
- long caboff, offset, length;
- mspack_system sys = this.system;
- byte* p, pend;
- byte state = 0;
- uint cablen_u32 = 0, foffset_u32 = 0;
- int false_cabs = 0;
-
- // Search through the full file length
- for (offset = 0; offset < flen; offset += length)
- {
- // Search length is either the full length of the search buffer, or the
- // amount of data remaining to the end of the file, whichever is less.
- length = flen - offset;
- if (length > this.searchbuf_size)
- {
- length = this.searchbuf_size;
- }
-
- // Fill the search buffer with data from disk */
- if (sys.read(fh, buf, (int)length) != (int)length)
- {
- return MSPACK_ERR.MSPACK_ERR_READ;
- }
-
- // FAQ avoidance strategy
- if ((offset == 0) && (EndGetI32(buf, 0) == 0x28635349))
- {
- sys.message(fh, "WARNING; found InstallShield header. Use unshield (https://github.com/twogood/unshield) to unpack this file");
- }
-
- // Read through the entire buffer.
- for (p = buf, pend = (byte*)buf.Pointer + length; p < pend;)
- {
- switch (state)
- {
- // Starting state
- case 0:
- // we spend most of our time in this while loop, looking for
- // a leading 'M' of the 'MSCF' signature
- while (p < pend && *p != 0x4D) p++;
- // If we found tht 'M', advance state
- if (p++ < pend) state = 1;
- break;
-
- // Verify that the next 3 bytes are 'S', 'C' and 'F'
- case 1: state = (byte)((*p++ == 0x53) ? 2 : 0); break;
- case 2: state = (byte)((*p++ == 0x43) ? 3 : 0); break;
- case 3: state = (byte)((*p++ == 0x46) ? 4 : 0); break;
-
- // We don't care about bytes 4-7 (see default: for action)
-
- // Bytes 8-11 are the overall length of the cabinet
- case 8: cablen_u32 = *p++; state++; break;
- case 9: cablen_u32 |= (uint)(*p++ << 8); state++; break;
- case 10: cablen_u32 |= (uint)(*p++ << 16); state++; break;
- case 11: cablen_u32 |= (uint)(*p++ << 24); state++; break;
-
- // We don't care about bytes 12-15 (see default: for action)
-
- // Bytes 16-19 are the offset within the cabinet of the filedata
- case 16: foffset_u32 = *p++; state++; break;
- case 17: foffset_u32 |= (uint)(*p++ << 8); state++; break;
- case 18: foffset_u32 |= (uint)(*p++ << 16); state++; break;
- case 19:
- foffset_u32 |= (uint)(*p++ << 24);
- // Now we have recieved 20 bytes of potential cab header. work out
- // the offset in the file of this potential cabinet */
- caboff = offset + (p - buf) - 20;
-
- // Should reading cabinet fail, restart search just after 'MSCF'
- offset = caboff + 4;
-
- // Capture the "length of cabinet" field if there is a cabinet at
- // offset 0 in the file, regardless of whether the cabinet can be
- // read correctly or not
- if (caboff == 0) firstlen = cablen_u32;
-
- // Check that the files offset is less than the alleged length of
- // the cabinet, and that the offset + the alleged length are
- // 'roughly' within the end of overall file length. In salvage
- // mode, don't check the alleged length, allow it to be garbage
- if ((foffset_u32 < cablen_u32) &&
- ((caboff + (long)foffset_u32) < (flen + 32)) &&
- (((caboff + (long)cablen_u32) < (flen + 32)) || this.salvage != 0))
- {
- // Likely cabinet found -- try reading it
- cab = new mscabd_cabinet();
- cab.filename = filename;
- if (ReadHeaders(sys, fh, cab, caboff, this.salvage, 1) != MSPACK_ERR.MSPACK_ERR_OK)
- {
- // Destroy the failed cabinet
- close(cab);
- false_cabs++;
- }
- else
- {
- // Cabinet read correctly!
-
- // Link the cab into the list
- if (link == null) firstcab = cab;
- else link.next = cab;
- link = cab;
-
- // Cause the search to restart after this cab's data.
- offset = caboff + (long)cablen_u32;
- }
- }
-
- // Restart search
- if (offset >= flen) return MSPACK_ERR.MSPACK_ERR_OK;
- if (sys.seek(fh, offset, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_START) != 0)
- {
- return MSPACK_ERR.MSPACK_ERR_SEEK;
- }
- length = 0;
- p = pend;
- state = 0;
- break;
-
- /* for bytes 4-7 and 12-15, just advance state/pointer */
- default:
- p++; state++;
- break;
- } /* switch(state) */
- } /* for (... p < pend ...) */
- } /* for (... offset < length ...) */
-
- if (false_cabs != 0)
- {
- System.Console.Error.WriteLine("%d false cabinets found", false_cabs);
- }
-
- return MSPACK_ERR.MSPACK_ERR_OK;
- }
-
- ///
- /// Appends one mscabd_cabinet to another, forming or extending a cabinet
- /// set.
- ///
- /// This will attempt to append one cabinet to another such that
- /// (cab.nextcab == nextcab) && (nextcab.prevcab == cab) and
- /// any folders split between the two cabinets are merged.
- ///
- /// The cabinets MUST be part of a cabinet set -- a cabinet set is a
- /// cabinet that spans more than one physical cabinet file on disk -- and
- /// must be appropriately matched.
- ///
- /// It can be determined if a cabinet has further parts to load by
- /// examining the mscabd_cabinet::flags field:
- ///
- /// - if (flags & MSCAB_HDR_PREVCAB) is non-zero, there is a
- /// predecessor cabinet to open() and prepend(). Its MS-DOS
- /// case-insensitive filename is mscabd_cabinet::prevname
- /// - if (flags & MSCAB_HDR_NEXTCAB) is non-zero, there is a
- /// successor cabinet to open() and append(). Its MS-DOS case-insensitive
- /// filename is mscabd_cabinet::nextname
- ///
- /// If the cabinets do not match, an error code will be returned. Neither
- /// cabinet has been altered, and both should be closed seperately.
- ///
- /// Files and folders in a cabinet set are a single entity. All cabinets
- /// in a set use the same file list, which is updated as cabinets in the
- /// set are added. All pointers to mscabd_folder and mscabd_file
- /// structures in either cabinet must be discarded and re-obtained after
- /// merging.
- ///
- /// The cabinet which will be appended to, predecessor of nextcab
- /// The cabinet which will be appended, successor of cab
- /// An error code, or MSPACK_ERR.MSPACK_ERR_OK if successful
- ///
- ///
- ///
- public MSPACK_ERR append(mscabd_cabinet cab, mscabd_cabinet nextcab)
- {
- return Merge(cab, nextcab);
- }
-
- ///
- /// Prepends one mscabd_cabinet to another, forming or extending a
- /// cabinet set.
- ///
- /// This will attempt to prepend one cabinet to another, such that
- /// (cab.prevcab == prevcab) && (prevcab.nextcab == cab). In
- /// all other respects, it is identical to append(). See append() for the
- /// full documentation.
- ///
- /// The cabinet which will be prepended to, successor of prevcab
- /// The cabinet which will be prepended, predecessor of cab
- /// An error code, or MSPACK_ERR.MSPACK_ERR_OK if successful
- ///
- ///
- ///
- public MSPACK_ERR prepend(mscabd_cabinet cab, mscabd_cabinet prevcab)
- {
- return Merge(prevcab, cab);
- }
-
- ///
- /// Joins cabinets together, also merges split folders between these two
- /// cabinets only. This includes freeing the duplicate folder and file(s)
- /// and allocating a further mscabd_folder_data structure to append to the
- /// merged folder's data parts list.
- ///
- private MSPACK_ERR Merge(mscabd_cabinet lcab, mscabd_cabinet rcab)
- {
- mscabd_folder_data data, ndata;
- mscabd_folder lfol, rfol;
- mscabd_file fi, rfi, lfi;
- mscabd_cabinet cab;
-
- mspack_system sys = this.system;
-
- // Basic args check
- if (lcab == null || rcab == null || (lcab == rcab))
- {
- System.Console.Error.WriteLine("lcab null, rcab null or lcab = rcab");
- return this.error = MSPACK_ERR.MSPACK_ERR_ARGS;
- }
-
- // Check there's not already a cabinet attached
- if (lcab.nextcab != null || rcab.prevcab != null)
- {
- System.Console.Error.WriteLine("cabs already joined");
- return this.error = MSPACK_ERR.MSPACK_ERR_ARGS;
- }
-
- // Do not create circular cabinet chains
- for (cab = lcab.prevcab; cab != null; cab = cab.prevcab)
- {
- if (cab == rcab)
- {
- System.Console.Error.WriteLine("circular!");
- return this.error = MSPACK_ERR.MSPACK_ERR_ARGS;
- }
- }
- for (cab = rcab.nextcab; cab != null; cab = cab.nextcab)
- {
- if (cab == lcab)
- {
- System.Console.Error.WriteLine("circular!");
- return this.error = MSPACK_ERR.MSPACK_ERR_ARGS;
- }
- }
-
- // Warn about odd set IDs or indices
- if (lcab.set_id != rcab.set_id)
- {
- sys.message(null, "WARNING; merged cabinets with differing Set IDs.");
- }
-
- if (lcab.set_index > rcab.set_index)
- {
- sys.message(null, "WARNING; merged cabinets with odd order.");
- }
-
- // Merging the last folder in lcab with the first folder in rcab
- lfol = lcab.folders;
- rfol = rcab.folders;
- while (lfol.next != null)
- lfol = lfol.next;
-
- // Do we need to merge folders?
- if (lfol.merge_next == null && rfol.merge_prev == null)
- {
- // No, at least one of the folders is not for merging
-
- // Attach cabs
- lcab.nextcab = rcab;
- rcab.prevcab = lcab;
-
- // Attach folders
- lfol.next = rfol;
-
- // Attach files
- fi = lcab.files;
- while (fi.next != null)
- fi = fi.next;
- fi.next = rcab.files;
- }
- else
- {
- // Folder merge required - do the files match?
- if (CanMergeFolders(sys, lfol, rfol) == 0)
- {
- return this.error = MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
- }
-
- // Allocate a new folder data structure
- data = new mscabd_folder_data();
-
- // Attach cabs
- lcab.nextcab = rcab;
- rcab.prevcab = lcab;
-
- // Append rfol's data to lfol
- ndata = lfol.data;
- while (ndata.next != null)
- ndata = ndata.next;
- ndata.next = data;
- data = rfol.data;
- rfol.data.next = null;
-
- // lfol becomes rfol.
- // NOTE: special case, don't merge if rfol is merge prev and next,
- // rfol.merge_next is going to be deleted, so keep lfol's version
- // instead
- lfol.num_blocks += rfol.num_blocks - 1;
- if ((rfol.merge_next == null) || (rfol.merge_next.folder != rfol))
- {
- lfol.merge_next = rfol.merge_next;
- }
-
- // Attach the rfol's folder (except the merge folder)
- while (lfol.next != null)
- lfol = lfol.next;
- lfol.next = rfol.next;
-
- // Free disused merge folder
- //sys.free(rfol);
-
- // Attach rfol's files
- fi = lcab.files;
- while (fi.next != null)
- fi = fi.next;
- fi.next = rcab.files;
-
- // Delete all files from rfol's merge folder
- lfi = null;
- for (fi = lcab.files; fi != null; fi = rfi)
- {
- rfi = fi.next;
- // If file's folder matches the merge folder, unlink and free it
- if (fi.folder == rfol)
- {
- if (lfi != null)
- lfi.next = rfi;
- else
- lcab.files = rfi;
- //sys.free(fi.filename);
- //sys.free(fi);
- }
- else
- lfi = fi;
- }
- }
-
- // All done! fix files and folders pointers in all cabs so they all
- // point to the same list
- for (cab = lcab.prevcab; cab != null; cab = cab.prevcab)
- {
- cab.files = lcab.files;
- cab.folders = lcab.folders;
- }
-
- for (cab = lcab.nextcab; cab != null; cab = cab.nextcab)
- {
- cab.files = lcab.files;
- cab.folders = lcab.folders;
- }
-
- return this.error = MSPACK_ERR.MSPACK_ERR_OK;
- }
-
- ///
- /// Decides if two folders are OK to merge
- ///
- private int CanMergeFolders(mspack_system sys, mscabd_folder lfol, mscabd_folder rfol)
- {
- mscabd_file lfi, rfi, l, r;
- int matching = 1;
-
- // Check that both folders use the same compression method/settings
- if (lfol.comp_type != rfol.comp_type)
- {
- System.Console.Error.WriteLine("folder merge: compression type mismatch");
- return 0;
- }
-
- /* check there are not too many data blocks after merging */
- if ((lfol.num_blocks + rfol.num_blocks) > CAB_FOLDERMAX)
- {
- System.Console.Error.WriteLine("folder merge: too many data blocks in merged folders");
- return 0;
- }
-
- if ((lfi = lfol.merge_next) == null || (rfi = rfol.merge_prev) == null)
- {
- System.Console.Error.WriteLine("folder merge: one cabinet has no files to merge");
- return 0;
- }
-
- // For all files in lfol (which is the last folder in whichever cab and
- // only has files to merge), compare them to the files from rfol. They
- // should be identical in number and order. to verify this, check the
- // offset and length of each file.
- for (l = lfi, r = rfi; l != null; l = l.next, r = r.next)
- {
- if (r == null || (l.offset != r.offset) || (l.length != r.length))
- {
- matching = 0;
- break;
- }
- }
-
- if (matching != 0)
- return 1;
-
- // If rfol does not begin with an identical copy of the files in lfol, make
- // make a judgement call; if at least ONE file from lfol is in rfol, allow
- // the merge with a warning about missing files.
- matching = 0;
- for (l = lfi; l != null; l = l.next)
- {
- for (r = rfi; r != null; r = r.next)
- {
- if (l.offset == r.offset && l.length == r.length)
- break;
- }
- if (r != null)
- matching = 1;
- else
- sys.message(null, $"WARNING; merged file {l.filename} not listed in both cabinets");
- }
- return matching;
- }
-
- ///
- /// Extracts a file from a cabinet or cabinet set.
- ///
- /// This extracts a compressed file in a cabinet and writes it to the given
- /// filename.
- ///
- /// The MS-DOS filename of the file, mscabd_file::filename, is NOT USED
- /// by extract(). The caller must examine this MS-DOS filename, copy and
- /// change it as necessary, create directories as necessary, and provide
- /// the correct filename as a parameter, which will be passed unchanged
- /// to the decompressor's mspack_system::open()
- ///
- /// If the file belongs to a split folder in a multi-part cabinet set,
- /// and not enough parts of the cabinet set have been loaded and appended
- /// or prepended, an error will be returned immediately.
- ///
- /// The file to be decompressed
- /// The filename of the file being written to
- /// An error code, or MSPACK_ERR.MSPACK_ERR_OK if successful
- public MSPACK_ERR extract(mscabd_file file, in string filename)
- {
- mspack_file fh;
- uint filelen;
-
- if (file == null)
- return this.error = MSPACK_ERR.MSPACK_ERR_ARGS;
-
- mspack_system sys = this.system;
- mscabd_folder fol = file.folder;
-
- // If offset is beyond 2GB, nothing can be extracted
- if (file.offset > CAB_LENGTHMAX)
- {
- return this.error = MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
- }
-
- /* if file claims to go beyond 2GB either error out,
- * or in salvage mode reduce file length so it fits 2GB limit
- */
- filelen = file.length;
- if (filelen > (CAB_LENGTHMAX - file.offset))
- {
- if (this.salvage != 0)
- {
- filelen = CAB_LENGTHMAX - file.offset;
- }
- else
- {
- return this.error = MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
- }
- }
-
- // Extraction impossible if no folder, or folder needs predecessor
- if (fol == null || fol.merge_prev != null)
- {
- sys.message(null, $"ERROR; file \"{file.filename}\" cannot be extracted, cabinet set is incomplete");
- return this.error = MSPACK_ERR.MSPACK_ERR_DECRUNCH;
- }
-
- // If file goes beyond what can be decoded, given an error.
- // In salvage mode, don't assume block sizes, just try decoding
- if (this.salvage == 0)
- {
- uint maxlen = fol.num_blocks * CAB_BLOCKMAX;
- if (file.offset > maxlen || filelen > (maxlen - file.offset))
- {
- sys.message(null, $"ERROR; file \"{file.filename}\" cannot be extracted, cabinet set is incomplete");
- return this.error = MSPACK_ERR.MSPACK_ERR_DECRUNCH;
- }
- }
-
- // Allocate generic decompression state
- if (this.d == null)
- {
- this.d = new None.DecompressState();
- this.d.sys = sys as CABSystem;
- }
-
- // Do we need to change folder or reset the current folder?
- if ((this.d.folder != fol) || (this.d.offset > file.offset) || this.d.state == null)
- {
- // Free any existing decompressor
- cabd_free_decomp(this);
-
- // Do we need to open a new cab file?
- if (this.d.infh == null || (fol.data.cab != this.d.incab))
- {
- // Close previous file handle if from a different cab
- if (this.d.infh != null)
- sys.close(this.d.infh);
- this.d.incab = fol.data.cab;
- this.d.infh = sys.open(fol.data.cab.filename, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_READ);
- if (this.d.infh == null)
- return this.error = MSPACK_ERR.MSPACK_ERR_OPEN;
- }
- // Seek to start of data blocks
- if (sys.seek(this.d.infh, fol.data.offset, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_START) != 0)
- {
- return this.error = MSPACK_ERR.MSPACK_ERR_SEEK;
- }
-
- // Set up decompressor
- if (cabd_init_decomp(this, fol.comp_type) != MSPACK_ERR.MSPACK_ERR_OK)
- {
- return this.error;
- }
-
- // Initialise new folder state
- this.d.folder = fol;
- this.d.data = fol.data;
- this.d.offset = 0;
- this.d.block = 0;
- this.d.outlen = 0;
- this.d.i_ptr = this.d.i_end = d.input;
-
- // Read_error lasts for the lifetime of a decompressor
- this.read_error = MSPACK_ERR.MSPACK_ERR_OK;
- }
-
- // Open file for output
- if ((fh = sys.open(filename, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_WRITE)) == null)
- {
- return this.error = MSPACK_ERR.MSPACK_ERR_OPEN;
- }
-
- this.error = MSPACK_ERR.MSPACK_ERR_OK;
-
- // If file has more than 0 bytes
- if (filelen != 0)
- {
- long bytes;
- MSPACK_ERR error;
- // Get to correct offset.
- // - use null fh to say 'no writing' to cabd_sys_write()
- // - if cabd_sys_read() has an error, it will set this.read_error
- // and pass back MSPACK_ERR_READ
- this.d.outfh = null;
- if ((bytes = file.offset - this.d.offset) != 0)
- {
- error = this.d.decompress(this.d.state, bytes);
- this.error = (error == MSPACK_ERR.MSPACK_ERR_READ) ? this.read_error : error;
- }
-
- // If getting to the correct offset was error free, unpack file
- if (this.error == MSPACK_ERR.MSPACK_ERR_OK)
- {
- this.d.outfh = fh;
- error = this.d.decompress(this.d.state, filelen);
- this.error = (error == MSPACK_ERR.MSPACK_ERR_READ) ? this.read_error : error;
- }
- }
-
- // Close output file
- sys.close(fh);
- this.d.outfh = null;
-
- return this.error;
- }
-
- ///
- /// Sets a CAB decompression engine parameter.
- ///
- /// The following parameters are defined:
- /// - #MSCABD_PARAM_SEARCHBUF: How many bytes should be allocated as a
- /// buffer when using search()? The minimum value is 4. The default
- /// value is 32768.
- /// - #MSCABD_PARAM_FIXMSZIP: If non-zero, extract() will ignore bad
- /// checksums and recover from decompression errors in MS-ZIP
- /// compressed folders. The default value is 0 (don't recover).
- /// - #MSCABD_PARAM_DECOMPBUF: How many bytes should be used as an input
- /// bit buffer by decompressors? The minimum value is 4. The default
- /// value is 4096.
- ///
- /// The parameter to set
- /// The value to set the parameter to
- ///
- /// 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.
- ///
- ///
- ///
- 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;
- }
-
- ///
- /// Returns the error code set by the most recently called method.
- ///
- /// This is useful for open() and search(), which do not return an error
- /// code directly.
- ///
- /// The most recent error code
- ///
- ///
- public MSPACK_ERR last_error()
- {
- return this.error;
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/CAB/cab.cs b/libmspack/CAB/cab.cs
deleted file mode 100644
index 6a35523..0000000
--- a/libmspack/CAB/cab.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-using static SabreTools.Compression.libmspack.CAB.Constants;
-
-namespace SabreTools.Compression.libmspack
-{
- public unsafe static class cab
- {
- #region decomp
-
- ///
- /// cabd_free_decomp frees decompression state, according to which method
- /// was used.
- ///
- public static MSPACK_ERR cabd_init_decomp(CAB.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 None.DecompressState(self.d);
- self.d.state = new None.State(self.d.sys, fh, fh, self.buf_size);
- break;
- case MSCAB_COMP.MSCAB_COMP_MSZIP:
- self.d = new mscabd_mszipd_decompress_state();
- 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;
- }
-
- ///
- /// cabd_init_decomp initialises decompression state, according to which
- /// decompression method was used. relies on self.d.folder being the same
- /// as when initialised.
- ///
- public static void cabd_free_decomp(CAB.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_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
- }
-}
\ No newline at end of file
diff --git a/libmspack/CAB/mscabd_cabinet.cs b/libmspack/CAB/mscabd_cabinet.cs
deleted file mode 100644
index dfb5588..0000000
--- a/libmspack/CAB/mscabd_cabinet.cs
+++ /dev/null
@@ -1,125 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- ///
- /// A structure which represents a single cabinet file.
- ///
- /// All fields are READ ONLY.
- ///
- /// If this cabinet is part of a merged cabinet set, the #files and #folders
- /// fields are common to all cabinets in the set, and will be identical.
- ///
- ///
- ///
- ///
- public unsafe class mscabd_cabinet
- {
- ///
- /// 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
- /// list.
- ///
- public mscabd_cabinet next { get; set; }
-
- ///
- /// The filename of the cabinet. More correctly, the filename of the
- /// physical file that the cabinet resides in. This is given by the
- /// library user and may be in any format.
- ///
- public string filename { get; set; }
-
- ///
- /// The file offset of cabinet within the physical file it resides in.
- ///
- public long base_offset { get; set; }
-
- ///
- /// The length of the cabinet file in bytes.
- ///
- public uint length { get; set; }
-
- ///
- /// The previous cabinet in a cabinet set, or null.
- ///
- public mscabd_cabinet prevcab { get; set; }
-
- ///
- /// The next cabinet in a cabinet set, or null.
- ///
- public mscabd_cabinet nextcab { get; set; }
-
- ///
- /// The filename of the previous cabinet in a cabinet set, or null.
- ///
- public string prevname { get; set; }
-
- ///
- /// The filename of the next cabinet in a cabinet set, or null.
- ///
- public string nextname { get; set; }
-
- ///
- /// The name of the disk containing the previous cabinet in a cabinet
- /// set, or null.
- ///
- public string previnfo { get; set; }
-
- ///
- /// The name of the disk containing the next cabinet in a cabinet set,
- /// or null.
- ///
- public string nextinfo { get; set; }
-
- ///
- /// A list of all files in the cabinet or cabinet set.
- ///
- public mscabd_file files { get; set; }
-
- ///
- /// A list of all folders in the cabinet or cabinet set.
- ///
- public mscabd_folder folders { get; set; }
-
- ///
- /// The set ID of the cabinet. All cabinets in the same set should have
- /// the same set ID.
- ///
- public ushort set_id { get; set; }
-
- ///
- /// The index number of the cabinet within the set. Numbering should
- /// start from 0 for the first cabinet in the set, and increment by 1 for
- /// each following cabinet.
- ///
- public ushort set_index { get; set; }
-
- ///
- /// The number of bytes reserved in the header area of the cabinet.
- ///
- /// If this is non-zero and flags has MSCAB_HDR_RESV set, this data can
- /// be read by the calling application. It is of the given length,
- /// located at offset (base_offset + MSCAB_HDR_RESV_OFFSET) in the
- /// cabinet file.
- ///
- public ushort header_resv { get; set; }
-
- ///
- /// Header flags.
- ///
- ///
- ///
- ///
- ///
- ///
- public MSCAB_HDR flags { get; set; }
-
- ///
- /// Offset to data blocks
- ///
- public long blocks_off { get; set; }
-
- ///
- /// Reserved space in data blocks
- ///
- public int block_resv { get; set; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/CAB/mscabd_decompress_state.cs b/libmspack/CAB/mscabd_decompress_state.cs
deleted file mode 100644
index de01f6d..0000000
--- a/libmspack/CAB/mscabd_decompress_state.cs
+++ /dev/null
@@ -1,83 +0,0 @@
-using SabreTools.Compression.libmspack.CAB;
-using static SabreTools.Compression.libmspack.CAB.Constants;
-
-namespace SabreTools.Compression.libmspack
-{
- public unsafe abstract class mscabd_decompress_state
- {
- ///
- /// Current folder we're extracting from
- ///
- public mscabd_folder folder { get; set; }
-
- ///
- /// Current folder split we're in
- ///
- public mscabd_folder_data data { get; set; }
-
- ///
- /// Uncompressed offset within folder
- ///
- public uint offset { get; set; }
-
- ///
- /// Which block are we decompressing?
- ///
- public uint block { get; set; }
-
- ///
- /// Cumulative sum of block output sizes
- ///
- public long outlen { get; set; }
-
- ///
- /// Special I/O code for decompressor
- ///
- public CABSystem sys { get; set; }
-
- ///
- /// Type of compression used by folder
- ///
- public MSCAB_COMP comp_type { get; set; }
-
- ///
- /// Decompressor state
- ///
- public object state { get; set; }
-
- ///
- /// Cabinet where input data comes from
- ///
- public mscabd_cabinet incab { get; set; }
-
- ///
- /// Input file handle
- ///
- public mspack_file infh { get; set; }
-
- ///
- /// Output file handle
- ///
- public mspack_file outfh { get; set; }
-
- ///
- /// Input data consumed
- ///
- public byte* i_ptr { get; set; }
-
- ///
- /// Input data end
- ///
- public byte* i_end { get; set; }
-
- ///
- /// One input block of data
- ///
- public FixedArray input { get; set; } = new FixedArray(CAB_INPUTBUF);
-
- ///
- /// Decompressor code
- ///
- public abstract MSPACK_ERR decompress(object data, long offset);
- }
-}
\ No newline at end of file
diff --git a/libmspack/CAB/mscabd_file.cs b/libmspack/CAB/mscabd_file.cs
deleted file mode 100644
index 57682ed..0000000
--- a/libmspack/CAB/mscabd_file.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- ///
- /// A structure which represents a single file in a cabinet or cabinet set.
- ///
- /// All fields are READ ONLY.
- ///
- public class mscabd_file
- {
- ///
- /// The next file in the cabinet or cabinet set, or null if this is the
- /// final file.
- ///
- public mscabd_file next { get; set; }
-
- ///
- /// The filename of the file.
- ///
- /// A null terminated string of up to 255 bytes in length, it may be in
- /// either ISO-8859-1 or UTF8 format, depending on the file attributes.
- ///
- public string filename { get; set; }
-
- ///
- /// The uncompressed length of the file, in bytes.
- ///
- public uint length { get; set; }
-
- ///
- /// File attributes.
- ///
- public MSCAB_ATTRIB attribs { get; set; }
-
- ///
- /// File's last modified time, hour field.
- ///
- public char time_h { get; set; }
-
- ///
- /// File's last modified time, minute field.
- ///
- public char time_m { get; set; }
-
- ///
- /// File's last modified time, second field.
- ///
- public char time_s { get; set; }
-
- ///
- /// File's last modified date, day field.
- ///
- public char date_d { get; set; }
-
- ///
- /// File's last modified date, month field.
- ///
- public char date_m { get; set; }
-
- ///
- /// File's last modified date, year field.
- ///
- public int date_y;
-
- ///
- /// A pointer to the folder that contains this file.
- ///
- public mscabd_folder folder { get; set; }
-
- ///
- /// The uncompressed offset of this file in its folder.
- ///
- public uint offset { get; set; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/CAB/mscabd_folder.cs b/libmspack/CAB/mscabd_folder.cs
deleted file mode 100644
index 31d17ff..0000000
--- a/libmspack/CAB/mscabd_folder.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- ///
- /// A structure which represents a single folder in a cabinet or cabinet set.
- ///
- /// All fields are READ ONLY.
- ///
- /// A folder is a single compressed stream of data. When uncompressed, it
- /// holds the data of one or more files. A folder may be split across more
- /// than one cabinet.
- ///
- public class mscabd_folder
- {
- ///
- /// A pointer to the next folder in this cabinet or cabinet set, or null
- /// if this is the final folder.
- ///
- public mscabd_folder next { get; set; }
-
- ///
- /// The compression format used by this folder.
- ///
- /// The macro MSCABD_COMP_METHOD() should be used on this field to get
- /// the algorithm used. The macro MSCABD_COMP_LEVEL() should be used to get
- /// the "compression level".
- ///
- ///
- ///
- public MSCAB_COMP comp_type { get; set; }
-
- ///
- /// The total number of data blocks used by this folder. This includes
- /// data blocks present in other files, if this folder spans more than
- /// one cabinet.
- ///
- public uint num_blocks { get; set; }
-
- ///
- /// Where are the data blocks?
- ///
- public mscabd_folder_data data { get; set; }
-
- ///
- /// First file needing backwards merge
- ///
- public mscabd_file merge_prev { get; set; }
-
- ///
- /// First file needing forwards merge
- ///
- public mscabd_file merge_next { get; set; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/CAB/mscabd_folder_data.cs b/libmspack/CAB/mscabd_folder_data.cs
deleted file mode 100644
index 91a2442..0000000
--- a/libmspack/CAB/mscabd_folder_data.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- ///
- /// There is one of these for every cabinet a folder spans
- ///
- public class mscabd_folder_data
- {
- public mscabd_folder_data next { get; set; }
-
- ///
- /// Cabinet file of this folder span
- ///
- public mscabd_cabinet cab { get; set; }
-
- ///
- /// Cabinet offset of first datablock
- ///
- public long offset { get; set; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/CHM/Compressor.cs b/libmspack/CHM/Compressor.cs
deleted file mode 100644
index d090cbb..0000000
--- a/libmspack/CHM/Compressor.cs
+++ /dev/null
@@ -1,169 +0,0 @@
-namespace SabreTools.Compression.libmspack.CHM
-{
- ///
- /// A compressor for .CHM (Microsoft HTMLHelp) files.
- ///
- /// All fields are READ ONLY.
- ///
- ///
- public class Compressor : BaseCompressor
- {
- public string temp_file { get; private set; }
-
- public int use_temp_file { get; private set; }
-
- ///
- /// Creates a new CHM compressor
- ///
- public Compressor()
- {
- this.system = new mspack_default_system();
- this.error = MSPACK_ERR.MSPACK_ERR_OK;
- }
-
- ///
- /// Generates a CHM help file.
- ///
- /// The help file will contain up to two sections, an Uncompressed
- /// section and potentially an MSCompressed (LZX compressed)
- /// section.
- ///
- /// While the contents listing of a CHM file is always in lexical order,
- /// the file list passed in will be taken as the correct order for files
- /// within the sections. It is in your interest to place similar files
- /// together for better compression.
- ///
- /// There are two modes of generation, to use a temporary file or not to
- /// use one. See use_temporary_file() for the behaviour of generate() in
- /// these two different modes.
- ///
- ///
- /// An array of mschmc_file structures, terminated
- /// with an entry whose mschmc_file::section field is
- /// #MSCHMC_ENDLIST. The order of the list is
- /// preserved within each section. The length of any
- /// mschmc_file::chm_filename string cannot exceed
- /// roughly 4096 bytes. Each source file must be able
- /// to supply as many bytes as given in the
- /// mschmc_file::length field.
- ///
- ///
- /// The file to write the generated CHM helpfile to.
- /// This is passed directly to mspack_system::open()
- ///
- /// An error code, or MSPACK_ERR_OK if successful
- ///
- ///
- public MSPACK_ERR generate(mschmc_file[] file_list, in string output_file) => MSPACK_ERR.MSPACK_ERR_OK;
-
- ///
- /// Specifies whether a temporary file is used during CHM generation.
- ///
- /// The CHM file format includes data about the compressed section (such
- /// as its overall size) that is stored in the output CHM file prior to
- /// the compressed section itself. This unavoidably requires that the
- /// compressed section has to be generated, before these details can be
- /// set. There are several ways this can be handled. Firstly, the
- /// compressed section could be generated entirely in memory before
- /// writing any of the output CHM file. This approach is not used in
- /// libmspack, as the compressed section can exceed the addressable
- /// memory space on most architectures.
- ///
- /// libmspack has two options, either to write these unknowable sections
- /// with blank data, generate the compressed section, then re-open the
- /// output file for update once the compressed section has been
- /// completed, or to write the compressed section to a temporary file,
- /// then write the entire output file at once, performing a simple
- /// file-to-file copy for the compressed section.
- ///
- /// The simple solution of buffering the entire compressed section in
- /// memory can still be used, if desired. As the temporary file's
- /// filename is passed directly to mspack_system::open(), it is possible
- /// for a custom mspack_system implementation to hold this file in memory,
- /// without writing to a disk.
- ///
- /// If a temporary file is set, generate() performs the following
- /// sequence of events: the temporary file is opened for writing, the
- /// compression algorithm writes to the temporary file, the temporary
- /// file is closed. Then the output file is opened for writing and the
- /// temporary file is re-opened for reading. The output file is written
- /// and the temporary file is read from. Both files are then closed. The
- /// temporary file itself is not deleted. If that is desired, the
- /// temporary file should be deleted after the completion of generate(),
- /// if it exists.
- ///
- /// If a temporary file is set not to be used, generate() performs the
- /// following sequence of events: the output file is opened for writing,
- /// then it is written and closed. The output file is then re-opened for
- /// update, the appropriate sections are seek()ed to and re-written, then
- /// the output file is closed.
- ///
- ///
- /// Non-zero if the temporary file should be used,
- /// zero if the temporary file should not be used.
- ///
- ///
- /// A file to temporarily write compressed data to,
- /// before opening it for reading and copying the
- /// contents to the output file. This is passed
- /// directly to mspack_system::open().
- ///
- /// An error code, or MSPACK_ERR_OK if successful
- ///
- public MSPACK_ERR use_temporary_file(int use_temp_file, in string temp_file) => MSPACK_ERR.MSPACK_ERR_OK;
-
- ///
- /// Sets a CHM compression engine parameter.
- ///
- /// The following parameters are defined:
- ///
- /// - #MSCHMC_PARAM_TIMESTAMP: Sets the "timestamp" of the CHM file
- /// generated. This is not a timestamp, see mschmd_header::timestamp
- /// for a description. If this timestamp is 0, generate() will use its
- /// own algorithm for making a unique ID, based on the lengths and
- /// names of files in the CHM itself. Defaults to 0, any value between
- /// 0 and (2^32)-1 is valid.
- /// - #MSCHMC_PARAM_LANGUAGE: Sets the "language" of the CHM file
- /// generated. This is not the language used in the CHM file, but the
- /// language setting of the user who ran the HTMLHelp compiler. It
- /// defaults to 0x0409. The valid range is between 0x0000 and 0x7F7F.
- /// - #MSCHMC_PARAM_LZXWINDOW: Sets the size of the LZX history window,
- /// which is also the interval at which the compressed data stream can be
- /// randomly accessed. The value is not a size in bytes, but a power of
- /// two. The default value is 16 (which makes the window 2^16 bytes, or
- /// 64 kilobytes), the valid range is from 15 (32 kilobytes) to 21 (2
- /// megabytes).
- /// - #MSCHMC_PARAM_DENSITY: Sets the "density" of quick reference
- /// entries stored at the end of directory listing chunk. Each chunk is
- /// 4096 bytes in size, and contains as many file entries as there is
- /// room for. At the other end of the chunk, a list of "quick reference"
- /// pointers is included. The offset of every 'N'th file entry is given a
- /// quick reference, where N = (2^density) + 1. The default density is
- /// 2. The smallest density is 0 (N=2), the maximum is 10 (N=1025). As
- /// each file entry requires at least 5 bytes, the maximum number of
- /// entries in a single chunk is roughly 800, so the maximum value 10
- /// can be used to indicate there are no quickrefs at all.
- /// - #MSCHMC_PARAM_INDEX: Sets whether or not to include quick lookup
- /// index chunk(s), in addition to normal directory listing chunks. A
- /// value of zero means no index chunks will be created, a non-zero value
- /// means index chunks will be created. The default is zero, "don't
- /// create an index".
- ///
- /// The parameter to set
- /// The value to set the parameter to
- ///
- /// MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if there
- /// is a problem with either parameter or value.
- ///
- ///
- public MSPACK_ERR set_param(MSCHMC_PARAM param, int value) => MSPACK_ERR.MSPACK_ERR_OK;
-
- ///
- /// Returns the error code set by the most recently called method.
- ///
- /// The most recent error code
- ///
- ///
- public MSPACK_ERR last_error() => MSPACK_ERR.MSPACK_ERR_OK;
- }
-}
\ No newline at end of file
diff --git a/libmspack/CHM/Constants.cs b/libmspack/CHM/Constants.cs
deleted file mode 100644
index 828c227..0000000
--- a/libmspack/CHM/Constants.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-namespace SabreTools.Compression.libmspack.CHM
-{
- public static class Constants
- {
- public const ushort chmhead_Signature = 0x0000;
- public const ushort chmhead_Version = 0x0004;
- public const ushort chmhead_HeaderLen = 0x0008;
- public const ushort chmhead_Unknown1 = 0x000C;
- public const ushort chmhead_Timestamp = 0x0010;
- public const ushort chmhead_LanguageID = 0x0014;
- public const ushort chmhead_GUID1 = 0x0018;
- public const ushort chmhead_GUID2 = 0x0028;
- public const ushort chmhead_SIZEOF = 0x0038;
-
- public const ushort chmhst_OffsetHS0 = 0x0000;
- public const ushort chmhst_LengthHS0 = 0x0008;
- public const ushort chmhst_OffsetHS1 = 0x0010;
- public const ushort chmhst_LengthHS1 = 0x0018;
- public const ushort chmhst_SIZEOF = 0x0020;
- public const ushort chmhst3_OffsetCS0 = 0x0020;
- public const ushort chmhst3_SIZEOF = 0x0028;
-
- public const ushort chmhs0_Unknown1 = 0x0000;
- public const ushort chmhs0_Unknown2 = 0x0004;
- public const ushort chmhs0_FileLen = 0x0008;
- public const ushort chmhs0_Unknown3 = 0x0010;
- public const ushort chmhs0_Unknown4 = 0x0014;
- public const ushort chmhs0_SIZEOF = 0x0018;
-
- public const ushort chmhs1_Signature = 0x0000;
- public const ushort chmhs1_Version = 0x0004;
- public const ushort chmhs1_HeaderLen = 0x0008;
- public const ushort chmhs1_Unknown1 = 0x000C;
- public const ushort chmhs1_ChunkSize = 0x0010;
- public const ushort chmhs1_Density = 0x0014;
- public const ushort chmhs1_Depth = 0x0018;
- public const ushort chmhs1_IndexRoot = 0x001C;
- public const ushort chmhs1_FirstPMGL = 0x0020;
- public const ushort chmhs1_LastPMGL = 0x0024;
- public const ushort chmhs1_Unknown2 = 0x0028;
- public const ushort chmhs1_NumChunks = 0x002C;
- public const ushort chmhs1_LanguageID = 0x0030;
- public const ushort chmhs1_GUID = 0x0034;
- public const ushort chmhs1_Unknown3 = 0x0044;
- public const ushort chmhs1_Unknown4 = 0x0048;
- public const ushort chmhs1_Unknown5 = 0x004C;
- public const ushort chmhs1_Unknown6 = 0x0050;
- public const ushort chmhs1_SIZEOF = 0x0054;
-
- public const ushort pmgl_Signature = 0x0000;
- public const ushort pmgl_QuickRefSize = 0x0004;
- public const ushort pmgl_Unknown1 = 0x0008;
- public const ushort pmgl_PrevChunk = 0x000C;
- public const ushort pmgl_NextChunk = 0x0010;
- public const ushort pmgl_Entries = 0x0014;
- public const ushort pmgl_headerSIZEOF = 0x0014;
-
- public const ushort pmgi_Signature = 0x0000;
- public const ushort pmgi_QuickRefSize = 0x0004;
- public const ushort pmgi_Entries = 0x0008;
- public const ushort pmgi_headerSIZEOF = 0x000C;
-
- public const ushort lzxcd_Length = 0x0000;
- public const ushort lzxcd_Signature = 0x0004;
- public const ushort lzxcd_Version = 0x0008;
- public const ushort lzxcd_ResetInterval = 0x000C;
- public const ushort lzxcd_WindowSize = 0x0010;
- public const ushort lzxcd_CacheSize = 0x0014;
- public const ushort lzxcd_Unknown1 = 0x0018;
- public const ushort lzxcd_SIZEOF = 0x001C;
-
- public const ushort lzxrt_Unknown1 = 0x0000;
- public const ushort lzxrt_NumEntries = 0x0004;
- public const ushort lzxrt_EntrySize = 0x0008;
- public const ushort lzxrt_TableOffset = 0x000C;
- public const ushort lzxrt_UncompLen = 0x0010;
- public const ushort lzxrt_CompLen = 0x0018;
- public const ushort lzxrt_FrameLen = 0x0020;
- public const ushort lzxrt_Entries = 0x0028;
- public const ushort lzxrt_headerSIZEOF = 0x0028;
- }
-}
\ No newline at end of file
diff --git a/libmspack/CHM/Decompressor.cs b/libmspack/CHM/Decompressor.cs
deleted file mode 100644
index da62113..0000000
--- a/libmspack/CHM/Decompressor.cs
+++ /dev/null
@@ -1,922 +0,0 @@
-using System;
-using System.Linq;
-using System.Runtime.InteropServices;
-using static SabreTools.Compression.libmspack.CHM.Constants;
-using static SabreTools.Compression.libmspack.macros;
-using static SabreTools.Compression.libmspack.system;
-
-namespace SabreTools.Compression.libmspack.CHM
-{
- ///
- /// A decompressor for .CHM (Microsoft HTMLHelp) files
- ///
- /// All fields are READ ONLY.
- ///
- ///
- public unsafe class Decompressor : BaseDecompressor
- {
- public mschmd_decompress_state d { get; private set; }
-
- // Filenames of the system files used for decompression.
- // Content and ControlData are essential.
- // ResetTable is preferred, but SpanInfo can be used if not available
- private const string content_name = "::DataSpace/Storage/MSCompressed/Content";
- private const string control_name = "::DataSpace/Storage/MSCompressed/ControlData";
- private const string spaninfo_name = "::DataSpace/Storage/MSCompressed/SpanInfo";
- private const string rtable_name = "::DataSpace/Storage/MSCompressed/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTable";
-
- // The GUIDs found in CHM header
- private static readonly byte[] guids = new byte[32]
- {
- // {7C01FD10-7BAA-11D0-9E0C-00A0-C922-E6EC}
- 0x10, 0xFD, 0x01, 0x7C, 0xAA, 0x7B, 0xD0, 0x11,
- 0x9E, 0x0C, 0x00, 0xA0, 0xC9, 0x22, 0xE6, 0xEC,
-
- // {7C01FD11-7BAA-11D0-9E0C-00A0-C922-E6EC}
- 0x11, 0xFD, 0x01, 0x7C, 0xAA, 0x7B, 0xD0, 0x11,
- 0x9E, 0x0C, 0x00, 0xA0, 0xC9, 0x22, 0xE6, 0xEC
- };
-
- ///
- /// Creates a new CHM decompressor
- ///
- public Decompressor()
- {
- this.system = new mspack_default_system();
- error = MSPACK_ERR.MSPACK_ERR_OK;
- d = null;
- }
-
- ///
- /// Destroys an existing CHM decompressor
- ///
- ~Decompressor()
- {
- mspack_system sys = this.system;
- if (this.d != null)
- {
- if (this.d.infh != null) sys.close(this.d.infh);
- if (this.d.state != null) lzxd_free(this.d.state);
- //sys.free(this.d);
- }
- //sys.free(this);
- }
-
- ///
- /// Opens a CHM helpfile and reads its contents.
- ///
- /// If the file opened is a valid CHM helpfile, all headers will be read
- /// 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
- /// is available from last_error().
- ///
- /// The filename pointer should be considered "in use" until close() is
- /// called on the CHM helpfile.
- ///
- ///
- /// The filename of the CHM helpfile. This is passed
- /// directly to mspack_system::open().
- ///
- /// A pointer to a mschmd_header structure, or null on failure
- ///
- public mschmd_header open(in string filename)
- {
- return chmd_real_open(filename, 1);
- }
-
- ///
- /// Closes a previously opened CHM helpfile.
- ///
- /// This closes a CHM helpfile, frees the mschmd_header and all
- /// mschmd_file structures associated with it (if any). This works on
- /// both helpfiles opened with open() and helpfiles opened with
- /// fast_open().
- ///
- /// The CHM header pointer is now invalid and cannot be used again. All
- /// mschmd_file pointers referencing that CHM are also now invalid, and
- /// cannot be used again.
- ///
- /// The CHM helpfile to close
- ///
- ///
- public void close(mschmd_header chm)
- {
- mschmd_file fi, nfi;
- mspack_system sys;
- uint i;
-
- sys = this.system;
-
- this.error = MSPACK_ERR.MSPACK_ERR_OK;
-
- // Free files
- for (fi = chm.files; fi != null; fi = nfi)
- {
- nfi = fi.next;
- //sys.free(fi);
- }
- for (fi = chm.sysfiles; fi != null; fi = nfi)
- {
- nfi = fi.next;
- //sys.free(fi);
- }
-
- // If this CHM was being decompressed, free decompression state
- if (this.d != null && (this.d.chm == chm))
- {
- if (this.d.infh != null) sys.close(this.d.infh);
- if (this.d.state != null) lzxd_free(this.d.state);
- //sys.free(this.d);
- this.d = null;
- }
-
- // If this CHM had a chunk cache, free it and contents
- if (chm.chunk_cache != null)
- {
- for (i = 0; i < chm.num_chunks; i++) sys.free(chm.chunk_cache[i]);
- sys.free(chm.chunk_cache);
- }
-
- //sys.free(chm);
- }
-
- ///
- /// Reads the basic CHM file headers. If the "entire" parameter is
- /// non-zero, all file entries will also be read. fills out a pre-existing
- /// mschmd_header structure, allocates memory for files as necessary
- ///
- private MSPACK_ERR chmd_read_headers(mspack_system sys, mspack_file fh, mschmd_header chm, int entire)
- {
- uint errors, num_chunks;
- FixedArray buf = new FixedArray(0x54);
- FixedArray chunk = null;
- byte* name, p, end;
- mschmd_file fi, link = null;
- long offset_hs0, filelen;
- int num_entries;
- MSPACK_ERR err = MSPACK_ERR.MSPACK_ERR_OK;
-
- // Initialise pointers
- chm.files = null;
- chm.sysfiles = null;
- chm.chunk_cache = null;
- chm.sec0.chm = chm;
- chm.sec0.id = 0;
- chm.sec1.chm = chm;
- chm.sec1.id = 1;
- chm.sec1.content = null;
- chm.sec1.control = null;
- chm.sec1.spaninfo = null;
- chm.sec1.rtable = null;
-
- // Read the first header
- if (sys.read(fh, buf, chmhead_SIZEOF) != chmhead_SIZEOF)
- {
- return MSPACK_ERR.MSPACK_ERR_READ;
- }
-
- // Check ITSF signature
- if (EndGetI32(buf, chmhead_Signature) != 0x46535449)
- {
- return MSPACK_ERR.MSPACK_ERR_SIGNATURE;
- }
-
- // Check both header GUIDs
- if (!buf.ToArray().Skip(chmhead_GUID1).Take(guids.Length).SequenceEqual(guids))
- {
- Console.Error.WriteLine("Incorrect GUIDs");
- return MSPACK_ERR.MSPACK_ERR_SIGNATURE;
- }
-
- chm.version = EndGetI32(buf, chmhead_Version);
- chm.timestamp = EndGetM32(buf, chmhead_Timestamp);
- chm.language = EndGetI32(buf, chmhead_LanguageID);
- if (chm.version > 3)
- {
- sys.message(fh, "WARNING; CHM version > 3");
- }
-
- // Read the header section table
- if (sys.read(fh, buf, chmhst3_SIZEOF) != chmhst3_SIZEOF)
- {
- return MSPACK_ERR.MSPACK_ERR_READ;
- }
-
- // chmhst3_OffsetCS0 does not exist in version 1 or 2 CHM files.
- // The offset will be corrected later, once HS1 is read.
- if (read_off64(&offset_hs0, &buf[chmhst_OffsetHS0], sys, fh) ||
- read_off64(&chm.dir_offset, &buf[chmhst_OffsetHS1], sys, fh) ||
- read_off64(&chm.sec0.offset, &buf[chmhst3_OffsetCS0], sys, fh))
- {
- return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
- }
-
- // Seek to header section 0
- if (sys.seek(fh, offset_hs0, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_START) != 0)
- {
- return MSPACK_ERR.MSPACK_ERR_SEEK;
- }
-
- // Read header section 0
- if (sys.read(fh, buf, chmhs0_SIZEOF) != chmhs0_SIZEOF)
- {
- return MSPACK_ERR.MSPACK_ERR_READ;
- }
-
- if (read_off64(&chm.length, &buf[chmhs0_FileLen], sys, fh))
- {
- return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
- }
-
- // Compare declared CHM file size against actual size
- if (mspack_sys_filelen(sys, fh, &filelen) == 0)
- {
- if (chm.length > filelen)
- {
- sys.message(fh, $"WARNING; file possibly truncated by {chm.length - filelen} bytes");
- }
- else if (chm.length < filelen)
- {
- sys.message(fh, $"WARNING; possible {filelen - chm.length} extra bytes at end of file");
- }
- }
-
- // Seek to header section 1
- if (sys.seek(fh, chm.dir_offset, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_START) != 0)
- {
- return MSPACK_ERR.MSPACK_ERR_SEEK;
- }
-
- // Read header section 1
- if (sys.read(fh, buf, chmhs1_SIZEOF) != chmhs1_SIZEOF)
- {
- return MSPACK_ERR.MSPACK_ERR_READ;
- }
-
- chm.dir_offset = sys.tell(fh);
- chm.chunk_size = EndGetI32(buf, chmhs1_ChunkSize);
- chm.density = EndGetI32(buf, chmhs1_Density);
- chm.depth = EndGetI32(buf, chmhs1_Depth);
- chm.index_root = EndGetI32(buf, chmhs1_IndexRoot);
- chm.num_chunks = EndGetI32(buf, chmhs1_NumChunks);
- chm.first_pmgl = EndGetI32(buf, chmhs1_FirstPMGL);
- chm.last_pmgl = EndGetI32(buf, chmhs1_LastPMGL);
-
- if (chm.version < 3)
- {
- // Versions before 3 don't have chmhst3_OffsetCS0
- chm.sec0.offset = chm.dir_offset + (chm.chunk_size * chm.num_chunks);
- }
-
- // Check if content offset or file size is wrong
- if (chm.sec0.offset > chm.length)
- {
- Console.Error.WriteLine("content section begins after file has ended");
- return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
- }
-
- // Ensure there are chunks and that chunk size is
- // large enough for signature and num_entries
- if (chm.chunk_size < (pmgl_Entries + 2))
- {
- Console.Error.WriteLine("chunk size not large enough");
- return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
- }
- if (chm.num_chunks == 0)
- {
- Console.Error.WriteLine("no chunks");
- return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
- }
-
- // The chunk_cache data structure is not great; large values for num_chunks
- // or num_chunks*chunk_size can exhaust all memory. Until a better chunk
- // cache is implemented, put arbitrary limits on num_chunks and chunk size.
- if (chm.num_chunks > 100000)
- {
- Console.Error.WriteLine("more than 100,000 chunks");
- return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
- }
- if (chm.chunk_size > 8192)
- {
- Console.Error.WriteLine("chunk size over 8192 (get in touch if this is valid)");
- return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
- }
- if ((long)chm.chunk_size * (long)chm.num_chunks > chm.length)
- {
- Console.Error.WriteLine("chunks larger than entire file");
- return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
- }
-
- // Common sense checks on header section 1 fields
- if (chm.chunk_size != 4096)
- {
- sys.message(fh, "WARNING; chunk size is not 4096");
- }
- if (chm.first_pmgl != 0)
- {
- sys.message(fh, "WARNING; first PMGL chunk is not zero");
- }
- if (chm.first_pmgl > chm.last_pmgl)
- {
- Console.Error.WriteLine("first pmgl chunk is after last pmgl chunk");
- return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
- }
- if (chm.index_root != 0xFFFFFFFF && chm.index_root >= chm.num_chunks)
- {
- Console.Error.WriteLine("index_root outside valid range");
- return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
- }
-
- // If we are doing a quick read, stop here!
- if (entire == 0)
- {
- return MSPACK_ERR.MSPACK_ERR_OK;
- }
-
- // Seek to the first PMGL chunk, and reduce the number of chunks to read
- if (chm.first_pmgl != 0)
- {
- long pmgl_offset = (long)chm.first_pmgl * (long)chm.chunk_size;
- if (sys.seek(fh, pmgl_offset, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_CUR) != 0)
- {
- return MSPACK_ERR.MSPACK_ERR_SEEK;
- }
- }
- num_chunks = chm.last_pmgl - chm.first_pmgl + 1;
-
- chunk = new FixedArray((int)chm.chunk_size);
-
- // Read and process all chunks from FirstPMGL to LastPMGL
- errors = 0;
- while (num_chunks-- > 0)
- {
- // Read next chunk
- if (sys.read(fh, chunk, (int)chm.chunk_size) != (int)chm.chunk_size)
- {
- sys.free(chunk);
- return MSPACK_ERR.MSPACK_ERR_READ;
- }
-
- // Process only directory (PMGL) chunks
- if (EndGetI32(chunk, pmgl_Signature) != 0x4C474D50) continue;
-
- if (EndGetI32(chunk, pmgl_QuickRefSize) < 2)
- {
- sys.message(fh, "WARNING; PMGL quickref area is too small");
- }
- if (EndGetI32(chunk, pmgl_QuickRefSize) >
- (chm.chunk_size - pmgl_Entries))
- {
- sys.message(fh, "WARNING; PMGL quickref area is too large");
- }
-
- p = (byte*)chunk.Pointer + pmgl_Entries;
- end = (byte*)chunk.Pointer + chm.chunk_size - 2;
- num_entries = EndGetI16(chunk, (int)(chm.chunk_size - 2));
-
- while (num_entries-- > 0)
- {
- uint name_len, section;
- long offset, length;
- name_len = read_encint(&p, end, &err);
- if (err != MSPACK_ERR.MSPACK_ERR_OK || (name_len > (uint)(end - p))) goto encint_err;
- name = p; p += name_len;
- section = read_encint(&p, end, &err);
- offset = read_encint(&p, end, &err);
- length = read_encint(&p, end, &err);
- if (err != MSPACK_ERR.MSPACK_ERR_OK) goto encint_err;
-
- // Ignore blank or one-char (e.g. "/") filenames we'd return as blank */
- if (name_len < 2 || name[0] == 0x00 || name[1] == 0x00) continue;
-
- // Empty files and directory names are stored as a file entry at
- // offset 0 with length 0. We want to keep empty files, but not
- // directory names, which end with a "/"
- if ((offset == 0) && (length == 0))
- {
- if ((name_len > 0) && (name[name_len - 1] == '/')) continue;
- }
-
- if (section > 1)
- {
- sys.message(fh, $"Invalid section number '{section}'.");
- continue;
- }
-
- fi = new mschmd_file();
- fi.next = null;
- fi.section = (section == 0 ? (mschmd_section)chm.sec0 : (mschmd_section)chm.sec1);
- fi.offset = offset;
- fi.length = length;
-
- char[] filenameArr = new char[name_len];
- Marshal.Copy((IntPtr)name, filenameArr, 0, (int)name_len);
- filenameArr[(int)name_len] = '\0';
- fi.filename = new string(filenameArr);
-
- if (name[0] == ':' && name[1] == ':')
- {
- // System file
- if (name_len == 40 && fi.filename.StartsWith(content_name))
- {
- chm.sec1.content = fi;
- }
- else if (name_len == 44 && fi.filename.StartsWith(control_name))
- {
- chm.sec1.control = fi;
- }
- else if (name_len == 41 && fi.filename.StartsWith(spaninfo_name))
- {
- chm.sec1.spaninfo = fi;
- }
- else if (name_len == 105 && fi.filename.StartsWith(rtable_name))
- {
- chm.sec1.rtable = fi;
- }
- fi.next = chm.sysfiles;
- chm.sysfiles = fi;
- }
- else
- {
- // Normal file
- if (link != null) link.next = fi; else chm.files = fi;
- link = fi;
- }
- }
-
- // This is reached either when num_entries runs out, or if
- // an ENCINT is badly encoded
- encint_err:
- if (num_entries >= 0)
- {
- Console.Error.WriteLine("bad encint before all entries could be read");
- errors++;
- }
- }
-
- sys.free(chunk);
- return (errors > 0) ? MSPACK_ERR.MSPACK_ERR_DATAFORMAT : MSPACK_ERR.MSPACK_ERR_OK;
- }
-
- ///
- /// Extracts a file from a CHM helpfile.
- ///
- /// This extracts a file from a CHM helpfile and writes it to the given
- /// filename. The filename of the file, mscabd_file::filename, is not
- /// used by extract(), but can be used by the caller as a guide for
- /// constructing an appropriate filename.
- ///
- /// This method works both with files found in the mschmd_header::files
- /// and mschmd_header::sysfiles list and mschmd_file structures generated
- /// on the fly by fast_find().
- ///
- /// The file to be decompressed
- /// The filename of the file being written to
- /// An error code, or MSPACK_ERR_OK if successful
- public MSPACK_ERR extract(mschmd_file file, in string filename) => throw new NotImplementedException();
-
- ///
- /// Returns the error code set by the most recently called method.
- ///
- /// This is useful for open() and fast_open(), which do not return an
- /// error code directly.
- ///
- /// The most recent error code
- ///
- ///
- public MSPACK_ERR last_error() => throw new NotImplementedException();
-
- ///
- /// Opens a CHM helpfile quickly.
- ///
- /// 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
- /// 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
- /// is available from last_error().
- ///
- /// The filename pointer should be considered "in use" until close() is
- /// called on the CHM helpfile.
- ///
- ///
- /// The filename of the CHM helpfile. This is passed
- /// directly to mspack_system::open().
- ///
- /// A pointer to a mschmd_header structure, or null on failure
- ///
- ///
- ///
- ///
- public mschmd_header fast_open(in string filename)
- {
- return chmd_real_open(filename, 0);
- }
-
- ///
- /// The real implementation of chmd_open() and chmd_fast_open(). It simply
- /// passes the "entire" parameter to chmd_read_headers(), which will then
- /// either read all headers, or a bare mininum.
- ///
- private mschmd_header chmd_real_open(in string filename, int entire)
- {
- mschmd_header chm = null;
- MSPACK_ERR error;
-
- mspack_system sys = this.system;
-
- mspack_file fh;
- if ((fh = sys.open(filename, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_READ)) != null)
- {
- chm = new mschmd_header();
- chm.filename = filename;
- error = chmd_read_headers(sys, fh, chm, entire);
- if (error != MSPACK_ERR.MSPACK_ERR_OK)
- {
- // If the error is DATAFORMAT, and there are some results, return
- // partial results with a warning, rather than nothing
- if (error == MSPACK_ERR.MSPACK_ERR_DATAFORMAT && (chm.files != null || chm.sysfiles != null))
- {
- sys.message(fh, "WARNING; contents are corrupt");
- error = MSPACK_ERR.MSPACK_ERR_OK;
- }
- else
- {
- close(chm);
- chm = null;
- }
- }
-
- this.error = error;
- sys.close(fh);
- }
- else
- {
- this.error = MSPACK_ERR.MSPACK_ERR_OPEN;
- }
- return chm;
- }
-
- ///
- /// Finds file details quickly.
- ///
- /// Instead of reading all CHM helpfile headers and building a list of
- /// files, fast_open() and fast_find() are intended for finding file
- /// details only when they are needed. The CHM file format includes an
- /// on-disk file index to allow this.
- ///
- /// Given a case-sensitive filename, fast_find() will search the on-disk
- /// index for that file.
- ///
- /// If the file was found, the caller-provided mschmd_file structure will
- /// be filled out like so:
- /// - 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
- ///
- /// 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
- /// - offset: 0
- /// - length: 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
- /// using the regular open().
- ///
- /// The CHM helpfile to search for the file
- /// The filename of the file to search for
- /// A pointer to a caller-provded mschmd_file structure
- /// sizeof(mschmd_file)
- /// An error code, or MSPACK_ERR_OK if successful
- ///
- ///
- ///
- ///
- public MSPACK_ERR fast_find(mschmd_header chm, in string filename, ref mschmd_file f_ptr, int f_size)
- {
- mspack_system sys;
- mspack_file fh;
-
- // p and end are initialised to prevent MSVC warning about "potentially"
- // uninitialised usage. This is provably untrue, but MS won't fix:
- // https://developercommunity.visualstudio.com/content/problem/363489/c4701-false-positive-warning.html
- FixedArray chunk;
- byte* p = null, end = null;
- MSPACK_ERR err = MSPACK_ERR.MSPACK_ERR_OK;
- int result = -1;
- uint n, sec;
-
- if (chm == null || f_ptr == null)
- {
- return MSPACK_ERR.MSPACK_ERR_ARGS;
- }
-
- sys = this.system;
-
- // Clear the results structure
- f_ptr = new mschmd_file();
-
- if ((fh = sys.open(chm.filename, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_READ)) == null)
- {
- return MSPACK_ERR.MSPACK_ERR_OPEN;
- }
-
- // Go through PMGI chunk hierarchy to reach PMGL chunk
- if (chm.index_root < chm.num_chunks)
- {
- n = chm.index_root;
- for (; ; )
- {
- if ((chunk = read_chunk(chm, fh, n)) == null)
- {
- sys.close(fh);
- return this.error;
- }
-
- // Search PMGI/PMGL chunk. exit early if no entry found
- if ((result = search_chunk(chm, chunk, filename, &p, &end)) <= 0)
- {
- break;
- }
-
- // Found result. loop around for next chunk if this is PMGI
- if (chunk[3] == 0x4C) break;
-
- n = read_encint(&p, end, &err);
- if (err != MSPACK_ERR.MSPACK_ERR_OK) goto encint_err;
- }
- }
- else
- {
- // PMGL chunks only, search from first_pmgl to last_pmgl
- for (n = chm.first_pmgl; n <= chm.last_pmgl; n = EndGetI32(chunk, pmgl_NextChunk))
- {
- if ((chunk = read_chunk(chm, fh, n)) == null)
- {
- err = this.error;
- break;
- }
-
- // Search PMGL chunk. exit if file found
- if ((result = search_chunk(chm, chunk, filename, &p, &end)) > 0)
- {
- break;
- }
-
- // Stop simple infinite loops: can't visit the same chunk twice
- if (n == EndGetI32(chunk, pmgl_NextChunk))
- {
- break;
- }
- }
- }
-
- // If we found a file, read it
- if (result > 0)
- {
- sec = read_encint(&p, end, &err);
- f_ptr.section = (sec == 0) ? (mschmd_section)chm.sec0 : (mschmd_section)chm.sec1;
- f_ptr.offset = read_encint(&p, end, &err);
- f_ptr.length = read_encint(&p, end, &err);
- if (err != MSPACK_ERR.MSPACK_ERR_OK) goto encint_err;
- }
- else if (result < 0)
- {
- err = MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
- }
-
- sys.close(fh);
- return this.error = err;
-
- encint_err:
- Console.Error.WriteLine("Bad encint in PGMI/PGML chunk");
- sys.close(fh);
- return this.error = MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
- }
-
- ///
- /// Reads the given chunk into memory, storing it in a chunk cache
- /// so it doesn't need to be read from disk more than once
- ///
- ///
- private FixedArray read_chunk(mschmd_header chm, mspack_file fh, uint chunk_num)
- {
- mspack_system sys = this.system;
- FixedArray buf;
-
- // Check arguments - most are already checked by chmd_fast_find
- if (chunk_num >= chm.num_chunks) return null;
-
- // Ensure chunk cache is available
- if (chm.chunk_cache == null)
- {
- chm.chunk_cache = new FixedArray[chm.num_chunks];
- if (chm.chunk_cache == null)
- {
- this.error = MSPACK_ERR.MSPACK_ERR_NOMEMORY;
- return null;
- }
- }
-
- // Try to answer out of chunk cache
- if (chm.chunk_cache[chunk_num] != null) return chm.chunk_cache[chunk_num];
-
- // Need to read chunk - allocate memory for it
- buf = new FixedArray((int)chm.chunk_size);
-
- // Seek to block and read it
- if (sys.seek(fh, chm.dir_offset + (chunk_num * chm.chunk_size), MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_START) != 0)
- {
- this.error = MSPACK_ERR.MSPACK_ERR_SEEK;
- sys.free(buf);
- return null;
- }
- if (sys.read(fh, buf, (int)chm.chunk_size) != (int)chm.chunk_size)
- {
- this.error = MSPACK_ERR.MSPACK_ERR_READ;
- sys.free(buf);
- return null;
- }
-
- // Check the signature. Is is PMGL or PMGI?
- if (!((buf[0] == 0x50) && (buf[1] == 0x4D) && (buf[2] == 0x47) && ((buf[3] == 0x4C) || (buf[3] == 0x49))))
- {
- this.error = MSPACK_ERR.MSPACK_ERR_SEEK;
- sys.free(buf);
- return null;
- }
-
- // All OK. Store chunk in cache and return it
- return chm.chunk_cache[chunk_num] = buf;
- }
-
- ///
- /// Searches a PMGI/PMGL chunk for a given filename entry. Returns -1 on
- /// data format error, 0 if entry definitely not found, 1 if entry
- /// found. In the latter case, *result and *result_end are set pointing
- /// to that entry's data (either the "next chunk" ENCINT for a PMGI or
- /// the section, offset and length ENCINTs for a PMGL).
- ///
- /// In the case of PMGL chunks, the entry has definitely been
- /// found. In the case of PMGI chunks, the entry which points to the
- /// chunk that may eventually contain that entry has been found.
- ///
- ///
- private int search_chunk(mschmd_header chm, in FixedArray chunk, in string filename, byte** result, byte** result_end)
- {
- byte* p;
- uint qr_size, num_entries, qr_entries, qr_density, name_len;
- uint L, R, M, entries_off, is_pmgl;
- int cmp;
- MSPACK_ERR err = MSPACK_ERR.MSPACK_ERR_OK;
-
- uint fname_len = (uint)filename.Length;
-
- // PMGL chunk or PMGI chunk? (note: read_chunk() has already
- // checked the rest of the characters in the chunk signature)
- if (chunk[3] == 0x4C)
- {
- is_pmgl = 1;
- entries_off = pmgl_Entries;
- }
- else
- {
- is_pmgl = 0;
- entries_off = pmgi_Entries;
- }
-
- // Step 1: binary search first filename of each QR entry
- // - target filename == entry
- // found file
- // - target filename < all entries
- // file not found
- // - target filename > all entries
- // proceed to step 2 using final entry
- // - target filename between two searched entries
- // proceed to step 2
- qr_size = EndGetI32(chunk, pmgl_QuickRefSize);
- int start = (int)(chm.chunk_size - 2);
- int end = (int)(chm.chunk_size - qr_size);
- num_entries = EndGetI16(chunk, (int)(chm.chunk_size - 2));
- qr_density = (uint)(1 + (1 << (int)chm.density));
- qr_entries = (num_entries + qr_density - 1) / qr_density;
-
- if (num_entries == 0)
- {
- Console.Error.WriteLine("Chunk has no entries");
- return -1;
- }
-
- if (qr_size > chm.chunk_size)
- {
- Console.Error.WriteLine("Quickref size > chunk size");
- return -1;
- }
-
- *result_end = &chunk[end];
-
- if (((int)qr_entries * 2) > (start - end))
- {
- Console.Error.WriteLine("WARNING; more quickrefs than quickref space");
- qr_entries = 0; // But we can live with it
- }
-
- if (qr_entries > 0)
- {
- L = 0;
- R = qr_entries - 1;
- do
- {
- // Pick new midpoint
- M = (L + R) >> 1;
-
- // Compare filename with entry QR points to
- p = &chunk[entries_off + (M != 0 ? EndGetI16(chunk, start - (int)(M << 1)) : 0)];
- name_len = read_encint(&p, end, &err);
- if (err != MSPACK_ERR.MSPACK_ERR_OK || (name_len > (uint)(end - p))) goto encint_err;
- cmp = compare(filename, (char*)p, fname_len, name_len);
-
- if (cmp == 0) break;
- else if (cmp < 0) { if (M) R = M - 1; else return 0; }
- else if (cmp > 0) L = M + 1;
- } while (L <= R);
- M = (L + R) >> 1;
-
- if (cmp == 0)
- {
- /* exact match! */
- p += name_len;
- *result = p;
- return 1;
- }
-
- /* otherwise, read the group of entries for QR entry M */
- p = &chunk[entries_off + (M ? EndGetI16(chunk, start - (M << 1)) : 0)];
- num_entries -= (M * qr_density);
- if (num_entries > qr_density) num_entries = qr_density;
- }
- else
- {
- p = &chunk[entries_off];
- }
-
- /* Step 2: linear search through the set of entries reached in step 1.
- * - filename == any entry
- * found entry
- * - filename < all entries (PMGI) or any entry (PMGL)
- * entry not found, stop now
- * - filename > all entries
- * entry not found (PMGL) / maybe found (PMGI)
- * -
- */
- *result = null;
- while (num_entries-- > 0)
- {
- name_len = read_encint(&p, end, &err);
- if (err || (name_len > (uint)(end - p))) goto encint_err;
- cmp = compare(filename, (char*)p, fname_len, name_len);
- p += name_len;
-
- if (cmp == 0)
- {
- /* entry found */
- *result = p;
- return 1;
- }
-
- if (cmp < 0)
- {
- /* entry not found (PMGL) / maybe found (PMGI) */
- break;
- }
-
- /* read and ignore the rest of this entry */
- if (is_pmgl)
- {
- while (p < end && (*p++ & 0x80)) ; /* skip section ENCINT */
- while (p < end && (*p++ & 0x80)) ; /* skip offset ENCINT */
- while (p < end && (*p++ & 0x80)) ; /* skip length ENCINT */
- }
- else
- {
- *result = p; /* store potential final result */
- while (p < end && (*p++ & 0x80)) ; /* skip chunk number ENCINT */
- }
- }
-
- /* PMGL? not found. PMGI? maybe found */
- return (is_pmgl) ? 0 : (*result ? 1 : 0);
-
- encint_err:
- Console.Error.WriteLine("bad encint while searching");
- return -1;
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/CHM/mschmc_file.cs b/libmspack/CHM/mschmc_file.cs
deleted file mode 100644
index f633c69..0000000
--- a/libmspack/CHM/mschmc_file.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- ///
- /// A structure which represents a file to be placed in a CHM helpfile.
- ///
- /// A contiguous array of these structures should be passed to
- /// mschm_compressor::generate(). The array list is terminated with an
- /// entry whose mschmc_file::section field is set to #MSCHMC_ENDLIST, the
- /// other fields in this entry are ignored.
- ///
- public class mschmc_file
- {
- ///
- /// One of values.
- ///
- public MSCHMC section { get; set; }
-
- ///
- /// The filename of the source file that will be added to the CHM. This
- /// is passed directly to mspack_system::open().
- ///
- public string filename { get; set; }
-
- ///
- /// The full path and filename of the file within the CHM helpfile, a
- /// UTF-1 encoded null-terminated string.
- ///
- public string chm_filename { get; set; }
-
- ///
- /// The length of the file, in bytes. This will be adhered to strictly
- /// and a read error will be issued if this many bytes cannot be read
- /// from the real file at CHM generation time.
- ///
- public long length { get; set; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/CHM/mschmd_decompress_state.cs b/libmspack/CHM/mschmd_decompress_state.cs
deleted file mode 100644
index aefd3ce..0000000
--- a/libmspack/CHM/mschmd_decompress_state.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- public class mschmd_decompress_state
- {
- ///
- /// CHM file being decompressed
- ///
- public mschmd_header chm { get; set; }
-
- ///
- /// Uncompressed length of LZX stream
- ///
- public long length { get; set; }
-
- ///
- /// Uncompressed offset within stream
- ///
- public long offset { get; set; }
-
- ///
- /// Offset in input file
- ///
- public long inoffset { get; set; }
-
- ///
- /// LZX decompressor state
- ///
- public lzxd_stream state { get; set; }
-
- ///
- /// Special I/O code for decompressor
- ///
- public mspack_system sys { get; set; }
-
- ///
- /// Input file handle
- ///
- public mspack_file infh { get; set; }
-
- ///
- /// Output file handle
- ///
- public mspack_file outfh { get; set; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/CHM/mschmd_file.cs b/libmspack/CHM/mschmd_file.cs
deleted file mode 100644
index 0b92633..0000000
--- a/libmspack/CHM/mschmd_file.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- ///
- /// A structure which represents a file stored in a CHM helpfile.
- ///
- /// All fields are READ ONLY.
- ///
- public class mschmd_file
- {
- ///
- /// A pointer to the next file in the list, or null if this is the final
- /// file.
- ///
- public mschmd_file next { get; set; }
-
- ///
- /// A pointer to the section that this file is located in. Indirectly,
- /// it also points to the CHM helpfile the file is located in.
- ///
- public mschmd_section section { get; set; }
-
- ///
- /// The offset within the section data that this file is located at.
- ///
- public long offset { get; set; }
-
- ///
- /// The length of this file, in bytes
- ///
- public long length { get; set; }
-
- ///
- /// The filename of this file -- a null terminated string in UTF-8.
- ///
- public string filename { get; set; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/CHM/mschmd_header.cs b/libmspack/CHM/mschmd_header.cs
deleted file mode 100644
index 844e5bc..0000000
--- a/libmspack/CHM/mschmd_header.cs
+++ /dev/null
@@ -1,120 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- ///
- /// A structure which represents a CHM helpfile.
- ///
- /// All fields are READ ONLY.
- ///
- public unsafe class mschmd_header
- {
- ///
- /// The version of the CHM file format used in this file.
- ///
- public uint version { get; set; }
-
- ///
- /// The "timestamp" of the CHM helpfile.
- ///
- /// It is the lower 32 bits of a 64-bit value representing the number of
- /// centiseconds since 1601-01-01 00:00:00 UTC, plus 42. It is not useful
- /// as a timestamp, but it is useful as a semi-unique ID.
- ///
- public uint timestamp { get; set; }
-
- ///
- /// The default Language and Country ID (LCID) of the user who ran the
- /// HTMLHelp Compiler. This is not the language of the CHM file itself.
- ///
- public uint language { get; set; }
-
- ///
- /// The filename of the CHM helpfile. This is given by the library user
- /// and may be in any format.
- ///
- public string filename { get; set; }
-
- ///
- /// The length of the CHM helpfile, in bytes.
- ///
- public long length { get; set; }
-
- ///
- /// A list of all non-system files in the CHM helpfile.
- ///
- public mschmd_file files { get; set; }
-
- ///
- /// A list of all system files in the CHM helpfile.
- ///
- /// System files are files which begin with "::". They are meta-files
- /// generated by the CHM creation process.
- ///
- public mschmd_file sysfiles { get; set; }
-
- ///
- /// The section 0 (uncompressed) data in this CHM helpfile.
- ///
- public mschmd_sec_uncompressed sec0 { get; set; }
-
- ///
- /// The section 1 (MSCompressed) data in this CHM helpfile.
- ///
- public mschmd_sec_mscompressed sec1 { get; set; }
-
- ///
- /// The file offset of the first PMGL/PMGI directory chunk.
- ///
- public long dir_offset { get; set; }
-
- ///
- /// The number of PMGL/PMGI directory chunks in this CHM helpfile.
- ///
- public uint num_chunks { get; set; }
-
- ///
- /// The size of each PMGL/PMGI chunk, in bytes.
- ///
- public uint chunk_size { get; set; }
-
- ///
- /// The "density" of the quick-reference section in PMGL/PMGI chunks.
- ///
- public uint density { get; set; }
-
- ///
- /// The depth of the index tree.
- ///
- /// - if 1, there are no PMGI chunks, only PMGL chunks.
- /// - if 2, there is 1 PMGI chunk. All chunk indices point to PMGL chunks.
- /// - if 3, the root PMGI chunk points to secondary PMGI chunks, which in
- /// turn point to PMGL chunks.
- /// - and so on...
- ///
- public uint depth { get; set; }
-
- ///
- /// The number of the root PMGI chunk.
- ///
- /// If there is no index in the CHM helpfile, this will be 0xFFFFFFFF.
- ///
- public uint index_root { get; set; }
-
- ///
- /// The number of the first PMGL chunk. Usually zero.
- /// Available only in CHM decoder version 2 and above.
- ///
- public uint first_pmgl { get; set; }
-
- ///
- /// The number of the last PMGL chunk. Usually num_chunks-1.
- /// Available only in CHM decoder version 2 and above.
- ///
- public uint last_pmgl { get; set; }
-
- ///
- /// A cache of loaded chunks, filled in by mschm_decoder::fast_find().
- /// Available only in CHM decoder version 2 and above.
- ///
- public FixedArray[] chunk_cache { get; set; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/CHM/mschmd_sec_mscompressed.cs b/libmspack/CHM/mschmd_sec_mscompressed.cs
deleted file mode 100644
index fc990d4..0000000
--- a/libmspack/CHM/mschmd_sec_mscompressed.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- ///
- /// A structure which represents the LZX compressed section of a CHM helpfile.
- ///
- /// All fields are READ ONLY.
- ///
- public class mschmd_sec_mscompressed : mschmd_section
- {
- ///
- /// A pointer to the meta-file which represents all LZX compressed data.
- ///
- public mschmd_file content { get; set; }
-
- ///
- /// A pointer to the file which contains the LZX control data.
- ///
- public mschmd_file control { get; set; }
-
- ///
- /// A pointer to the file which contains the LZX reset table.
- ///
- public mschmd_file rtable { get; set; }
-
- ///
- /// A pointer to the file which contains the LZX span information.
- /// Available only in CHM decoder version 2 and above.
- ///
- public mschmd_file spaninfo { get; set; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/CHM/mschmd_sec_uncompressed.cs b/libmspack/CHM/mschmd_sec_uncompressed.cs
deleted file mode 100644
index ef5e8ee..0000000
--- a/libmspack/CHM/mschmd_sec_uncompressed.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- ///
- /// A structure which represents the uncompressed section of a CHM helpfile.
- ///
- /// All fields are READ ONLY.
- ///
- public class mschmd_sec_uncompressed : mschmd_section
- {
- ///
- /// The file offset of where this section begins in the CHM helpfile.
- ///
- public long offset { get; set; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/CHM/mschmd_section.cs b/libmspack/CHM/mschmd_section.cs
deleted file mode 100644
index 28f4265..0000000
--- a/libmspack/CHM/mschmd_section.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- ///
- /// A structure which represents a section of a CHM helpfile.
- ///
- /// All fields are READ ONLY.
- ///
- /// Not used directly, but used as a generic base type for
- /// mschmd_sec_uncompressed and mschmd_sec_mscompressed.
- ///
- public class mschmd_section
- {
- ///
- /// A pointer to the CHM helpfile that contains this section.
- ///
- public mschmd_header chm { get; set; }
-
- ///
- /// The section ID. Either 0 for the uncompressed section
- /// mschmd_sec_uncompressed, or 1 for the LZX compressed section
- /// mschmd_sec_mscompressed. No other section IDs are known.
- ///
- public uint id { get; set; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/Constants.cs b/libmspack/Constants.cs
deleted file mode 100644
index 4e6f91c..0000000
--- a/libmspack/Constants.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- public static class Constants
- {
- ///
- /// Offset from start of cabinet to the reserved header data (if present).
- ///
- public const int MSCAB_HDR_RESV_OFFSET = 0x28;
- }
-}
\ No newline at end of file
diff --git a/libmspack/Enums.cs b/libmspack/Enums.cs
deleted file mode 100644
index 058c74c..0000000
--- a/libmspack/Enums.cs
+++ /dev/null
@@ -1,422 +0,0 @@
-using System;
-
-namespace SabreTools.Compression.libmspack
-{
- #region mspack.h
-
- ///
- /// mspack_system::open() mode
- ///
- public enum MSPACK_SYS_OPEN : int
- {
- ///
- /// Open existing file for reading
- ///
- MSPACK_SYS_OPEN_READ = 0,
-
- ///
- /// Open new file for writing
- ///
- MSPACK_SYS_OPEN_WRITE = 1,
-
- ///
- /// Open existing file for writing
- ///
- MSPACK_SYS_OPEN_UPDATE = 2,
-
- ///
- /// Open existing file for writing
- ///
- MSPACK_SYS_OPEN_APPEND = 3,
- }
-
- ///
- /// mspack_system::seek() mode
- ///
- public enum MSPACK_SYS_SEEK : int
- {
- ///
- /// Seek relative to start of file
- ///
- MSPACK_SYS_SEEK_START = 0,
-
- ///
- /// Seek relative to current offset
- ///
- MSPACK_SYS_SEEK_CUR = 1,
-
- ///
- /// Seek relative to end of file
- ///
- MSPACK_SYS_SEEK_END = 2,
- }
-
- ///
- /// Error code
- ///
- public enum MSPACK_ERR : int
- {
- MSPACK_ERR_OK = 0,
-
- ///
- /// Bad arguments to method
- ///
- MSPACK_ERR_ARGS = 1,
-
- ///
- /// Error opening file
- ///
- MSPACK_ERR_OPEN = 2,
-
- ///
- /// Error reading file
- ///
- MSPACK_ERR_READ = 3,
-
- ///
- /// Error writing file
- ///
- MSPACK_ERR_WRITE = 4,
-
- ///
- /// Seek error
- ///
- MSPACK_ERR_SEEK = 5,
-
- ///
- /// Out of memory
- ///
- MSPACK_ERR_NOMEMORY = 6,
-
- ///
- /// Bad "magic id" in file
- ///
- MSPACK_ERR_SIGNATURE = 7,
-
- ///
- /// Bad or corrupt file format
- ///
- MSPACK_ERR_DATAFORMAT = 8,
-
- ///
- /// Bad checksum or CRC
- ///
- MSPACK_ERR_CHECKSUM = 9,
-
- ///
- /// Error during compression
- ///
- MSPACK_ERR_CRUNCH = 10,
-
- ///
- /// Error during decompression
- ///
- MSPACK_ERR_DECRUNCH = 11,
- }
-
- ///
- /// Cabinet header flag
- ///
- [Flags]
- public enum MSCAB_HDR : int
- {
- ///
- /// Cabinet has a predecessor
- ///
- MSCAB_HDR_PREVCAB = 0x01,
-
- ///
- /// Cabinet has a successor
- ///
- MSCAB_HDR_NEXTCAB = 0x02,
-
- ///
- /// Cabinet has reserved header space
- ///
- MSCAB_HDR_RESV = 0x04,
- }
-
- ///
- /// Compression mode
- ///
- public enum MSCAB_COMP : int
- {
- ///
- /// No compression
- ///
- MSCAB_COMP_NONE = 0,
-
- ///
- /// MSZIP (deflate) compression
- ///
- MSCAB_COMP_MSZIP = 1,
-
- ///
- /// Quantum compression
- ///
- MSCAB_COMP_QUANTUM = 2,
-
- ///
- /// LZX compression
- ///
- MSCAB_COMP_LZX = 3,
- }
-
- ///
- /// mscabd_file::attribs attribute
- ///
- [Flags]
- public enum MSCAB_ATTRIB : int
- {
- ///
- /// File is read-only
- ///
- MSCAB_ATTRIB_RDONLY = 0x01,
-
- ///
- /// File is hidden
- ///
- MSCAB_ATTRIB_HIDDEN = 0x02,
-
- ///
- /// File is an operating system file
- ///
- MSCAB_ATTRIB_SYSTEM = 0x04,
-
- ///
- /// File is "archived"
- ///
- MSCAB_ATTRIB_ARCH = 0x20,
-
- ///
- /// File is an executable program
- ///
- MSCAB_ATTRIB_EXEC = 0x40,
-
- ///
- /// Filename is UTF8, not ISO-8859-1
- ///
- MSCAB_ATTRIB_UTF_NAME = 0x80,
- }
-
- ///
- /// mschmc_file::section value
- ///
- public enum MSCHMC : int
- {
- ///
- /// End of CHM file list
- ///
- MSCHMC_ENDLIST = 0,
-
- ///
- /// This file is in the Uncompressed section
- ///
- MSCHMC_UNCOMP = 1,
-
- ///
- /// This file is in the MSCompressed section
- ///
- MSCHMC_MSCOMP = 2,
- }
-
- ///
- /// msszddd_header::format value
- ///
- public enum MSSZDD_FMT : int
- {
- ///
- /// A regular SZDD file
- ///
- MSSZDD_FMT_NORMAL = 0,
-
- ///
- /// A special QBasic SZDD file
- ///
- MSSZDD_FMT_QBASIC = 1,
- }
-
- ///
- /// WAJ compression type
- ///
- public enum MSKWAJ_COMP : int
- {
- ///
- /// No compression
- ///
- MSKWAJ_COMP_NONE = 0,
-
- ///
- /// No compression, 0xFF XOR "encryption"
- ///
- MSKWAJ_COMP_XOR = 1,
-
- ///
- /// LZSS (same method as SZDD)
- ///
- MSKWAJ_COMP_SZDD = 2,
-
- ///
- /// LZ+Huffman compression
- ///
- MSKWAJ_COMP_LZH = 3,
-
- ///
- /// MSZIP
- ///
- MSKWAJ_COMP_MSZIP = 4,
- }
-
- ///
- /// KWAJ optional header flag
- ///
- [Flags]
- public enum MSKWAJ_HDR : int
- {
- ///
- /// Decompressed file length is included
- ///
- MSKWAJ_HDR_HASLENGTH = 0x01,
-
- ///
- /// Unknown 2-byte structure is included
- ///
- MSKWAJ_HDR_HASUNKNOWN1 = 0x02,
-
- ///
- /// Unknown multi-sized structure is included
- ///
- MSKWAJ_HDR_HASUNKNOWN2 = 0x04,
-
- ///
- /// File name (no extension) is included
- ///
- MSKWAJ_HDR_HASFILENAME = 0x08,
-
- ///
- /// File extension is included
- ///
- MSKWAJ_HDR_HASFILEEXT = 0x10,
-
- ///
- /// Extra text is included
- ///
- MSKWAJ_HDR_HASEXTRATEXT = 0x20,
- }
-
- #region Parameters
-
- ///
- /// mscab_decompressor::set_param() parameter
- ///
- public enum MSCABD_PARAM : int
- {
- ///
- /// Search buffer size
- ///
- MSCABD_PARAM_SEARCHBUF = 0,
-
- ///
- /// Repair MS-ZIP streams?
- ///
- MSCABD_PARAM_FIXMSZIP = 1,
-
- ///
- /// Size of decompression buffer
- ///
- MSCABD_PARAM_DECOMPBUF = 2,
-
- ///
- /// Salvage data from bad cabinets?
- /// If enabled, open() will skip file with bad folder indices or filenames
- /// rather than reject the whole cabinet, and extract() will limit rather than
- /// reject files with invalid offsets and lengths, and bad data block checksums
- /// will be ignored. Available only in CAB decoder version 2 and above.
- ///
- MSCABD_PARAM_SALVAGE = 3,
- }
-
- ///
- /// mschm_compressor::set_param() parameter
- ///
- public enum MSCHMC_PARAM : int
- {
- ///
- /// "timestamp" header
- ///
- MSCHMC_PARAM_TIMESTAMP = 0,
-
- ///
- /// "language" header
- ///
- MSCHMC_PARAM_LANGUAGE = 1,
-
- ///
- /// LZX window size
- ///
- MSCHMC_PARAM_LZXWINDOW = 2,
-
- ///
- /// Intra-chunk quickref density
- ///
- MSCHMC_PARAM_DENSITY = 3,
-
- ///
- /// Whether to create indices
- ///
- MSCHMC_PARAM_INDEX = 4,
- }
-
- ///
- /// msszdd_compressor::set_param() parameter
- ///
- public enum MSSZDDC_PARAM : int
- {
- ///
- /// The missing character
- ///
- MSSZDDC_PARAM_MISSINGCHAR = 0,
- }
-
- ///
- /// mskwaj_compressor::set_param() parameter
- ///
- public enum MSKWAJC_PARAM : int
- {
- ///
- /// Compression type
- ///
- MSKWAJC_PARAM_COMP_TYPE = 0,
-
- ///
- /// Include the length of the uncompressed file in the header?
- ///
- MSKWAJC_PARAM_INCLUDE_LENGTH = 1,
- }
-
- ///
- /// msoab_decompressor::set_param() parameter
- ///
- public enum MSOABD_PARAM : int
- {
- ///
- /// Size of decompression buffer
- ///
- MSOABD_PARAM_DECOMPBUF = 0,
- }
-
- #endregion
-
- #endregion
-
- #region lzss.h
-
- public enum LZSS_MODE : int
- {
- LZSS_MODE_EXPAND = 0,
- LZSS_MODE_MSHELP = 1,
- LZSS_MODE_QBASIC = 2,
- }
-
- #endregion
-}
\ No newline at end of file
diff --git a/libmspack/FixedArray.cs b/libmspack/FixedArray.cs
deleted file mode 100644
index 9493f11..0000000
--- a/libmspack/FixedArray.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-namespace SabreTools.Compression.libmspack
-{
- public unsafe class FixedArray where T : struct
- {
- ///
- /// Direct access to the internal pointer
- ///
- public IntPtr Pointer { get; private set; }
-
- ///
- /// Size of the T object
- ///
- private int sizeofT { get { return Marshal.SizeOf(typeof(T)); } }
-
- ///
- /// Length of the fixed array
- ///
- private int _length;
-
- public T this[int i]
- {
- get
- {
- if (i < 0 || i >= _length)
- return default;
-
- return (T)Marshal.PtrToStructure(Pointer + i * sizeofT, typeof(T));
- }
- set
- {
- if (i < 0 || i >= _length)
- return;
-
- Marshal.StructureToPtr(value, Pointer + i * sizeofT, false);
- }
- }
-
- public FixedArray(int length)
- {
- Pointer = Marshal.AllocHGlobal(sizeofT * length);
- _length = 0;
- }
-
- ~FixedArray()
- {
- Marshal.FreeHGlobal(Pointer);
- }
-
- public static implicit operator T*(FixedArray arr) => (T*)arr.Pointer;
-
- public static implicit operator T[](FixedArray arr) => arr.ToArray();
-
- ///
- public bool SequenceEqual(T[] arr)
- {
- if (arr.Length < _length)
- return false;
-
- for (int i = 0; i < _length; i++)
- {
- if (!this[i].Equals(arr[i]))
- return false;
- }
-
- return true;
- }
-
- ///
- /// Convert the unmanaged data to an array
- ///
- /// Array created from the pointer data
- public T[] ToArray()
- {
- T[] arr = new T[_length];
- for (int i = 0; i < _length; i++)
- {
- arr[i] = this[i];
- }
-
- return arr;
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/HLP/Compressor.cs b/libmspack/HLP/Compressor.cs
deleted file mode 100644
index 4b3ac8c..0000000
--- a/libmspack/HLP/Compressor.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace SabreTools.Compression.libmspack.HLP
-{
- ///
- /// TODO
- ///
- public class Compressor : BaseCompressor
- {
- ///
- /// Creates a new HLP compressor
- ///
- public Compressor()
- {
- this.system = new mspack_default_system();
- this.error = MSPACK_ERR.MSPACK_ERR_OK;
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/HLP/Decompressor.cs b/libmspack/HLP/Decompressor.cs
deleted file mode 100644
index 91f2327..0000000
--- a/libmspack/HLP/Decompressor.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace SabreTools.Compression.libmspack.HLP
-{
- ///
- /// TODO
- ///
- public class Decompressor : BaseDecompressor
- {
- ///
- /// Creates a new HLP decompressor
- ///
- public Decompressor()
- {
- this.system = new mspack_default_system();
- this.error = MSPACK_ERR.MSPACK_ERR_OK;
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/KWAJ/Compressor.cs b/libmspack/KWAJ/Compressor.cs
deleted file mode 100644
index 59183bd..0000000
--- a/libmspack/KWAJ/Compressor.cs
+++ /dev/null
@@ -1,111 +0,0 @@
-namespace SabreTools.Compression.libmspack.KWAJ
-{
- ///
- /// A compressor for the KWAJ file format.
- ///
- /// All fields are READ ONLY.
- ///
- public unsafe class Compressor : BaseCompressor
- {
- public int[] param { get; private set; } = new int[2];
-
- ///
- /// Creates a new KWAJ compressor
- ///
- public Compressor()
- {
- this.system = new mspack_default_system();
- this.error = MSPACK_ERR.MSPACK_ERR_OK;
- }
-
- ///
- /// Reads an input file and creates a compressed output file in the
- /// KWAJ compressed file format. The KWAJ compression format is quick
- /// but gives poor compression. It is possible for the compressed output
- /// file to be larger than the input file.
- ///
- ///
- /// The name of the file to compressed. This is passed
- /// passed directly to mspack_system::open()
- ///
- ///
- /// The name of the file to write compressed data to.
- /// This is passed directly to mspack_system::open().
- ///
- ///
- /// The length of the uncompressed file, or -1 to indicate
- /// that this should be determined automatically by using
- /// mspack_system::seek() on the input file.
- ///
- /// An error code, or MSPACK_ERR_OK if successful
- ///
- public MSPACK_ERR compress(in string input, in string output, long length) => MSPACK_ERR.MSPACK_ERR_OK;
-
- ///
- /// Sets an KWAJ compression engine parameter.
- ///
- /// The following parameters are defined:
- ///
- /// - #MSKWAJC_PARAM_COMP_TYPE: the compression method to use. Must
- /// be one of #MSKWAJC_COMP_NONE, #MSKWAJC_COMP_XOR, #MSKWAJ_COMP_SZDD
- /// or #MSKWAJ_COMP_LZH. The default is #MSKWAJ_COMP_LZH.
- ///
- /// - #MSKWAJC_PARAM_INCLUDE_LENGTH: a boolean; should the compressed
- /// output file should include the uncompressed length of the input
- /// file in the header? This adds 4 bytes to the size of the output
- /// file. A value of zero says "no", non-zero says "yes". The default
- /// is "no".
- ///
- /// The parameter to set
- /// The value to set the parameter to
- ///
- /// MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if there
- /// is a problem with either parameter or value.
- ///
- ///
- public MSPACK_ERR set_param(MSKWAJC_PARAM param, int value) => MSPACK_ERR.MSPACK_ERR_OK;
-
- ///
- /// Sets the original filename of the file before compression,
- /// which will be stored in the header of the output file.
- ///
- /// The filename should be a null-terminated string, it must be an
- /// 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
- /// header. This is the default.
- ///
- /// The original filename to use
- ///
- /// MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if the
- /// filename is too long
- ///
- public MSPACK_ERR set_filename(in string filename) => MSPACK_ERR.MSPACK_ERR_OK;
-
- ///
- /// Sets arbitrary data that will be stored in the header of the
- /// output file, uncompressed. It can be up to roughly 64 kilobytes,
- /// 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
- /// length, no extra data is included in the header. This is the
- /// default.
- ///
- /// A pointer to the data to be stored in the header
- /// the length of the data in bytes
- ///
- /// MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS extra data
- /// is too long
- ///
- public MSPACK_ERR set_extra_data(void* data, int bytes) => MSPACK_ERR.MSPACK_ERR_OK;
-
- ///
- /// Returns the error code set by the most recently called method.
- ///
- /// The most recent error code
- ///
- public MSPACK_ERR last_error() => MSPACK_ERR.MSPACK_ERR_OK;
- }
-}
\ No newline at end of file
diff --git a/libmspack/KWAJ/Constants.cs b/libmspack/KWAJ/Constants.cs
deleted file mode 100644
index 0dd210e..0000000
--- a/libmspack/KWAJ/Constants.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-namespace SabreTools.Compression.libmspack.KWAJ
-{
- public static class Constants
- {
- public const byte kwajh_Signature1 = 0x00;
- public const byte kwajh_Signature2 = 0x04;
- public const byte kwajh_CompMethod = 0x08;
- public const byte kwajh_DataOffset = 0x0a;
- public const byte kwajh_Flags = 0x0c;
- public const byte kwajh_SIZEOF = 0x0e;
-
- ///
- /// Input buffer size during decompression - not worth parameterising IMHO
- ///
- public const int KWAJ_INPUT_SIZE = 2048;
-
- ///
- /// Huffman codes that are 9 bits or less are decoded immediately
- ///
- public const int KWAJ_TABLEBITS = 9;
-
- // Number of codes in each huffman table
- public const int KWAJ_MATCHLEN1_SYMS = 16;
- public const int KWAJ_MATCHLEN2_SYMS = 16;
- public const int KWAJ_LITLEN_SYMS = 32;
- public const int KWAJ_OFFSET_SYMS = 64;
- public const int KWAJ_LITERAL_SYMS = 256;
-
- // Define decoding table sizes
- public const int KWAJ_TABLESIZE = 1 << KWAJ_TABLEBITS;
- public const int KWAJ_MATCHLEN1_TBLSIZE = KWAJ_TABLESIZE + (KWAJ_MATCHLEN1_SYMS * 2);
- public const int KWAJ_MATCHLEN2_TBLSIZE = KWAJ_TABLESIZE + (KWAJ_MATCHLEN2_SYMS * 2);
- public const int KWAJ_LITLEN_TBLSIZE = KWAJ_TABLESIZE + (KWAJ_LITLEN_SYMS * 2);
- public const int KWAJ_OFFSET_TBLSIZE = KWAJ_TABLESIZE + (KWAJ_OFFSET_SYMS * 2);
- public const int KWAJ_LITERAL_TBLSIZE = KWAJ_TABLESIZE + (KWAJ_LITERAL_SYMS * 2);
- }
-}
\ No newline at end of file
diff --git a/libmspack/KWAJ/Decompressor.cs b/libmspack/KWAJ/Decompressor.cs
deleted file mode 100644
index 17972ca..0000000
--- a/libmspack/KWAJ/Decompressor.cs
+++ /dev/null
@@ -1,375 +0,0 @@
-using System;
-using static SabreTools.Compression.libmspack.KWAJ.Constants;
-using static SabreTools.Compression.libmspack.macros;
-
-namespace SabreTools.Compression.libmspack.KWAJ
-{
- ///
- /// A decompressor for KWAJ compressed files.
- ///
- /// All fields are READ ONLY.
- ///
- public unsafe class Decompressor : BaseDecompressor
- {
- ///
- /// Creates a new KWAJ decompressor.
- ///
- public Decompressor()
- {
- this.system = new mspack_default_system();
- this.error = MSPACK_ERR.MSPACK_ERR_OK;
- }
-
- ///
- /// Destroys an existing KWAJ decompressor
- ///
- ~Decompressor()
- {
- mspack_system sys = this.system;
- //sys.free(this);
- }
-
- ///
- /// Opens a KWAJ file and reads the header.
- ///
- /// 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
- /// is available from last_error().
- ///
- /// The filename pointer should be considered "in use" until close() is
- /// called on the KWAJ file.
- ///
- ///
- /// The filename of the KWAJ compressed file. This is
- /// passed directly to mspack_system::open().
- ///
- /// A pointer to a mskwajd_header structure, or null on failure
- ///
- public mskwajd_header Open(in string filename)
- {
- mspack_system sys = this.system;
-
- mspack_file fh = sys.open(filename, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_READ);
- if (fh == null)
- {
- this.error = MSPACK_ERR.MSPACK_ERR_OPEN;
- return null;
- }
-
- mskwajd_header hdr = new mskwajd_header();
- hdr.fh = fh;
-
- MSPACK_ERR err;
- if ((err = ReadHeaders(sys, fh, hdr)) != MSPACK_ERR.MSPACK_ERR_OK)
- {
- Close(hdr);
- this.error = err;
- return null;
- }
-
- return hdr;
- }
-
- ///
- /// Closes a previously opened KWAJ file.
- ///
- /// This closes a KWAJ file and frees the mskwajd_header associated
- /// with it. The KWAJ header pointer is now invalid and cannot be
- /// used again.
- ///
- /// The KWAJ file to close
- ///
- public void Close(mskwajd_header kwaj)
- {
- if (this.system == null)
- return;
-
- // Close the file handle associated
- this.system.close(kwaj.fh);
-
- // Free the memory associated
- //this.system.free(hdr.filename);
- //this.system.free(hdr.extra);
- //this.system.free(hdr);
-
- this.error = MSPACK_ERR.MSPACK_ERR_OK;
- }
-
- ///
- /// Reads the headers of a KWAJ format file
- ///
- private MSPACK_ERR ReadHeaders(mspack_system sys, mspack_file fh, mskwajd_header hdr)
- {
- FixedArray buf = new FixedArray(16);
- int i;
-
- // Read in the header
- if (sys.read(fh, buf, kwajh_SIZEOF) != kwajh_SIZEOF)
- {
- return MSPACK_ERR.MSPACK_ERR_READ;
- }
-
- // Check for "KWAJ" signature
- if ((BitConverter.ToUInt32(buf, kwajh_Signature1) != 0x4A41574B) ||
- (BitConverter.ToUInt32(buf, kwajh_Signature2) != 0xD127F088))
- {
- return MSPACK_ERR.MSPACK_ERR_SIGNATURE;
- }
-
- // Basic header fields
- hdr.comp_type = (MSKWAJ_COMP)BitConverter.ToUInt16(buf, kwajh_CompMethod);
- hdr.data_offset = BitConverter.ToUInt16(buf, kwajh_DataOffset);
- hdr.headers = (MSKWAJ_HDR)BitConverter.ToUInt16(buf, kwajh_Flags);
- hdr.length = 0;
- hdr.filename = null;
- hdr.extra = null;
- hdr.extra_length = 0;
-
- // Optional headers
-
- // 4 bytes: length of unpacked file
- if (hdr.headers.HasFlag(MSKWAJ_HDR.MSKWAJ_HDR_HASLENGTH))
- {
- if (sys.read(fh, buf, 4) != 4)
- return MSPACK_ERR.MSPACK_ERR_READ;
-
- hdr.length = BitConverter.ToUInt32(buf, 0);
- }
-
- // 2 bytes: unknown purpose
- if (hdr.headers.HasFlag(MSKWAJ_HDR.MSKWAJ_HDR_HASUNKNOWN1))
- {
- if (sys.read(fh, buf, 2) != 2)
- return MSPACK_ERR.MSPACK_ERR_READ;
- }
-
- // 2 bytes: length of section, then [length] bytes: unknown purpose
- if (hdr.headers.HasFlag(MSKWAJ_HDR.MSKWAJ_HDR_HASUNKNOWN2))
- {
- if (sys.read(fh, buf, 2) != 2)
- return MSPACK_ERR.MSPACK_ERR_READ;
- i = BitConverter.ToUInt16(buf, 0);
- if (sys.seek(fh, i, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_CUR) != 0)
- return MSPACK_ERR.MSPACK_ERR_SEEK;
- }
-
- // Filename and extension
- if (hdr.headers.HasFlag(MSKWAJ_HDR.MSKWAJ_HDR_HASFILENAME | MSKWAJ_HDR.MSKWAJ_HDR_HASFILEEXT))
- {
- int len;
-
- // Allocate memory for maximum length filename
- char* fn = (char*)sys.alloc(13);
- if ((hdr.extra = fn) == null)
- return MSPACK_ERR.MSPACK_ERR_NOMEMORY;
-
- // Copy filename if present
- if (hdr.headers.HasFlag(MSKWAJ_HDR.MSKWAJ_HDR_HASFILENAME))
- {
- // Read and copy up to 9 bytes of a null terminated string
- if ((len = sys.read(fh, buf, 9)) < 2)
- return MSPACK_ERR.MSPACK_ERR_READ;
-
- for (i = 0; i < len; i++)
- if ((*fn++ = (char)buf[i]) == '\0')
- break;
-
- // If string was 9 bytes with no null terminator, reject it
- if (i == 9 && buf[8] != '\0')
- return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
-
- // Seek to byte after string ended in file
- if (sys.seek(fh, i + 1 - len, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_CUR) != 0)
- return MSPACK_ERR.MSPACK_ERR_SEEK;
-
- fn--; // Remove the null terminator
- }
-
- // Copy extension if present
- if (hdr.headers.HasFlag(MSKWAJ_HDR.MSKWAJ_HDR_HASFILEEXT))
- {
- *fn++ = '.';
-
- // Read and copy up to 4 bytes of a null terminated string
- if ((len = sys.read(fh, buf, 4)) < 2)
- return MSPACK_ERR.MSPACK_ERR_READ;
-
- for (i = 0; i < len; i++)
- if ((*fn++ = (char)buf[i]) == '\0')
- break;
-
- // If string was 4 bytes with no null terminator, reject it
- if (i == 4 && buf[3] != '\0')
- return MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
-
- // Seek to byte after string ended in file
- if (sys.seek(fh, i + 1 - len, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_CUR) != 0)
- return MSPACK_ERR.MSPACK_ERR_SEEK;
-
- fn--; // Remove the null terminator
- }
- *fn = '\0';
- }
-
- // 2 bytes: extra text length then [length] bytes of extra text data
- if (hdr.headers.HasFlag(MSKWAJ_HDR.MSKWAJ_HDR_HASEXTRATEXT))
- {
- if (sys.read(fh, buf, 2) != 2)
- return MSPACK_ERR.MSPACK_ERR_READ;
-
- i = EndGetI16(buf, 0);
- hdr.extra = (char*)sys.alloc(i + 1);
- if (hdr.extra == null)
- return MSPACK_ERR.MSPACK_ERR_NOMEMORY;
-
- if (sys.read(fh, hdr.extra, i) != i)
- return MSPACK_ERR.MSPACK_ERR_READ;
-
- hdr.extra[i] = '\0';
- hdr.extra_length = (ushort)i;
- }
-
- return MSPACK_ERR.MSPACK_ERR_OK;
- }
-
- ///
- /// Extracts the compressed data from a KWAJ file.
- ///
- /// This decompresses the compressed KWAJ data stream and writes it to
- /// an output file.
- ///
- /// The KWAJ file to extract data from
- ///
- /// The filename to write the decompressed data to. This
- /// is passed directly to mspack_system::open().
- ///
- /// An error code, or MSPACK_ERR_OK if successful
- public MSPACK_ERR Extract(mskwajd_header kwaj, in string filename)
- {
- if (kwaj == null)
- return this.error = MSPACK_ERR.MSPACK_ERR_ARGS;
-
- mspack_system sys = this.system;
- mspack_file fh = kwaj.fh;
-
- // Seek to the compressed data
- if (sys.seek(fh, kwaj.data_offset, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_START) != 0)
- {
- return this.error = MSPACK_ERR.MSPACK_ERR_SEEK;
- }
-
- // Open file for output
- mspack_file outfh;
- if ((outfh = sys.open(filename, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_WRITE)) == null)
- {
- return this.error = MSPACK_ERR.MSPACK_ERR_OPEN;
- }
-
- this.error = MSPACK_ERR.MSPACK_ERR_OK;
-
- // Decompress based on format
- if (kwaj.comp_type == MSKWAJ_COMP.MSKWAJ_COMP_NONE || kwaj.comp_type == MSKWAJ_COMP.MSKWAJ_COMP_XOR)
- {
- // NONE is a straight copy. XOR is a copy xored with 0xFF
- byte* buf = (byte*)sys.alloc(KWAJ_INPUT_SIZE);
- if (buf != null)
- {
- int read, i;
- while ((read = sys.read(fh, buf, KWAJ_INPUT_SIZE)) > 0)
- {
- if (kwaj.comp_type == MSKWAJ_COMP.MSKWAJ_COMP_XOR)
- {
- for (i = 0; i < read; i++)
- buf[i] ^= 0xFF;
- }
-
- if (sys.write(outfh, buf, read) != read)
- {
- this.error = MSPACK_ERR.MSPACK_ERR_WRITE;
- break;
- }
- }
-
- if (read < 0)
- this.error = MSPACK_ERR.MSPACK_ERR_READ;
-
- sys.free(buf);
- }
- else
- {
- this.error = MSPACK_ERR.MSPACK_ERR_NOMEMORY;
- }
- }
- else if (kwaj.comp_type == MSKWAJ_COMP.MSKWAJ_COMP_SZDD)
- {
- this.error = lzss_decompress(sys, fh, outfh, KWAJ_INPUT_SIZE, LZSS_MODE.LZSS_MODE_QBASIC);
- }
- else if (kwaj.comp_type == MSKWAJ_COMP.MSKWAJ_COMP_LZH)
- {
- kwajd_stream lzh = lzh_init(sys, fh, outfh);
- this.error = (lzh != null) ? lzh_decompress(lzh) : MSPACK_ERR.MSPACK_ERR_NOMEMORY;
- lzh_free(lzh);
- }
- else if (kwaj.comp_type == MSKWAJ_COMP.MSKWAJ_COMP_MSZIP)
- {
- mszipd_stream zip = mszipd_init(sys, fh, outfh, KWAJ_INPUT_SIZE, 0);
- this.error = (zip != null) ? mszipd_decompress_kwaj(zip) : MSPACK_ERR.MSPACK_ERR_NOMEMORY;
- mszipd_free(zip);
- }
- else
- {
- this.error = MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
- }
-
- // Close output file
- sys.close(outfh);
-
- return this.error;
- }
-
- ///
- /// Decompresses an KWAJ file to an output file in one step.
- ///
- /// This opens an KWAJ file as input, reads the header, then decompresses
- /// the compressed data immediately to an output file, finally closing
- /// both the input and output file. It is more convenient to use than
- /// open() then extract() then close(), if you do not need to know the
- /// KWAJ output size or output filename.
- ///
- ///
- /// The filename of the input KWAJ file. This is passed
- /// directly to mspack_system::open().
- ///
- ///
- /// The filename to write the decompressed data to. This
- /// is passed directly to mspack_system::open().
- ///
- /// An error code, or MSPACK_ERR_OK if successful
- public MSPACK_ERR Decompress(in string input, in string output)
- {
- mskwajd_header hdr;
- if ((hdr = Open(input)) == null)
- return this.error;
-
- MSPACK_ERR error = Extract(hdr, output);
- Close(hdr);
- return this.error = error;
- }
-
- ///
- /// Returns the error code set by the most recently called method.
- ///
- /// This is useful for open() which does not return an
- /// error code directly.
- ///
- /// The most recent error code
- ///
- ///
- public MSPACK_ERR LastError()
- {
- return this.error;
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/KWAJ/kwajd_stream.cs b/libmspack/KWAJ/kwajd_stream.cs
deleted file mode 100644
index 8bf8599..0000000
--- a/libmspack/KWAJ/kwajd_stream.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-using static SabreTools.Compression.libmspack.KWAJ.Constants;
-using static SabreTools.Compression.libmspack.lzss;
-
-namespace SabreTools.Compression.libmspack
-{
- public unsafe class kwajd_stream : readbits
- {
- #region Huffman code lengths
-
- public byte[] MATCHLEN1_len { get; set; } = new byte[KWAJ_MATCHLEN1_SYMS];
-
- public byte[] MATCHLEN2_len { get; set; } = new byte[KWAJ_MATCHLEN2_SYMS];
-
- public byte[] LITLEN_len { get; set; } = new byte[KWAJ_LITLEN_SYMS];
-
- public byte[] OFFSET_len { get; set; } = new byte[KWAJ_OFFSET_SYMS];
-
- public byte[] LITERAL_len { get; set; } = new byte[KWAJ_LITERAL_SYMS];
-
- #endregion
-
- #region Huffman decoding tables
-
- public ushort[] MATCHLEN1_table { get; set; } = new ushort[KWAJ_MATCHLEN1_TBLSIZE];
-
- public ushort[] MATCHLEN2_table { get; set; } = new ushort[KWAJ_MATCHLEN2_TBLSIZE];
-
- public ushort[] LITLEN_table { get; set; } = new ushort[KWAJ_LITLEN_TBLSIZE];
-
- public ushort[] OFFSET_table { get; set; } = new ushort[KWAJ_OFFSET_TBLSIZE];
-
- public ushort[] LITERAL_table { get; set; } = new ushort[KWAJ_LITERAL_TBLSIZE];
-
- #endregion
-
- #region Input buffer
-
- public new byte[] inbuf { get; set; } = new byte[KWAJ_INPUT_SIZE];
-
- #endregion
-
- #region History window
-
- 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);
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/KWAJ/mskwajd_header.cs b/libmspack/KWAJ/mskwajd_header.cs
deleted file mode 100644
index f87ffdf..0000000
--- a/libmspack/KWAJ/mskwajd_header.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- ///
- /// A structure which represents an KWAJ compressed file.
- ///
- /// All fields are READ ONLY.
- ///
- public unsafe class mskwajd_header
- {
- ///
- /// The compression type
- ///
- public MSKWAJ_COMP comp_type { get; set; }
-
- ///
- /// The offset in the file where the compressed data stream begins
- ///
- public long data_offset { get; set; }
-
- ///
- /// Flags indicating which optional headers were included.
- ///
- public MSKWAJ_HDR headers { get; set; }
-
- ///
- /// The amount of uncompressed data in the file, or 0 if not present.
- ///
- public long length { get; set; }
-
- ///
- /// Output filename, or null if not present
- ///
- public char* filename { get; set; }
-
- ///
- /// Extra uncompressed data (usually text) in the header.
- /// This data can contain nulls so use extra_length to get the size.
- ///
- public char* extra { get; set; }
-
- ///
- /// Length of extra uncompressed data in the header
- ///
- public ushort extra_length { get; set; }
-
- public mspack_file fh { get; set; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/LIT/Compressor.cs b/libmspack/LIT/Compressor.cs
deleted file mode 100644
index abe76ce..0000000
--- a/libmspack/LIT/Compressor.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace SabreTools.Compression.libmspack.LIT
-{
- ///
- /// TODO
- ///
- public class Compressor : BaseCompressor
- {
- ///
- /// Creates a new LIT compressor
- ///
- public Compressor()
- {
- this.system = new mspack_default_system();
- this.error = MSPACK_ERR.MSPACK_ERR_OK;
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/LIT/Decompressor.cs b/libmspack/LIT/Decompressor.cs
deleted file mode 100644
index e2a7b3b..0000000
--- a/libmspack/LIT/Decompressor.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace SabreTools.Compression.libmspack.LIT
-{
- ///
- /// TODO
- ///
- public class Decompressor : BaseDecompressor
- {
- ///
- /// Creates a new LIT decompressor
- ///
- public Decompressor()
- {
- this.system = new mspack_default_system();
- this.error = MSPACK_ERR.MSPACK_ERR_OK;
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/LZSS/lzss.cs b/libmspack/LZSS/lzss.cs
deleted file mode 100644
index f6eac7c..0000000
--- a/libmspack/LZSS/lzss.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- public static class lzss
- {
- public const int LZSS_WINDOW_SIZE = 4096;
- public const byte LZSS_WINDOW_FILL = 0x20;
-
- ///
- /// Decompresses an LZSS stream.
- ///
- /// Input bytes will be read in as necessary using the system->read()
- /// function with the input file handle given. This will continue until
- /// system->read() returns 0 bytes, or an error. Errors will be passed
- /// out of the function as MSPACK_ERR_READ errors. Input streams should
- /// convey an "end of input stream" by refusing to supply all the bytes
- /// that LZSS asks for when they reach the end of the stream, rather
- /// than return an error code.
- ///
- /// Output bytes will be passed to the system->write() function, using
- /// the output file handle given. More than one call may be made to
- /// system->write().
- ///
- /// As EXPAND.EXE (SZDD/KWAJ), Microsoft Help and QBasic have slightly
- /// different encodings for the control byte and matches, a "mode"
- /// parameter is allowed, to choose the encoding.
- ///
- ///
- /// An mspack_system structure used to read from
- /// the input stream and write to the output
- /// stream, also to allocate and free memory.
- ///
- /// An input stream with the LZSS data.
- /// An output stream to write the decoded data to.
- /// The number of bytes to use as an input bitstream buffer.
- /// One of values
- /// An error code, or MSPACK_ERR_OK if successful
- public static MSPACK_ERR lzss_decompress(mspack_system system, mspack_file input, mspack_file output, int input_buffer_size, LZSS_MODE mode) => MSPACK_ERR.MSPACK_ERR_OK;
- }
-}
\ No newline at end of file
diff --git a/libmspack/LZX/lzx.cs b/libmspack/LZX/lzx.cs
deleted file mode 100644
index ad2b907..0000000
--- a/libmspack/LZX/lzx.cs
+++ /dev/null
@@ -1,147 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- public static class lzx
- {
- // Some constants defined by the LZX specification
- public const int LZX_MIN_MATCH = 2;
- public const int LZX_MAX_MATCH = 257;
- public const int LZX_NUM_CHARS = 256;
- public const int LZX_BLOCKTYPE_INVALID = 0; /* also blocktypes 4-7 invalid */
- public const int LZX_BLOCKTYPE_VERBATIM = 1;
- public const int LZX_BLOCKTYPE_ALIGNED = 2;
- public const int LZX_BLOCKTYPE_UNCOMPRESSED = 3;
- public const int LZX_PRETREE_NUM_ELEMENTS = 20;
- public const int LZX_ALIGNED_NUM_ELEMENTS = 8; /* aligned offset tree #elements */
- public const int LZX_NUM_PRIMARY_LENGTHS = 7; /* this one missing from spec! */
- public const int LZX_NUM_SECONDARY_LENGTHS = 249; /* length tree #elements */
-
- // LZX huffman defines: tweak tablebits as desired
- public const int LZX_PRETREE_MAXSYMBOLS = LZX_PRETREE_NUM_ELEMENTS;
- public const int LZX_PRETREE_TABLEBITS = 6;
- public const int LZX_MAINTREE_MAXSYMBOLS = LZX_NUM_CHARS + 290 * 8;
- public const int LZX_MAINTREE_TABLEBITS = 12;
- public const int LZX_LENGTH_MAXSYMBOLS = LZX_NUM_SECONDARY_LENGTHS + 1;
- public const int LZX_LENGTH_TABLEBITS = 12;
- public const int LZX_ALIGNED_MAXSYMBOLS = LZX_ALIGNED_NUM_ELEMENTS;
- public const int LZX_ALIGNED_TABLEBITS = 7;
- public const int LZX_LENTABLE_SAFETY = 64; /* table decoding overruns are allowed */
-
- public const int LZX_FRAME_SIZE = 32768; /* the size of a frame in LZX */
-
- ///
- /// Allocates and initialises LZX decompression state for decoding an LZX
- /// stream.
- ///
- /// This routine uses system->alloc() to allocate memory. If memory
- /// allocation fails, or the parameters to this function are invalid,
- /// null is returned.
- ///
- ///
- /// An mspack_system structure used to read from
- /// the input stream and write to the output
- /// stream, also to allocate and free memory.
- ///
- /// An input stream with the LZX data.
- /// An output stream to write the decoded data to.
- ///
- /// The size of the decoding window, which must be
- /// between 15 and 21 inclusive for regular LZX
- /// data, or between 17 and 25 inclusive for
- /// LZX DELTA data.
- ///
- ///
- /// The interval at which the LZX bitstream is
- /// reset, in multiples of LZX frames (32678
- /// bytes), e.g. a value of 2 indicates the input
- /// stream resets after every 65536 output bytes.
- /// A value of 0 indicates that the bitstream never
- /// resets, such as in CAB LZX streams.
- ///
- /// The number of bytes to use as an input bitstream buffer.
- ///
- /// The length in bytes of the entirely
- /// decompressed output stream, if known in
- /// advance. It is used to correctly perform the
- /// Intel E8 transformation, which must stop 6
- /// bytes before the very end of the
- /// decompressed stream. It is not otherwise used
- /// or adhered to. If the full decompressed
- /// length is known in advance, set it here.
- /// If it is NOT known, use the value 0, and call
- /// lzxd_set_output_length() once it is
- /// known. If never set, 4 of the final 6 bytes
- /// of the output stream may be incorrect.
- ///
- ///
- /// Should be zero for all regular LZX data,
- /// non-zero for LZX DELTA encoded data.
- ///
- ///
- /// A pointer to an initialised lzxd_stream structure, or null if
- /// there was not enough memory or parameters to the function were wrong.
- ///
- 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;
-
- ///
- /// See description of output_length in lzxd_init()
- ///
- public static void lzxd_set_output_length(lzxd_stream lzx, long output_length) { }
-
- ///
- /// Reads LZX DELTA reference data into the window and allows
- /// lzxd_decompress() to reference it.
- ///
- /// Call this before the first call to lzxd_decompress().
- ///
- /// The LZX stream to apply this reference data to
- ///
- /// An mspack_system implementation to use with the
- /// input param. Only read() will be called.
- ///
- ///
- /// An input file handle to read reference data using
- /// system->read().
- ///
- ///
- /// The length of the reference data. Cannot be longer
- /// than the LZX window size.
- ///
- /// An error code, or MSPACK_ERR_OK if successful
- public static MSPACK_ERR lzxd_set_reference_data(lzxd_stream lzx, mspack_system system, mspack_file input, uint length) => MSPACK_ERR.MSPACK_ERR_OK;
-
- ///
- /// Decompresses entire or partial LZX streams.
- ///
- /// The number of bytes of data that should be decompressed is given as the
- /// out_bytes parameter. If more bytes are decoded than are needed, they
- /// will be kept over for a later invocation.
- ///
- /// The output bytes will be passed to the system->write() function given in
- /// lzxd_init(), using the output file handle given in lzxd_init(). More than
- /// one call may be made to system->write().
- ///
- /// Input bytes will be read in as necessary using the system->read()
- /// function given in lzxd_init(), using the input file handle given in
- /// lzxd_init(). This will continue until system->read() returns 0 bytes,
- /// or an error. Errors will be passed out of the function as
- /// MSPACK_ERR_READ errors. Input streams should convey an "end of input
- /// stream" by refusing to supply all the bytes that LZX asks for when they
- /// reach the end of the stream, rather than return an error code.
- ///
- /// If any error code other than MSPACK_ERR_OK is returned, the stream
- /// should be considered unusable and lzxd_decompress() should not be
- /// called again on this stream.
- ///
- /// LZX decompression state, as allocated by lzxd_init().
- /// The number of bytes of data to decompress.
- /// An error code, or MSPACK_ERR_OK if successful
- public static MSPACK_ERR lzxd_decompress(lzxd_stream lzx, long out_bytes) => MSPACK_ERR.MSPACK_ERR_OK;
-
- ///
- /// Frees all state associated with an LZX data stream. This will call
- /// system->free() using the system pointer given in lzxd_init().
- ///
- /// LZX decompression state to free.
- public static void lzxd_free(lzxd_stream lzx) { }
- }
-}
\ No newline at end of file
diff --git a/libmspack/LZX/lzxd_stream.cs b/libmspack/LZX/lzxd_stream.cs
deleted file mode 100644
index 1b1e972..0000000
--- a/libmspack/LZX/lzxd_stream.cs
+++ /dev/null
@@ -1,148 +0,0 @@
-using static SabreTools.Compression.libmspack.lzx;
-
-namespace SabreTools.Compression.libmspack
-{
- public unsafe class lzxd_stream : readbits
- {
- ///
- /// Number of bytes actually output
- ///
- public long offset { get; set; }
-
- ///
- /// Overall decompressed length of stream
- ///
- public long length { get; set; }
-
- ///
- /// Decoding window
- ///
- public byte* window { get; set; }
-
- ///
- /// Window size
- ///
- public uint window_size { get; set; }
-
- ///
- /// LZX DELTA reference data size
- ///
- public uint ref_data_size { get; set; }
-
- ///
- /// Number of match_offset entries in table
- ///
- public uint num_offsets { get; set; }
-
- ///
- /// Current frame offset within in window
- ///
- public uint frame_posn { get; set; }
-
- ///
- /// The number of 32kb frames processed
- ///
- public uint frame { get; set; }
-
- ///
- /// Which frame do we reset the compressor?
- ///
- public uint reset_interval { get; set; }
-
- ///
- /// For the LRU offset system
- ///
- public uint R0 { get; set; }
-
- ///
- /// For the LRU offset system
- ///
- public uint R1 { get; set; }
-
- ///
- /// For the LRU offset system
- ///
- public uint R2 { get; set; }
-
- ///
- /// Uncompressed length of this LZX block
- ///
- public uint block_length { get; set; }
-
- ///
- /// Uncompressed bytes still left to decode
- ///
- public uint block_remaining { get; set; }
-
- ///
- /// Magic header value used for transform
- ///
- public int intel_filesize { get; set; }
-
- ///
- /// Has intel E8 decoding started?
- ///
- public byte intel_started { get; set; }
-
- ///
- /// Type of the current block
- ///
- public byte block_type { get; set; }
-
- ///
- /// Have we started decoding at all yet?
- ///
- public byte header_read { get; set; }
-
- ///
- /// Have we reached the end of input?
- ///
- public new byte input_end { get; set; }
-
- ///
- /// Does stream follow LZX DELTA spec?
- ///
- public byte is_delta { get; set; }
-
- #region Huffman code lengths
-
- public byte[] PRETREE_len { get; set; } = new byte[LZX_PRETREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
-
- public byte[] MAINTREE_len { get; set; } = new byte[LZX_MAINTREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
-
- public byte[] LENGTH_len { get; set; } = new byte[LZX_LENGTH_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
-
- public byte[] ALIGNED_len { get; set; } = new byte[LZX_ALIGNED_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
-
- #endregion
-
- #region Huffman decoding tables
-
- public ushort[] PRETREE_table { get; set; } = new ushort[(1 << LZX_PRETREE_TABLEBITS) + (LZX_PRETREE_MAXSYMBOLS * 2)];
-
- public ushort[] MAINTREE_table { get; set; } = new ushort[(1 << LZX_MAINTREE_TABLEBITS) + (LZX_MAINTREE_MAXSYMBOLS * 2)];
-
- public ushort[] LENGTH_table { get; set; } = new ushort[(1 << LZX_LENGTH_TABLEBITS) + (LZX_LENGTH_MAXSYMBOLS * 2)];
-
- public ushort[] ALIGNED_table { get; set; } = new ushort[(1 << LZX_ALIGNED_TABLEBITS) + (LZX_ALIGNED_MAXSYMBOLS * 2)];
-
- public byte LENGTH_empty { get; set; }
-
- #endregion
-
- ///
- /// This is used purely for doing the intel E8 transform
- ///
- 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);
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/MSZIP/mszip.cs b/libmspack/MSZIP/mszip.cs
deleted file mode 100644
index 8182b59..0000000
--- a/libmspack/MSZIP/mszip.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- public static class mszip
- {
- ///
- /// Size of LZ history window
- ///
- public const int MSZIP_FRAME_SIZE = 32768;
-
- ///
- /// Literal/length huffman tree
- ///
- public const int MSZIP_LITERAL_MAXSYMBOLS = 288;
-
- public const int MSZIP_LITERAL_TABLEBITS = 9;
-
- ///
- /// Distance huffman tree
- ///
- public const int MSZIP_DISTANCE_MAXSYMBOLS = 32;
-
- public const int MSZIP_DISTANCE_TABLEBITS = 6;
-
- // If there are less direct lookup entries than symbols, the longer
- // code pointers will be <= maxsymbols. This must not happen, or we
- // will decode entries badly
- public const int MSZIP_LITERAL_TABLESIZE = MSZIP_LITERAL_MAXSYMBOLS * 4;
- public const int MSZIP_DISTANCE_TABLESIZE = 1 << MSZIP_DISTANCE_TABLEBITS + (MSZIP_DISTANCE_MAXSYMBOLS * 2);
-
- ///
- /// Allocates MS-ZIP decompression stream for decoding the given stream.
- ///
- /// - uses system->alloc() to allocate memory
- ///
- /// - returns null if not enough memory
- ///
- /// - input_buffer_size is how many bytes to use as an input bitstream buffer
- ///
- /// - if repair_mode is non-zero, errors in decompression will be skipped
- /// and 'holes' left will be filled with zero bytes. This allows at least
- /// a partial recovery of erroneous data.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static mszipd_stream mszipd_init(mspack_system system, mspack_file input, mspack_file output, int input_buffer_size, int repair_mode) => null;
-
- ///
- /// Decompresses, or decompresses more of, an MS-ZIP stream.
- ///
- /// - out_bytes of data will be decompressed and the function will return
- /// with an MSPACK_ERR_OK return code.
- ///
- /// - decompressing will stop as soon as out_bytes is reached. if the true
- /// amount of bytes decoded spills over that amount, they will be kept for
- /// a later invocation of mszipd_decompress().
- ///
- /// - the output bytes will be passed to the system->write() function given in
- /// mszipd_init(), using the output file handle given in mszipd_init(). More
- /// than one call may be made to system->write()
- ///
- /// - MS-ZIP will read input bytes as necessary using the system->read()
- /// function given in mszipd_init(), using the input file handle given in
- /// mszipd_init(). This will continue until system->read() returns 0 bytes,
- /// or an error.
- ///
- ///
- ///
- ///
- public static MSPACK_ERR mszipd_decompress(mszipd_stream zip, long out_bytes) => MSPACK_ERR.MSPACK_ERR_OK;
-
- ///
- /// Decompresses an entire MS-ZIP stream in a KWAJ file. Acts very much
- /// like mszipd_decompress(), but doesn't take an out_bytes parameter
- ///
- ///
- ///
- public static MSPACK_ERR mszipd_decompress_kwaj(mszipd_stream zip) => MSPACK_ERR.MSPACK_ERR_OK;
-
- ///
- /// Frees all stream associated with an MS-ZIP data stream
- ///
- /// - calls system->free() using the system pointer given in mszipd_init()
- ///
- ///
- public static void mszipd_free(mszipd_stream zip) { }
- }
-}
\ No newline at end of file
diff --git a/libmspack/MSZIP/mszipd_stream.cs b/libmspack/MSZIP/mszipd_stream.cs
deleted file mode 100644
index 1f01490..0000000
--- a/libmspack/MSZIP/mszipd_stream.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using static SabreTools.Compression.libmspack.lzx;
-using static SabreTools.Compression.libmspack.mszip;
-
-namespace SabreTools.Compression.libmspack
-{
- public unsafe class mszipd_stream : readbits
- {
- ///
- /// inflate() will call this whenever the window should be emptied.
- ///
- ///
- ///
- public int flush_window(uint val) => 0;
-
- public int repair_mode { get; set; }
-
- public int bytes_output { get; set; }
-
- #region Huffman code lengths
-
- public byte[] LITERAL_len { get; set; } = new byte[MSZIP_LITERAL_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
-
- public byte[] DISTANCE_len { get; set; } = new byte[MSZIP_DISTANCE_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
-
- #endregion
-
- #region Huffman decoding tables
-
- public ushort[] LITERAL_table { get; set; } = new ushort[(1 << MSZIP_LITERAL_TABLESIZE) + (LZX_PRETREE_MAXSYMBOLS * 2)];
-
- public ushort[] DISTANCE_table { get; set; } = new ushort[(1 << MSZIP_DISTANCE_TABLESIZE) + (LZX_MAINTREE_MAXSYMBOLS * 2)];
-
- #endregion
-
- ///
- /// 32kb history window
- ///
- public byte[] window { get; set; } = new byte[MSZIP_FRAME_SIZE];
-
- public override void READ_BYTES()
- {
- READ_IF_NEEDED;
- INJECT_BITS_LSB(*i_ptr++, 8);
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/None/DecompressState.cs b/libmspack/None/DecompressState.cs
deleted file mode 100644
index fde6e1b..0000000
--- a/libmspack/None/DecompressState.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-namespace SabreTools.Compression.libmspack.None
-{
- public unsafe class DecompressState : mscabd_decompress_state
- {
- public DecompressState()
- {
- this.comp_type = MSCAB_COMP.MSCAB_COMP_NONE;
- this.state = null;
- }
-
- public DecompressState(mscabd_decompress_state oldstate)
- {
- this.comp_type = MSCAB_COMP.MSCAB_COMP_NONE;
- this.state = null;
- if (oldstate != null)
- {
- this.folder = oldstate.folder;
- this.data = oldstate.data;
- this.offset = oldstate.offset;
- this.block = oldstate.block;
- this.outlen = oldstate.outlen;
- this.sys = oldstate.sys;
- this.incab = oldstate.incab;
- this.infh = oldstate.infh;
- this.outfh = oldstate.outfh;
- this.i_ptr = oldstate.i_ptr;
- this.i_end = oldstate.i_end;
- this.input = oldstate.input;
- }
- }
-
- ///
- public override unsafe MSPACK_ERR decompress(object data, long bytes)
- {
- State s = data as State;
- while (bytes > 0)
- {
- int run = (bytes > s.BufferSize) ? s.BufferSize : (int)bytes;
- if (s.InternalSystem.read(s.Input, s.Buffer, run) != run) return MSPACK_ERR.MSPACK_ERR_READ;
- if (s.InternalSystem.write(s.Output, s.Buffer, run) != run) return MSPACK_ERR.MSPACK_ERR_WRITE;
- bytes -= run;
- }
-
- return MSPACK_ERR.MSPACK_ERR_OK;
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/None/State.cs b/libmspack/None/State.cs
deleted file mode 100644
index 1b87b68..0000000
--- a/libmspack/None/State.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-namespace SabreTools.Compression.libmspack.None
-{
- ///
- /// The "not compressed" method decompressor
- ///
- public unsafe class State
- {
- public mspack_system InternalSystem { get; private set; }
-
- public mspack_file Input { get; private set; }
-
- public mspack_file Output { get; private set; }
-
- public FixedArray Buffer { get; private set; }
-
- public int BufferSize { get; private set; }
-
- public State(mspack_system sys, mspack_file infh, mspack_file outfh, int bufsize)
- {
- this.InternalSystem = sys;
- this.Input = infh;
- this.Output = outfh;
- this.Buffer = new FixedArray(bufsize);
- this.BufferSize = bufsize;
- }
-
- ~State()
- {
- mspack_system sys = this.InternalSystem;
- sys.free(this.Buffer);
- //sys.free(this);
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/OAB/Compressor.cs b/libmspack/OAB/Compressor.cs
deleted file mode 100644
index 64d3418..0000000
--- a/libmspack/OAB/Compressor.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using System;
-
-namespace SabreTools.Compression.libmspack.OAB
-{
- ///
- /// A compressor for the Offline Address Book (OAB) format.
- ///
- /// All fields are READ ONLY.
- ///
- public class Compressor : BaseCompressor
- {
- ///
- /// Creates a new OAB compressor
- ///
- public Compressor()
- {
- throw new NotImplementedException();
- }
-
- ///
- /// Destroys an existing OAB compressor
- ///
- ~Compressor()
- {
- throw new NotImplementedException();
- }
-
- ///
- /// Compress a full OAB file.
- ///
- /// The input file will be read and the compressed contents written to the
- /// output file.
- ///
- ///
- /// The filename of the input file. This is passed
- /// directly to mspack_system::open().
- ///
- ///
- /// The filename of the output file. This is passed
- /// directly to mspack_system::open().
- ///
- /// An error code, or MSPACK_ERR_OK if successful
- public MSPACK_ERR compress(in string input, in string output) => throw new NotImplementedException();
-
- ///
- /// Generate a compressed incremental OAB patch file.
- ///
- /// The two uncompressed files "input" and "base" will be read, and an
- /// incremental patch to generate "input" from "base" will be written to
- /// the output file.
- ///
- ///
- /// The filename of the input file containing the new
- /// version of its contents. This is passed directly
- /// to mspack_system::open().
- ///
- ///
- /// The filename of the original base file containing
- /// the old version of its contents, against which the
- /// incremental patch shall generated. This is passed
- /// directly to mspack_system::open().
- ///
- ///
- /// The filename of the output file. This is passed
- /// directly to mspack_system::open().
- ///
- /// An error code, or MSPACK_ERR_OK if successful
- public MSPACK_ERR compress_incremental(in string input, in string @base, in string output) => throw new NotImplementedException();
- }
-}
\ No newline at end of file
diff --git a/libmspack/OAB/Decompressor.cs b/libmspack/OAB/Decompressor.cs
deleted file mode 100644
index 5f0e879..0000000
--- a/libmspack/OAB/Decompressor.cs
+++ /dev/null
@@ -1,400 +0,0 @@
-using static SabreTools.Compression.libmspack.macros;
-using static SabreTools.Compression.libmspack.oab;
-
-namespace SabreTools.Compression.libmspack.OAB
-{
- ///
- /// A decompressor for .LZX (Offline Address Book) files
- ///
- /// All fields are READ ONLY.
- ///
- ///
- ///
- public unsafe class Decompressor : BaseDecompressor
- {
- public int buf_size { get; private set; }
-
- ///
- /// Creates a new OAB decompressor
- ///
- public Decompressor()
- {
- this.system = new OABSystem();
- this.error = MSPACK_ERR.MSPACK_ERR_OK;
- this.buf_size = 4096;
- }
-
- ///
- /// Decompresses a full Offline Address Book file.
- ///
- /// If the input file is a valid compressed Offline Address Book file,
- /// it will be read and the decompressed contents will be written to
- /// the output file.
- ///
- ///
- /// The filename of the input file. This is passed
- /// directly to mspack_system::open().
- ///
- ///
- /// The filename of the output file. This is passed
- /// directly to mspack_system::open().
- ///
- /// An error code, or MSPACK_ERR.MSPACK_ERR_OK if successful
- public MSPACK_ERR decompress(in string input, in string output)
- {
- mspack_system sys;
- mspack_file infh = null;
- mspack_file outfh = null;
- FixedArray buf = null;
- FixedArray hdrbuf = new FixedArray(oabhead_SIZEOF);
- uint block_max, target_size;
- lzxd_stream lzx = null;
- OABSystem oabd_sys;
- uint window_bits;
- MSPACK_ERR ret = MSPACK_ERR.MSPACK_ERR_OK;
-
- sys = this.system;
-
- infh = sys.open(input, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_READ);
- if (infh == null)
- {
- ret = MSPACK_ERR.MSPACK_ERR_OPEN;
- goto outlbl;
- }
-
- if (sys.read(infh, hdrbuf, oabhead_SIZEOF) != oabhead_SIZEOF)
- {
- ret = MSPACK_ERR.MSPACK_ERR_READ;
- goto outlbl;
- }
-
- if (EndGetI32(hdrbuf, oabhead_VersionHi) != 3 ||
- EndGetI32(hdrbuf, oabhead_VersionLo) != 1)
- {
- ret = MSPACK_ERR.MSPACK_ERR_SIGNATURE;
- goto outlbl;
- }
-
- block_max = EndGetI32(hdrbuf, oabhead_BlockMax);
- target_size = EndGetI32(hdrbuf, oabhead_TargetSize);
-
- outfh = sys.open(output, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_WRITE);
- if (outfh == null)
- {
- ret = MSPACK_ERR.MSPACK_ERR_OPEN;
- goto outlbl;
- }
-
- buf = new FixedArray(this.buf_size);
- if (buf == null)
- {
- ret = MSPACK_ERR.MSPACK_ERR_NOMEMORY;
- goto outlbl;
- }
-
- oabd_sys = sys as OABSystem;
-
- oabd_file in_ofh = new oabd_file();
- in_ofh.orig_sys = sys;
- in_ofh.orig_file = infh;
-
- oabd_file out_ofh = new oabd_file();
- out_ofh.orig_sys = sys;
- out_ofh.orig_file = outfh;
-
- while (target_size > 0)
- {
- uint blk_csize, blk_dsize, blk_crc, blk_flags;
-
- if (sys.read(infh, buf, oabblk_SIZEOF) != oabblk_SIZEOF)
- {
- ret = MSPACK_ERR.MSPACK_ERR_READ;
- goto outlbl;
- }
- blk_flags = EndGetI32(buf, oabblk_Flags);
- blk_csize = EndGetI32(buf, oabblk_CompSize);
- blk_dsize = EndGetI32(buf, oabblk_UncompSize);
- blk_crc = EndGetI32(buf, oabblk_CRC);
-
- if (blk_dsize > block_max || blk_dsize > target_size || blk_flags > 1)
- {
- ret = MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
- goto outlbl;
- }
-
- if (blk_flags == 0)
- {
- // Uncompressed block
- if (blk_dsize != blk_csize)
- {
- ret = MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
- goto outlbl;
- }
- ret = copy_fh(sys, infh, outfh, (int)blk_dsize, buf, this.buf_size);
- if (ret != MSPACK_ERR.MSPACK_ERR_OK) goto outlbl;
- }
- else
- {
- // LZX compressed block
- window_bits = 17;
-
- while (window_bits < 25 && (1 << (int)window_bits) < blk_dsize)
- window_bits++;
-
- in_ofh.available = (int)blk_csize;
- out_ofh.crc = 0xffffffff;
-
- lzx = lzxd_init(&oabd_sys, (void*)&in_ofh, (void*)&out_ofh, window_bits, 0, this.buf_size, blk_dsize, 1);
- if (lzx == null)
- {
- ret = MSPACK_ERR.MSPACK_ERR_NOMEMORY;
- goto outlbl;
- }
-
- ret = lzxd_decompress(lzx, blk_dsize);
- if (ret != MSPACK_ERR.MSPACK_ERR_OK)
- goto outlbl;
-
- lzxd_free(lzx);
- lzx = null;
-
- // Consume any trailing padding bytes before the next block
- ret = copy_fh(sys, infh, null, in_ofh.available, buf, this.buf_size);
- if (ret != MSPACK_ERR.MSPACK_ERR_OK) goto outlbl;
-
- if (out_ofh.crc != blk_crc)
- {
- ret = MSPACK_ERR.MSPACK_ERR_CHECKSUM;
- goto outlbl;
- }
- }
- target_size -= blk_dsize;
- }
-
- outlbl:
- if (lzx != null) lzxd_free(lzx);
- if (outfh != null) sys.close(outfh);
- if (infh != null) sys.close(infh);
- sys.free(buf);
-
- return ret;
- }
-
- ///
- /// Decompresses an Offline Address Book with an incremental patch file.
- ///
- /// This requires both a full UNCOMPRESSED Offline Address Book file to
- /// act as the "base", and a compressed incremental patch file as input.
- /// If the input file is valid, it will be decompressed with reference to
- /// the base file, and the decompressed contents will be written to the
- /// output file.
- ///
- /// There is no way to tell what the right base file is for the given
- /// incremental patch, but if you get it wrong, this will usually result
- /// in incorrect data being decompressed, which will then fail a checksum
- /// test.
- ///
- ///
- /// The filename of the input file. This is passed
- /// directly to mspack_system::open().
- ///
- ///
- /// The filename of the base file to which the
- /// incremental patch shall be applied. This is passed
- /// directly to mspack_system::open().
- ///
- ///
- /// The filename of the output file. This is passed
- /// directly to mspack_system::open().
- ///
- /// An error code, or MSPACK_ERR.MSPACK_ERR_OK if successful
- public MSPACK_ERR decompress_incremental(in string input, in string @base, in string output)
- {
- mspack_file infh = null, basefh = null, outfh = null;
- lzxd_stream lzx = null;
- FixedArray buf = null;
- uint window_bits, window_size;
- MSPACK_ERR ret = MSPACK_ERR.MSPACK_ERR_OK;
-
- mspack_system sys = this.system;
-
- infh = sys.open(input, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_READ);
- if (infh == null)
- {
- ret = MSPACK_ERR.MSPACK_ERR_OPEN;
- goto outlbl;
- }
-
- FixedArray hdrbuf = new FixedArray(patchhead_SIZEOF);
- if (sys.read(infh, hdrbuf, patchhead_SIZEOF) != patchhead_SIZEOF)
- {
- ret = MSPACK_ERR.MSPACK_ERR_READ;
- goto outlbl;
- }
-
- if (EndGetI32(hdrbuf, patchhead_VersionHi) != 3 ||
- EndGetI32(hdrbuf, patchhead_VersionLo) != 2)
- {
- ret = MSPACK_ERR.MSPACK_ERR_SIGNATURE;
- goto outlbl;
- }
-
- uint block_max = EndGetI32(hdrbuf, patchhead_BlockMax);
- uint target_size = EndGetI32(hdrbuf, patchhead_TargetSize);
-
- // We use it for reading block headers too
- if (block_max < patchblk_SIZEOF)
- block_max = patchblk_SIZEOF;
-
- basefh = sys.open(@base, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_READ);
- if (basefh == null)
- {
- ret = MSPACK_ERR.MSPACK_ERR_OPEN;
- goto outlbl;
- }
-
- outfh = sys.open(output, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_WRITE);
- if (outfh == null)
- {
- ret = MSPACK_ERR.MSPACK_ERR_OPEN;
- goto outlbl;
- }
-
- buf = new FixedArray(this.buf_size);
- if (buf == null)
- {
- ret = MSPACK_ERR.MSPACK_ERR_NOMEMORY;
- goto outlbl;
- }
-
- OABSystem oabd_sys = sys as OABSystem;
-
- oabd_file in_ofh = new oabd_file();
- in_ofh.orig_sys = sys;
- in_ofh.orig_file = infh;
-
- oabd_file out_ofh = new oabd_file();
- out_ofh.orig_sys = sys;
- out_ofh.orig_file = outfh;
-
- while (target_size > 0)
- {
- if (sys.read(infh, buf, patchblk_SIZEOF) != patchblk_SIZEOF)
- {
- ret = MSPACK_ERR.MSPACK_ERR_READ;
- goto outlbl;
- }
-
- uint blk_csize = EndGetI32(buf, patchblk_PatchSize);
- uint blk_dsize = EndGetI32(buf, patchblk_TargetSize);
- uint blk_ssize = EndGetI32(buf, patchblk_SourceSize);
- uint blk_crc = EndGetI32(buf, patchblk_CRC);
-
- if (blk_dsize > block_max || blk_dsize > target_size ||
- blk_ssize > block_max)
- {
- ret = MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
- goto outlbl;
- }
-
-
- window_size = (uint)((blk_ssize + 32767) & ~32767);
- window_size += blk_dsize;
- window_bits = 17;
-
- while (window_bits < 25 && (1 << (int)window_bits) < window_size)
- window_bits++;
-
- in_ofh.available = (int)blk_csize;
- out_ofh.crc = 0xffffffff;
-
- lzx = lzxd_init(&oabd_sys, (void*)&in_ofh, (void*)&out_ofh, window_bits, 0, 4096, blk_dsize, 1);
- if (lzx == null)
- {
- ret = MSPACK_ERR.MSPACK_ERR_NOMEMORY;
- goto outlbl;
- }
- ret = lzxd_set_reference_data(lzx, sys, basefh, blk_ssize);
- if (ret != MSPACK_ERR.MSPACK_ERR_OK)
- goto outlbl;
-
- ret = lzxd_decompress(lzx, blk_dsize);
- if (ret != MSPACK_ERR.MSPACK_ERR_OK)
- goto outlbl;
-
- lzxd_free(lzx);
- lzx = null;
-
- // Consume any trailing padding bytes before the next block
- ret = copy_fh(sys, infh, null, in_ofh.available, buf, this.buf_size);
- if (ret != MSPACK_ERR.MSPACK_ERR_OK) goto outlbl;
-
- if (out_ofh.crc != blk_crc)
- {
- ret = MSPACK_ERR.MSPACK_ERR_CHECKSUM;
- goto outlbl;
- }
-
- target_size -= blk_dsize;
- }
-
- outlbl:
- if (lzx != null) lzxd_free(lzx);
- if (outfh != null) sys.close(outfh);
- if (basefh != null) sys.close(basefh);
- if (infh != null) sys.close(infh);
- //if (buf != null) sys.free(buf);
-
- return ret;
- }
-
- private static MSPACK_ERR copy_fh(mspack_system sys, mspack_file infh, mspack_file outfh, int bytes_to_copy, byte* buf, int buf_size)
- {
- while (bytes_to_copy > 0)
- {
- int run = buf_size;
- if (run > bytes_to_copy)
- {
- run = bytes_to_copy;
- }
- if (sys.read(infh, buf, run) != run)
- {
- return MSPACK_ERR.MSPACK_ERR_READ;
- }
- if (outfh != null && sys.write(outfh, buf, run) != run)
- {
- return MSPACK_ERR.MSPACK_ERR_WRITE;
- }
- bytes_to_copy -= run;
- }
-
- return MSPACK_ERR.MSPACK_ERR_OK;
- }
-
- ///
- /// Sets an OAB decompression engine parameter. Available only in OAB
- /// decompressor version 2 and above.
- ///
- /// - #MSOABD_PARAM_DECOMPBUF: How many bytes should be used as an input
- /// buffer by decompressors? The minimum value is 16. The default value
- /// is 4096.
- ///
- /// The parameter to set
- /// The value to set the parameter to
- ///
- /// 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.
- ///
- public MSPACK_ERR set_param(MSOABD_PARAM param, int value)
- {
- if (param == MSOABD_PARAM.MSOABD_PARAM_DECOMPBUF && value >= 16)
- {
- // Must be at least 16 bytes (patchblk_SIZEOF, oabblk_SIZEOF)
- this.buf_size = value;
- return MSPACK_ERR.MSPACK_ERR_OK;
- }
-
- return MSPACK_ERR.MSPACK_ERR_ARGS;
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/OAB/OABSystem.cs b/libmspack/OAB/OABSystem.cs
deleted file mode 100644
index 8fe0678..0000000
--- a/libmspack/OAB/OABSystem.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-namespace SabreTools.Compression.libmspack.OAB
-{
- public unsafe class OABSystem : mspack_default_system
- {
- ///
- public override unsafe int read(mspack_file base_file, void* buf, int size)
- {
- oabd_file file = (oabd_file)base_file;
- int bytes_read;
-
- if (size > file.available)
- size = file.available;
-
- bytes_read = file.orig_sys.read(file.orig_file, buf, size);
- if (bytes_read < 0)
- return bytes_read;
-
- file.available -= bytes_read;
- return bytes_read;
- }
-
- ///
- public override unsafe int write(mspack_file base_file, void* buf, int size)
- {
- oabd_file file = (oabd_file)base_file;
- int bytes_written = file.orig_sys.write(file.orig_file, buf, size);
-
- if (bytes_written > 0)
- file.crc = mspack.crc32(file.crc, buf, bytes_written);
-
- return bytes_written;
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/OAB/oab.cs b/libmspack/OAB/oab.cs
deleted file mode 100644
index f868a43..0000000
--- a/libmspack/OAB/oab.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- public static class oab
- {
- public const int oabhead_VersionHi = 0x0000;
- public const int oabhead_VersionLo = 0x0004;
- public const int oabhead_BlockMax = 0x0008;
- public const int oabhead_TargetSize = 0x000c;
- public const int oabhead_SIZEOF = 0x0010;
-
- public const int oabblk_Flags = 0x0000;
- public const int oabblk_CompSize = 0x0004;
- public const int oabblk_UncompSize = 0x0008;
- public const int oabblk_CRC = 0x000c;
- public const int oabblk_SIZEOF = 0x0010;
-
- public const int patchhead_VersionHi = 0x0000;
- public const int patchhead_VersionLo = 0x0004;
- public const int patchhead_BlockMax = 0x0008;
- public const int patchhead_SourceSize = 0x000c;
- public const int patchhead_TargetSize = 0x0010;
- public const int patchhead_SourceCRC = 0x0014;
- public const int patchhead_TargetCRC = 0x0018;
- public const int patchhead_SIZEOF = 0x001c;
-
- public const int patchblk_PatchSize = 0x0000;
- public const int patchblk_TargetSize = 0x0004;
- public const int patchblk_SourceSize = 0x0008;
- public const int patchblk_CRC = 0x000c;
- public const int patchblk_SIZEOF = 0x0010;
- }
-}
\ No newline at end of file
diff --git a/libmspack/OAB/oabd_file.cs b/libmspack/OAB/oabd_file.cs
deleted file mode 100644
index 4a838b9..0000000
--- a/libmspack/OAB/oabd_file.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- public class oabd_file : mspack_file
- {
- public mspack_system orig_sys { get; set; }
-
- public mspack_file orig_file { get; set; }
-
- public uint crc { get; set; }
-
- public int available { get; set; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/Quantum/qtm.cs b/libmspack/Quantum/qtm.cs
deleted file mode 100644
index 4bf9c7e..0000000
--- a/libmspack/Quantum/qtm.cs
+++ /dev/null
@@ -1,241 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- 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;
- }
- }
- }
-
- ///
- /// Allocates Quantum decompression state for decoding the given stream.
- ///
- /// - returns null if window_bits is outwith the range 10 to 21 (inclusive).
- ///
- /// - uses system.alloc() to allocate memory
- ///
- /// - returns null if not enough memory
- ///
- /// - window_bits is the size of the Quantum window, from 1Kb (10) to 2Mb (21).
- ///
- /// - input_buffer_size is the number of bytes to use to store bitstream data.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- 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;
- qtm.model0 = new qtmd_model(qtm.m0sym, 0, 64);
- qtm.model1 = new qtmd_model(qtm.m1sym, 64, 64);
- qtm.model2 = new qtmd_model(qtm.m2sym, 128, 64);
- qtm.model3 = new qtmd_model(qtm.m3sym, 192, 64);
- qtm.model4 = new qtmd_model(qtm.m4sym, 0, (i > 24) ? 24 : i);
- qtm.model5 = new qtmd_model(qtm.m5sym, 0, (i > 36) ? 36 : i);
- qtm.model6 = new qtmd_model(qtm.m6sym, 0, i);
- qtm.model6len = new qtmd_model(qtm.m6lsym, 0, 27);
- qtm.model7 = new qtmd_model(qtm.m7sym, 0, 7);
-
- // All ok
- return qtm;
- }
-
- ///
- /// Decompresses, or decompresses more of, a Quantum stream.
- ///
- /// - out_bytes of data will be decompressed and the function will return
- /// with an MSPACK_ERR_OK return code.
- ///
- /// - decompressing will stop as soon as out_bytes is reached. if the true
- /// 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
- /// qtmd_init(), using the output file handle given in qtmd_init(). More
- /// than one call may be made to system.write()
- ///
- /// - 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,
- /// or an error.
- ///
- ///
- ///
- ///
- public static MSPACK_ERR qtmd_decompress(qtmd_stream qtm, long out_bytes) => MSPACK_ERR.MSPACK_ERR_OK;
-
- ///
- /// Frees all state associated with a Quantum data stream
- ///
- /// - calls system.free() using the system pointer given in qtmd_init()
- ///
- ///
- 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);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/Quantum/qtmd_model.cs b/libmspack/Quantum/qtmd_model.cs
deleted file mode 100644
index b08fc7d..0000000
--- a/libmspack/Quantum/qtmd_model.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- public unsafe class qtmd_model
- {
- public int shiftsleft { get; set; }
-
- public int entries { get; set; }
-
- public qtmd_modelsym[] syms { get; set; }
-
- ///
- /// Initialises a model to decode symbols from [start] to [start]+[len]-1
- ///
- public qtmd_model(qtmd_modelsym[] syms, int start, int len)
- {
- this.shiftsleft = 4;
- this.entries = len;
- this.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
- }
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/Quantum/qtmd_modelsym.cs b/libmspack/Quantum/qtmd_modelsym.cs
deleted file mode 100644
index 149c610..0000000
--- a/libmspack/Quantum/qtmd_modelsym.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- public class qtmd_modelsym
- {
- public ushort sym { get; set; }
-
- public ushort cumfreq { get; set; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/Quantum/qtmd_stream.cs b/libmspack/Quantum/qtmd_stream.cs
deleted file mode 100644
index 2424b2a..0000000
--- a/libmspack/Quantum/qtmd_stream.cs
+++ /dev/null
@@ -1,126 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- public unsafe class qtmd_stream : readbits
- {
- ///
- /// Decoding window
- ///
- public byte* window { get; set; }
-
- ///
- /// Window size
- ///
- public uint window_size { get; set; }
-
- ///
- /// Bytes remaining for current frame
- ///
- public uint frame_todo { get; set; }
-
- ///
- /// High arith coding state
- ///
- public ushort H { get; set; }
-
- ///
- /// Low arith coding state
- ///
- public ushort L { get; set; }
-
- ///
- /// Current arith coding state
- ///
- public ushort C { get; set; }
-
- ///
- /// Have we started decoding a new frame?
- ///
- public byte header_read { get; set; }
-
- #region Models
-
- #region Four literal models, each representing 64 symbols
-
- ///
- /// model0 for literals from 0 to 63 (selector = 0)
- ///
- public qtmd_model model0 { get; set; }
-
- ///
- /// model1 for literals from 64 to 127 (selector = 1)
- ///
- public qtmd_model model1 { get; set; }
-
- ///
- /// model2 for literals from 128 to 191 (selector = 2)
- ///
- public qtmd_model model2 { get; set; }
-
- ///
- /// model3 for literals from 129 to 255 (selector = 3)
- ///
- public qtmd_model model3 { get; set; }
-
- #endregion
-
- #region Three match models
-
- ///
- /// model4 for match with fixed length of 3 bytes
- ///
- public qtmd_model model4 { get; set; }
-
- ///
- /// model5 for match with fixed length of 4 bytes
- ///
- public qtmd_model model5 { get; set; }
-
- ///
- /// model6 for variable length match, encoded with model6len model
- ///
- public qtmd_model model6 { get; set; }
-
- public qtmd_model model6len { get; set; }
-
- #endregion
-
- ///
- /// selector model. 0-6 to say literal (0,1,2,3) or match (4,5,6)
- ///
- public qtmd_model model7 { get; set; }
-
- #endregion
-
- #region Symbol arrays for all models
-
- public qtmd_modelsym[] m0sym { get; set; } = new qtmd_modelsym[64 + 1];
-
- public qtmd_modelsym[] m1sym { get; set; } = new qtmd_modelsym[64 + 1];
-
- public qtmd_modelsym[] m2sym { get; set; } = new qtmd_modelsym[64 + 1];
-
- public qtmd_modelsym[] m3sym { get; set; } = new qtmd_modelsym[64 + 1];
-
- public qtmd_modelsym[] m4sym { get; set; } = new qtmd_modelsym[24 + 1];
-
- public qtmd_modelsym[] m5sym { get; set; } = new qtmd_modelsym[36 + 1];
-
- public qtmd_modelsym[] m6sym { get; set; } = new qtmd_modelsym[42 + 1];
-
- public qtmd_modelsym[] m6lsym { get; set; } = new qtmd_modelsym[27 + 1];
-
- 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);
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/SZDD/Compressor.cs b/libmspack/SZDD/Compressor.cs
deleted file mode 100644
index d8c1cd3..0000000
--- a/libmspack/SZDD/Compressor.cs
+++ /dev/null
@@ -1,88 +0,0 @@
-namespace SabreTools.Compression.libmspack.SZDD
-{
- ///
- /// A compressor for the SZDD file format.
- ///
- /// All fields are READ ONLY.
- ///
- public abstract class Compressor : BaseCompressor
- {
- ///
- /// Creates a new SZDD compressor
- ///
- public Compressor()
- {
- this.system = new mspack_default_system();
- this.error = MSPACK_ERR.MSPACK_ERR_OK;
- }
-
- ///
- /// Reads an input file and creates a compressed output file in the
- /// SZDD compressed file format. The SZDD compression format is quick
- /// but gives poor compression. It is possible for the compressed output
- /// file to be larger than the input file.
- ///
- /// Conventionally, SZDD compressed files have the final character in
- /// their filename replaced with an underscore, to show they are
- /// compressed. The missing character is stored in the compressed file
- /// itself. This is due to the restricted filename conventions of MS-DOS,
- /// most operating systems, such as UNIX, simply append another file
- /// extension to the existing filename. As mspack does not deal with
- /// filenames, this is left up to you. If you wish to set the missing
- /// character stored in the file header, use set_param() with the
- /// #MSSZDDC_PARAM_MISSINGCHAR parameter.
- ///
- /// "Stream" compression (where the length of the input data is not
- /// known) is not possible. The length of the input data is stored in the
- /// header of the SZDD file and must therefore be known before any data
- /// is compressed. Due to technical limitations of the file format, the
- /// maximum size of uncompressed file that will be accepted is 2147483647
- /// bytes.
- ///
- ///
- /// The name of the file to compressed. This is passed
- /// passed directly to mspack_system::open()
- ///
- ///
- /// The name of the file to write compressed data to.
- /// This is passed directly to mspack_system::open().
- ///
- ///
- /// The length of the uncompressed file, or -1 to indicate
- /// that this should be determined automatically by using
- /// mspack_system::seek() on the input file.
- ///
- /// An error code, or MSPACK_ERR_OK if successful
- ///
- public abstract MSPACK_ERR compress(in string input, in string output, long length);
-
- ///
- /// Sets an SZDD compression engine parameter.
- ///
- /// The following parameters are defined:
- ///
- /// - #MSSZDDC_PARAM_CHARACTER: the "missing character", the last character
- /// in the uncompressed file's filename, which is traditionally replaced
- /// with an underscore to show the file is compressed. Traditionally,
- /// this can only be a character that is a valid part of an MS-DOS,
- /// filename, but libmspack permits any character between 0x00 and 0xFF
- /// to be stored. 0x00 is the default, and it represents "no character
- /// stored".
- ///
- /// The parameter to set
- /// The value to set the parameter to
- ///
- /// MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if there
- /// is a problem with either parameter or value.
- ///
- ///
- public abstract MSPACK_ERR set_param(MSSZDDC_PARAM param, int value);
-
- ///
- /// Returns the error code set by the most recently called method.
- ///
- /// The most recent error code
- ///
- public abstract MSPACK_ERR last_error();
- }
-}
\ No newline at end of file
diff --git a/libmspack/SZDD/Constants.cs b/libmspack/SZDD/Constants.cs
deleted file mode 100644
index 5679b8c..0000000
--- a/libmspack/SZDD/Constants.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-/* This file is part of libmspack.
- * (C) 2003-2004 Stuart Caie.
- *
- * libmspack is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License (LGPL) version 2.1
- *
- * For further details, see the file COPYING.LIB distributed with libmspack
- */
-
-namespace SabreTools.Compression.libmspack.SZDD
-{
- public static class Constants
- {
- ///
- /// Input buffer size during decompression - not worth parameterising IMHO
- ///
- public const int SZDD_INPUT_SIZE = 2048;
- }
-}
\ No newline at end of file
diff --git a/libmspack/SZDD/Decompressor.cs b/libmspack/SZDD/Decompressor.cs
deleted file mode 100644
index a1bc5ed..0000000
--- a/libmspack/SZDD/Decompressor.cs
+++ /dev/null
@@ -1,231 +0,0 @@
-using static SabreTools.Compression.libmspack.macros;
-using static SabreTools.Compression.libmspack.SZDD.Constants;
-
-namespace SabreTools.Compression.libmspack.SZDD
-{
- ///
- /// A decompressor for SZDD compressed files.
- ///
- /// All fields are READ ONLY.
- ///
- ///
- ///
- public unsafe class Decompressor : BaseDecompressor
- {
- ///
- /// Creates a new SZDD decompressor
- ///
- public Decompressor()
- {
- this.system = new mspack_default_system();
- this.error = MSPACK_ERR.MSPACK_ERR_OK;
- }
-
- ///
- /// Destroys an existing SZDD decompressor
- ///
- ~Decompressor()
- {
- mspack_system sys = this.system;
- //sys.free(self);
- }
-
- ///
- /// Opens a SZDD file and reads the header.
- ///
- /// 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
- /// is available from last_error().
- ///
- /// The filename pointer should be considered "in use" until close() is
- /// called on the SZDD file.
- ///
- ///
- /// 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
- ///
- 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 = ReadHeaders(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.
- ///
- /// This closes a SZDD file and frees the msszddd_header associated with
- /// it.
- ///
- /// The SZDD header pointer is now invalid and cannot be used again.
- ///
- /// The SZDD file to close
- 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 ReadHeaders(mspack_system sys, mspack_file fh, msszddd_header hdr)
- {
- FixedArray buf = new FixedArray(8);
-
- // Read and check signature
- if (sys.read(fh, buf, 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, buf, 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, buf, 4) != 4) return MSPACK_ERR.MSPACK_ERR_READ;
- hdr.missing_char = '\0';
- hdr.length = EndGetI32(buf, 0);
- }
- else
- {
- return MSPACK_ERR.MSPACK_ERR_SIGNATURE;
- }
-
- return MSPACK_ERR.MSPACK_ERR_OK;
- }
-
- ///
- /// Extracts the compressed data from a SZDD file.
- ///
- /// This decompresses the compressed SZDD data stream and writes it to
- /// an output file.
- ///
- /// The SZDD file to extract data from
- ///
- /// The filename to write the decompressed data to. This
- /// is passed directly to mspack_system::open().
- ///
- /// An error code, or MSPACK_ERR_OK if successful
- 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.
- ///
- /// This opens an SZDD file as input, reads the header, then decompresses
- /// the compressed data immediately to an output file, finally closing
- /// both the input and output file. It is more convenient to use than
- /// open() then extract() then close(), if you do not need to know the
- /// SZDD output size or missing character.
- ///
- ///
- /// The filename of the input SZDD file. This is passed
- /// directly to mspack_system::open().
- ///
- ///
- /// The filename to write the decompressed data to. This
- /// is passed directly to mspack_system::open().
- ///
- /// An error code, or MSPACK_ERR_OK if successful
- public MSPACK_ERR decompress(in string input, in string output)
- {
- 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.
- ///
- /// This is useful for open() which does not return an
- /// error code directly.
- ///
- /// The most recent error code
- ///
- ///
- ///
- public MSPACK_ERR last_error()
- {
- return this.error;
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/SZDD/msszddd_header.cs b/libmspack/SZDD/msszddd_header.cs
deleted file mode 100644
index 74cdb1f..0000000
--- a/libmspack/SZDD/msszddd_header.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- ///
- /// A structure which represents an SZDD compressed file.
- ///
- /// All fields are READ ONLY.
- ///
- public class msszddd_header
- {
- public mspack_file fh { get; set; }
-
- ///
- /// The file format
- ///
- public MSSZDD_FMT format { get; set; }
-
- ///
- /// The amount of data in the SZDD file once uncompressed.
- ///
- public long length { get; set; }
-
- ///
- /// The last character in the filename, traditionally replaced with an
- /// underscore to show the file is compressed. The null character is used
- /// to show that this character has not been stored (e.g. because the
- /// filename is not known). Generally, only characters that may appear in
- /// an MS-DOS filename (except ".") are valid.
- ///
- public char missing_char { get; set; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/crc32.cs b/libmspack/crc32.cs
deleted file mode 100644
index 7887f7d..0000000
--- a/libmspack/crc32.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
- * code or tables extracted from it, as desired without restriction.
- *
- * First, the polynomial itself and its table of feedback terms. The
- * polynomial is
- * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
- *
- * Note that we take it "backwards" and put the highest-order term in
- * the lowest-order bit. The X^32 term is "implied"; the LSB is the
- * X^31 term, etc. The X^0 term (usually shown as "+1") results in
- * the MSB being 1
- *
- * Note that the usual hardware shift register implementation, which
- * is what we're using (we're merely optimizing it by doing eight-bit
- * chunks at a time) shifts bits into the lowest-order term. In our
- * implementation, that means shifting towards the right. Why do we
- * do it this way? Because the calculated CRC must be transmitted in
- * order from highest-order term to lowest-order term. UARTs transmit
- * characters in order from LSB to MSB. By storing the CRC this way
- * we hand it to the UART in the order low-byte to high-byte; the UART
- * sends each low-bit to hight-bit; and the result is transmission bit
- * by bit from highest- to lowest-order term without requiring any bit
- * shuffling on our part. Reception works similarly
- *
- * The feedback terms table consists of 256, 32-bit entries. Notes
- *
- * The table can be generated at runtime if desired; code to do so
- * is shown later. It might not be obvious, but the feedback
- * terms simply represent the results of eight shift/xor opera
- * tions for all combinations of data and CRC register values
- *
- * The values must be right-shifted by eight bits by the "updcrc
- * logic; the shift must be unsigned (bring in zeroes). On some
- * hardware you could probably optimize the shift in assembler by
- * using byte-swap instructions
- * polynomial $edb88320
- */
-
-namespace SabreTools.Compression.libmspack
-{
- public unsafe static partial class mspack
- {
- private static readonly uint[] crc32_table = new uint[256]
- {
- 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
- 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
- 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
- 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
- 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
- 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
- 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
- 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
- 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
- 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
- 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
- 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
- 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
- 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
- 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
- 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
- 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
- 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
- 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
- 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
- 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
- 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
- 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
- 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
- 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
- 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
- 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
- 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
- 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
- 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
- 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
- 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
- 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
- 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
- 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
- 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
- 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
- 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
- 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
- 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
- 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
- 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
- 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
- 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
- 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
- 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
- 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
- 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
- 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
- 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
- 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
- 0x2d02ef8d
- };
-
- ///
- /// Return a 32-bit CRC of the contents of the buffer.
- ///
- ///
- ///
- ///
- ///
- public static uint crc32(uint val, void* ss, int len)
- {
- byte* s = (byte*)ss;
- while (--len >= 0)
- {
- val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
- }
-
- return val;
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/macros.cs b/libmspack/macros.cs
deleted file mode 100644
index 311a76a..0000000
--- a/libmspack/macros.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- public static class macros
- {
- private static uint __egi32(FixedArray a, int n)
- {
- return (uint)((a[n + 3] << 24) | (a[n + 2] << 16) | (a[n + 1] << 8) | (a[n + 0]));
- }
-
- public static ulong EndGetI64(FixedArray a, int n)
- {
- return (__egi32(a, n + 4) << 32) | __egi32(a, n + 0);
- }
-
- public static uint EndGetI32(FixedArray a, int n)
- {
- return __egi32(a, n + 0);
- }
-
- public static ushort EndGetI16(FixedArray a, int n)
- {
- return (ushort)((a[n + 1] << 8) | a[n + 0]);
- }
-
- public static uint EndGetM32(FixedArray a, int n)
- {
- return (uint)((a[n + 0] << 24) | (a[n + 1] << 16) | (a[n + 2] << 8) | (a[n + 3]));
- }
-
- public static ushort EndGetM16(FixedArray a, int n)
- {
- return (ushort)((a[n + 0] << 8) | a[n + 1]);
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/mspack_default_system.cs b/libmspack/mspack_default_system.cs
deleted file mode 100644
index 8d25cb2..0000000
--- a/libmspack/mspack_default_system.cs
+++ /dev/null
@@ -1,140 +0,0 @@
-using System;
-using System.IO;
-using System.Runtime.InteropServices;
-
-namespace SabreTools.Compression.libmspack
-{
- public class mspack_default_system : mspack_system
- {
- ///
- public override mspack_file open(in string filename, MSPACK_SYS_OPEN mode)
- {
- FileMode fmode;
- FileAccess faccess;
-
- switch (mode)
- {
- case MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_READ: fmode = FileMode.Open; faccess = FileAccess.Read; break;
- case MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_WRITE: fmode = FileMode.OpenOrCreate; faccess = FileAccess.Write; break;
- case MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_UPDATE: fmode = FileMode.Open; faccess = FileAccess.ReadWrite; break;
- case MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_APPEND: fmode = FileMode.Append; faccess = FileAccess.ReadWrite; break;
- default: return null;
- }
-
- try
- {
- var fh = new mspack_file_p
- {
- name = filename,
- fh = File.Open(filename, fmode, faccess),
- };
- return fh;
- }
- catch
- {
- return null;
- }
- }
-
- ///
- public override void close(mspack_file file)
- {
- if (file is mspack_file_p self)
- self.fh?.Dispose();
- }
-
- ///
- public override unsafe int read(mspack_file file, void* buffer, int bytes)
- {
- try
- {
- if (file is mspack_file_p self && buffer != null && bytes >= 0)
- {
- var ums = new UnmanagedMemoryStream((byte*)buffer, bytes);
- self.fh.CopyTo(ums, bytes);
- return bytes;
- }
- }
- catch { }
-
- return -1;
- }
-
- ///
- public override unsafe int write(mspack_file file, void* buffer, int bytes)
- {
- try
- {
- if (file is mspack_file_p self && buffer != null && bytes >= 0)
- {
- var ums = new UnmanagedMemoryStream((byte*)buffer, bytes);
- ums.CopyTo(self.fh, bytes);
- return bytes;
- }
- }
- catch { }
-
- return -1;
- }
-
- ///
- public override int seek(mspack_file file, long offset, MSPACK_SYS_SEEK mode)
- {
- try
- {
- if (file is mspack_file_p self)
- {
- SeekOrigin origin;
- switch (mode)
- {
- case MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_START: origin = SeekOrigin.Begin; break;
- case MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_CUR: origin = SeekOrigin.Current; break;
- case MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_END: origin = SeekOrigin.End; break;
- default: return -1;
- }
-
- self.fh.Seek(offset, origin);
- return 0;
- }
- }
- catch { }
-
- return -1;
- }
-
- ///
- public override long tell(mspack_file file)
- {
- var self = file as mspack_file_p;
- return self != null ? self.fh.Position : 0;
- }
-
- ///
- public override void message(mspack_file file, in string format, params string[] args)
- {
- if (file != null) Console.Write((file as mspack_file_p)?.name);
- Console.Write(format, args);
- Console.Write("\n");
- }
-
- ///
- public override unsafe void* alloc(int bytes)
- {
- return (void*)new FixedArray(bytes).Pointer;
- }
-
- ///
- public override unsafe void free(void* ptr)
- {
- Marshal.FreeCoTaskMem((IntPtr)ptr);
- }
-
- ///
- public override unsafe void copy(void* src, void* dest, int bytes)
- {
- byte[] temp = new byte[bytes];
- Marshal.Copy((IntPtr)src, temp, 0, bytes);
- Marshal.Copy(temp, 0, (IntPtr)dest, bytes);
- }
- }
-}
\ No newline at end of file
diff --git a/libmspack/mspack_file.cs b/libmspack/mspack_file.cs
deleted file mode 100644
index 10e5d43..0000000
--- a/libmspack/mspack_file.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- ///
- /// A structure which represents an open file handle. The contents of this
- /// structure are determined by the implementation of the
- /// mspack_system::open() method.
- ///
- public unsafe abstract class mspack_file { }
-}
\ No newline at end of file
diff --git a/libmspack/mspack_file_p.cs b/libmspack/mspack_file_p.cs
deleted file mode 100644
index 344d5a0..0000000
--- a/libmspack/mspack_file_p.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System.IO;
-
-namespace SabreTools.Compression.libmspack
-{
- public class mspack_file_p : mspack_file
- {
- public Stream fh { get; set; }
-
- public string name { get; set; }
- }
-}
\ No newline at end of file
diff --git a/libmspack/mspack_system.cs b/libmspack/mspack_system.cs
deleted file mode 100644
index b8a2ed3..0000000
--- a/libmspack/mspack_system.cs
+++ /dev/null
@@ -1,170 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- ///
- /// A structure which abstracts file I/O and memory management.
- ///
- /// The library always uses the mspack_system structure for interaction
- /// 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
- /// decompressor constructor will result in a default mspack_system being
- /// used, where all methods are implemented with the standard C library.
- ///
- /// However, all constructors support being given a custom created
- /// mspack_system structure, with the library user's own methods. This
- /// allows for more abstract interaction, such as reading and writing files
- /// directly to memory, or from a network socket or pipe.
- ///
- /// Implementors of an mspack_system structure should read all
- /// documentation entries for every structure member, and write methods
- /// which conform to those standards.
- ///
- public unsafe abstract class mspack_system
- {
- ///
- /// Opens a file for reading, writing, appending or updating
- ///
- ///
- /// The file to be opened. It is passed directly from the
- /// library caller without being modified, so it is up to
- /// the caller what this parameter actually represents.
- ///
- /// One of values
- ///
- /// 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
- /// pointer indicates an error condition.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public abstract mspack_file open(in string filename, MSPACK_SYS_OPEN mode);
-
- ///
- /// Closes a previously opened file. If any memory was allocated for this
- /// particular file handle, it should be freed at this time.
- ///
- /// The file to close
- ///
- public abstract void close(mspack_file file);
-
- ///
- /// Reads a given number of bytes from an open file.
- ///
- /// The file to read from
- /// The location where the read bytes should be stored
- /// The number of bytes to read from the file
- ///
- /// The number of bytes successfully read (this can be less than
- /// the number requested), zero to mark the end of file, or less
- /// than zero to indicate an error. The library does not "retry"
- /// reads and assumes short reads are due to EOF, so you should
- /// avoid returning short reads because of transient errors.
- ///
- ///
- ///
- public abstract int read(mspack_file file, void* buffer, int bytes);
-
- ///
- /// Writes a given number of bytes to an open file.
- ///
- /// The file to write to
- /// The location where the written bytes should be read from
- /// The number of bytes to write to the file
- ///
- /// The number of bytes successfully written, this can be less
- /// than the number requested. Zero or less can indicate an error
- /// where no bytes at all could be written. All cases where less
- /// bytes were written than requested are considered by the library
- /// to be an error.
- ///
- ///
- ///
- public abstract int write(mspack_file file, void* buffer, int bytes);
-
- ///
- /// Seeks to a specific file offset within an open file.
- ///
- /// Sometimes the library needs to know the length of a file. It does
- /// this by seeking to the end of the file with seek(file, 0,
- /// MSPACK_SYS_SEEK_END), then calling tell(). Implementations may want
- /// to make a special case for this.
- ///
- /// Due to the potentially varying 32/64 bit datatype off_t on some
- /// architectures, the #MSPACK_SYS_SELFTEST macro MUST be used before
- /// using the library. If not, the error caused by the library passing an
- /// inappropriate stackframe to seek() is subtle and hard to trace.
- ///
- /// The file to be seeked
- /// An offset to seek, measured in bytes
- /// One of values
- /// Zero for success, non-zero for an error
- ///
- ///
- public abstract int seek(mspack_file file, long offset, MSPACK_SYS_SEEK mode);
-
- ///
- /// Returns the current file position (in bytes) of the given file.
- ///
- /// The file whose file position is wanted
- /// The current file position of the file
- ///
- ///
- public abstract long tell(mspack_file file);
-
- ///
- /// Used to send messages from the library to the user.
- ///
- /// Occasionally, the library generates warnings or other messages in
- /// plain english to inform the human user. These are informational only
- /// and can be ignored if not wanted.
- ///
- ///
- /// May be a file handle returned from open() if this message
- /// pertains to a specific open file, or null if not related to
- /// a specific file.
- ///
- ///
- /// a printf() style format string. It does NOT include a
- /// trailing newline.
- ///
- public abstract void message(mspack_file file, in string format, params string[] args);
-
- ///
- /// Allocates memory
- ///
- /// The number of bytes to allocate
- ///
- /// A pointer to the requested number of bytes, or null if
- /// not enough memory is available
- ///
- ///
- public abstract void* alloc(int bytes);
-
- ///
- /// Frees memory
- ///
- /// The memory to be freed. null is accepted and ignored.
- ///
- public abstract void free(void* ptr);
-
- ///
- /// Copies from one region of memory to another.
- ///
- /// The regions of memory are guaranteed not to overlap, are usually less
- /// than 256 bytes, and may not be aligned. Please note that the source
- /// parameter comes before the destination parameter, unlike the standard
- /// C function memcpy().
- ///
- /// The region of memory to copy from
- /// The region of memory to copy to
- /// The size of the memory region, in bytes
- public abstract void copy(void* src, void* dest, int bytes);
- }
-}
\ No newline at end of file
diff --git a/libmspack/readbits.cs b/libmspack/readbits.cs
deleted file mode 100644
index ce14eba..0000000
--- a/libmspack/readbits.cs
+++ /dev/null
@@ -1,245 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- public unsafe abstract class readbits
- {
- ///
- /// I/O routines
- ///
- public mspack_system sys { get; set; }
-
- ///
- /// Input file handle
- ///
- public mspack_file input { get; set; }
-
- ///
- /// Output file handle
- ///
- public mspack_file output { get; set; }
-
- ///
- /// Decompression offset within window
- ///
- 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; }
-
- ///
- #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 (ReadInput() != 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 ReadInput()
- {
- 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
- }
-}
\ No newline at end of file
diff --git a/libmspack/readhuff.cs b/libmspack/readhuff.cs
deleted file mode 100644
index fb2d027..0000000
--- a/libmspack/readhuff.cs
+++ /dev/null
@@ -1,206 +0,0 @@
-namespace SabreTools.Compression.libmspack
-{
- public unsafe static class readhuff
- {
- public const int HUFF_MAXBITS = 16;
-
- #region MSB
-
- ///
- /// This function was originally coded by David Tritscher.
- /// It builds a fast huffman decoding table from
- /// a canonical huffman code lengths table.
- ///
- /// Total number of symbols in this huffman tree.
- ///
- /// Any symbols with a code length of nbits or less can be decoded
- /// in one lookup of the table.
- ///
- /// A table to get code lengths from [0 to nsyms-1]
- ///
- /// The table to fill up with decoded symbols and pointers.
- /// Should be ((1<
- /// Returns 0 for OK or 1 for error
- public static int make_decode_table_MSB(uint nsyms, uint nbits, byte* length, ushort* table)
- {
- ushort sym, next_symbol;
- uint leaf, fill;
- byte bit_num;
- uint pos = 0; // The current position in the decode table
- uint table_mask = (uint)(1 << (int)nbits);
- uint bit_mask = table_mask >> 1; // Don't do 0 length codes
-
- // Fill entries for codes short enough for a direct mapping
- for (bit_num = 1; bit_num <= nbits; bit_num++)
- {
- for (sym = 0; sym < nsyms; sym++)
- {
- if (length[sym] != bit_num) continue;
- leaf = pos;
-
- if ((pos += bit_mask) > table_mask) return 1; // Table overrun
-
- // Fill all possible lookups of this symbol with the symbol itself
- for (fill = bit_mask; fill-- > 0;) table[leaf++] = sym;
- }
- bit_mask >>= 1;
- }
-
- // Exit with success if table is now complete
- if (pos == table_mask) return 0;
-
- // Mark all remaining table entries as unused
- for (sym = (ushort)pos; sym < table_mask; sym++)
- {
- table[sym] = 0xFFFF;
- }
-
- // next_symbol = base of allocation for long codes
- next_symbol = (ushort)(((table_mask >> 1) < nsyms) ? nsyms : (table_mask >> 1));
-
- // Give ourselves room for codes to grow by up to 16 more bits.
- // codes now start at bit nbits+16 and end at (nbits+16-codelength)
- pos <<= 16;
- table_mask <<= 16;
- bit_mask = 1 << 15;
-
- for (bit_num = (byte)(nbits + 1); bit_num <= HUFF_MAXBITS; bit_num++)
- {
- for (sym = 0; sym < nsyms; sym++)
- {
- if (length[sym] != bit_num) continue;
- if (pos >= table_mask) return 1; // Table overflow
-
- leaf = pos >> 16;
- for (fill = 0; fill < (bit_num - nbits); fill++)
- {
- // If this path hasn't been taken yet, 'allocate' two entries
- if (table[leaf] == 0xFFFF)
- {
- table[(next_symbol << 1)] = 0xFFFF;
- table[(next_symbol << 1) + 1] = 0xFFFF;
- table[leaf] = next_symbol++;
- }
-
- // Follow the path and select either left or right for next bit
- leaf = (uint)(table[leaf] << 1);
- if (((pos >> (int)(15 - fill)) & 1) != 0) leaf++;
- }
- table[leaf] = sym;
- pos += bit_mask;
- }
- bit_mask >>= 1;
- }
-
- // Full table?
- return (pos == table_mask) ? 0 : 1;
- }
-
- #endregion
-
- #region LSB
-
- ///
- /// This function was originally coded by David Tritscher.
- /// It builds a fast huffman decoding table from
- /// a canonical huffman code lengths table.
- ///
- /// Total number of symbols in this huffman tree.
- ///
- /// Any symbols with a code length of nbits or less can be decoded
- /// in one lookup of the table.
- ///
- /// A table to get code lengths from [0 to nsyms-1]
- ///
- /// The table to fill up with decoded symbols and pointers.
- /// Should be ((1<
- /// Returns 0 for OK or 1 for error
- public static int make_decode_table_LSB(uint nsyms, uint nbits, byte* length, ushort* table)
- {
- ushort sym, next_symbol;
- uint leaf, fill;
- uint reverse;
- byte bit_num;
- uint pos = 0; // The current position in the decode table
- uint table_mask = (uint)(1 << (int)nbits);
- uint bit_mask = table_mask >> 1; // Don't do 0 length codes
-
- // Fill entries for codes short enough for a direct mapping
- for (bit_num = 1; bit_num <= nbits; bit_num++)
- {
- for (sym = 0; sym < nsyms; sym++)
- {
- if (length[sym] != bit_num) continue;
-
- // Reverse the significant bits
- fill = length[sym]; reverse = pos >> (int)(nbits - fill); leaf = 0;
- do { leaf <<= 1; leaf |= reverse & 1; reverse >>= 1; } while (--fill > 0);
-
- if ((pos += bit_mask) > table_mask) return 1; // Table overrun
-
- // Fill all possible lookups of this symbol with the symbol itself
- fill = bit_mask; next_symbol = (ushort)(1 << bit_num);
- do { table[leaf] = sym; leaf += next_symbol; } while (--fill > 0);
- }
- bit_mask >>= 1;
- }
-
- // Exit with success if table is now complete
- if (pos == table_mask) return 0;
-
- // Mark all remaining table entries as unused
- for (sym = (ushort)pos; sym < table_mask; sym++)
- {
- reverse = sym; leaf = 0; fill = nbits;
- do { leaf <<= 1; leaf |= reverse & 1; reverse >>= 1; } while (--fill > 0);
- table[leaf] = 0xFFFF;
- }
-
- // next_symbol = base of allocation for long codes
- next_symbol = (ushort)(((table_mask >> 1) < nsyms) ? nsyms : (table_mask >> 1));
-
- // Give ourselves room for codes to grow by up to 16 more bits.
- // codes now start at bit nbits+16 and end at (nbits+16-codelength)
- pos <<= 16;
- table_mask <<= 16;
- bit_mask = 1 << 15;
-
- for (bit_num = (byte)(nbits + 1); bit_num <= HUFF_MAXBITS; bit_num++)
- {
- for (sym = 0; sym < nsyms; sym++)
- {
- if (length[sym] != bit_num) continue;
- if (pos >= table_mask) return 1; // Table overflow
-
- // leaf = the first nbits of the code, reversed
- reverse = pos >> 16; leaf = 0; fill = nbits;
- do { leaf <<= 1; leaf |= reverse & 1; reverse >>= 1; } while (--fill > 0);
- for (fill = 0; fill < (bit_num - nbits); fill++)
- {
- // If this path hasn't been taken yet, 'allocate' two entries
- if (table[leaf] == 0xFFFF)
- {
- table[(next_symbol << 1)] = 0xFFFF;
- table[(next_symbol << 1) + 1] = 0xFFFF;
- table[leaf] = next_symbol++;
- }
-
- // Follow the path and select either left or right for next bit
- leaf = (uint)(table[leaf] << 1);
- if (((pos >> (int)(15 - fill)) & 1) != 0) leaf++;
- }
- table[leaf] = sym;
- pos += bit_mask;
- }
- bit_mask >>= 1;
- }
-
- // Full table?
- return (pos == table_mask) ? 0 : 1;
- }
-
- #endregion
- }
-}
\ No newline at end of file
diff --git a/libmspack/system.cs b/libmspack/system.cs
deleted file mode 100644
index e272f61..0000000
--- a/libmspack/system.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/* This file is part of libmspack.
- * (C) 2003-2018 Stuart Caie.
- *
- * libmspack is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License (LGPL) version 2.1
- *
- * For further details, see the file COPYING.LIB distributed with libmspack
- */
-
-namespace SabreTools.Compression.libmspack
-{
- public unsafe static class system
- {
- ///
- /// Returns the length of a file opened for reading
- ///
- 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;
-
- // Get current offset
- long current = system.tell(file);
-
- // Seek to end of file
- if (system.seek(file, 0, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_END) != 0)
- {
- return MSPACK_ERR.MSPACK_ERR_SEEK;
- }
-
- // Get offset of end of file
- *length = system.tell(file);
-
- // Seek back to original offset
- if (system.seek(file, current, MSPACK_SYS_SEEK.MSPACK_SYS_SEEK_START) != 0)
- {
- return MSPACK_ERR.MSPACK_ERR_SEEK;
- }
-
- return MSPACK_ERR.MSPACK_ERR_OK;
- }
- }
-}
\ No newline at end of file