Add everything from lzx.h

This commit is contained in:
Matt Nadareski
2023-09-19 11:36:47 -04:00
parent 48f8397c81
commit 2413b5feeb
3 changed files with 328 additions and 0 deletions

View File

@@ -1,4 +1,5 @@
using static SabreTools.Compression.libmspack.kwaj;
using static SabreTools.Compression.libmspack.lzss;
namespace SabreTools.Compression.libmspack
{

147
libmspack/lzx.cs Normal file
View File

@@ -0,0 +1,147 @@
namespace SabreTools.Compression.libmspack
{
public static class lzx
{
// Some constants defined by the LZX specification
public const int LZX_MIN_MATCH = 2;
public const int LZX_MAX_MATCH = 257;
public const int LZX_NUM_CHARS = 256;
public const int LZX_BLOCKTYPE_INVALID = 0; /* also blocktypes 4-7 invalid */
public const int LZX_BLOCKTYPE_VERBATIM = 1;
public const int LZX_BLOCKTYPE_ALIGNED = 2;
public const int LZX_BLOCKTYPE_UNCOMPRESSED = 3;
public const int LZX_PRETREE_NUM_ELEMENTS = 20;
public const int LZX_ALIGNED_NUM_ELEMENTS = 8; /* aligned offset tree #elements */
public const int LZX_NUM_PRIMARY_LENGTHS = 7; /* this one missing from spec! */
public const int LZX_NUM_SECONDARY_LENGTHS = 249; /* length tree #elements */
// LZX huffman defines: tweak tablebits as desired
public const int LZX_PRETREE_MAXSYMBOLS = LZX_PRETREE_NUM_ELEMENTS;
public const int LZX_PRETREE_TABLEBITS = 6;
public const int LZX_MAINTREE_MAXSYMBOLS = LZX_NUM_CHARS + 290 * 8;
public const int LZX_MAINTREE_TABLEBITS = 12;
public const int LZX_LENGTH_MAXSYMBOLS = LZX_NUM_SECONDARY_LENGTHS + 1;
public const int LZX_LENGTH_TABLEBITS = 12;
public const int LZX_ALIGNED_MAXSYMBOLS = LZX_ALIGNED_NUM_ELEMENTS;
public const int LZX_ALIGNED_TABLEBITS = 7;
public const int LZX_LENTABLE_SAFETY = 64; /* table decoding overruns are allowed */
public const int LZX_FRAME_SIZE = 32768; /* the size of a frame in LZX */
/// <summary>
/// Allocates and initialises LZX decompression state for decoding an LZX
/// stream.
///
/// This routine uses system->alloc() to allocate memory. If memory
/// allocation fails, or the parameters to this function are invalid,
/// NULL is returned.
/// </summary>
/// <param name="system">
/// An mspack_system structure used to read from
/// the input stream and write to the output
/// stream, also to allocate and free memory.
/// </param>
/// <param name="input">An input stream with the LZX data.</param>
/// <param name="output">An output stream to write the decoded data to.</param>
/// <param name="window_bits">
/// The size of the decoding window, which must be
/// between 15 and 21 inclusive for regular LZX
/// data, or between 17 and 25 inclusive for
/// LZX DELTA data.
/// </param>
/// <param name="reset_interval">
/// The interval at which the LZX bitstream is
/// reset, in multiples of LZX frames (32678
/// bytes), e.g. a value of 2 indicates the input
/// stream resets after every 65536 output bytes.
/// A value of 0 indicates that the bitstream never
/// resets, such as in CAB LZX streams.
/// </param>
/// <param name="input_buffer_size">The number of bytes to use as an input bitstream buffer.</param>
/// <param name="output_length">
/// The length in bytes of the entirely
/// decompressed output stream, if known in
/// advance. It is used to correctly perform the
/// Intel E8 transformation, which must stop 6
/// bytes before the very end of the
/// decompressed stream. It is not otherwise used
/// or adhered to. If the full decompressed
/// length is known in advance, set it here.
/// If it is NOT known, use the value 0, and call
/// lzxd_set_output_length() once it is
/// known. If never set, 4 of the final 6 bytes
/// of the output stream may be incorrect.
/// </param>
/// <param name="is_delta">
/// Should be zero for all regular LZX data,
/// non-zero for LZX DELTA encoded data.
/// </param>
/// <returns>
/// A pointer to an initialised lzxd_stream structure, or NULL if
/// there was not enough memory or parameters to the function were wrong.
/// </returns>
public static lzxd_stream lzxd_init(mspack_system system, mspack_file input, mspack_file output, int window_bits, int reset_interval, int input_buffer_size, long output_length, char is_delta) => null;
/// <summary>
/// See description of output_length in lzxd_init()
/// </summary>
public static void lzxd_set_output_length(lzxd_stream lzx, long output_length) { }
/// <summary>
/// Reads LZX DELTA reference data into the window and allows
/// lzxd_decompress() to reference it.
///
/// Call this before the first call to lzxd_decompress().
/// </summary>
/// <param name="lzx">The LZX stream to apply this reference data to</param>
/// <param name="system">
/// An mspack_system implementation to use with the
/// input param. Only read() will be called.
/// </param>
/// <param name="input">
/// An input file handle to read reference data using
/// system->read().
/// </param>
/// <param name="length">
/// The length of the reference data. Cannot be longer
/// than the LZX window size.
/// </param>
/// <returns>An error code, or MSPACK_ERR_OK if successful</returns>
public static MSPACK_ERR lzxd_set_reference_data(lzxd_stream lzx, mspack_system system, mspack_file input, uint length) => MSPACK_ERR.MSPACK_ERR_OK;
/// <summary>
/// Decompresses entire or partial LZX streams.
///
/// The number of bytes of data that should be decompressed is given as the
/// out_bytes parameter. If more bytes are decoded than are needed, they
/// will be kept over for a later invocation.
///
/// The output bytes will be passed to the system->write() function given in
/// lzxd_init(), using the output file handle given in lzxd_init(). More than
/// one call may be made to system->write().
///
/// Input bytes will be read in as necessary using the system->read()
/// function given in lzxd_init(), using the input file handle given in
/// lzxd_init(). This will continue until system->read() returns 0 bytes,
/// or an error. Errors will be passed out of the function as
/// MSPACK_ERR_READ errors. Input streams should convey an "end of input
/// stream" by refusing to supply all the bytes that LZX asks for when they
/// reach the end of the stream, rather than return an error code.
///
/// If any error code other than MSPACK_ERR_OK is returned, the stream
/// should be considered unusable and lzxd_decompress() should not be
/// called again on this stream.
/// </summary>
/// <param name="lzx">LZX decompression state, as allocated by lzxd_init().</param>
/// <param name="out_bytes">The number of bytes of data to decompress.</param>
/// <returns>An error code, or MSPACK_ERR_OK if successful</returns>
public static MSPACK_ERR lzxd_decompress(lzxd_stream lzx, long out_bytes) => MSPACK_ERR.MSPACK_ERR_OK;
/// <summary>
/// Frees all state associated with an LZX data stream. This will call
/// system->free() using the system pointer given in lzxd_init().
/// </summary>
/// <param name="lzx">LZX decompression state to free.</param>
public static void lzxd_free(lzxd_stream lzx) { }
}
}

180
libmspack/lzxd_stream.cs Normal file
View File

@@ -0,0 +1,180 @@
using static SabreTools.Compression.libmspack.lzx;
namespace SabreTools.Compression.libmspack
{
public unsafe class lzxd_stream
{
/// <summary>
/// I/O routines
/// </summary>
public mspack_system sys { get; set; }
/// <summary>
/// Input file handle
/// </summary>
public mspack_file input { get; set; }
/// <summary>
/// Output file handle
/// </summary>
public mspack_file output { get; set; }
/// <summary>
/// Number of bytes actually output
/// </summary>
public long offset { get; set; }
/// <summary>
/// Overall decompressed length of stream
/// </summary>
public long length { get; set; }
/// <summary>
/// Decoding window
/// </summary>
public byte* window { get; set; }
/// <summary>
/// Window size
/// </summary>
public uint window_size { get; set; }
/// <summary>
/// LZX DELTA reference data size
/// </summary>
public uint ref_data_size { get; set; }
/// <summary>
/// Number of match_offset entries in table
/// </summary>
public uint num_offsets { get; set; }
/// <summary>
/// Decompression offset within window
/// </summary>
public uint window_posn { get; set; }
/// <summary>
/// Current frame offset within in window
/// </summary>
public uint frame_posn { get; set; }
/// <summary>
/// The number of 32kb frames processed
/// </summary>
public uint frame { get; set; }
/// <summary>
/// Which frame do we reset the compressor?
/// </summary>
public uint reset_interval { get; set; }
/// <summary>
/// For the LRU offset system
/// </summary>
public uint R0 { get; set; }
/// <summary>
/// For the LRU offset system
/// </summary>
public uint R1 { get; set; }
/// <summary>
/// For the LRU offset system
/// </summary>
public uint R2 { get; set; }
/// <summary>
/// Uncompressed length of this LZX block
/// </summary>
public uint block_length { get; set; }
/// <summary>
/// Uncompressed bytes still left to decode
/// </summary>
public uint block_remaining { get; set; }
/// <summary>
/// Magic header value used for transform
/// </summary>
public int intel_filesize { get; set; }
/// <summary>
/// Has intel E8 decoding started?
/// </summary>
public byte intel_started { get; set; }
/// <summary>
/// Type of the current block
/// </summary>
public byte block_type { get; set; }
/// <summary>
/// Have we started decoding at all yet?
/// </summary>
public byte header_read { get; set; }
/// <summary>
/// Have we reached the end of input?
/// </summary>
public byte input_end { get; set; }
/// <summary>
/// Does stream follow LZX DELTA spec?
/// </summary>
public byte is_delta { get; set; }
public MSPACK_ERR error { get; set; }
#region I/O buffering
public byte* inbuf { get; set; }
public byte* i_ptr { get; set; }
public byte* i_end { get; set; }
public byte* o_ptr { get; set; }
public byte* o_end { get; set; }
public uint bit_buffer { get; set; }
public uint bits_left { get; set; }
public uint inbuf_size { get; set; }
#endregion
#region Huffman code lengths
public byte[] PRETREE_len { get; set; } = new byte[LZX_PRETREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
public byte[] MAINTREE_len { get; set; } = new byte[LZX_MAINTREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
public byte[] LENGTH_len { get; set; } = new byte[LZX_LENGTH_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
public byte[] ALIGNED_len { get; set; } = new byte[LZX_ALIGNED_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
#endregion
#region Huffman decoding tables
public ushort[] PRETREE_table { get; set; } = new ushort[(1 << LZX_PRETREE_TABLEBITS) + (LZX_PRETREE_MAXSYMBOLS * 2)];
public ushort[] MAINTREE_table { get; set; } = new ushort[(1 << LZX_MAINTREE_TABLEBITS) + (LZX_MAINTREE_MAXSYMBOLS * 2)];
public ushort[] LENGTH_table { get; set; } = new ushort[(1 << LZX_LENGTH_TABLEBITS) + (LZX_LENGTH_MAXSYMBOLS * 2)];
public ushort[] ALIGNED_table { get; set; } = new ushort[(1 << LZX_ALIGNED_TABLEBITS) + (LZX_ALIGNED_MAXSYMBOLS * 2)];
public byte LENGTH_empty { get; set; }
#endregion
/// <summary>
/// This is used purely for doing the intel E8 transform
/// </summary>
public byte[] e8_buf { get; set; } = new byte[LZX_FRAME_SIZE];
}
}