diff --git a/BurnOutSharp/BurnOutSharp.csproj b/BurnOutSharp/BurnOutSharp.csproj
index 487eb05d..c98dcd1f 100644
--- a/BurnOutSharp/BurnOutSharp.csproj
+++ b/BurnOutSharp/BurnOutSharp.csproj
@@ -66,4 +66,8 @@
+
+
+
+
diff --git a/BurnOutSharp/External/libmspack/CAB/Cabinet.cs b/BurnOutSharp/External/libmspack/CAB/Cabinet.cs
index 3b9f10f7..7f4c42d1 100644
--- a/BurnOutSharp/External/libmspack/CAB/Cabinet.cs
+++ b/BurnOutSharp/External/libmspack/CAB/Cabinet.cs
@@ -69,9 +69,9 @@ namespace LibMSPackSharp.CAB
/// 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 class Cabinet
{
#region Internal
diff --git a/BurnOutSharp/External/libmspack/CAB/Compressor.cs b/BurnOutSharp/External/libmspack/CAB/Compressor.cs
index befc5215..5bf72ee1 100644
--- a/BurnOutSharp/External/libmspack/CAB/Compressor.cs
+++ b/BurnOutSharp/External/libmspack/CAB/Compressor.cs
@@ -21,6 +21,6 @@ namespace LibMSPackSharp.CAB
///
public class Compressor
{
- public int Dummy { get; set; }
+ public SystemImpl System { get; set; }
}
}
diff --git a/BurnOutSharp/External/libmspack/CAB/CompressorImpl.cs b/BurnOutSharp/External/libmspack/CAB/CompressorImpl.cs
deleted file mode 100644
index 430be7b7..00000000
--- a/BurnOutSharp/External/libmspack/CAB/CompressorImpl.cs
+++ /dev/null
@@ -1,19 +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 LibMSPackSharp.CAB
-{
- ///
- /// TODO
- ///
- public class CompressorImpl : Compressor
- {
- public SystemImpl System { get; set; }
- }
-}
diff --git a/BurnOutSharp/External/libmspack/CAB/Constants.cs b/BurnOutSharp/External/libmspack/CAB/Constants.cs
new file mode 100644
index 00000000..522c61f2
--- /dev/null
+++ b/BurnOutSharp/External/libmspack/CAB/Constants.cs
@@ -0,0 +1,91 @@
+/* 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
+ */
+
+/* Cabinet (.CAB) files are a form of file archive. Each cabinet contains
+ * "folders", which are compressed spans of data. Each cabinet has
+ * "files", whose metadata is in the cabinet header, but whose actual data
+ * is stored compressed in one of the "folders". Cabinets can span more
+ * than one physical file on disk, in which case they are a "cabinet set",
+ * and usually the last folder of each cabinet extends into the next
+ * cabinet.
+ *
+ * For a complete description of the format, see the MSDN site:
+ * http://msdn.microsoft.com/en-us/library/bb267310.aspx
+ */
+
+/* Notes on compliance with cabinet specification:
+ *
+ * One of the main changes between cabextract 0.6 and libmspack's cab
+ * decompressor is the move from block-oriented decompression to
+ * stream-oriented decompression.
+ *
+ * cabextract would read one data block from disk, decompress it with the
+ * appropriate method, then write the decompressed data. The CAB
+ * specification is specifically designed to work like this, as it ensures
+ * compression matches do not span the maximum decompressed block size
+ * limit of 32kb.
+ *
+ * However, the compression algorithms used are stream oriented, with
+ * specific hacks added to them to enforce the "individual 32kb blocks"
+ * rule in CABs. In other file formats, they do not have this limitation.
+ *
+ * In order to make more generalised decompressors, libmspack's CAB
+ * decompressor has moved from being block-oriented to more stream
+ * oriented. This also makes decompression slightly faster.
+ *
+ * However, this leads to incompliance with the CAB specification. The
+ * CAB controller can no longer ensure each block of input given to the
+ * decompressors is matched with their output. The "decompressed size" of
+ * each individual block is thrown away.
+ *
+ * Each CAB block is supposed to be seen as individually compressed. This
+ * means each consecutive data block can have completely different
+ * "uncompressed" sizes, ranging from 1 to 32768 bytes. However, in
+ * reality, all data blocks in a folder decompress to exactly 32768 bytes,
+ * excepting the final block.
+ *
+ * Given this situation, the decompression algorithms are designed to
+ * realign their input bitstreams on 32768 output-byte boundaries, and
+ * various other special cases have been made. libmspack will not
+ * correctly decompress LZX or Quantum compressed folders where the blocks
+ * do not follow this "32768 bytes until last block" pattern. It could be
+ * implemented if needed, but hopefully this is not necessary -- it has
+ * not been seen in over 3Gb of CAB archives.
+ */
+
+namespace LibMSPackSharp.CAB
+{
+ public static class Constants
+ {
+ // 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;
+ }
+}
diff --git a/BurnOutSharp/External/libmspack/CAB/DecompressState.cs b/BurnOutSharp/External/libmspack/CAB/DecompressState.cs
index b8b2d5a2..501c71b7 100644
--- a/BurnOutSharp/External/libmspack/CAB/DecompressState.cs
+++ b/BurnOutSharp/External/libmspack/CAB/DecompressState.cs
@@ -66,12 +66,12 @@ namespace LibMSPackSharp.CAB
///
/// Input file handle
///
- public object InputFileHandle { get; set; }
+ public DefaultFileImpl InputFileHandle { get; set; }
///
/// Output file handle
///
- public object OutputFileHandle { get; set; }
+ public DefaultFileImpl OutputFileHandle { get; set; }
///
/// Input data consumed
@@ -86,6 +86,6 @@ namespace LibMSPackSharp.CAB
///
/// One input block of data
///
- public byte[] Input { get; set; } = new byte[Implementation.CAB_INPUTBUF];
+ public byte[] Input { get; set; } = new byte[Constants.CAB_INPUTBUF];
}
}
diff --git a/BurnOutSharp/External/libmspack/CAB/Decompressor.cs b/BurnOutSharp/External/libmspack/CAB/Decompressor.cs
index 25095713..99f40ad6 100644
--- a/BurnOutSharp/External/libmspack/CAB/Decompressor.cs
+++ b/BurnOutSharp/External/libmspack/CAB/Decompressor.cs
@@ -15,6 +15,9 @@
*/
using System;
+using System.Text;
+using LibMSPackSharp.Compression;
+using static LibMSPackSharp.CAB.Constants;
namespace LibMSPackSharp.CAB
{
@@ -27,6 +30,28 @@ namespace LibMSPackSharp.CAB
///
public class Decompressor
{
+ #region Fields
+
+ public DecompressState State { get; set; }
+
+ public SystemImpl System { get; set; }
+
+ public int BufferSize { get; set; }
+
+ public int SearchBufferSize { get; set; }
+
+ public bool FixMSZip { get; set; }
+
+ public bool Salvage { get; set; }
+
+ public Error Error { get; set; }
+
+ public Error ReadError { get; set; }
+
+ #endregion
+
+ #region Public Functionality
+
///
/// Opens a cabinet file and reads its contents.
///
@@ -40,13 +65,32 @@ namespace LibMSPackSharp.CAB
/// The filename pointer should be considered "in use" until close() is
/// called on the cabinet.
///
- /// A self-referential pointer to the Decompressor instance being called
/// The filename of the cabinet file. This is passed directly to SystemImpl::open().
/// A pointer to a Cabinet structure, or NULL on failure
- ///
- ///
- ///
- public Func Open;
+ ///
+ ///
+ ///
+ public Cabinet Open(string filename)
+ {
+ DefaultFileImpl fileHandle = System.Open(filename, OpenMode.MSPACK_SYS_OPEN_READ);
+ if (fileHandle == null)
+ {
+ Error = Error.MSPACK_ERR_OPEN;
+ return null;
+ }
+
+ Cabinet cab = new Cabinet() { Filename = filename };
+ Error error = ReadHeaders(fileHandle, cab, 0, Salvage, false);
+ if (error != Error.MSPACK_ERR_OK)
+ {
+ Close(cab);
+ cab = null;
+ }
+
+ Error = error;
+ System.Close(fileHandle);
+ return cab;
+ }
///
/// Closes a previously opened cabinet or cabinet set.
@@ -72,13 +116,57 @@ namespace LibMSPackSharp.CAB
/// not allocated by the library. The caller should free this itself if
/// necessary, before it is lost forever.
///
- /// A self-referential pointer to the Decompressor instance being called
- /// The cabinet to close
- ///
- ///
- ///
- ///
- public Action Close;
+ /// The cabinet to close
+ ///
+ ///
+ ///
+ ///
+ public void Close(Cabinet cabinet)
+ {
+ FolderData dat, ndat;
+ Cabinet cab;
+ Folder fol, nfol;
+ InternalFile fi, nfi;
+
+ Error = Error.MSPACK_ERR_OK;
+
+ while (cabinet != null)
+ {
+ // Free files
+ for (fi = cabinet.Files; fi != null; fi = nfi)
+ {
+ nfi = fi.Next;
+ }
+
+ // Free folders
+ for (fol = cabinet.Folders; fol != null; fol = nfol)
+ {
+ nfol = fol.Next;
+
+ // Free folder decompression state if it has been decompressed
+ if (State != null && (State.Folder == fol))
+ {
+ if (State.InputFileHandle != null)
+ System.Close(State.InputFileHandle);
+
+ FreeDecompressionState();
+ State = null;
+ }
+
+ // Free folder data segments
+ for (dat = fol.Data.Next; dat != null; dat = ndat)
+ {
+ ndat = dat.Next;
+ }
+ }
+
+ // Free actual cabinet structure
+ cab = cabinet.Next;
+
+ // Repeat full procedure again with the cab.Next pointer (if set)
+ cabinet = cab;
+ }
+ }
///
/// Searches a regular file for embedded cabinets.
@@ -107,19 +195,47 @@ namespace LibMSPackSharp.CAB
/// close() should only be called on the result of search(), not on any
/// subsequent cabinets in the Cabinet::next chain.
///
- ///
- /// a self-referential pointer to the Decompressor
- /// instance being called
- ///
- ///
- /// the filename of the file to search for cabinets. This
- /// is passed directly to SystemImpl::open().
- ///
+ /// The filename of the file to search for cabinets. This is passed directly to SystemImpl::open().
/// a pointer to a Cabinet structure, or NULL
- ///
- ///
- ///
- public Func Search;
+ ///
+ ///
+ ///
+ public Cabinet Search(string filename)
+ {
+ // Allocate a search buffer
+ byte[] search_buf = new byte[SearchBufferSize];
+ if (search_buf == null)
+ {
+ Error = Error.MSPACK_ERR_NOMEMORY;
+ return null;
+ }
+
+ // Open file and get its full file length
+ DefaultFileImpl fh; Cabinet cab = null;
+ if ((fh = System.Open(filename, OpenMode.MSPACK_SYS_OPEN_READ)) != null)
+ {
+ long firstlen = 0;
+ if ((Error = System.GetFileLength(fh, out long filelen)) == Error.MSPACK_ERR_OK)
+ Error = Find(search_buf, fh, filename, filelen, ref firstlen, out cab);
+
+ // Truncated / extraneous data warning:
+ if (firstlen != 0 && (firstlen != filelen) && (cab == null || cab.BaseOffset == 0))
+ {
+ if (firstlen < filelen)
+ System.Message(fh, $"WARNING; possible {filelen - firstlen} extra bytes at end of file.");
+ else
+ System.Message(fh, $"WARNING; file possibly truncated by {firstlen - filelen} bytes.");
+ }
+
+ System.Close(fh);
+ }
+ else
+ {
+ Error = Error.MSPACK_ERR_OPEN;
+ }
+
+ return cab;
+ }
///
/// Appends one Cabinet to another, forming or extending a cabinet
@@ -152,23 +268,13 @@ namespace LibMSPackSharp.CAB
/// structures in either cabinet must be discarded and re-obtained after
/// merging.
///
- ///
- /// a self-referential pointer to the Decompressor
- /// instance being called
- ///
- ///
- /// the cabinet which will be appended to,
- /// predecessor of nextcab
- ///
- ///
- /// the cabinet which will be appended,
- /// successor of cab
- ///
+ /// 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_OK if successful
- ///
- ///
- ///
- public Func Append;
+ ///
+ ///
+ ///
+ public Error Append(Cabinet cab, Cabinet nextcab) => Merge(cab, nextcab);
///
/// Prepends one Cabinet to another, forming or extending a
@@ -179,23 +285,13 @@ namespace LibMSPackSharp.CAB
/// all other respects, it is identical to append(). See append() for the
/// full documentation.
///
- ///
- /// a self-referential pointer to the Decompressor
- /// instance being called
- ///
- ///
- /// the cabinet which will be prepended to,
- /// successor of nextcab
- ///
- ///
- /// the cabinet which will be prepended,
- /// predecessor of cab
- ///
+ /// 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_OK if successful
- ///
- ///
- ///
- public Func Prepend;
+ ///
+ ///
+ ///
+ public Error Prepend(Cabinet cab, Cabinet prevcab) => Merge(prevcab, cab);
///
/// Extracts a file from a cabinet or cabinet set.
@@ -213,14 +309,139 @@ namespace LibMSPackSharp.CAB
/// and not enough parts of the cabinet set have been loaded and appended
/// or prepended, an error will be returned immediately.
///
- ///
- /// a self-referential pointer to the Decompressor
- /// instance being called
- ///
/// the file to be decompressed
/// the filename of the file being written to
/// an error code, or MSPACK_ERR_OK if successful
- public Func Extract;
+ public Error Extract(InternalFile file, string filename)
+ {
+ if (file == null)
+ return Error = Error.MSPACK_ERR_ARGS;
+
+ Folder fol = file.Folder;
+
+ // If offset is beyond 2GB, nothing can be extracted
+ if (file.Header.FolderOffset > CAB_LENGTHMAX)
+ return Error = Error.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
+ long filelen = file.Header.UncompressedSize;
+ if (filelen > CAB_LENGTHMAX || (file.Header.FolderOffset + filelen) > CAB_LENGTHMAX)
+ {
+ if (Salvage)
+ filelen = CAB_LENGTHMAX - file.Header.FolderOffset;
+ else
+ return Error = Error.MSPACK_ERR_DATAFORMAT;
+ }
+
+ // Extraction impossible if no folder, or folder needs predecessor
+ if (fol == null || fol.MergePrev != null)
+ {
+ System.Message(null, $"ERROR; file \"{file.Filename}\" cannot be extracted, cabinet set is incomplete");
+ return Error = Error.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 (!Salvage)
+ {
+ long maxlen = fol.Header.NumBlocks * CAB_BLOCKMAX;
+ if ((file.Header.FolderOffset + filelen) > maxlen)
+ {
+ System.Message(null, $"ERROR; file \"{file.Filename}\" cannot be extracted, cabinet set is incomplete");
+ return Error = Error.MSPACK_ERR_DECRUNCH;
+ }
+ }
+
+ // Allocate generic decompression state
+ if (State == null)
+ {
+ State = new DecompressState() { Sys = System };
+
+ State.Sys.Read = SysRead;
+ State.Sys.Write = SysWrite;
+ }
+
+ // Do we need to change folder or reset the current folder?
+ if ((State.Folder != fol) || (State.Offset > file.Header.FolderOffset) || State.DecompressorState == null)
+ {
+ // Free any existing decompressor
+ FreeDecompressionState();
+
+ // Do we need to open a new cab file?
+ if (State.InputFileHandle == null || (fol.Data.Cab != State.InputCabinet))
+ {
+ // Close previous file handle if from a different cab
+ if (State.InputFileHandle != null)
+ System.Close(State.InputFileHandle);
+
+ State.InputCabinet = fol.Data.Cab;
+ State.InputFileHandle = System.Open(fol.Data.Cab.Filename, OpenMode.MSPACK_SYS_OPEN_READ);
+ if (State.InputFileHandle == null)
+ return Error = Error.MSPACK_ERR_OPEN;
+ }
+
+ // Seek to start of data blocks
+ if (!System.Seek(State.InputFileHandle, fol.Data.Offset, SeekMode.MSPACK_SYS_SEEK_START))
+ return Error = Error.MSPACK_ERR_SEEK;
+
+ // Set up decompressor
+ if (InitDecompressionState(fol.Header.CompType) != Error.MSPACK_ERR_OK)
+ return Error;
+
+ // Initialise new folder state
+ State.Folder = fol;
+ State.Data = fol.Data;
+ State.Offset = 0;
+ State.Block = 0;
+ State.Outlen = 0;
+ State.InputPointer = State.InputEnd = 0;
+
+ // Read_error lasts for the lifetime of a decompressor
+ ReadError = Error.MSPACK_ERR_OK;
+ }
+
+ // Open file for output
+ DefaultFileImpl fh = System.Open(filename, OpenMode.MSPACK_SYS_OPEN_WRITE);
+ if (fh == null)
+ return Error = Error.MSPACK_ERR_OPEN;
+
+ Error = Error.MSPACK_ERR_OK;
+
+ // If file has more than 0 bytes
+ if (filelen != 0)
+ {
+ long bytes;
+ Error 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 self.ReadError
+ // and pass back MSPACK_ERR_READ
+ State.OutputFileHandle = null;
+ if ((bytes = file.Header.FolderOffset - State.Offset) != 0)
+ {
+ error = State.Decompress(State.DecompressorState, bytes);
+ Error = (error == Error.MSPACK_ERR_READ) ? ReadError : error;
+ }
+
+ // If getting to the correct offset was error free, unpack file
+ if (Error == Error.MSPACK_ERR_OK)
+ {
+ State.OutputFileHandle = fh;
+ InitDecompressionState(fol.Header.CompType);
+
+ error = State.Decompress(State.DecompressorState, filelen);
+ Error = (error == Error.MSPACK_ERR_READ) ? ReadError : error;
+ }
+ }
+
+ // Close output file
+ System.Close(fh);
+ State.OutputFileHandle = null;
+
+ return Error;
+ }
///
/// Sets a CAB decompression engine parameter.
@@ -236,33 +457,1032 @@ namespace LibMSPackSharp.CAB
/// bit buffer by decompressors? The minimum value is 4. The default
/// value is 4096.
///
- ///
- /// a self-referential pointer to the Decompressor
- /// instance being called
- ///
/// 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 Func SetParam;
+ ///
+ ///
+ public Error SetParam(Parameters param, int value)
+ {
+ switch (param)
+ {
+ case Parameters.MSCABD_PARAM_SEARCHBUF:
+ if (value < 4)
+ return Error.MSPACK_ERR_ARGS;
+
+ SearchBufferSize = value;
+ break;
+
+ case Parameters.MSCABD_PARAM_FIXMSZIP:
+ FixMSZip = value != 0;
+ break;
+
+ case Parameters.MSCABD_PARAM_DECOMPBUF:
+ if (value < 4)
+ return Error.MSPACK_ERR_ARGS;
+
+ BufferSize = value;
+ break;
+
+ case Parameters.MSCABD_PARAM_SALVAGE:
+ Salvage = value != 0;
+ break;
+
+ default:
+ return Error.MSPACK_ERR_ARGS;
+ }
+
+ return Error.MSPACK_ERR_OK;
+ }
+
+ #endregion
+
+ #region Decompression State
///
- /// 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.
+ /// Initialises decompression state, according to which
+ /// decompression method was used. relies on self.State.Folder being the same
+ /// as when initialised.
///
- ///
- /// a self-referential pointer to the Decompressor
- /// instance being called
- ///
- /// the most recent error code
- ///
- ///
- public Func LastError;
+ internal Error InitDecompressionState(CompressionType ct)
+ {
+ State.CompressionType = ct;
+ switch (ct & CompressionType.COMPTYPE_MASK)
+ {
+ case CompressionType.COMPTYPE_NONE:
+ State.Decompress = None.Decompress;
+ State.DecompressorState = None.Init(State.Sys, State.InputFileHandle, State.OutputFileHandle, BufferSize);
+ break;
+
+ case CompressionType.COMPTYPE_MSZIP:
+ State.Decompress = MSZIP.Decompress;
+ State.DecompressorState = MSZIP.Init(State.Sys, State.InputFileHandle, State.OutputFileHandle, BufferSize, FixMSZip);
+ break;
+
+ case CompressionType.COMPTYPE_QUANTUM:
+ State.Decompress = QTM.Decompress;
+ State.DecompressorState = QTM.Init(State.Sys, State.InputFileHandle, State.OutputFileHandle, ((ushort)ct >> 8) & 0x1f, BufferSize);
+ break;
+
+ case CompressionType.COMPTYPE_LZX:
+ State.Decompress = LZX.Decompress;
+ State.DecompressorState = LZX.Init(State.Sys, State.InputFileHandle, State.OutputFileHandle, ((ushort)ct >> 8) & 0x1f, 0, BufferSize, 0, false);
+ break;
+
+ default:
+ return Error = Error.MSPACK_ERR_DATAFORMAT;
+ }
+
+ return Error = (State.DecompressorState != null) ? Error.MSPACK_ERR_OK : Error.MSPACK_ERR_NOMEMORY;
+ }
+
+ ///
+ /// Frees decompression state, according to which method was used.
+ ///
+ ///
+ internal void FreeDecompressionState()
+ {
+ if (State?.DecompressorState == null)
+ return;
+
+ State.Decompress = null;
+ State.DecompressorState = null;
+ }
+
+ #endregion
+
+ #region I/O Methods
+
+ ///
+ /// 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
+ ///
+ internal static int SysRead(object file, byte[] buffer, int pointer, int bytes)
+ {
+ if (file is Decompressor self)
+ {
+ SystemImpl sys = self.System;
+
+ int avail, todo, outlen = 0;
+
+ bool ignore_cksum = self.Salvage ||
+ (self.FixMSZip &&
+ ((self.State.CompressionType & CompressionType.COMPTYPE_MASK) == CompressionType.COMPTYPE_MSZIP));
+ bool ignore_blocksize = self.Salvage;
+
+ todo = bytes;
+ while (todo > 0)
+ {
+ avail = self.State.InputEnd - self.State.InputPointer;
+
+ // 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;
+
+ Array.Copy(self.State.Input, self.State.InputPointer, buffer, pointer, avail);
+ self.State.InputPointer += avail;
+ pointer += avail;
+ todo -= avail;
+ }
+ else
+ {
+ // Out of data, read a new block
+
+ // Check if we're out of input blocks, advance block counter
+ if (self.State.Block++ >= self.State.Folder.Header.NumBlocks)
+ {
+ if (!self.Salvage)
+ self.ReadError = Error.MSPACK_ERR_DATAFORMAT;
+ else
+ Console.WriteLine("Ran out of CAB input blocks prematurely");
+
+ break;
+ }
+
+ // Read a block
+ self.ReadError = SysReadBlock(sys, self.State, ref outlen, ignore_cksum, ignore_blocksize);
+ if (self.ReadError != Error.MSPACK_ERR_OK)
+ return -1;
+
+ self.State.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 ((self.State.CompressionType & CompressionType.COMPTYPE_MASK) == CompressionType.COMPTYPE_QUANTUM)
+ self.State.Input[self.State.InputEnd++] = 0xFF;
+
+ // Is this the last block?
+ if (self.State.Block >= self.State.Folder.Header.NumBlocks)
+ {
+ if ((self.State.CompressionType & CompressionType.COMPTYPE_MASK) == CompressionType.COMPTYPE_LZX)
+ {
+ // Special LZX hack -- on the last block, inform LZX of the
+ // size of the output data stream.
+ LZX.SetOutputLength(self.State.DecompressorState as LZXDStream, self.State.Outlen);
+ }
+ }
+ }
+ }
+
+ return bytes - todo;
+ }
+ else if (file is DefaultFileImpl impl)
+ {
+ return SystemImpl.DefaultSystem.Read(file, buffer, pointer, bytes);
+ }
+
+ return -1;
+ }
+
+ ///
+ /// The internal writer function which the decompressors
+ /// use. it either writes data to disk (self.State.OutputFileHandle) with the real
+ /// sys.write() function, or does nothing with the data when
+ /// self.State.OutputFileHandle == null. advances self.State.Offset
+ ///
+ internal static int SysWrite(object file, byte[] buffer, int pointer, int bytes)
+ {
+ if (file is Decompressor self)
+ {
+ self.State.Offset += (uint)bytes;
+ if (self.State.OutputFileHandle != null)
+ return self.System.Write(self.State.OutputFileHandle, buffer, pointer, bytes);
+
+ return bytes;
+ }
+ else if (file is DefaultFileImpl impl)
+ {
+ return SystemImpl.DefaultSystem.Write(file, buffer, pointer, bytes);
+ }
+
+ // Unknown file to write to
+ return 0;
+ }
+
+ ///
+ /// 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 Error SysReadBlock(SystemImpl sys, DecompressState d, ref int output, bool ignore_cksum, bool ignore_blocksize)
+ {
+ byte[] hdr = new byte[_DataBlockHeader.Size];
+ int full_len;
+
+ // Reset the input block pointer and end of block pointer
+ d.InputPointer = d.InputEnd = 0;
+
+ do
+ {
+ // Read the block header
+ if (SystemImpl.DefaultSystem.Read(d.InputFileHandle, hdr, 0, _DataBlockHeader.Size) != _DataBlockHeader.Size)
+ return Error.MSPACK_ERR_READ;
+
+ // Skip any reserved block headers
+ if (d.Data.Cab.Header.HeaderReserved != 0 && !sys.Seek(d.InputFileHandle, d.Data.Cab.Header.HeaderReserved, SeekMode.MSPACK_SYS_SEEK_CUR))
+ return Error.MSPACK_ERR_SEEK;
+
+ // Create a block header from the data
+ Error err = _DataBlockHeader.Create(hdr, out _DataBlockHeader dataBlockHeader);
+ if (err != Error.MSPACK_ERR_OK)
+ return err;
+
+ // Blocks must not be over CAB_INPUTMAX in size
+ full_len = (d.InputEnd - d.InputPointer) + dataBlockHeader.CompressedSize; // Include cab-spanning blocks
+ if (full_len > CAB_INPUTMAX)
+ {
+ Console.WriteLine($"Block size {full_len} > CAB_INPUTMAX");
+
+ // In salvage mode, blocks can be 65535 bytes but no more than that
+ if (!ignore_blocksize || full_len > CAB_INPUTMAX_SALVAGE)
+ return Error.MSPACK_ERR_DATAFORMAT;
+ }
+
+ // Blocks must not expand to more than CAB_BLOCKMAX
+ if (dataBlockHeader.UncompressedSize > CAB_BLOCKMAX)
+ {
+ Console.WriteLine("block size > CAB_BLOCKMAX");
+ if (!ignore_blocksize)
+ return Error.MSPACK_ERR_DATAFORMAT;
+ }
+
+ // Read the block data
+ if (SystemImpl.DefaultSystem.Read(d.InputFileHandle, d.Input, d.InputEnd, dataBlockHeader.CompressedSize) != dataBlockHeader.CompressedSize)
+ return Error.MSPACK_ERR_READ;
+
+ // Perform checksum test on the block (if one is stored)
+ if (dataBlockHeader.CheckSum != 0)
+ {
+ uint sum2 = Checksum(d.Input, d.InputEnd, dataBlockHeader.CompressedSize, 0);
+ if (Checksum(hdr, 4, 4, sum2) != dataBlockHeader.CheckSum)
+ {
+ if (!ignore_cksum)
+ return Error.MSPACK_ERR_CHECKSUM;
+
+ sys.Message(d.InputFileHandle, "WARNING; bad block checksum found");
+ }
+ }
+
+ // Advance end of block pointer to include newly read data
+ d.InputEnd += dataBlockHeader.CompressedSize;
+
+ // 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 ((output = dataBlockHeader.UncompressedSize) != 0)
+ return Error.MSPACK_ERR_OK;
+
+ // Otherwise, advance to next cabinet
+
+ // Close current file handle
+ sys.Close(d.InputFileHandle);
+ d.InputFileHandle = null;
+
+ // Advance to next member in the cabinet set
+ if ((d.Data = d.Data.Next) == null)
+ {
+ sys.Message(d.InputFileHandle, "WARNING; ran out of cabinets in set. Are any missing?");
+ return Error.MSPACK_ERR_DATAFORMAT;
+ }
+
+ // Open next cab file
+ d.InputCabinet = d.Data.Cab;
+ if ((d.InputFileHandle = sys.Open(d.InputCabinet.Filename, OpenMode.MSPACK_SYS_OPEN_READ)) == null)
+ return Error.MSPACK_ERR_OPEN;
+
+ // Seek to start of data blocks
+ if (!sys.Seek(d.InputFileHandle, d.Data.Offset, SeekMode.MSPACK_SYS_SEEK_START))
+ return Error.MSPACK_ERR_SEEK;
+ } while (true);
+ }
+
+ private static uint Checksum(byte[] data, int pointer, uint bytes, uint cksum)
+ {
+ uint len, ul = 0;
+
+ for (len = bytes >> 2; len-- != 0; pointer += 4)
+ {
+ cksum ^= (uint)((data[pointer + 0]) | (data[pointer + 1] << 8) | (data[pointer + 2] << 16) | (data[pointer + 3] << 24));
+ }
+
+ switch (bytes & 3)
+ {
+ case 3:
+ ul |= (uint)(data[pointer++] << 16);
+ ul |= (uint)(data[pointer++] << 8);
+ ul |= data[pointer];
+ break;
+
+ case 2:
+ ul |= (uint)(data[pointer++] << 8);
+ ul |= data[pointer];
+ break;
+
+ case 1:
+ ul |= data[pointer];
+ break;
+ }
+
+ cksum ^= ul;
+ return cksum;
+ }
+
+ #endregion
+
+ #region Helpers
+
+ ///
+ /// Decides if two folders are OK to merge
+ ///
+ private bool CanMergeFolders(Folder lfol, Folder rfol)
+ {
+ InternalFile lfi, rfi, l, r;
+ bool matching = true;
+
+ // Check that both folders use the same compression method/settings
+ if (lfol.Header.CompType != rfol.Header.CompType)
+ {
+ Console.WriteLine("folder merge: compression type mismatch");
+ return false;
+ }
+
+ // Check there are not too many data blocks after merging
+ if ((lfol.Header.NumBlocks + rfol.Header.NumBlocks) > CAB_FOLDERMAX)
+ {
+ Console.WriteLine("folder merge: too many data blocks in merged folders");
+ return false;
+ }
+
+ if ((lfi = lfol.MergeNext) == null || (rfi = rfol.MergePrev) == null)
+ {
+ Console.WriteLine("folder merge: one cabinet has no files to merge");
+ return false;
+ }
+
+ // 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.Header.FolderOffset != r.Header.FolderOffset) || (l.Header.UncompressedSize != r.Header.UncompressedSize))
+ {
+ matching = false;
+ break;
+ }
+ }
+
+ if (matching)
+ return true;
+
+ // 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 = false;
+ for (l = lfi; l != null; l = l.Next)
+ {
+ for (r = rfi; r != null; r = r.Next)
+ {
+ if (l.Header.FolderOffset == r.Header.FolderOffset && l.Header.UncompressedSize == r.Header.UncompressedSize)
+ break;
+ }
+
+ if (r != null)
+ matching = true;
+ else
+ System.Message(null, $"WARNING; merged file {l.Filename} not listed in both cabinets");
+ }
+
+ return matching;
+ }
+
+ ///
+ /// The inner loop of , to make it easier to
+ /// break out of the loop and be sure that all resources are freed
+ ///
+ private Error Find(byte[] buf, DefaultFileImpl fh, string filename, long flen, ref long firstlen, out Cabinet firstcab)
+ {
+ firstcab = null;
+ Cabinet cab, link = null;
+ long caboff, offset, length;
+ long 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 > SearchBufferSize)
+ length = SearchBufferSize;
+
+ // Fill the search buffer with data from disk
+ if (System.Read(fh, buf, 0, (int)length) != (int)length)
+ return Error.MSPACK_ERR_READ;
+
+ // FAQ avoidance strategy
+ if (offset == 0 && BitConverter.ToUInt32(buf, 0) == 0x28635349)
+ System.Message(fh, "WARNING; found InstallShield header. Use unshield (https://github.com/twogood/unshield) to unpack this file");
+
+ // Read through the entire buffer.
+ for (p = 0, pend = 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 && buf[p] != 0x4D)
+ {
+ p++;
+ }
+
+ // If we found that 'M', advance state
+ if (p++ < pend)
+ state = 1;
+
+ break;
+
+ // Verify that the next 3 bytes are 'S', 'C' and 'F'
+ case 1:
+ state = (byte)(buf[p++] == 0x53 ? 2 : 0);
+ break;
+ case 2:
+ state = (byte)(buf[p++] == 0x43 ? 3 : 0);
+ break;
+ case 3:
+ state = (byte)(buf[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 = buf[p++];
+ state++;
+ break;
+ case 9:
+ cablen_u32 |= (uint)buf[p++] << 8;
+ state++;
+ break;
+ case 10:
+ cablen_u32 |= (uint)buf[p++] << 16;
+ state++;
+ break;
+ case 11:
+ cablen_u32 |= (uint)buf[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 = buf[p++];
+ state++;
+ break;
+ case 17:
+ foffset_u32 |= (uint)buf[p++] << 8;
+ state++;
+ break;
+ case 18:
+ foffset_u32 |= (uint)buf[p++] << 16;
+ state++;
+ break;
+ case 19:
+ foffset_u32 |= (uint)buf[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 - 20;
+
+ // Should reading cabinet fail, restart search just after 'MSCF'
+ offset = caboff + 4;
+
+ // Vapture 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 + foffset_u32) < (flen + 32)) &&
+ (((caboff + cablen_u32) < (flen + 32)) || Salvage))
+ {
+ // Likely cabinet found -- try reading it
+ cab = new Cabinet() { Filename = filename };
+
+ if (ReadHeaders(fh, cab, caboff, Salvage, quiet: true) != Error.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 + cablen_u32;
+ }
+ }
+
+ // Restart search
+ if (offset >= flen)
+ return Error.MSPACK_ERR_OK;
+
+ if (!System.Seek(fh, offset, SeekMode.MSPACK_SYS_SEEK_START))
+ return Error.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;
+ }
+ }
+ }
+
+ if (false_cabs != 0)
+ Console.WriteLine($"{false_cabs} false cabinets found");
+
+ return Error.MSPACK_ERR_OK;
+ }
+
+ ///
+ /// 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 Error Merge(Cabinet lcab, Cabinet rcab)
+ {
+ FolderData data, ndata;
+ Folder lfol, rfol;
+ InternalFile fi, rfi, lfi;
+
+ // Basic args check
+ if (lcab == null || rcab == null || (lcab == rcab))
+ {
+ Console.WriteLine("lcab null, rcab null or lcab = rcab");
+ return Error = Error.MSPACK_ERR_ARGS;
+ }
+
+ // Check there's not already a cabinet attached
+ if (lcab.NextCabinet != null || rcab.PreviousCabinet != null)
+ {
+ Console.WriteLine("Cabs already joined");
+ return Error = Error.MSPACK_ERR_ARGS;
+ }
+
+ // Do not create circular cabinet chains
+ Cabinet cab;
+ for (cab = lcab.PreviousCabinet; cab != null; cab = cab.PreviousCabinet)
+ {
+ if (cab == rcab)
+ {
+ Console.WriteLine("circular!");
+ return Error = Error.MSPACK_ERR_ARGS;
+ }
+ }
+ for (cab = rcab.NextCabinet; cab != null; cab = cab.NextCabinet)
+ {
+ if (cab == lcab)
+ {
+ Console.WriteLine("circular!");
+ return Error = Error.MSPACK_ERR_ARGS;
+ }
+ }
+
+ // Warn about odd set IDs or indices
+ if (lcab.Header.SetID != rcab.Header.SetID)
+ System.Message(null, "WARNING; merged cabinets with differing Set IDs.");
+
+ if (lcab.Header.CabinetIndex > rcab.Header.CabinetIndex)
+ System.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.MergeNext == null && rfol.MergePrev == null)
+ {
+ // No, at least one of the folders is not for merging
+
+ // Attach cabs
+ lcab.NextCabinet = rcab;
+ rcab.PreviousCabinet = 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(lfol, rfol))
+ return Error = Error.MSPACK_ERR_DATAFORMAT;
+
+ // Allocate a new folder data structure
+ data = new FolderData();
+
+ // Attach cabs
+ lcab.NextCabinet = rcab;
+ rcab.PreviousCabinet = 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.MergeNext is going to be deleted, so keep lfol's version
+ // instead
+ lfol.Header.NumBlocks += (ushort)(rfol.Header.NumBlocks - 1);
+ if ((rfol.MergeNext == null) || (rfol.MergeNext.Folder != rfol))
+ lfol.MergeNext = rfol.MergeNext;
+
+ // Attach the rfol's folder (except the merge folder)
+ while (lfol.Next != null)
+ {
+ lfol = lfol.Next;
+ }
+
+ lfol.Next = rfol.Next;
+
+ // 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;
+ }
+ else
+ {
+ lfi = fi;
+ }
+ }
+ }
+
+ // All done! fix files and folders pointers in alsl cabs so they all
+ // point to the same list
+ for (cab = lcab.PreviousCabinet; cab != null; cab = cab.PreviousCabinet)
+ {
+ cab.Files = lcab.Files;
+ cab.Folders = lcab.Folders;
+ }
+
+ for (cab = lcab.NextCabinet; cab != null; cab = cab.NextCabinet)
+ {
+ cab.Files = lcab.Files;
+ cab.Folders = lcab.Folders;
+ }
+
+ return Error = Error.MSPACK_ERR_OK;
+ }
+
+ ///
+ /// Reads the cabinet file header, folder list and file list.
+ /// Fills out a pre-existing Cabinet structure, allocates memory
+ /// for folders and files as necessary
+ ///
+ private Error ReadHeaders(DefaultFileImpl fh, Cabinet cab, long offset, bool salvage, bool quiet)
+ {
+ Error err = Error.MSPACK_ERR_OK;
+ Folder fol, linkfol = null;
+ InternalFile linkfile = null;
+ byte[] buf = new byte[64];
+
+ // Initialise pointers
+ if (cab == null)
+ cab = new Cabinet();
+
+ cab.Next = null;
+ cab.Files = null;
+ cab.Folders = null;
+ cab.PreviousCabinet = cab.NextCabinet = null;
+ cab.PreviousName = cab.NextName = null;
+ cab.PreviousInfo = cab.NextInfo = null;
+
+ cab.BaseOffset = offset;
+
+ // Seek to CFHEADER
+ if (!System.Seek(fh, offset, SeekMode.MSPACK_SYS_SEEK_START))
+ return Error.MSPACK_ERR_SEEK;
+
+ // Read in the CFHEADER
+ if (System.Read(fh, buf, 0, _CabinetHeader.Size) != _CabinetHeader.Size)
+ return Error.MSPACK_ERR_READ;
+
+ // Create a new header based on that
+ err = _CabinetHeader.Create(buf, out _CabinetHeader cabinetHeader);
+ if (err != Error.MSPACK_ERR_OK)
+ return err;
+
+ // Assign the header
+ cab.Header = cabinetHeader;
+
+ // Check for the extended header
+ if (cab.Header.Flags.HasFlag(HeaderFlags.MSCAB_HDR_RESV))
+ {
+ if (System.Read(fh, buf, 0, _CabinetHeader.ExtendedSize) != _CabinetHeader.ExtendedSize)
+ return Error.MSPACK_ERR_READ;
+
+ // Populate the extended header
+ cabinetHeader.PopulateExtendedHeader(buf);
+
+ // Skip the reserved header
+ if (cab.Header.HeaderReserved != 0)
+ {
+ if (!System.Seek(fh, cab.Header.HeaderReserved, SeekMode.MSPACK_SYS_SEEK_CUR))
+ return Error.MSPACK_ERR_SEEK;
+ }
+ }
+
+ // Read name and info of preceeding cabinet in set, if present
+ if (cab.Header.Flags.HasFlag(HeaderFlags.MSCAB_HDR_PREVCAB))
+ {
+ cab.PreviousName = ReadString(fh, false, ref err);
+ if (err != Error.MSPACK_ERR_OK)
+ return err;
+
+ cab.PreviousInfo = ReadString(fh, true, ref err);
+ if (err != Error.MSPACK_ERR_OK)
+ return err;
+ }
+
+ // Read name and info of next cabinet in set, if present
+ if (cab.Header.Flags.HasFlag(HeaderFlags.MSCAB_HDR_NEXTCAB))
+ {
+ cab.NextName = ReadString(fh, false, ref err);
+ if (err != Error.MSPACK_ERR_OK)
+ return err;
+
+ cab.NextInfo = ReadString(fh, true, ref err);
+ if (err != Error.MSPACK_ERR_OK)
+ return err;
+ }
+
+ // Read folders
+ for (int i = 0; i < cab.Header.NumFolders; i++)
+ {
+ // Read in the FOHEADER
+ if (System.Read(fh, buf, 0, _FolderHeader.Size) != _FolderHeader.Size)
+ return Error.MSPACK_ERR_READ;
+
+ if (cab.Header.FolderReserved != 0)
+ {
+ if (!System.Seek(fh, cab.Header.FolderReserved, SeekMode.MSPACK_SYS_SEEK_CUR))
+ return Error.MSPACK_ERR_SEEK;
+ }
+
+ // Create an empty folder
+ fol = new Folder()
+ {
+ Next = null,
+ MergePrev = null,
+ MergeNext = null,
+ };
+
+ // Create a new header based on that
+ err = _FolderHeader.Create(buf, out _FolderHeader folderHeader);
+ if (err != Error.MSPACK_ERR_OK)
+ return err;
+
+ // Assign the header
+ fol.Header = folderHeader;
+
+ // Set the folder data fields
+ fol.Data = new FolderData();
+ fol.Data.Next = null;
+ fol.Data.Cab = cab;
+ fol.Data.Offset = offset + fol.Header.DataOffset;
+
+ // Link folder into list of folders
+ if (linkfol == null)
+ cab.Folders = fol;
+ else
+ linkfol.Next = fol;
+
+ linkfol = fol;
+ }
+
+ // Read files
+ for (int i = 0; i < cab.Header.NumFiles; i++)
+ {
+ // Read in the FIHEADER
+ if (System.Read(fh, buf, 0, _FileHeader.Size) != _FileHeader.Size)
+ return Error.MSPACK_ERR_READ;
+
+ InternalFile file = new InternalFile() { Next = null };
+
+ // Create a new header based on that
+ err = _FileHeader.Create(buf, out _FileHeader fileHeader);
+ if (err != Error.MSPACK_ERR_OK)
+ return err;
+
+ // Assign the header
+ file.Header = fileHeader;
+
+ // Set folder pointer
+ if (file.Header.FolderIndex < FileFlags.CONTINUED_FROM_PREV)
+ {
+ // Normal folder index; count up to the correct folder
+ if ((int)file.Header.FolderIndex < cab.Header.NumFolders)
+ {
+ Folder ifol = cab.Folders;
+ while (file.Header.FolderIndex-- != 0)
+ {
+ if (ifol != null)
+ ifol = ifol.Next;
+ }
+
+ file.Folder = ifol;
+ }
+ else
+ {
+ Console.WriteLine("Invalid folder index");
+ file.Folder = null;
+ }
+ }
+ else
+ {
+ // Either CONTINUED_TO_NEXT, CONTINUED_FROM_PREV or CONTINUED_PREV_AND_NEXT
+ if (file.Header.FolderIndex == FileFlags.CONTINUED_TO_NEXT || file.Header.FolderIndex == FileFlags.CONTINUED_PREV_AND_NEXT)
+ {
+ // Get last folder
+ Folder ifol = cab.Folders;
+ while (ifol.Next != null)
+ {
+ ifol = ifol.Next;
+ }
+
+ file.Folder = ifol;
+
+ // Set "merge next" pointer
+ fol = ifol;
+ if (fol.MergeNext == null)
+ fol.MergeNext = file;
+ }
+
+ if (file.Header.FolderIndex == FileFlags.CONTINUED_FROM_PREV || file.Header.FolderIndex == FileFlags.CONTINUED_PREV_AND_NEXT)
+ {
+ // Get first folder
+ file.Folder = cab.Folders;
+
+ // Set "merge prev" pointer
+ fol = file.Folder;
+ if (fol.MergePrev == null)
+ fol.MergePrev = file;
+ }
+ }
+
+ // Get filename
+ file.Filename = ReadString(fh, false, ref err);
+
+ // If folder index or filename are bad, either skip it or fail
+ if (err != Error.MSPACK_ERR_OK || file.Folder == null)
+ {
+ if (salvage)
+ continue;
+
+ return err != Error.MSPACK_ERR_OK ? err : Error.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 */
+ Console.WriteLine($"No files found, even though header claimed to have {cab.Header.NumFiles} files");
+ return Error.MSPACK_ERR_DATAFORMAT;
+ }
+
+ return Error.MSPACK_ERR_OK;
+ }
+
+ private string ReadString(DefaultFileImpl fh, bool permitEmpty, ref Error error)
+ {
+ long position = System.Tell(fh);
+ byte[] buf = new byte[256];
+ int len, i;
+
+ // Read up to 256 bytes
+ if ((len = System.Read(fh, buf, 0, 256)) <= 0)
+ {
+ error = Error.MSPACK_ERR_READ;
+ return null;
+ }
+
+ // Search for a null terminator in the buffer
+ bool ok = false;
+ for (i = 0; i < len; i++)
+ {
+ if (buf[i] == 0x00)
+ {
+ ok = true;
+ break;
+ }
+ }
+
+ // Optionally reject empty strings
+ if (i == 0 && !permitEmpty)
+ ok = false;
+
+ if (!ok)
+ {
+ error = Error.MSPACK_ERR_DATAFORMAT;
+ return null;
+ }
+
+ len = i + 1;
+
+ // Set the data stream to just after the string and return
+ if (!System.Seek(fh, position + len, SeekMode.MSPACK_SYS_SEEK_START))
+ {
+ error = Error.MSPACK_ERR_SEEK;
+ return null;
+ }
+
+ error = Error.MSPACK_ERR_OK;
+ return Encoding.ASCII.GetString(buf, 0, len);
+ }
+
+ #endregion
}
}
diff --git a/BurnOutSharp/External/libmspack/CAB/DecompressorImpl.cs b/BurnOutSharp/External/libmspack/CAB/DecompressorImpl.cs
deleted file mode 100644
index 8a98b89d..00000000
--- a/BurnOutSharp/External/libmspack/CAB/DecompressorImpl.cs
+++ /dev/null
@@ -1,30 +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 LibMSPackSharp.CAB
-{
- public class DecompressorImpl : Decompressor
- {
- public DecompressState State { get; set; }
-
- public SystemImpl System { get; set; }
-
- public int BufferSize { get; set; }
-
- public int SearchBufferSize { get; set; }
-
- public bool FixMSZip { get; set; }
-
- public bool Salvage { get; set; }
-
- public Error Error { get; set; }
-
- public Error ReadError { get; set; }
- }
-}
diff --git a/BurnOutSharp/External/libmspack/CAB/Implementation.cs b/BurnOutSharp/External/libmspack/CAB/Implementation.cs
deleted file mode 100644
index e1936576..00000000
--- a/BurnOutSharp/External/libmspack/CAB/Implementation.cs
+++ /dev/null
@@ -1,1586 +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
- */
-
-/* Cabinet (.CAB) files are a form of file archive. Each cabinet contains
- * "folders", which are compressed spans of data. Each cabinet has
- * "files", whose metadata is in the cabinet header, but whose actual data
- * is stored compressed in one of the "folders". Cabinets can span more
- * than one physical file on disk, in which case they are a "cabinet set",
- * and usually the last folder of each cabinet extends into the next
- * cabinet.
- *
- * For a complete description of the format, see the MSDN site:
- * http://msdn.microsoft.com/en-us/library/bb267310.aspx
- */
-
-/* Notes on compliance with cabinet specification:
- *
- * One of the main changes between cabextract 0.6 and libmspack's cab
- * decompressor is the move from block-oriented decompression to
- * stream-oriented decompression.
- *
- * cabextract would read one data block from disk, decompress it with the
- * appropriate method, then write the decompressed data. The CAB
- * specification is specifically designed to work like this, as it ensures
- * compression matches do not span the maximum decompressed block size
- * limit of 32kb.
- *
- * However, the compression algorithms used are stream oriented, with
- * specific hacks added to them to enforce the "individual 32kb blocks"
- * rule in CABs. In other file formats, they do not have this limitation.
- *
- * In order to make more generalised decompressors, libmspack's CAB
- * decompressor has moved from being block-oriented to more stream
- * oriented. This also makes decompression slightly faster.
- *
- * However, this leads to incompliance with the CAB specification. The
- * CAB controller can no longer ensure each block of input given to the
- * decompressors is matched with their output. The "decompressed size" of
- * each individual block is thrown away.
- *
- * Each CAB block is supposed to be seen as individually compressed. This
- * means each consecutive data block can have completely different
- * "uncompressed" sizes, ranging from 1 to 32768 bytes. However, in
- * reality, all data blocks in a folder decompress to exactly 32768 bytes,
- * excepting the final block.
- *
- * Given this situation, the decompression algorithms are designed to
- * realign their input bitstreams on 32768 output-byte boundaries, and
- * various other special cases have been made. libmspack will not
- * correctly decompress LZX or Quantum compressed folders where the blocks
- * do not follow this "32768 bytes until last block" pattern. It could be
- * implemented if needed, but hopefully this is not necessary -- it has
- * not been seen in over 3Gb of CAB archives.
- */
-
-using System;
-using System.Text;
-using LibMSPackSharp.Compression;
-
-namespace LibMSPackSharp.CAB
-{
- public static class Implementation
- {
- #region Generic CAB Definitions
-
- // 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;
-
- #endregion
-
- #region CABD_OPEN
-
- ///
- /// Opens a file and tries to read it as a cabinet file
- ///
- public static Cabinet Open(Decompressor d, string filename)
- {
- DecompressorImpl self = d as DecompressorImpl;
- Cabinet cab = null;
-
- if (self == null)
- return null;
-
- SystemImpl system = self.System;
- object fileHandle;
- if ((fileHandle = system.Open(system, filename, OpenMode.MSPACK_SYS_OPEN_READ)) != null)
- {
- cab = new Cabinet();
- cab.Filename = filename;
- Error error = ReadHeaders(system, fileHandle, cab, 0, self.Salvage, false);
- if (error != Error.MSPACK_ERR_OK)
- {
- Close(self, cab);
- cab = null;
- }
-
- self.Error = error;
- system.Close(fileHandle);
- }
- else
- {
- self.Error = Error.MSPACK_ERR_OPEN;
- }
-
- return cab;
- }
-
- #endregion
-
- #region CABD_CLOSE
-
- ///
- /// Frees all memory associated with a given Cabinet.
- ///
- public static void Close(Decompressor d, Cabinet origcab)
- {
- DecompressorImpl self = d as DecompressorImpl;
-
- FolderData dat, ndat;
- Cabinet cab, ncab;
- Folder fol, nfol;
- InternalFile fi, nfi;
-
- if (self == null)
- return;
-
- SystemImpl sys = self.System;
-
- self.Error = Error.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 (self.State != null && (self.State.Folder == fol))
- {
- if (self.State.InputFileHandle != null)
- sys.Close(self.State.InputFileHandle);
-
- FreeDecompressionState(self);
- sys.Free(self.State);
- self.State = 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.PreviousCabinet;
- sys.Free(cab.PreviousName);
- sys.Free(cab.NextName);
- sys.Free(cab.PreviousInfo);
- sys.Free(cab.NextInfo);
- if (cab != origcab)
- sys.Free(cab);
- }
-
- // Free successor cabinets
- for (cab = origcab.NextCabinet; cab != null; cab = ncab)
- {
- ncab = cab.NextCabinet;
- sys.Free(cab.PreviousName);
- sys.Free(cab.NextName);
- sys.Free(cab.PreviousInfo);
- 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;
- }
- }
-
- #endregion
-
- #region CABD_READ_HEADERS
-
- ///
- /// Reads the cabinet file header, folder list and file list.
- /// Fills out a pre-existing Cabinet structure, allocates memory
- /// for folders and files as necessary
- ///
- public static Error ReadHeaders(SystemImpl sys, object fh, Cabinet cab, long offset, bool salvage, bool quiet)
- {
- int i, x;
- Error err = Error.MSPACK_ERR_OK;
- Folder fol, linkfol = null;
- InternalFile file, linkfile = null;
- byte[] buf = new byte[64];
-
- // Initialise pointers
- if (cab == null)
- cab = new Cabinet();
-
- cab.Next = null;
- cab.Files = null;
- cab.Folders = null;
- cab.PreviousCabinet = cab.NextCabinet = null;
- cab.PreviousName = cab.NextName = null;
- cab.PreviousInfo = cab.NextInfo = null;
-
- cab.BaseOffset = offset;
-
- // Seek to CFHEADER
- if (!sys.Seek(fh, offset, SeekMode.MSPACK_SYS_SEEK_START))
- return Error.MSPACK_ERR_SEEK;
-
- // Read in the CFHEADER
- if (sys.Read(fh, buf, 0, _CabinetHeader.Size) != _CabinetHeader.Size)
- return Error.MSPACK_ERR_READ;
-
- // Create a new header based on that
- err = _CabinetHeader.Create(buf, out _CabinetHeader cabinetHeader);
- if (err != Error.MSPACK_ERR_OK)
- return err;
-
- // Assign the header
- cab.Header = cabinetHeader;
-
- // Check for the extended header
- if (cab.Header.Flags.HasFlag(HeaderFlags.MSCAB_HDR_RESV))
- {
- if (sys.Read(fh, buf, 0, _CabinetHeader.ExtendedSize) != _CabinetHeader.ExtendedSize)
- return Error.MSPACK_ERR_READ;
-
- // Populate the extended header
- cabinetHeader.PopulateExtendedHeader(buf);
-
- // Skip the reserved header
- if (cab.Header.HeaderReserved != 0)
- {
- if (!sys.Seek(fh, cab.Header.HeaderReserved, SeekMode.MSPACK_SYS_SEEK_CUR))
- return Error.MSPACK_ERR_SEEK;
- }
- }
-
- // Read name and info of preceeding cabinet in set, if present
- if (cab.Header.Flags.HasFlag(HeaderFlags.MSCAB_HDR_PREVCAB))
- {
- cab.PreviousName = ReadString(sys, fh, false, ref err);
- if (err != Error.MSPACK_ERR_OK)
- return err;
-
- cab.PreviousInfo = ReadString(sys, fh, true, ref err);
- if (err != Error.MSPACK_ERR_OK)
- return err;
- }
-
- // Read name and info of next cabinet in set, if present
- if (cab.Header.Flags.HasFlag(HeaderFlags.MSCAB_HDR_NEXTCAB))
- {
- cab.NextName = ReadString(sys, fh, false, ref err);
- if (err != Error.MSPACK_ERR_OK)
- return err;
-
- cab.NextInfo = ReadString(sys, fh, true, ref err);
- if (err != Error.MSPACK_ERR_OK)
- return err;
- }
-
- // Read folders
- for (i = 0; i < cab.Header.NumFolders; i++)
- {
- // Read in the FOHEADER
- if (sys.Read(fh, buf, 0, _FolderHeader.Size) != _FolderHeader.Size)
- return Error.MSPACK_ERR_READ;
-
- if (cab.Header.FolderReserved != 0)
- {
- if (!sys.Seek(fh, cab.Header.FolderReserved, SeekMode.MSPACK_SYS_SEEK_CUR))
- return Error.MSPACK_ERR_SEEK;
- }
-
- // Create an empty folder
- fol = new Folder()
- {
- Next = null,
- MergePrev = null,
- MergeNext = null,
- };
-
- // Create a new header based on that
- err = _FolderHeader.Create(buf, out _FolderHeader folderHeader);
- if (err != Error.MSPACK_ERR_OK)
- return err;
-
- // Assign the header
- fol.Header = folderHeader;
-
- // Set the folder data fields
- fol.Data = new FolderData();
- fol.Data.Next = null;
- fol.Data.Cab = cab;
- fol.Data.Offset = offset + fol.Header.DataOffset;
-
- // Link folder into list of folders
- if (linkfol == null)
- cab.Folders = fol;
- else
- linkfol.Next = fol;
-
- linkfol = fol;
- }
-
- // Read files
- for (i = 0; i < cab.Header.NumFiles; i++)
- {
- // Read in the FIHEADER
- if (sys.Read(fh, buf, 0, _FileHeader.Size) != _FileHeader.Size)
- return Error.MSPACK_ERR_READ;
-
- file = new InternalFile() { Next = null };
-
- // Create a new header based on that
- err = _FileHeader.Create(buf, out _FileHeader fileHeader);
- if (err != Error.MSPACK_ERR_OK)
- return err;
-
- // Assign the header
- file.Header = fileHeader;
-
- // Set folder pointer
- if (file.Header.FolderIndex < FileFlags.CONTINUED_FROM_PREV)
- {
- // Normal folder index; count up to the correct folder
- if ((int)file.Header.FolderIndex < cab.Header.NumFolders)
- {
- Folder ifol = cab.Folders;
- while (file.Header.FolderIndex-- != 0)
- {
- if (ifol != null)
- ifol = ifol.Next;
- }
-
- file.Folder = ifol;
- }
- else
- {
- Console.WriteLine("invalid folder index");
- file.Folder = null;
- }
- }
- else
- {
- // Either CONTINUED_TO_NEXT, CONTINUED_FROM_PREV or CONTINUED_PREV_AND_NEXT
- if (file.Header.FolderIndex == FileFlags.CONTINUED_TO_NEXT || file.Header.FolderIndex == FileFlags.CONTINUED_PREV_AND_NEXT)
- {
- // Get last folder
- Folder ifol = cab.Folders;
- while (ifol.Next != null)
- {
- ifol = ifol.Next;
- }
-
- file.Folder = ifol;
-
- // Set "merge next" pointer
- fol = ifol;
- if (fol.MergeNext == null)
- fol.MergeNext = file;
- }
-
- if (file.Header.FolderIndex == FileFlags.CONTINUED_FROM_PREV || file.Header.FolderIndex == FileFlags.CONTINUED_PREV_AND_NEXT)
- {
- // Get first folder
- file.Folder = cab.Folders;
-
- // Set "merge prev" pointer
- fol = file.Folder;
- if (fol.MergePrev == null)
- fol.MergePrev = file;
- }
- }
-
- // Get filename
- file.Filename = ReadString(sys, fh, false, ref err);
-
- // If folder index or filename are bad, either skip it or fail
- if (err != Error.MSPACK_ERR_OK || file.Folder == null)
- {
- sys.Free(file.Filename);
- sys.Free(file);
- if (salvage)
- continue;
-
- return err != Error.MSPACK_ERR_OK ? err : Error.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 */
- Console.WriteLine($"No files found, even though header claimed to have {cab.Header.NumFiles} files");
- return Error.MSPACK_ERR_DATAFORMAT;
- }
-
- return Error.MSPACK_ERR_OK;
- }
-
- private static string ReadString(SystemImpl sys, object fh, bool permitEmpty, ref Error error)
- {
- long position = sys.Tell(fh);
- byte[] buf = new byte[256];
- int len, i;
-
- // Read up to 256 bytes
- if ((len = sys.Read(fh, buf, 0, 256)) <= 0)
- {
- error = Error.MSPACK_ERR_READ;
- return null;
- }
-
- // Search for a null terminator in the buffer
- bool ok = false;
- for (i = 0; i < len; i++)
- {
- if (buf[i] == 0x00)
- {
- ok = true;
- break;
- }
- }
-
- // Optionally reject empty strings
- if (i == 0 && !permitEmpty)
- ok = false;
-
- if (!ok)
- {
- error = Error.MSPACK_ERR_DATAFORMAT;
- return null;
- }
-
- len = i + 1;
-
- // Set the data stream to just after the string and return
- if (!sys.Seek(fh, position + len, SeekMode.MSPACK_SYS_SEEK_START))
- {
- error = Error.MSPACK_ERR_SEEK;
- return null;
- }
-
- error = Error.MSPACK_ERR_OK;
- return Encoding.ASCII.GetString(buf, 0, len);
- }
-
- #endregion
-
- #region CABD_SEARCH, CABD_FIND
-
- ///
- /// Opens a file, finds its extent, allocates a search buffer,
- /// then reads through the whole file looking for possible cabinet headers.
- /// If it finds any, it tries to read them as real cabinets. Returns a linked
- /// list of results
- ///
- public static Cabinet Search(Decompressor d, string filename)
- {
- DecompressorImpl self = d as DecompressorImpl;
-
- if (self == null)
- return null;
-
- SystemImpl sys = self.System;
-
- // Allocate a search buffer
- byte[] search_buf = sys.Alloc(sys, self.SearchBufferSize);
- if (search_buf == null)
- {
- self.Error = Error.MSPACK_ERR_NOMEMORY;
- return null;
- }
-
- // Open file and get its full file length
- object fh; Cabinet cab = null;
- if ((fh = sys.Open(sys, filename, OpenMode.MSPACK_SYS_OPEN_READ)) != null)
- {
- long firstlen = 0;
- if ((self.Error = SystemImpl.GetFileLength(sys, fh, out long filelen)) == Error.MSPACK_ERR_OK)
- self.Error = Find(self, search_buf, fh, filename, filelen, ref firstlen, out cab);
-
- // Truncated / extraneous data warning:
- if (firstlen != 0 && (firstlen != filelen) && (cab == null || cab.BaseOffset == 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
- {
- self.Error = Error.MSPACK_ERR_OPEN;
- }
-
- // Free the search buffer
- sys.Free(search_buf);
-
- return cab;
- }
-
- ///
- /// The inner loop of , to make it easier to
- /// break out of the loop and be sure that all resources are freed
- ///
- public static Error Find(DecompressorImpl self, byte[] buf, object fh, string filename, long flen, ref long firstlen, out Cabinet firstcab)
- {
- firstcab = null;
- Cabinet cab, link = null;
- long caboff, offset, length;
- SystemImpl sys = self.System;
- long 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 > self.SearchBufferSize)
- length = self.SearchBufferSize;
-
- // Fill the search buffer with data from disk
- if (sys.Read(fh, buf, 0, (int)length) != (int)length)
- return Error.MSPACK_ERR_READ;
-
- // FAQ avoidance strategy
- if (offset == 0 && BitConverter.ToUInt32(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 = 0, pend = 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 && buf[p] != 0x4D)
- {
- p++;
- }
-
- // If we found that 'M', advance state
- if (p++ < pend)
- state = 1;
-
- break;
-
- // Verify that the next 3 bytes are 'S', 'C' and 'F'
- case 1:
- state = (byte)(buf[p++] == 0x53 ? 2 : 0);
- break;
- case 2:
- state = (byte)(buf[p++] == 0x43 ? 3 : 0);
- break;
- case 3:
- state = (byte)(buf[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 = buf[p++];
- state++;
- break;
- case 9:
- cablen_u32 |= (uint)buf[p++] << 8;
- state++;
- break;
- case 10:
- cablen_u32 |= (uint)buf[p++] << 16;
- state++;
- break;
- case 11:
- cablen_u32 |= (uint)buf[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 = buf[p++];
- state++;
- break;
- case 17:
- foffset_u32 |= (uint)buf[p++] << 8;
- state++;
- break;
- case 18:
- foffset_u32 |= (uint)buf[p++] << 16;
- state++;
- break;
- case 19:
- foffset_u32 |= (uint)buf[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 - 20;
-
- // Should reading cabinet fail, restart search just after 'MSCF'
- offset = caboff + 4;
-
- // Vapture 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 + foffset_u32) < (flen + 32)) &&
- (((caboff + cablen_u32) < (flen + 32)) || self.Salvage))
- {
- // Likely cabinet found -- try reading it
- cab = new Cabinet() { Filename = filename };
-
- if (ReadHeaders(sys, fh, cab, caboff, self.Salvage, quiet: true) != Error.MSPACK_ERR_OK)
- {
- // Destroy the failed cabinet
- Close(self, 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 + cablen_u32;
- }
- }
-
- // Restart search
- if (offset >= flen)
- return Error.MSPACK_ERR_OK;
-
- if (!sys.Seek(fh, offset, SeekMode.MSPACK_SYS_SEEK_START))
- return Error.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;
- }
- }
- }
-
- if (false_cabs != 0)
- Console.WriteLine($"{false_cabs} false cabinets found");
-
- return Error.MSPACK_ERR_OK;
- }
-
- #endregion
-
- #region CABD_MERGE, CABD_PREPEND, CABD_APPEND
-
- ///
- public static Error Prepend(Decompressor d, Cabinet cab, Cabinet prevcab)
- {
- return Merge(d, prevcab, cab);
- }
-
- ///
- public static Error Append(Decompressor d, Cabinet cab, Cabinet nextcab)
- {
- return Merge(d, cab, nextcab);
- }
-
- ///
- /// 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.
- ///
- public static Error Merge(Decompressor d, Cabinet lcab, Cabinet rcab)
- {
- DecompressorImpl self = d as DecompressorImpl;
-
- FolderData data, ndata;
- Folder lfol, rfol;
- InternalFile fi, rfi, lfi;
-
- if (self == null)
- return Error.MSPACK_ERR_ARGS;
-
- SystemImpl sys = self.System;
-
- // Basic args check
- if (lcab == null || rcab == null || (lcab == rcab))
- {
- Console.WriteLine("lcab null, rcab null or lcab = rcab");
- return self.Error = Error.MSPACK_ERR_ARGS;
- }
-
- // Check there's not already a cabinet attached
- if (lcab.NextCabinet != null || rcab.PreviousCabinet != null)
- {
- Console.WriteLine("cabs already joined");
- return self.Error = Error.MSPACK_ERR_ARGS;
- }
-
- // Do not create circular cabinet chains
- Cabinet cab;
- for (cab = lcab.PreviousCabinet; cab != null; cab = cab.PreviousCabinet)
- {
- if (cab == rcab)
- {
- Console.WriteLine("circular!");
- return self.Error = Error.MSPACK_ERR_ARGS;
- }
- }
- for (cab = rcab.NextCabinet; cab != null; cab = cab.NextCabinet)
- {
- if (cab == lcab)
- {
- Console.WriteLine("circular!");
- return self.Error = Error.MSPACK_ERR_ARGS;
- }
- }
-
- // Warn about odd set IDs or indices
- if (lcab.Header.SetID != rcab.Header.SetID)
- sys.Message(null, "WARNING; merged cabinets with differing Set IDs.");
-
- if (lcab.Header.CabinetIndex > rcab.Header.CabinetIndex)
- 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.MergeNext == null && rfol.MergePrev == null)
- {
- // No, at least one of the folders is not for merging
-
- // Attach cabs
- lcab.NextCabinet = rcab;
- rcab.PreviousCabinet = 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))
- return self.Error = Error.MSPACK_ERR_DATAFORMAT;
-
- // Allocate a new folder data structure
- data = new FolderData();
-
- // Attach cabs
- lcab.NextCabinet = rcab;
- rcab.PreviousCabinet = 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.MergeNext is going to be deleted, so keep lfol's version
- // instead
- lfol.Header.NumBlocks += (ushort)(rfol.Header.NumBlocks - 1);
- if ((rfol.MergeNext == null) || (rfol.MergeNext.Folder != rfol))
- lfol.MergeNext = rfol.MergeNext;
-
- // 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 alsl cabs so they all
- // point to the same list
- for (cab = lcab.PreviousCabinet; cab != null; cab = cab.PreviousCabinet)
- {
- cab.Files = lcab.Files;
- cab.Folders = lcab.Folders;
- }
-
- for (cab = lcab.NextCabinet; cab != null; cab = cab.NextCabinet)
- {
- cab.Files = lcab.Files;
- cab.Folders = lcab.Folders;
- }
-
- return self.Error = Error.MSPACK_ERR_OK;
- }
-
- ///
- /// Decides if two folders are OK to merge
- ///
- private static bool CanMergeFolders(SystemImpl sys, Folder lfol, Folder rfol)
- {
- InternalFile lfi, rfi, l, r;
- bool matching = true;
-
- // Check that both folders use the same compression method/settings
- if (lfol.Header.CompType != rfol.Header.CompType)
- {
- Console.WriteLine("folder merge: compression type mismatch");
- return false;
- }
-
- // Check there are not too many data blocks after merging
- if ((lfol.Header.NumBlocks + rfol.Header.NumBlocks) > CAB_FOLDERMAX)
- {
- Console.WriteLine("folder merge: too many data blocks in merged folders");
- return false;
- }
-
- if ((lfi = lfol.MergeNext) == null || (rfi = rfol.MergePrev) == null)
- {
- Console.WriteLine("folder merge: one cabinet has no files to merge");
- return false;
- }
-
- // 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.Header.FolderOffset != r.Header.FolderOffset) || (l.Header.UncompressedSize != r.Header.UncompressedSize))
- {
- matching = false;
- break;
- }
- }
-
- if (matching)
- return true;
-
- // 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 = false;
- for (l = lfi; l != null; l = l.Next)
- {
- for (r = rfi; r != null; r = r.Next)
- {
- if (l.Header.FolderOffset == r.Header.FolderOffset && l.Header.UncompressedSize == r.Header.UncompressedSize)
- break;
- }
-
- if (r != null)
- matching = true;
- else
- sys.Message(null, $"WARNING; merged file {l.Filename} not listed in both cabinets");
- }
-
- return matching;
- }
-
- #endregion
-
- #region CABD_EXTRACT
-
- ///
- /// Extracts a file from a cabinet
- ///
- public static Error Extract(Decompressor d, InternalFile file, string filename)
- {
- DecompressorImpl self = d as DecompressorImpl;
- object fh;
-
- if (self == null)
- return Error.MSPACK_ERR_ARGS;
- if (file == null)
- return self.Error = Error.MSPACK_ERR_ARGS;
-
- SystemImpl sys = self.System;
- Folder fol = file.Folder;
-
- // If offset is beyond 2GB, nothing can be extracted
- if (file.Header.FolderOffset > CAB_LENGTHMAX)
- return self.Error = Error.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
- long filelen = file.Header.UncompressedSize;
- if (filelen > CAB_LENGTHMAX || (file.Header.FolderOffset + filelen) > CAB_LENGTHMAX)
- {
- if (self.Salvage)
- filelen = CAB_LENGTHMAX - file.Header.FolderOffset;
- else
- return self.Error = Error.MSPACK_ERR_DATAFORMAT;
- }
-
- // Extraction impossible if no folder, or folder needs predecessor
- if (fol == null || fol.MergePrev != null)
- {
- sys.Message(null, $"ERROR; file \"{file.Filename}\" cannot be extracted, cabinet set is incomplete");
- return self.Error = Error.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 (!self.Salvage)
- {
- long maxlen = fol.Header.NumBlocks * CAB_BLOCKMAX;
- if ((file.Header.FolderOffset + filelen) > maxlen)
- {
- sys.Message(null, $"ERROR; file \"{file.Filename}\" cannot be extracted, cabinet set is incomplete");
- return self.Error = Error.MSPACK_ERR_DECRUNCH;
- }
- }
-
- // Allocate generic decompression state
- if (self.State == null)
- {
- self.State = new DecompressState();
- self.State.Folder = null;
- self.State.Data = null;
- self.State.Sys = sys;
- self.State.Sys.Read = SysRead;
- self.State.Sys.Write = SysWrite;
- self.State.DecompressorState = null;
- self.State.InputFileHandle = null;
- self.State.InputCabinet = null;
- }
-
- // Do we need to change folder or reset the current folder?
- if ((self.State.Folder != fol) || (self.State.Offset > file.Header.FolderOffset) || self.State.DecompressorState == null)
- {
- // Free any existing decompressor
- FreeDecompressionState(self);
-
- // Do we need to open a new cab file?
- if (self.State.InputFileHandle == null || (fol.Data.Cab != self.State.InputCabinet))
- {
- // Close previous file handle if from a different cab
- if (self.State.InputFileHandle != null)
- sys.Close(self.State.InputFileHandle);
-
- self.State.InputCabinet = fol.Data.Cab;
- self.State.InputFileHandle = sys.Open(sys, fol.Data.Cab.Filename, OpenMode.MSPACK_SYS_OPEN_READ);
- if (self.State.InputFileHandle == null)
- return self.Error = Error.MSPACK_ERR_OPEN;
- }
-
- // Seek to start of data blocks
- if (!sys.Seek(self.State.InputFileHandle, fol.Data.Offset, SeekMode.MSPACK_SYS_SEEK_START))
- return self.Error = Error.MSPACK_ERR_SEEK;
-
- // Set up decompressor
- if (InitDecompressionState(self, fol.Header.CompType) != Error.MSPACK_ERR_OK)
- return self.Error;
-
- // Initialise new folder state
- self.State.Folder = fol;
- self.State.Data = fol.Data;
- self.State.Offset = 0;
- self.State.Block = 0;
- self.State.Outlen = 0;
- self.State.InputPointer = self.State.InputEnd = 0;
-
- // read_error lasts for the lifetime of a decompressor
- self.ReadError = Error.MSPACK_ERR_OK;
- }
-
- // Open file for output
- if ((fh = sys.Open(sys, filename, OpenMode.MSPACK_SYS_OPEN_WRITE)) == null)
- return self.Error = Error.MSPACK_ERR_OPEN;
-
- self.Error = Error.MSPACK_ERR_OK;
-
- // If file has more than 0 bytes
- if (filelen != 0)
- {
- long bytes;
- Error 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 self.ReadError
- // and pass back MSPACK_ERR_READ
- self.State.OutputFileHandle = null;
- if ((bytes = file.Header.FolderOffset - self.State.Offset) != 0)
- {
- error = self.State.Decompress(self.State.DecompressorState, bytes);
- self.Error = (error == Error.MSPACK_ERR_READ) ? self.ReadError : error;
- }
-
- // If getting to the correct offset was error free, unpack file
- if (self.Error == Error.MSPACK_ERR_OK)
- {
- self.State.OutputFileHandle = fh;
- error = self.State.Decompress(self.State.DecompressorState, filelen);
- self.Error = (error == Error.MSPACK_ERR_READ) ? self.ReadError : error;
- }
- }
-
- // Close output file
- sys.Close(fh);
- self.State.OutputFileHandle = null;
-
- return self.Error;
- }
-
- #endregion
-
- #region CABD_INIT_DECOMP, CABD_FREE_DECOMP
-
- ///
- /// Initialises decompression state, according to which
- /// decompression method was used. relies on self.State.Folder being the same
- /// as when initialised.
- ///
- public static Error InitDecompressionState(DecompressorImpl self, CompressionType ct)
- {
- object fh = self;
-
- self.State.CompressionType = ct;
-
- switch (ct & CompressionType.COMPTYPE_MASK)
- {
- case CompressionType.COMPTYPE_NONE:
- self.State.Decompress = NoneDecompress;
- self.State.DecompressorState = NoneInit(self.State.Sys, fh, fh, self.BufferSize);
- break;
-
- case CompressionType.COMPTYPE_MSZIP:
- self.State.Decompress = MSZIP.Decompress;
- self.State.DecompressorState = MSZIP.Init(self.State.Sys, fh, fh, self.BufferSize, self.FixMSZip);
- break;
-
- case CompressionType.COMPTYPE_QUANTUM:
- self.State.Decompress = QTM.Decompress;
- self.State.DecompressorState = QTM.Init(self.State.Sys, fh, fh, ((ushort)ct >> 8) & 0x1f, self.BufferSize);
- break;
-
- case CompressionType.COMPTYPE_LZX:
- self.State.Decompress = LZX.Decompress;
- self.State.DecompressorState = LZX.Init(self.State.Sys, fh, fh, ((ushort)ct >> 8) & 0x1f, 0, self.BufferSize, 0, false);
- break;
-
- default:
- return self.Error = Error.MSPACK_ERR_DATAFORMAT;
- }
-
- return self.Error = (self.State.DecompressorState != null) ? Error.MSPACK_ERR_OK : Error.MSPACK_ERR_NOMEMORY;
- }
-
- ///
- /// Frees decompression state, according to which method was used.
- ///
- ///
- public static void FreeDecompressionState(DecompressorImpl self)
- {
- if (self == null || self.State == null || self.State.DecompressorState == null)
- return;
-
- switch (self.State.CompressionType & CompressionType.COMPTYPE_MASK)
- {
- case CompressionType.COMPTYPE_NONE:
- NoneFree(self.State.DecompressorState);
- break;
-
- case CompressionType.COMPTYPE_MSZIP:
- MSZIP.Free(self.State.DecompressorState);
- break;
-
- case CompressionType.COMPTYPE_QUANTUM:
- QTM.Free(self.State.DecompressorState);
- break;
-
- case CompressionType.COMPTYPE_LZX:
- LZX.Free(self.State.DecompressorState);
- break;
- }
-
- self.State.Decompress = null;
- self.State.DecompressorState = null;
- }
-
- #endregion
-
- #region CABD_SYS_READ, CABD_SYS_WRITE
-
- ///
- /// 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
- ///
- private static int SysRead(object file, byte[] buffer, int pointer, int bytes)
- {
- DecompressorImpl self = file as DecompressorImpl;
- if (self == null)
- return 0;
-
- SystemImpl sys = self.System;
-
- int avail, todo, outlen = 0;
-
- bool ignore_cksum = self.Salvage ||
- (self.FixMSZip &&
- ((self.State.CompressionType & CompressionType.COMPTYPE_MASK) == CompressionType.COMPTYPE_MSZIP));
- bool ignore_blocksize = self.Salvage;
-
- todo = bytes;
- while (todo > 0)
- {
- avail = self.State.InputEnd - self.State.InputPointer;
-
- // 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.State.Input, self.State.InputPointer, buffer, pointer, avail);
- self.State.InputPointer += avail;
- pointer += avail;
- todo -= avail;
- }
- else
- {
- // Out of data, read a new block
-
- // Check if we're out of input blocks, advance block counter
- if (self.State.Block++ >= self.State.Folder.Header.NumBlocks)
- {
- if (!self.Salvage)
- self.ReadError = Error.MSPACK_ERR_DATAFORMAT;
- else
- Console.WriteLine("Ran out of CAB input blocks prematurely");
-
- break;
- }
-
- // Read a block
- self.ReadError = SysReadBlock(sys, self.State, ref outlen, ignore_cksum, ignore_blocksize);
- if (self.ReadError != Error.MSPACK_ERR_OK)
- return -1;
-
- self.State.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 ((self.State.CompressionType & CompressionType.COMPTYPE_MASK) == CompressionType.COMPTYPE_QUANTUM)
- self.State.Input[self.State.InputEnd++] = 0xFF;
-
- // Is this the last block?
- if (self.State.Block >= self.State.Folder.Header.NumBlocks)
- {
- if ((self.State.CompressionType & CompressionType.COMPTYPE_MASK) == CompressionType.COMPTYPE_LZX)
- {
- // Special LZX hack -- on the last block, inform LZX of the
- // size of the output data stream.
- LZX.SetOutputLength(self.State.DecompressorState as LZXDStream, self.State.Outlen);
- }
- }
- }
- }
-
- return bytes - todo;
- }
-
- ///
- /// The internal writer function which the decompressors
- /// use. it either writes data to disk (self.State.OutputFileHandle) with the real
- /// sys.write() function, or does nothing with the data when
- /// self.State.OutputFileHandle == null. advances self.State.Offset
- ///
- private static int SysWrite(object file, byte[] buffer, int pointer, int bytes)
- {
- if (file is DecompressorImpl self)
- {
- self.State.Offset += (uint)bytes;
- if (self.State.OutputFileHandle != null)
- return self.System.Write(self.State.OutputFileHandle, buffer, pointer, bytes);
-
- return bytes;
- }
- else if (file is DefaultFileImpl impl)
- {
- return SystemImpl.DefaultSystem.Write(file, buffer, pointer, bytes);
- }
-
- // Unknown file to write to
- return 0;
- }
-
- #endregion
-
- #region CABD_SYS_READ_BLOCK
-
- ///
- /// 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 Error SysReadBlock(SystemImpl sys, DecompressState d, ref int output, bool ignore_cksum, bool ignore_blocksize)
- {
- byte[] hdr = new byte[_DataBlockHeader.Size];
- int full_len;
-
- // Reset the input block pointer and end of block pointer
- d.InputPointer = d.InputEnd = 0;
-
- do
- {
- // Read the block header
- if (SystemImpl.DefaultSystem.Read(d.InputFileHandle, hdr, 0, _DataBlockHeader.Size) != _DataBlockHeader.Size)
- return Error.MSPACK_ERR_READ;
-
- // Skip any reserved block headers
- if (d.Data.Cab.Header.HeaderReserved != 0 && !sys.Seek(d.InputFileHandle, d.Data.Cab.Header.HeaderReserved, SeekMode.MSPACK_SYS_SEEK_CUR))
- return Error.MSPACK_ERR_SEEK;
-
- // Create a block header from the data
- Error err = _DataBlockHeader.Create(hdr, out _DataBlockHeader dataBlockHeader);
- if (err != Error.MSPACK_ERR_OK)
- return err;
-
- // Blocks must not be over CAB_INPUTMAX in size
- full_len = (d.InputEnd - d.InputPointer) + dataBlockHeader.CompressedSize; // Include cab-spanning blocks
- if (full_len > CAB_INPUTMAX)
- {
- Console.WriteLine($"Block size {full_len} > CAB_INPUTMAX");
-
- // In salvage mode, blocks can be 65535 bytes but no more than that
- if (!ignore_blocksize || full_len > CAB_INPUTMAX_SALVAGE)
- return Error.MSPACK_ERR_DATAFORMAT;
- }
-
- // Blocks must not expand to more than CAB_BLOCKMAX
- if (dataBlockHeader.UncompressedSize > CAB_BLOCKMAX)
- {
- Console.WriteLine("block size > CAB_BLOCKMAX");
- if (!ignore_blocksize)
- return Error.MSPACK_ERR_DATAFORMAT;
- }
-
- // Read the block data
- if (SystemImpl.DefaultSystem.Read(d.InputFileHandle, d.Input, d.InputEnd, dataBlockHeader.CompressedSize) != dataBlockHeader.CompressedSize)
- return Error.MSPACK_ERR_READ;
-
- // Perform checksum test on the block (if one is stored)
- if (dataBlockHeader.CheckSum != 0)
- {
- uint sum2 = Checksum(d.Input, d.InputEnd, dataBlockHeader.CompressedSize, 0);
- if (Checksum(hdr, 4, 4, sum2) != dataBlockHeader.CheckSum)
- {
- if (!ignore_cksum)
- return Error.MSPACK_ERR_CHECKSUM;
-
- sys.Message(d.InputFileHandle, "WARNING; bad block checksum found");
- }
- }
-
- // Advance end of block pointer to include newly read data
- d.InputEnd += dataBlockHeader.CompressedSize;
-
- // 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 ((output = dataBlockHeader.UncompressedSize) != 0)
- return Error.MSPACK_ERR_OK;
-
- // Otherwise, advance to next cabinet
-
- // Close current file handle
- sys.Close(d.InputFileHandle);
- d.InputFileHandle = null;
-
- // Advance to next member in the cabinet set
- if ((d.Data = d.Data.Next) == null)
- {
- sys.Message(d.InputFileHandle, "WARNING; ran out of cabinets in set. Are any missing?");
- return Error.MSPACK_ERR_DATAFORMAT;
- }
-
- // Open next cab file
- d.InputCabinet = d.Data.Cab;
- if ((d.InputFileHandle = sys.Open(sys, d.InputCabinet.Filename, OpenMode.MSPACK_SYS_OPEN_READ)) == null)
- return Error.MSPACK_ERR_OPEN;
-
- // Seek to start of data blocks
- if (!sys.Seek(d.InputFileHandle, d.Data.Offset, SeekMode.MSPACK_SYS_SEEK_START))
- return Error.MSPACK_ERR_SEEK;
- } while (true);
- }
-
- private static uint Checksum(byte[] data, int pointer, uint bytes, uint cksum)
- {
- uint len, ul = 0;
-
- for (len = bytes >> 2; len-- != 0; pointer += 4)
- {
- cksum ^= (uint)((data[pointer + 0]) | (data[pointer + 1] << 8) | (data[pointer + 2] << 16) | (data[pointer + 3] << 24));
- }
-
- switch (bytes & 3)
- {
- case 3:
- ul |= (uint)(data[pointer++] << 16);
- ul |= (uint)(data[pointer++] << 8);
- ul |= data[pointer];
- break;
-
- case 2:
- ul |= (uint)(data[pointer++] << 8);
- ul |= data[pointer];
- break;
-
- case 1:
- ul |= data[pointer];
- break;
- }
-
- cksum ^= ul;
- return cksum;
- }
-
- #endregion
-
- #region NONED_INIT, NONED_DECOMPRESS, NONED_FREE
-
- internal static NoneState NoneInit(SystemImpl sys, object input, object output, int bufsize)
- {
- NoneState state = new NoneState();
- byte[] buf = sys.Alloc(sys, bufsize);
- if (state != null && buf != null)
- {
- state.Sys = sys;
- state.Input = input;
- state.Output = output;
- state.Buffer = buf;
- state.BufferSize = bufsize;
- }
- else
- {
- sys.Free(buf);
- sys.Free(state);
- state = null;
- }
-
- return state;
- }
-
- internal static Error NoneDecompress(object s, long bytes)
- {
- NoneState state = (NoneState)s;
- if (state == null)
- return Error.MSPACK_ERR_ARGS;
-
- int run;
- while (bytes > 0)
- {
- run = (bytes > state.BufferSize) ? state.BufferSize : (int)bytes;
-
- if (state.Sys.Read(state.Input, state.Buffer, 0, run) != run)
- return Error.MSPACK_ERR_READ;
-
- if (state.Sys.Write(state.Output, state.Buffer, 0, run) != run)
- return Error.MSPACK_ERR_WRITE;
-
- bytes -= run;
- }
- return Error.MSPACK_ERR_OK;
- }
-
- internal static void NoneFree(object s)
- {
- NoneState state = s as NoneState;
- if (state != null)
- {
- SystemImpl sys = state.Sys;
- sys.Free(state.Buffer);
- sys.Free(state);
- }
- }
-
- #endregion
-
- #region CABD_PARAM
-
- ///
- /// Allows a parameter to be set
- ///
- public static Error Param(Decompressor d, Parameters param, int value)
- {
- DecompressorImpl self = d as DecompressorImpl;
- if (self == null)
- return Error.MSPACK_ERR_ARGS;
-
- switch (param)
- {
- case Parameters.MSCABD_PARAM_SEARCHBUF:
- if (value < 4)
- return Error.MSPACK_ERR_ARGS;
-
- self.SearchBufferSize = value;
- break;
-
- case Parameters.MSCABD_PARAM_FIXMSZIP:
- self.FixMSZip = value != 0;
- break;
-
- case Parameters.MSCABD_PARAM_DECOMPBUF:
- if (value < 4)
- return Error.MSPACK_ERR_ARGS;
-
- self.BufferSize = value;
- break;
-
- case Parameters.MSCABD_PARAM_SALVAGE:
- self.Salvage = value != 0;
- break;
-
- default:
- return Error.MSPACK_ERR_ARGS;
- }
-
- return Error.MSPACK_ERR_OK;
- }
-
- #endregion
-
- #region CABD_ERROR
-
- ///
- /// Returns the last error that occurred
- ///
- public static Error LastError(Decompressor d)
- {
- DecompressorImpl self = d as DecompressorImpl;
- return (self != null) ? self.Error : Error.MSPACK_ERR_ARGS;
- }
-
- #endregion
- }
-}
diff --git a/BurnOutSharp/External/libmspack/CHM/DecompressState.cs b/BurnOutSharp/External/libmspack/CHM/DecompressState.cs
index 24786506..6cab3a6c 100644
--- a/BurnOutSharp/External/libmspack/CHM/DecompressState.cs
+++ b/BurnOutSharp/External/libmspack/CHM/DecompressState.cs
@@ -41,11 +41,11 @@ namespace LibMSPackSharp.CHM
///
/// Input file handle
///
- public object InputFileHandle { get; set; }
+ public DefaultFileImpl InputFileHandle { get; set; }
///
/// Output file handle
///
- public object OutputFileHandle { get; set; }
+ public DefaultFileImpl OutputFileHandle { get; set; }
}
}
diff --git a/BurnOutSharp/External/libmspack/CHM/Implementation.cs b/BurnOutSharp/External/libmspack/CHM/Implementation.cs
index 096d468d..c5cbe079 100644
--- a/BurnOutSharp/External/libmspack/CHM/Implementation.cs
+++ b/BurnOutSharp/External/libmspack/CHM/Implementation.cs
@@ -152,8 +152,8 @@ namespace LibMSPackSharp.CHM
SystemImpl sys = self.System;
- object fh;
- if ((fh = sys.Open(sys, filename, OpenMode.MSPACK_SYS_OPEN_READ)) != null)
+ DefaultFileImpl fh;
+ if ((fh = sys.Open(filename, OpenMode.MSPACK_SYS_OPEN_READ)) != null)
{
chm = new Header();
chm.Filename = filename;
@@ -209,12 +209,11 @@ namespace LibMSPackSharp.CHM
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
@@ -223,25 +222,8 @@ namespace LibMSPackSharp.CHM
if (self.State.InputFileHandle != null)
sys.Close(self.State.InputFileHandle);
- if (self.State.State != null)
- LZX.Free(self.State.State);
-
- sys.Free(self.State);
self.State = null;
}
-
- // If this CHM had a chunk cache, free it and contents
- if (chm.ChunkCache != null)
- {
- for (i = 0; i < chm.NumChunks; i++)
- {
- sys.Free(chm.ChunkCache[i]);
- }
-
- sys.Free(chm.ChunkCache);
- }
-
- sys.Free(chm);
}
#endregion
@@ -267,10 +249,10 @@ namespace LibMSPackSharp.CHM
/// non-zero, all file entries will also be read. fills out a pre-existing
/// mschmd_header structure, allocates memory for files as necessary
///
- public static Error ReadHeaders(SystemImpl sys, object fh, Header chm, bool entire)
+ public static Error ReadHeaders(SystemImpl sys, DefaultFileImpl fh, Header chm, bool entire)
{
uint section, nameLen, x, errors, numChunks;
- byte[] buf = new byte[0x54], chunk = null;
+ byte[] buf = new byte[0x54];
int name, p, end;
DecompressFile fi, link = null;
long offset, length;
@@ -431,8 +413,7 @@ namespace LibMSPackSharp.CHM
numChunks = chm.LastPMGL - x + 1;
- if ((chunk = sys.Alloc(sys, (int)chm.ChunkSize)) == null)
- return Error.MSPACK_ERR_NOMEMORY;
+ byte[] chunk = new byte[chm.ChunkSize];
// Read and process all chunks from FirstPMGL to LastPMGL
errors = 0;
@@ -440,10 +421,7 @@ namespace LibMSPackSharp.CHM
{
// Read next chunk
if (sys.Read(fh, chunk, 0, (int)chm.ChunkSize) != (int)chm.ChunkSize)
- {
- sys.Free(chunk);
return Error.MSPACK_ERR_READ;
- }
// Process only directory (PMGL) chunks
if (BitConverter.ToUInt32(chunk, pmgl_Signature) != 0x4C474D50)
@@ -573,7 +551,6 @@ namespace LibMSPackSharp.CHM
}
}
- sys.Free(chunk);
return (errors > 0) ? Error.MSPACK_ERR_DATAFORMAT : Error.MSPACK_ERR_OK;
}
@@ -592,7 +569,7 @@ namespace LibMSPackSharp.CHM
{
DecompressorImpl self = d as DecompressorImpl;
SystemImpl sys;
- object fh;
+ DefaultFileImpl fh;
// p and end are initialised to prevent MSVC warning about "potentially"
// uninitialised usage. This is provably untrue, but MS won't fix:
@@ -610,7 +587,7 @@ namespace LibMSPackSharp.CHM
// Clear the results structure
f_ptr = new DecompressFile();
- if ((fh = sys.Open(sys, chm.Filename, OpenMode.MSPACK_SYS_OPEN_READ)) == null)
+ if ((fh = sys.Open(chm.Filename, OpenMode.MSPACK_SYS_OPEN_READ)) == null)
return Error.MSPACK_ERR_OPEN;
// Go through PMGI chunk hierarchy to reach PMGL chunk
@@ -722,10 +699,9 @@ namespace LibMSPackSharp.CHM
/// 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
///
- public static byte[] ReadChunk(DecompressorImpl self, Header chm, object fh, uint chunkNum)
+ public static byte[] ReadChunk(DecompressorImpl self, Header chm, DefaultFileImpl fh, uint chunkNum)
{
SystemImpl sys = self.System;
- byte[] buf;
// Check arguments - most are already checked by chmd_fast_find
if (chunkNum >= chm.NumChunks)
@@ -740,24 +716,18 @@ namespace LibMSPackSharp.CHM
return chm.ChunkCache[chunkNum];
// Need to read chunk - allocate memory for it
- if ((buf = sys.Alloc(sys, (int)chm.ChunkSize)) == null)
- {
- self.Error = Error.MSPACK_ERR_NOMEMORY;
- return null;
- }
+ byte[] buf = new byte[chm.ChunkSize];
// Seek to block and read it
if (!sys.Seek(fh, (chm.DirOffset + (chunkNum * chm.ChunkSize)), SeekMode.MSPACK_SYS_SEEK_START))
{
self.Error = Error.MSPACK_ERR_SEEK;
- sys.Free(buf);
return null;
}
if (sys.Read(fh, buf, 0, (int)chm.ChunkSize) != (int)chm.ChunkSize)
{
self.Error = Error.MSPACK_ERR_READ;
- sys.Free(buf);
return null;
}
@@ -765,7 +735,6 @@ namespace LibMSPackSharp.CHM
if (!((buf[0] == 0x50) && (buf[1] == 0x4D) && (buf[2] == 0x47) && ((buf[3] == 0x4C) || (buf[3] == 0x49))))
{
self.Error = Error.MSPACK_ERR_SEEK;
- sys.Free(buf);
return null;
}
@@ -1025,20 +994,17 @@ namespace LibMSPackSharp.CHM
if (self.State.InputFileHandle != null)
sys.Close(self.State.InputFileHandle);
- if (self.State.State != null)
- LZX.Free(self.State.State);
-
self.State.Header = chm;
self.State.Offset = 0;
self.State.State = null;
- self.State.InputFileHandle = sys.Open(sys, chm.Filename, OpenMode.MSPACK_SYS_OPEN_READ);
+ self.State.InputFileHandle = sys.Open(chm.Filename, OpenMode.MSPACK_SYS_OPEN_READ);
if (self.State.InputFileHandle == null)
return self.Error = Error.MSPACK_ERR_OPEN;
}
// Open file for output
- object fh;
- if ((fh = sys.Open(sys, filename, OpenMode.MSPACK_SYS_OPEN_WRITE)) == null)
+ DefaultFileImpl fh;
+ if ((fh = sys.Open(filename, OpenMode.MSPACK_SYS_OPEN_WRITE)) == null)
return self.Error = Error.MSPACK_ERR_OPEN;
// If file is empty, simply creating it is enough
@@ -1093,10 +1059,7 @@ namespace LibMSPackSharp.CHM
if (self.State.State == null || (file.Offset < self.State.Offset))
{
if (self.State.State != null)
- {
- LZX.Free(self.State.State);
self.State.State = null;
- }
if (InitDecompressor(self, file) != Error.MSPACK_ERR_OK)
break;
@@ -1128,12 +1091,7 @@ namespace LibMSPackSharp.CHM
// If an LZX error occured, the LZX decompressor is now useless
if (self.Error != Error.MSPACK_ERR_OK)
- {
- if (self.State.State != null)
- LZX.Free(self.State.State);
-
self.State.State = null;
- }
break;
}
@@ -1220,7 +1178,6 @@ namespace LibMSPackSharp.CHM
// Check LZXC signature
if (BitConverter.ToUInt32(data, lzxcd_Signature) != 0x43585A4C)
{
- sys.Free(data);
return self.Error = Error.MSPACK_ERR_SIGNATURE;
}
@@ -1237,13 +1194,9 @@ namespace LibMSPackSharp.CHM
break;
default:
Console.WriteLine("bad controldata version");
- sys.Free(data);
return self.Error = Error.MSPACK_ERR_DATAFORMAT;
}
- // Free ControlData
- sys.Free(data);
-
// Find window_bits from window_size
switch (window_size)
{
@@ -1304,7 +1257,7 @@ namespace LibMSPackSharp.CHM
length -= self.State.Offset;
// Initialise LZX stream
- self.State.State = LZX.Init(self.State.Sys, self.State.InputFileHandle, self, window_bits, reset_interval / LZX.LZX_FRAME_SIZE, 4096, length, false);
+ self.State.State = LZX.Init(self.State.Sys, self.State.InputFileHandle, self.State.OutputFileHandle, window_bits, reset_interval / LZX.LZX_FRAME_SIZE, 4096, length, false);
if (self.State.State == null)
self.Error = Error.MSPACK_ERR_NOMEMORY;
@@ -1359,16 +1312,12 @@ namespace LibMSPackSharp.CHM
if (BitConverter.ToUInt32(data, lzxrt_FrameLen) != LZX.LZX_FRAME_SIZE)
{
Console.WriteLine(("bad reset table frame length"));
- sys.Free(data);
return false;
}
// Get the uncompressed length of the LZX stream
if ((length_ptr = BitConverter.ToInt64(data, lzxrt_UncompLen)) == 0)
- {
- sys.Free(data);
return false;
- }
uint entrysize = BitConverter.ToUInt32(data, lzxrt_EntrySize);
uint pos = BitConverter.ToUInt32(data, lzxrt_TableOffset) + (entry * entrysize);
@@ -1397,9 +1346,6 @@ namespace LibMSPackSharp.CHM
err = Error.MSPACK_ERR_ARGS;
}
- // Free the reset table
- sys.Free(data);
-
// Return success
return (err == Error.MSPACK_ERR_OK);
}
@@ -1442,10 +1388,6 @@ namespace LibMSPackSharp.CHM
// Get the uncompressed length of the LZX stream
length_ptr = BitConverter.ToInt64(data, 0);
- sys.Free(data);
- if (err != Error.MSPACK_ERR_OK)
- return Error.MSPACK_ERR_DATAFORMAT;
-
if (length_ptr <= 0)
{
Console.WriteLine("output length is invalid");
@@ -1514,14 +1456,12 @@ namespace LibMSPackSharp.CHM
if (sys.Seek(self.State.InputFileHandle, file.Section.Header.Sec0.Offset + file.Offset, SeekMode.MSPACK_SYS_SEEK_START))
{
self.Error = Error.MSPACK_ERR_SEEK;
- sys.Free(data);
return null;
}
if (sys.Read(self.State.InputFileHandle, data, 0, len) != len)
{
self.Error = Error.MSPACK_ERR_READ;
- sys.Free(data);
return null;
}
diff --git a/BurnOutSharp/External/libmspack/Compression/LZSS.cs b/BurnOutSharp/External/libmspack/Compression/LZSS.cs
index a40a4071..d667a206 100644
--- a/BurnOutSharp/External/libmspack/Compression/LZSS.cs
+++ b/BurnOutSharp/External/libmspack/Compression/LZSS.cs
@@ -79,59 +79,50 @@ namespace LibMSPackSharp.Compression
uint pos = LZSS_WINDOW_SIZE - (uint)((mode == LZSSMode.LZSS_MODE_QBASIC) ? 18 : 16);
uint invert = (uint)((mode == LZSSMode.LZSS_MODE_MSHELP) ? ~0 : 0);
- int iPtr = 0, iEnd = 0;
+ int i_ptr = 0, i_end = 0;
// Loop forever; exit condition is in ENSURE_BYTES macro
for (; ; )
{
//ENSURE_BYTES
- if (iPtr >= iEnd)
+ if (i_ptr >= i_end)
{
read = system.Read(input, window, inbuf, inputBufferSize);
if (read <= 0)
- {
- system.Free(window);
return (read < 0) ? Error.MSPACK_ERR_READ : Error.MSPACK_ERR_OK;
- }
- iPtr = 0;
- iEnd = read;
+ i_ptr = 0;
+ i_end = read;
}
- c = window[iPtr++] ^ invert;
+ c = window[i_ptr++] ^ invert;
for (i = 0x01; (i & 0xFF) != 0; i <<= 1)
{
if (c != 0 & i != 0)
{
// Literal
//ENSURE_BYTES
- if (iPtr >= iEnd)
+ if (i_ptr >= i_end)
{
read = system.Read(input, window, inbuf, inputBufferSize);
if (read <= 0)
- {
- system.Free(window);
return (read < 0) ? Error.MSPACK_ERR_READ : Error.MSPACK_ERR_OK;
- }
- iPtr = 0;
- iEnd = read;
+ i_ptr = 0;
+ i_end = read;
}
- window[pos] = window[iPtr++];
+ window[pos] = window[i_ptr++];
//ENSURE_BYTES
- if (iPtr >= iEnd)
+ if (i_ptr >= i_end)
{
read = system.Read(input, window, inbuf, inputBufferSize);
if (read <= 0)
- {
- system.Free(window);
return (read < 0) ? Error.MSPACK_ERR_READ : Error.MSPACK_ERR_OK;
- }
- iPtr = 0;
- iEnd = read;
+ i_ptr = 0;
+ i_end = read;
}
pos++; pos &= LZSS_WINDOW_SIZE - 1;
@@ -140,47 +131,38 @@ namespace LibMSPackSharp.Compression
{
// Match
//ENSURE_BYTES
- if (iPtr >= iEnd)
+ if (i_ptr >= i_end)
{
read = system.Read(input, window, inbuf, inputBufferSize);
if (read <= 0)
- {
- system.Free(window);
return (read < 0) ? Error.MSPACK_ERR_READ : Error.MSPACK_ERR_OK;
- }
- iPtr = 0;
- iEnd = read;
+ i_ptr = 0;
+ i_end = read;
}
- mpos = window[iPtr++];
+ mpos = window[i_ptr++];
//ENSURE_BYTES
- if (iPtr >= iEnd)
+ if (i_ptr >= i_end)
{
read = system.Read(input, window, inbuf, inputBufferSize);
if (read <= 0)
- {
- system.Free(window);
return (read < 0) ? Error.MSPACK_ERR_READ : Error.MSPACK_ERR_OK;
- }
- iPtr = 0;
- iEnd = read;
+ i_ptr = 0;
+ i_end = read;
}
- mpos |= (uint)(window[iPtr] & 0xF0) << 4;
- len = (uint)(window[iPtr++] & 0x0F) + 3;
+ mpos |= (uint)(window[i_ptr] & 0xF0) << 4;
+ len = (uint)(window[i_ptr++] & 0x0F) + 3;
while (len-- != 0)
{
window[pos] = window[mpos];
//WRITE_BYTE;
if (system.Write(output, window, (int)pos, 1) != 1)
- {
- system.Free(window);
return Error.MSPACK_ERR_WRITE;
- }
pos++;
pos &= LZSS_WINDOW_SIZE - 1;
diff --git a/BurnOutSharp/External/libmspack/Compression/LZX.cs b/BurnOutSharp/External/libmspack/Compression/LZX.cs
index 5b8fe037..6e305897 100644
--- a/BurnOutSharp/External/libmspack/Compression/LZX.cs
+++ b/BurnOutSharp/External/libmspack/Compression/LZX.cs
@@ -267,7 +267,7 @@ namespace LibMSPackSharp.Compression
/// a pointer to an initialised LZXDStream structure, or null if
/// there was not enough memory or parameters to the function were wrong.
///
- public static LZXDStream Init(SystemImpl system, object input, object output, int windowBits, int resetInterval, int inputBufferSize, long outputLength, bool isDelta)
+ public static LZXDStream Init(SystemImpl system, DefaultFileImpl input, DefaultFileImpl output, int windowBits, int resetInterval, int inputBufferSize, long outputLength, bool isDelta)
{
uint windowSize = (uint)(1 << windowBits);
@@ -984,7 +984,7 @@ namespace LibMSPackSharp.Compression
if (i > this_run)
i = this_run;
- lzx.Sys.Copy(lzx.InputBuffer, i_ptr, window, rundest, i);
+ Array.Copy(lzx.InputBuffer, i_ptr, window, rundest, i);
rundest += i;
i_ptr += i;
this_run -= i;
@@ -1044,7 +1044,7 @@ namespace LibMSPackSharp.Compression
int abs_off, rel_off;
lzx.OutputPointer = data;
- lzx.Sys.Copy(lzx.Window, (int)lzx.FramePosition, lzx.e8_buf, data, (int)frame_size);
+ Array.Copy(lzx.Window, (int)lzx.FramePosition, lzx.e8_buf, data, (int)frame_size);
while (data < dataend)
{
@@ -1112,23 +1112,6 @@ namespace LibMSPackSharp.Compression
return Error.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 Free(object s)
- {
- LZXDStream lzx = s as LZXDStream;
- if (lzx != null)
- {
- SystemImpl sys = lzx.Sys;
- sys.Free(lzx.InputBuffer);
- sys.Free(lzx.Window);
- sys.Free(lzx);
- }
- }
-
private static Error ReadLens(LZXDStream lzx, byte[] lens, uint first, uint last)
{
// Bit buffer and huffman symbol decode variables
diff --git a/BurnOutSharp/External/libmspack/Compression/MSZIP.cs b/BurnOutSharp/External/libmspack/Compression/MSZIP.cs
index ff4f6fc1..d3394628 100644
--- a/BurnOutSharp/External/libmspack/Compression/MSZIP.cs
+++ b/BurnOutSharp/External/libmspack/Compression/MSZIP.cs
@@ -93,7 +93,7 @@ namespace LibMSPackSharp.Compression
/// and 'holes' left will be filled with zero bytes. This allows at least
/// a partial recovery of erroneous data.
///
- public static MSZIPDStream Init(SystemImpl system, object input, object output, int input_buffer_size, bool repair_mode)
+ public static MSZIPDStream Init(SystemImpl system, DefaultFileImpl input, DefaultFileImpl output, int input_buffer_size, bool repair_mode)
{
if (system == null)
return null;
@@ -329,22 +329,6 @@ namespace LibMSPackSharp.Compression
return Error.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 Free(object s)
- {
- MSZIPDStream zip = s as MSZIPDStream;
- if (zip != null)
- {
- SystemImpl sys = zip.Sys;
- sys.Free(zip.InputBuffer);
- sys.Free(zip);
- }
- }
-
private static InflateErrorCode ReadLens(MSZIPDStream zip)
{
// For the bit buffer and huffman decoding
@@ -467,14 +451,14 @@ namespace LibMSPackSharp.Compression
// Copy LITERAL code lengths and clear any remaining
i = lit_codes;
- zip.Sys.Copy(lens, 0, zip.LITERAL_len, 0, i);
+ Array.Copy(lens, 0, zip.LITERAL_len, 0, i);
while (i < MSZIP_LITERAL_MAXSYMBOLS)
{
zip.LITERAL_len[i++] = 0;
}
i = dist_codes;
- zip.Sys.Copy(lens, lit_codes, zip.DISTANCE_len, 0, i);
+ Array.Copy(lens, lit_codes, zip.DISTANCE_len, 0, i);
while (i < MSZIP_DISTANCE_MAXSYMBOLS)
{
zip.DISTANCE_len[i++] = 0;
@@ -561,7 +545,7 @@ namespace LibMSPackSharp.Compression
if (this_run > (MSZIP_FRAME_SIZE - zip.WindowPosition))
this_run = (int)(MSZIP_FRAME_SIZE - zip.WindowPosition);
- zip.Sys.Copy(zip.InputBuffer, i_ptr, zip.Window, (int)zip.WindowPosition, this_run);
+ Array.Copy(zip.InputBuffer, i_ptr, zip.Window, (int)zip.WindowPosition, this_run);
zip.WindowPosition += (uint)this_run;
i_ptr += this_run;
length -= this_run;
diff --git a/BurnOutSharp/External/libmspack/Compression/None.cs b/BurnOutSharp/External/libmspack/Compression/None.cs
new file mode 100644
index 00000000..d298779d
--- /dev/null
+++ b/BurnOutSharp/External/libmspack/Compression/None.cs
@@ -0,0 +1,56 @@
+/* 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 LibMSPackSharp.Compression
+{
+ public class None
+ {
+ public static NoneState Init(SystemImpl sys, DefaultFileImpl input, DefaultFileImpl output, int bufsize)
+ {
+ NoneState state = new NoneState();
+ byte[] buf = new byte[bufsize];
+ if (state != null && buf != null)
+ {
+ state.Sys = sys;
+ state.Input = input;
+ state.Output = output;
+ state.Buffer = buf;
+ state.BufferSize = bufsize;
+ }
+ else
+ {
+ state = null;
+ }
+
+ return state;
+ }
+
+ public static Error Decompress(object s, long bytes)
+ {
+ NoneState state = (NoneState)s;
+ if (state == null)
+ return Error.MSPACK_ERR_ARGS;
+
+ int run;
+ while (bytes > 0)
+ {
+ run = (bytes > state.BufferSize) ? state.BufferSize : (int)bytes;
+
+ if (state.Sys.Read(state.Input, state.Buffer, 0, run) != run)
+ return Error.MSPACK_ERR_READ;
+
+ if (state.Sys.Write(state.Output, state.Buffer, 0, run) != run)
+ return Error.MSPACK_ERR_WRITE;
+
+ bytes -= run;
+ }
+ return Error.MSPACK_ERR_OK;
+ }
+ }
+}
diff --git a/BurnOutSharp/External/libmspack/CAB/NoneState.cs b/BurnOutSharp/External/libmspack/Compression/NoneState.cs
similarity index 94%
rename from BurnOutSharp/External/libmspack/CAB/NoneState.cs
rename to BurnOutSharp/External/libmspack/Compression/NoneState.cs
index 64a279a5..17d047c5 100644
--- a/BurnOutSharp/External/libmspack/CAB/NoneState.cs
+++ b/BurnOutSharp/External/libmspack/Compression/NoneState.cs
@@ -7,7 +7,7 @@
* For further details, see the file COPYING.LIB distributed with libmspack
*/
-namespace LibMSPackSharp.CAB
+namespace LibMSPackSharp.Compression
{
///
/// The "not compressed" method decompressor
diff --git a/BurnOutSharp/External/libmspack/Compression/QTM.cs b/BurnOutSharp/External/libmspack/Compression/QTM.cs
index 3a254ab5..82e75ac8 100644
--- a/BurnOutSharp/External/libmspack/Compression/QTM.cs
+++ b/BurnOutSharp/External/libmspack/Compression/QTM.cs
@@ -91,7 +91,7 @@ namespace LibMSPackSharp.Compression
/// - 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 QTMDStream Init(SystemImpl system, object input, object output, int window_bits, int input_buffer_size)
+ public static QTMDStream Init(SystemImpl system, DefaultFileImpl input, DefaultFileImpl output, int window_bits, int input_buffer_size)
{
uint window_size = (uint)(1 << window_bits);
@@ -474,22 +474,6 @@ namespace LibMSPackSharp.Compression
return Error.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 Free(object s)
- {
- QTMDStream qtm = s as QTMDStream;
- if (qtm != null)
- {
- SystemImpl sys = qtm.Sys;
- sys.Free(qtm.Window);
- sys.Free(qtm.InputBuffer);
- sys.Free(qtm);
- }
- }
-
///
/// Arithmetic decoder:
///
diff --git a/BurnOutSharp/External/libmspack/KWAJ/HeaderImpl.cs b/BurnOutSharp/External/libmspack/KWAJ/HeaderImpl.cs
index b64bb420..7589c20e 100644
--- a/BurnOutSharp/External/libmspack/KWAJ/HeaderImpl.cs
+++ b/BurnOutSharp/External/libmspack/KWAJ/HeaderImpl.cs
@@ -11,6 +11,6 @@ namespace LibMSPackSharp.KWAJ
{
public class HeaderImpl : Header
{
- public object FileHandle { get; set; }
+ public DefaultFileImpl FileHandle { get; set; }
}
}
diff --git a/BurnOutSharp/External/libmspack/KWAJ/Implementation.cs b/BurnOutSharp/External/libmspack/KWAJ/Implementation.cs
index 14a5604c..0049e20a 100644
--- a/BurnOutSharp/External/libmspack/KWAJ/Implementation.cs
+++ b/BurnOutSharp/External/libmspack/KWAJ/Implementation.cs
@@ -76,7 +76,7 @@ namespace LibMSPackSharp.KWAJ
SystemImpl sys = self.System;
- object fh = sys.Open(sys, filename, OpenMode.MSPACK_SYS_OPEN_READ);
+ DefaultFileImpl fh = sys.Open(filename, OpenMode.MSPACK_SYS_OPEN_READ);
HeaderImpl hdr = new HeaderImpl();
if (fh != null && hdr != null)
{
@@ -96,7 +96,6 @@ namespace LibMSPackSharp.KWAJ
if (fh != null)
sys.Close(fh);
- sys.Free(hdr);
hdr = null;
}
@@ -121,9 +120,6 @@ namespace LibMSPackSharp.KWAJ
// Close the file handle associated
self.System.Close(hdr_p.FileHandle);
- // Free the memory associated
- self.System.Free(hdr);
-
self.Error = Error.MSPACK_ERR_OK;
}
@@ -134,7 +130,7 @@ namespace LibMSPackSharp.KWAJ
///
/// Reads the headers of a KWAJ format file
///
- public static Error ReadHeaders(SystemImpl sys, object fh, Header hdr)
+ public static Error ReadHeaders(SystemImpl sys, DefaultFileImpl fh, Header hdr)
{
int i;
@@ -287,7 +283,7 @@ namespace LibMSPackSharp.KWAJ
return self.Error = Error.MSPACK_ERR_ARGS;
SystemImpl sys = self.System;
- object fh = (hdr as HeaderImpl)?.FileHandle;
+ DefaultFileImpl fh = (hdr as HeaderImpl)?.FileHandle;
if (fh == null)
return Error.MSPACK_ERR_ARGS;
@@ -296,8 +292,8 @@ namespace LibMSPackSharp.KWAJ
return self.Error = Error.MSPACK_ERR_SEEK;
// Open file for output
- object outfh;
- if ((outfh = sys.Open(sys, filename, OpenMode.MSPACK_SYS_OPEN_WRITE)) == null)
+ DefaultFileImpl outfh;
+ if ((outfh = sys.Open(filename, OpenMode.MSPACK_SYS_OPEN_WRITE)) == null)
return self.Error = Error.MSPACK_ERR_OPEN;
self.Error = Error.MSPACK_ERR_OK;
@@ -329,8 +325,6 @@ namespace LibMSPackSharp.KWAJ
if (read < 0)
self.Error = Error.MSPACK_ERR_READ;
-
- sys.Free(buf);
}
else if (hdr.CompressionType == CompressionType.MSKWAJ_COMP_SZDD)
{
@@ -340,13 +334,11 @@ namespace LibMSPackSharp.KWAJ
{
InternalStream lzh = LZHInit(sys, fh, outfh);
self.Error = (lzh != null) ? LZHDecompress(lzh) : Error.MSPACK_ERR_NOMEMORY;
- LZHFree(lzh);
}
else if (hdr.CompressionType == CompressionType.MSKWAJ_COMP_MSZIP)
{
MSZIPDStream zip = MSZIP.Init(sys, fh, outfh, KWAJ_INPUT_SIZE, false);
self.Error = (zip != null) ? MSZIP.DecompressKWAJ(zip) : Error.MSPACK_ERR_NOMEMORY;
- MSZIP.Free(zip);
}
else
{
@@ -588,15 +580,6 @@ namespace LibMSPackSharp.KWAJ
return Error.MSPACK_ERR_OK;
}
- private static void LZHFree(InternalStream lzh)
- {
- if (lzh == null || lzh.Sys == null)
- return;
-
- SystemImpl sys = lzh.Sys;
- sys.Free(lzh);
- }
-
public static Error LZHReadLens(InternalStream lzh, uint type, uint numsyms, byte[] lens)
{
uint bit_buffer = 0, bits_left = 0;
diff --git a/BurnOutSharp/External/libmspack/Library.cs b/BurnOutSharp/External/libmspack/Library.cs
index f24e5c80..53dc2800 100644
--- a/BurnOutSharp/External/libmspack/Library.cs
+++ b/BurnOutSharp/External/libmspack/Library.cs
@@ -129,8 +129,6 @@
* use of extract(), and any other methods, with the mutex
*/
-using LibMSPackSharp.Compression;
-
namespace LibMSPackSharp
{
public static class Library
@@ -160,16 +158,8 @@ namespace LibMSPackSharp
if (!SystemImpl.ValidSystem(sys))
return null;
- return new CAB.DecompressorImpl()
+ return new CAB.Decompressor()
{
- Open = CAB.Implementation.Open,
- Close = CAB.Implementation.Close,
- Search = CAB.Implementation.Search,
- Extract = CAB.Implementation.Extract,
- Prepend = CAB.Implementation.Prepend,
- Append = CAB.Implementation.Append,
- SetParam = CAB.Implementation.Param,
- LastError = CAB.Implementation.LastError,
System = sys,
State = null,
Error = Error.MSPACK_ERR_OK,
@@ -184,8 +174,8 @@ namespace LibMSPackSharp
///
/// Destroys an existing CAB compressor.
///
- /// the to destroy
- public static void DestroyCABCompressor(CAB.Compressor c)
+ /// the to destroy
+ public static void DestroyCABCompressor(CAB.Compressor self)
{
// TODO
}
@@ -193,10 +183,9 @@ namespace LibMSPackSharp
///
/// Destroys an existing CAB decompressor.
///
- /// the to destroy
- public static void DestroyCABDecompressor(CAB.Decompressor d)
+ /// the to destroy
+ public static void DestroyCABDecompressor(CAB.Decompressor self)
{
- CAB.DecompressorImpl self = d as CAB.DecompressorImpl;
if (self != null)
{
SystemImpl sys = self.System;
@@ -205,11 +194,8 @@ namespace LibMSPackSharp
if (self.State.InputFileHandle != null)
sys.Close(self.State.InputFileHandle);
- CAB.Implementation.FreeDecompressionState(self);
- sys.Free(self.State);
+ self.FreeDecompressionState();
}
-
- sys.Free(self);
}
}
@@ -277,13 +263,7 @@ namespace LibMSPackSharp
{
if (self.State.InputFileHandle != null)
sys.Close(self.State.InputFileHandle);
-
- if (self.State.State != null)
- LZX.Free(self.State.State);
-
- sys.Free(self.State);
}
- sys.Free(self);
}
}
@@ -427,15 +407,7 @@ namespace LibMSPackSharp
/// Destroys an existing SZDD decompressor.
///
/// the to destroy
- public static void DestroySZDDDecompressor(SZDD.Decompressor d)
- {
- SZDD.DecompressorImpl self = d as SZDD.DecompressorImpl;
- if (self != null)
- {
- SystemImpl sys = self.System;
- sys.Free(self);
- }
- }
+ public static void DestroySZDDDecompressor(SZDD.Decompressor d) { }
#endregion
@@ -489,15 +461,7 @@ namespace LibMSPackSharp
/// Destroys an existing KWAJ decompressor.
///
/// the to destroy
- public static void DestroyKWAJDecompressor(KWAJ.Decompressor d)
- {
- KWAJ.DecompressorImpl self = d as KWAJ.DecompressorImpl;
- if (self != null)
- {
- SystemImpl sys = self.System;
- sys.Free(self);
- }
- }
+ public static void DestroyKWAJDecompressor(KWAJ.Decompressor d) { }
#endregion
@@ -549,15 +513,7 @@ namespace LibMSPackSharp
/// Destroys an existing OAB decompressor.
///
/// the to destroy
- public static void DestroyOABDecompressor(OAB.Decompressor d)
- {
- OAB.DecompressorImpl self = d as OAB.DecompressorImpl;
- if (self != null)
- {
- SystemImpl sys = self.System;
- sys.Free(self);
- }
- }
+ public static void DestroyOABDecompressor(OAB.Decompressor d) { }
#endregion
}
diff --git a/BurnOutSharp/External/libmspack/OAB/Implementation.cs b/BurnOutSharp/External/libmspack/OAB/Implementation.cs
index ce70c758..5023e235 100644
--- a/BurnOutSharp/External/libmspack/OAB/Implementation.cs
+++ b/BurnOutSharp/External/libmspack/OAB/Implementation.cs
@@ -118,12 +118,10 @@ namespace LibMSPackSharp.OAB
SystemImpl sys = self.System;
- object infh = sys.Open(sys, input, OpenMode.MSPACK_SYS_OPEN_READ);
+ DefaultFileImpl infh = sys.Open(input, OpenMode.MSPACK_SYS_OPEN_READ);
if (infh == null)
{
ret = Error.MSPACK_ERR_OPEN;
- if (lzx != null)
- LZX.Free(lzx);
if (infh != null)
sys.Close(infh);
@@ -133,8 +131,6 @@ namespace LibMSPackSharp.OAB
if (sys.Read(infh, hdrbuf, 0, oabhead_SIZEOF) != oabhead_SIZEOF)
{
ret = Error.MSPACK_ERR_READ;
- if (lzx != null)
- LZX.Free(lzx);
if (infh != null)
sys.Close(infh);
@@ -145,8 +141,6 @@ namespace LibMSPackSharp.OAB
BitConverter.ToUInt32(hdrbuf, oabhead_VersionLo) != 1)
{
ret = Error.MSPACK_ERR_SIGNATURE;
- if (lzx != null)
- LZX.Free(lzx);
if (infh != null)
sys.Close(infh);
@@ -156,12 +150,10 @@ namespace LibMSPackSharp.OAB
uint block_max = BitConverter.ToUInt32(hdrbuf, oabhead_BlockMax);
uint target_size = BitConverter.ToUInt32(hdrbuf, oabhead_TargetSize);
- object outfh = sys.Open(sys, output, OpenMode.MSPACK_SYS_OPEN_WRITE);
+ DefaultFileImpl outfh = sys.Open(output, OpenMode.MSPACK_SYS_OPEN_WRITE);
if (outfh == null)
{
ret = Error.MSPACK_ERR_OPEN;
- if (lzx != null)
- LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (infh != null)
@@ -189,14 +181,11 @@ namespace LibMSPackSharp.OAB
if (sys.Read(infh, buf, 0, oabblk_SIZEOF) != oabblk_SIZEOF)
{
ret = Error.MSPACK_ERR_READ;
- if (lzx != null)
- LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (infh != null)
sys.Close(infh);
- sys.Free(buf);
return ret;
}
@@ -208,14 +197,11 @@ namespace LibMSPackSharp.OAB
if (blk_dsize > block_max || blk_dsize > target_size || blk_flags > 1)
{
ret = Error.MSPACK_ERR_DATAFORMAT;
- if (lzx != null)
- LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (infh != null)
sys.Close(infh);
- sys.Free(buf);
return ret;
}
@@ -225,28 +211,22 @@ namespace LibMSPackSharp.OAB
if (blk_dsize != blk_csize)
{
ret = Error.MSPACK_ERR_DATAFORMAT;
- if (lzx != null)
- LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (infh != null)
sys.Close(infh);
- sys.Free(buf);
return ret;
}
ret = CopyFileHandle(sys, infh, outfh, (int)blk_dsize, buf, self.BufferSize);
if (ret != Error.MSPACK_ERR_OK)
{
- if (lzx != null)
- LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (infh != null)
sys.Close(infh);
- sys.Free(buf);
return ret;
}
}
@@ -272,53 +252,42 @@ namespace LibMSPackSharp.OAB
if (infh != null)
sys.Close(infh);
- sys.Free(buf);
return ret;
}
ret = LZX.Decompress(lzx, blk_dsize);
if (ret != Error.MSPACK_ERR_OK)
{
- if (lzx != null)
- LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (infh != null)
sys.Close(infh);
- sys.Free(buf);
return ret;
}
- LZX.Free(lzx);
lzx = null;
// Consume any trailing padding bytes before the next block
ret = CopyFileHandle(sys, infh, null, in_ofh.Available, buf, self.BufferSize);
if (ret != Error.MSPACK_ERR_OK)
{
- if (lzx != null)
- LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (infh != null)
sys.Close(infh);
- sys.Free(buf);
return ret;
}
if (out_ofh.CRC != blk_crc)
{
ret = Error.MSPACK_ERR_CHECKSUM;
- if (lzx != null)
- LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (infh != null)
sys.Close(infh);
- sys.Free(buf);
return ret;
}
}
@@ -326,14 +295,11 @@ namespace LibMSPackSharp.OAB
target_size -= blk_dsize;
}
- if (lzx != null)
- LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (infh != null)
sys.Close(infh);
- sys.Free(buf);
return ret;
}
@@ -355,12 +321,10 @@ namespace LibMSPackSharp.OAB
SystemImpl sys = self.System;
- object infh = sys.Open(sys, input, OpenMode.MSPACK_SYS_OPEN_READ);
+ DefaultFileImpl infh = sys.Open(input, OpenMode.MSPACK_SYS_OPEN_READ);
if (infh == null)
{
ret = Error.MSPACK_ERR_OPEN;
- if (lzx != null)
- LZX.Free(lzx);
if (infh != null)
sys.Close(infh);
@@ -370,8 +334,6 @@ namespace LibMSPackSharp.OAB
if (sys.Read(infh, hdrbuf, 0, patchhead_SIZEOF) != patchhead_SIZEOF)
{
ret = Error.MSPACK_ERR_READ;
- if (lzx != null)
- LZX.Free(lzx);
if (infh != null)
sys.Close(infh);
@@ -382,8 +344,6 @@ namespace LibMSPackSharp.OAB
BitConverter.ToUInt32(hdrbuf, patchhead_VersionLo) != 2)
{
ret = Error.MSPACK_ERR_SIGNATURE;
- if (lzx != null)
- LZX.Free(lzx);
if (infh != null)
sys.Close(infh);
@@ -397,12 +357,10 @@ namespace LibMSPackSharp.OAB
if (block_max < patchblk_SIZEOF)
block_max = patchblk_SIZEOF;
- object basefh = sys.Open(sys, basePath, OpenMode.MSPACK_SYS_OPEN_READ);
+ DefaultFileImpl basefh = sys.Open(basePath, OpenMode.MSPACK_SYS_OPEN_READ);
if (basefh == null)
{
ret = Error.MSPACK_ERR_OPEN;
- if (lzx != null)
- LZX.Free(lzx);
if (basefh != null)
sys.Close(basefh);
if (infh != null)
@@ -411,12 +369,10 @@ namespace LibMSPackSharp.OAB
return ret;
}
- object outfh = sys.Open(sys, output, OpenMode.MSPACK_SYS_OPEN_WRITE);
+ DefaultFileImpl outfh = sys.Open(output, OpenMode.MSPACK_SYS_OPEN_WRITE);
if (outfh == null)
{
ret = Error.MSPACK_ERR_OPEN;
- if (lzx != null)
- LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (basefh != null)
@@ -446,8 +402,6 @@ namespace LibMSPackSharp.OAB
if (sys.Read(infh, buf, 0, patchblk_SIZEOF) != patchblk_SIZEOF)
{
ret = Error.MSPACK_ERR_READ;
- if (lzx != null)
- LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (basefh != null)
@@ -455,7 +409,6 @@ namespace LibMSPackSharp.OAB
if (infh != null)
sys.Close(infh);
- sys.Free(buf);
return ret;
}
@@ -467,8 +420,6 @@ namespace LibMSPackSharp.OAB
if (blk_dsize > block_max || blk_dsize > target_size || blk_ssize > block_max)
{
ret = Error.MSPACK_ERR_DATAFORMAT;
- if (lzx != null)
- LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (basefh != null)
@@ -476,7 +427,6 @@ namespace LibMSPackSharp.OAB
if (infh != null)
sys.Close(infh);
- sys.Free(buf);
return ret;
}
@@ -501,15 +451,12 @@ namespace LibMSPackSharp.OAB
if (infh != null)
sys.Close(infh);
- sys.Free(buf);
return ret;
}
ret = LZX.SetReferenceData(lzx, sys, basefh, blk_ssize);
if (ret != Error.MSPACK_ERR_OK)
{
- if (lzx != null)
- LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (basefh != null)
@@ -517,15 +464,12 @@ namespace LibMSPackSharp.OAB
if (infh != null)
sys.Close(infh);
- sys.Free(buf);
return ret;
}
ret = LZX.Decompress(lzx, blk_dsize);
if (ret != Error.MSPACK_ERR_OK)
{
- if (lzx != null)
- LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (basefh != null)
@@ -533,19 +477,15 @@ namespace LibMSPackSharp.OAB
if (infh != null)
sys.Close(infh);
- sys.Free(buf);
return ret;
}
- LZX.Free(lzx);
lzx = null;
// Consume any trailing padding bytes before the next block
ret = CopyFileHandle(sys, infh, null, in_ofh.Available, buf, self.BufferSize);
if (ret != Error.MSPACK_ERR_OK)
{
- if (lzx != null)
- LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (basefh != null)
@@ -553,15 +493,12 @@ namespace LibMSPackSharp.OAB
if (infh != null)
sys.Close(infh);
- sys.Free(buf);
return ret;
}
if (out_ofh.CRC != blk_crc)
{
ret = Error.MSPACK_ERR_CHECKSUM;
- if (lzx != null)
- LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (basefh != null)
@@ -569,15 +506,12 @@ namespace LibMSPackSharp.OAB
if (infh != null)
sys.Close(infh);
- sys.Free(buf);
return ret;
}
target_size -= blk_dsize;
}
- if (lzx != null)
- LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (basefh != null)
@@ -585,7 +519,6 @@ namespace LibMSPackSharp.OAB
if (infh != null)
sys.Close(infh);
- sys.Free(buf);
return ret;
}
diff --git a/BurnOutSharp/External/libmspack/OAB/InternalFile.cs b/BurnOutSharp/External/libmspack/OAB/InternalFile.cs
index 0a99a7f6..1d04e89b 100644
--- a/BurnOutSharp/External/libmspack/OAB/InternalFile.cs
+++ b/BurnOutSharp/External/libmspack/OAB/InternalFile.cs
@@ -16,7 +16,7 @@
namespace LibMSPackSharp.OAB
{
- public class InternalFile
+ public class InternalFile : DefaultFileImpl
{
public SystemImpl OrigSys { get; set; }
diff --git a/BurnOutSharp/External/libmspack/SZDD/HeaderImpl.cs b/BurnOutSharp/External/libmspack/SZDD/HeaderImpl.cs
index 185d0699..a0a1e310 100644
--- a/BurnOutSharp/External/libmspack/SZDD/HeaderImpl.cs
+++ b/BurnOutSharp/External/libmspack/SZDD/HeaderImpl.cs
@@ -11,6 +11,6 @@ namespace LibMSPackSharp.SZDD
{
public class HeaderImpl : Header
{
- public object FileHandle { get; set; }
+ public DefaultFileImpl FileHandle { get; set; }
}
}
diff --git a/BurnOutSharp/External/libmspack/SZDD/Implementation.cs b/BurnOutSharp/External/libmspack/SZDD/Implementation.cs
index c069b14e..e019b422 100644
--- a/BurnOutSharp/External/libmspack/SZDD/Implementation.cs
+++ b/BurnOutSharp/External/libmspack/SZDD/Implementation.cs
@@ -33,7 +33,7 @@ namespace LibMSPackSharp.SZDD
SystemImpl sys = self.System;
- object fh = sys.Open(sys, filename, OpenMode.MSPACK_SYS_OPEN_READ);
+ DefaultFileImpl fh = sys.Open(filename, OpenMode.MSPACK_SYS_OPEN_READ);
HeaderImpl hdr = new HeaderImpl();
if (fh != null && hdr != null)
{
@@ -53,7 +53,6 @@ namespace LibMSPackSharp.SZDD
if (fh != null)
sys.Close(fh);
- sys.Free(hdr);
hdr = null;
}
@@ -78,9 +77,6 @@ namespace LibMSPackSharp.SZDD
// Close the file handle associated
self.System.Close(hdr_p.FileHandle);
- // Free the memory associated
- self.System.Free(hdr);
-
self.Error = Error.MSPACK_ERR_OK;
}
@@ -158,7 +154,7 @@ namespace LibMSPackSharp.SZDD
SystemImpl sys = self.System;
- object fh = (hdr as HeaderImpl)?.FileHandle;
+ DefaultFileImpl fh = (hdr as HeaderImpl)?.FileHandle;
if (fh == null)
return Error.MSPACK_ERR_ARGS;
@@ -168,8 +164,8 @@ namespace LibMSPackSharp.SZDD
return self.Error = Error.MSPACK_ERR_SEEK;
// Open file for output
- object outfh;
- if ((outfh = sys.Open(sys, filename, OpenMode.MSPACK_SYS_OPEN_WRITE)) == null)
+ DefaultFileImpl outfh;
+ if ((outfh = sys.Open(filename, OpenMode.MSPACK_SYS_OPEN_WRITE)) == null)
return self.Error = Error.MSPACK_ERR_OPEN;
// Decompress the data
diff --git a/BurnOutSharp/External/libmspack/SystemImpl.cs b/BurnOutSharp/External/libmspack/SystemImpl.cs
index 1831e2de..9938c561 100644
--- a/BurnOutSharp/External/libmspack/SystemImpl.cs
+++ b/BurnOutSharp/External/libmspack/SystemImpl.cs
@@ -43,13 +43,6 @@ namespace LibMSPackSharp
///
/// Opens a file for reading, writing, appending or updating.
///
- ///
- /// a self-referential pointer to the SystemImpl
- /// structure whose Open() method is being called. If
- /// this pointer is required by Close(), Read(), Write(),
- /// Seek() or Tell(), it should be stored in the result
- /// structure at this time.
- ///
///
/// the file to be opened. It is passed directly from the
/// library caller without being modified, so it is up to
@@ -57,21 +50,55 @@ namespace LibMSPackSharp
///
/// One of the values
///
- /// a pointer to a mspack_file structure. This structure officially
+ /// A pointer to a DefaultFileImpl structure. This structure officially
/// contains no members, its true contents are up to the
/// SystemImpl implementor. It should contain whatever is needed
/// for other SystemImpl methods to operate. Returning the null
/// pointer indicates an error condition.
///
- public Func Open;
+ public DefaultFileImpl Open(string filename, OpenMode mode)
+ {
+ try
+ {
+ DefaultFileImpl fileHandle = new DefaultFileImpl();
+ switch (mode)
+ {
+ case OpenMode.MSPACK_SYS_OPEN_READ:
+ fileHandle.FileHandle = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+ break;
+
+ case OpenMode.MSPACK_SYS_OPEN_WRITE:
+ fileHandle.FileHandle = File.Open(filename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
+ break;
+
+ case OpenMode.MSPACK_SYS_OPEN_UPDATE:
+ fileHandle.FileHandle = File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
+ break;
+
+ case OpenMode.MSPACK_SYS_OPEN_APPEND:
+ fileHandle.FileHandle = File.Open(filename, FileMode.Append, FileAccess.ReadWrite, FileShare.ReadWrite);
+ break;
+
+ default:
+ return null;
+ }
+
+ return fileHandle;
+ }
+ catch (Exception ex)
+ {
+ Message(null, $"Could not open {filename}: {ex}");
+ return null;
+ }
+ }
///
/// 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 Action