mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-04-28 09:21:08 +00:00
Constants
This commit is contained in:
@@ -19,6 +19,7 @@ using System.IO;
|
||||
using System.Text;
|
||||
using LibMSPackSharp.Compression;
|
||||
using static LibMSPackSharp.Constants;
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.CHM
|
||||
{
|
||||
@@ -242,7 +243,7 @@ namespace LibMSPackSharp.CHM
|
||||
return Error = err;
|
||||
|
||||
// Validate reset_interval
|
||||
if (lzxControlData.ResetInterval == 0 || (lzxControlData.ResetInterval % LZX.LZX_FRAME_SIZE) != 0)
|
||||
if (lzxControlData.ResetInterval == 0 || (lzxControlData.ResetInterval % LZX_FRAME_SIZE) != 0)
|
||||
{
|
||||
Console.WriteLine("Bad controldata reset interval");
|
||||
return Error = Error.MSPACK_ERR_DATAFORMAT;
|
||||
@@ -252,7 +253,7 @@ namespace LibMSPackSharp.CHM
|
||||
int entry = (int)(file.Offset / lzxControlData.ResetInterval);
|
||||
|
||||
// Convert from reset interval multiple (usually 64k) to 32k frames
|
||||
entry *= (int)lzxControlData.ResetInterval / LZX.LZX_FRAME_SIZE;
|
||||
entry *= (int)lzxControlData.ResetInterval / LZX_FRAME_SIZE;
|
||||
|
||||
// Read the reset table entry
|
||||
if (ReadResetTable(sec, (uint)entry, out long length, out long offset))
|
||||
@@ -284,11 +285,11 @@ namespace LibMSPackSharp.CHM
|
||||
State.InOffset = file.Section.Header.Sec0.Offset + sec.Content.Offset + offset;
|
||||
|
||||
// Set start offset and overall remaining stream length
|
||||
State.Offset = entry * LZX.LZX_FRAME_SIZE;
|
||||
State.Offset = entry * LZX_FRAME_SIZE;
|
||||
length -= State.Offset;
|
||||
|
||||
// Initialise LZX stream
|
||||
State.State = LZX.Init(State.System, State.InputFileHandle, State.OutputFileHandle, windowBits, (int)lzxControlData.ResetInterval / LZX.LZX_FRAME_SIZE, 4096, length, false);
|
||||
State.State = LZX.Init(State.System, State.InputFileHandle, State.OutputFileHandle, windowBits, (int)lzxControlData.ResetInterval / LZX_FRAME_SIZE, 4096, length, false);
|
||||
|
||||
if (State.State == null)
|
||||
Error = Error.MSPACK_ERR_NOMEMORY;
|
||||
@@ -1081,7 +1082,7 @@ namespace LibMSPackSharp.CHM
|
||||
return false;
|
||||
|
||||
// Check sanity of reset table
|
||||
if (lzxResetTable.FrameLength != LZX.LZX_FRAME_SIZE)
|
||||
if (lzxResetTable.FrameLength != LZX_FRAME_SIZE)
|
||||
{
|
||||
Console.WriteLine("Bad reset table frame length");
|
||||
return false;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using LibMSPackSharp.Compression;
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.CHM
|
||||
{
|
||||
@@ -94,8 +94,8 @@ namespace LibMSPackSharp.CHM
|
||||
controlData.WindowSize = BitConverter.ToUInt32(buffer, 0x0010);
|
||||
break;
|
||||
case 2:
|
||||
controlData.ResetInterval = BitConverter.ToUInt32(buffer, 0x000C) * LZX.LZX_FRAME_SIZE;
|
||||
controlData.WindowSize = BitConverter.ToUInt32(buffer, 0x0010) * LZX.LZX_FRAME_SIZE;
|
||||
controlData.ResetInterval = BitConverter.ToUInt32(buffer, 0x000C) * LZX_FRAME_SIZE;
|
||||
controlData.WindowSize = BitConverter.ToUInt32(buffer, 0x0010) * LZX_FRAME_SIZE;
|
||||
break;
|
||||
default:
|
||||
return Error.MSPACK_ERR_DATAFORMAT;
|
||||
|
||||
78
BurnOutSharp/External/libmspack/Compression/BufferState.cs
vendored
Normal file
78
BurnOutSharp/External/libmspack/Compression/BufferState.cs
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2013 Stuart Caie.
|
||||
*
|
||||
* The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
|
||||
* by Microsoft Corporation.
|
||||
*
|
||||
* libmspack is free software { get; set; } 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 BufferState
|
||||
{
|
||||
/// <summary>
|
||||
/// i_ptr
|
||||
/// </summary>
|
||||
public int InputPointer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// i_end
|
||||
/// </summary>
|
||||
public int InputEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// bit_buffer
|
||||
/// </summary>
|
||||
public uint BitBuffer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// bits_left
|
||||
/// </summary>
|
||||
public int BitsLeft { get; set; }
|
||||
|
||||
#region Common
|
||||
|
||||
/// <summary>
|
||||
/// Initialises bitstream state in state structure
|
||||
/// </summary>
|
||||
public void Init()
|
||||
{
|
||||
InputPointer = 0;
|
||||
InputEnd = 0;
|
||||
BitBuffer = 0;
|
||||
BitsLeft = 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MSB
|
||||
|
||||
/// <summary>
|
||||
/// Removes N bits from the bit buffer
|
||||
/// </summary>
|
||||
public void REMOVE_BITS_MSB(int nbits)
|
||||
{
|
||||
BitBuffer <<= nbits;
|
||||
BitsLeft -= nbits;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LSB
|
||||
|
||||
/// <summary>
|
||||
/// Removes N bits from the bit buffer
|
||||
/// </summary>
|
||||
public void REMOVE_BITS_LSB(int nbits)
|
||||
{
|
||||
BitBuffer >>= nbits;
|
||||
BitsLeft -= nbits;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -17,42 +17,17 @@ namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public abstract class CompressionStream : BaseDecompressState
|
||||
{
|
||||
#region Constants
|
||||
|
||||
/// <summary>
|
||||
/// Number of bits in a character
|
||||
/// </summary>
|
||||
private const int CHAR_BIT = 8;
|
||||
|
||||
/// <summary>
|
||||
/// Bit width of a UInt32 bit buffer
|
||||
/// </summary>
|
||||
public const int BITBUF_WIDTH = 4 * CHAR_BIT;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum bits in a Huffman code
|
||||
/// </summary>
|
||||
public const int HUFF_MAXBITS = 16;
|
||||
|
||||
#endregion
|
||||
|
||||
#region I/O buffering
|
||||
|
||||
public byte[] InputBuffer { get; set; }
|
||||
|
||||
public uint InputBufferSize { get; set; }
|
||||
|
||||
public int InputPointer { get; set; }
|
||||
|
||||
public int InputEnd { get; set; }
|
||||
|
||||
public int OutputPointer { get; set; }
|
||||
|
||||
public int OutputEnd { get; set; }
|
||||
|
||||
public uint BitBuffer { get; set; }
|
||||
|
||||
public int BitsLeft { get; set; }
|
||||
internal BufferState BufferState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Have we reached the end of input?
|
||||
@@ -137,43 +112,44 @@ namespace LibMSPackSharp.Compression
|
||||
/// </summary>
|
||||
public void INIT_BITS()
|
||||
{
|
||||
InputPointer = 0;
|
||||
InputEnd = 0;
|
||||
BitBuffer = 0;
|
||||
BitsLeft = 0;
|
||||
BufferState = new BufferState();
|
||||
BufferState.Init();
|
||||
EndOfInput = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores bitstream state in state structure
|
||||
/// </summary>
|
||||
public void STORE_BITS(int i_ptr, int i_end, uint bit_buffer, int bits_left)
|
||||
public void STORE_BITS(BufferState state)
|
||||
{
|
||||
InputPointer = i_ptr;
|
||||
InputEnd = i_end;
|
||||
BitBuffer = bit_buffer;
|
||||
BitsLeft = bits_left;
|
||||
BufferState.InputPointer = state.InputPointer;
|
||||
BufferState.InputEnd = state.InputEnd;
|
||||
BufferState.BitBuffer = state.BitBuffer;
|
||||
BufferState.BitsLeft = state.BitsLeft;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restores bitstream state from state structure
|
||||
/// </summary>
|
||||
public void RESTORE_BITS(out int i_ptr, out int i_end, out uint bit_buffer, out int bits_left)
|
||||
public BufferState RESTORE_BITS()
|
||||
{
|
||||
i_ptr = InputPointer;
|
||||
i_end = InputEnd;
|
||||
bit_buffer = BitBuffer;
|
||||
bits_left = BitsLeft;
|
||||
return new BufferState()
|
||||
{
|
||||
InputPointer = BufferState.InputPointer,
|
||||
InputEnd = BufferState.InputEnd,
|
||||
BitBuffer = BufferState.BitBuffer,
|
||||
BitsLeft = BufferState.BitsLeft,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure there are at least N bits in the bit buffer
|
||||
/// </summary>
|
||||
public void ENSURE_BITS(int nbits, ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left)
|
||||
public void ENSURE_BITS(int nbits, BufferState state)
|
||||
{
|
||||
while (bits_left < nbits)
|
||||
while (state.BitsLeft < nbits)
|
||||
{
|
||||
READ_BYTES(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
READ_BYTES(state);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return;
|
||||
}
|
||||
@@ -182,23 +158,23 @@ namespace LibMSPackSharp.Compression
|
||||
/// <summary>
|
||||
/// Read from the input if the buffer is empty
|
||||
/// </summary>
|
||||
public void READ_IF_NEEDED(ref int i_ptr, ref int i_end)
|
||||
public void READ_IF_NEEDED(BufferState state)
|
||||
{
|
||||
if (i_ptr >= i_end)
|
||||
if (state.InputPointer >= state.InputEnd)
|
||||
{
|
||||
ReadInput();
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return;
|
||||
|
||||
i_ptr = InputPointer;
|
||||
i_end = InputEnd;
|
||||
state.InputPointer = BufferState.InputPointer;
|
||||
state.InputEnd = BufferState.InputEnd;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read bytes from the input into the bit buffer
|
||||
/// </summary>
|
||||
public abstract void READ_BYTES(ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left);
|
||||
public abstract void READ_BYTES(BufferState state);
|
||||
|
||||
/// <summary>
|
||||
/// Read an input stream and fill the buffer
|
||||
@@ -231,8 +207,8 @@ namespace LibMSPackSharp.Compression
|
||||
}
|
||||
|
||||
// Update i_ptr and i_end
|
||||
InputPointer = 0;
|
||||
InputEnd = read;
|
||||
BufferState.InputPointer = 0;
|
||||
BufferState.InputEnd = read;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -242,10 +218,10 @@ namespace LibMSPackSharp.Compression
|
||||
/// <summary>
|
||||
/// Inject data into the bit buffer
|
||||
/// </summary>
|
||||
public void INJECT_BITS_MSB(int bitdata, int nbits, ref uint bit_buffer, ref int bits_left)
|
||||
public void INJECT_BITS_MSB(int bitdata, int nbits, BufferState state)
|
||||
{
|
||||
bit_buffer |= (uint)(bitdata << (BITBUF_WIDTH - nbits - bits_left));
|
||||
bits_left += nbits;
|
||||
state.BitBuffer |= (uint)(bitdata << (BITBUF_WIDTH - nbits - state.BitsLeft));
|
||||
state.BitsLeft += nbits;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -256,52 +232,43 @@ namespace LibMSPackSharp.Compression
|
||||
/// <summary>
|
||||
/// Takes N bits from the buffer and puts them in var
|
||||
/// </summary>
|
||||
public long READ_BITS_MSB(int nbits, ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left)
|
||||
public long READ_BITS_MSB(int nbits, BufferState state)
|
||||
{
|
||||
ENSURE_BITS(nbits, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
ENSURE_BITS(nbits, state);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return -1;
|
||||
|
||||
long temp = PEEK_BITS_MSB(nbits, bit_buffer);
|
||||
long temp = PEEK_BITS_MSB(nbits, state.BitBuffer);
|
||||
|
||||
REMOVE_BITS_MSB(nbits, ref bit_buffer, ref bits_left);
|
||||
state.REMOVE_BITS_MSB(nbits);
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read multiple bits and put them in var
|
||||
/// </summary>
|
||||
public long READ_MANY_BITS_MSB(int nbits, ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left)
|
||||
public long READ_MANY_BITS_MSB(int nbits, BufferState state)
|
||||
{
|
||||
byte needed = (byte)(nbits), bitrun;
|
||||
long temp = 0;
|
||||
while (needed > 0)
|
||||
{
|
||||
if (bits_left <= (BITBUF_WIDTH - 16))
|
||||
if (state.BitsLeft <= (BITBUF_WIDTH - 16))
|
||||
{
|
||||
READ_BYTES(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
READ_BYTES(state);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return -1;
|
||||
}
|
||||
|
||||
bitrun = (byte)((bits_left < needed) ? bits_left : needed);
|
||||
temp = (temp << bitrun) | PEEK_BITS_MSB(bitrun, bit_buffer);
|
||||
REMOVE_BITS_MSB(bitrun, ref bit_buffer, ref bits_left);
|
||||
bitrun = (byte)((state.BitsLeft < needed) ? state.BitsLeft : needed);
|
||||
temp = (temp << bitrun) | PEEK_BITS_MSB(bitrun, state.BitBuffer);
|
||||
state.REMOVE_BITS_MSB(bitrun);
|
||||
needed -= bitrun;
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes N bits from the bit buffer
|
||||
/// </summary>
|
||||
public void REMOVE_BITS_MSB(int nbits, ref uint bit_buffer, ref int bits_left)
|
||||
{
|
||||
bit_buffer <<= nbits;
|
||||
bits_left -= nbits;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LSB
|
||||
@@ -309,10 +276,10 @@ namespace LibMSPackSharp.Compression
|
||||
/// <summary>
|
||||
/// Inject data into the bit buffer
|
||||
/// </summary>
|
||||
public void INJECT_BITS_LSB(int bitdata, int nbits, ref uint bit_buffer, ref int bits_left)
|
||||
public void INJECT_BITS_LSB(int bitdata, int nbits, BufferState state)
|
||||
{
|
||||
bit_buffer |= (uint)(bitdata << bits_left);
|
||||
bits_left += nbits;
|
||||
state.BitBuffer |= (uint)(bitdata << state.BitsLeft);
|
||||
state.BitsLeft += nbits;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -323,47 +290,38 @@ namespace LibMSPackSharp.Compression
|
||||
/// <summary>
|
||||
/// Extracts without removing N bits from the bit buffer using a bit mask
|
||||
/// </summary>
|
||||
public long PEEK_BITS_T_LSB(int nbits, uint bit_buffer) => bit_buffer & lsb_bit_mask[(nbits)];
|
||||
public long PEEK_BITS_T_LSB(int nbits, uint bit_buffer) => bit_buffer & LSBBitMask[(nbits)];
|
||||
|
||||
/// <summary>
|
||||
/// Takes N bits from the buffer and puts them in var
|
||||
/// </summary>
|
||||
public long READ_BITS_LSB(int nbits, ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left)
|
||||
public long READ_BITS_LSB(int nbits, BufferState state)
|
||||
{
|
||||
ENSURE_BITS(nbits, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
ENSURE_BITS(nbits, state);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return -1;
|
||||
|
||||
long temp = PEEK_BITS_LSB(nbits, bit_buffer);
|
||||
long temp = PEEK_BITS_LSB(nbits, state.BitBuffer);
|
||||
|
||||
REMOVE_BITS_LSB(nbits, ref bit_buffer, ref bits_left);
|
||||
state.REMOVE_BITS_LSB(nbits);
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes N bits from the buffer and puts them in var using a bit mask
|
||||
/// </summary>
|
||||
public long READ_BITS_T_LSB(int nbits, ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left)
|
||||
public long READ_BITS_T_LSB(int nbits, BufferState state)
|
||||
{
|
||||
ENSURE_BITS(nbits, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
ENSURE_BITS(nbits, state);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return -1;
|
||||
|
||||
long temp = PEEK_BITS_T_LSB(nbits, bit_buffer);
|
||||
long temp = PEEK_BITS_T_LSB(nbits, state.BitBuffer);
|
||||
|
||||
REMOVE_BITS_LSB(nbits, ref bit_buffer, ref bits_left);
|
||||
state.REMOVE_BITS_LSB(nbits);
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes N bits from the bit buffer
|
||||
/// </summary>
|
||||
public void REMOVE_BITS_LSB(int nbits, ref uint bit_buffer, ref int bits_left)
|
||||
{
|
||||
bit_buffer >>= nbits;
|
||||
bits_left -= nbits;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
@@ -385,14 +343,14 @@ namespace LibMSPackSharp.Compression
|
||||
/// Decodes the next huffman symbol from the input bitstream into var.
|
||||
/// Do not use this macro on a table unless build_decode_table() succeeded.
|
||||
/// </summary>
|
||||
public long READ_HUFFSYM_MSB(ushort[] table, byte[] lengths, int tablebits, int maxsymbols, ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left)
|
||||
public long READ_HUFFSYM_MSB(ushort[] table, byte[] lengths, int tablebits, int maxsymbols, BufferState state)
|
||||
{
|
||||
ENSURE_BITS(HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
ushort sym = table[PEEK_BITS_MSB(tablebits, bit_buffer)];
|
||||
ENSURE_BITS(HUFF_MAXBITS, state);
|
||||
ushort sym = table[PEEK_BITS_MSB(tablebits, state.BitBuffer)];
|
||||
if (sym >= maxsymbols)
|
||||
HUFF_TRAVERSE_MSB(ref sym, table, tablebits, maxsymbols, bit_buffer);
|
||||
HUFF_TRAVERSE_MSB(ref sym, table, tablebits, maxsymbols, state.BitBuffer);
|
||||
|
||||
REMOVE_BITS_MSB(lengths[sym], ref bit_buffer, ref bits_left);
|
||||
state.REMOVE_BITS_MSB(lengths[sym]);
|
||||
return sym;
|
||||
}
|
||||
|
||||
@@ -523,14 +481,14 @@ namespace LibMSPackSharp.Compression
|
||||
/// Decodes the next huffman symbol from the input bitstream into var.
|
||||
/// Do not use this macro on a table unless build_decode_table() succeeded.
|
||||
/// </summary>
|
||||
public long READ_HUFFSYM_LSB(ushort[] table, byte[] lengths, int tablebits, int maxsymbols, ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left)
|
||||
public long READ_HUFFSYM_LSB(ushort[] table, byte[] lengths, int tablebits, int maxsymbols, BufferState state)
|
||||
{
|
||||
ENSURE_BITS(HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
ushort sym = table[PEEK_BITS_LSB(tablebits, bit_buffer)];
|
||||
ENSURE_BITS(HUFF_MAXBITS, state);
|
||||
ushort sym = table[PEEK_BITS_LSB(tablebits, state.BitBuffer)];
|
||||
if (sym >= maxsymbols)
|
||||
HUFF_TRAVERSE_LSB(ref sym, table, tablebits, maxsymbols, bit_buffer);
|
||||
HUFF_TRAVERSE_LSB(ref sym, table, tablebits, maxsymbols, state.BitBuffer);
|
||||
|
||||
REMOVE_BITS_LSB(lengths[sym], ref bit_buffer, ref bits_left);
|
||||
state.REMOVE_BITS_LSB(lengths[sym]);
|
||||
return sym;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,11 +11,282 @@ namespace LibMSPackSharp.Compression
|
||||
{
|
||||
internal static class Constants
|
||||
{
|
||||
/* lsb_bit_mask[n] = (1 << n) - 1 */
|
||||
internal static readonly ushort[] lsb_bit_mask = new ushort[17]
|
||||
#region readbits.h
|
||||
|
||||
/// <summary>
|
||||
/// Bit width of a UInt32 bit buffer
|
||||
/// </summary>
|
||||
public const int BITBUF_WIDTH = 4 * CHAR_BIT;
|
||||
|
||||
/// <summary>
|
||||
/// Number of bits in a character
|
||||
/// </summary>
|
||||
internal const int CHAR_BIT = 8;
|
||||
|
||||
// lsb_bit_mask[n] = (1 << n) - 1
|
||||
internal static readonly ushort[] LSBBitMask = new ushort[17]
|
||||
{
|
||||
0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
|
||||
0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#region readhuff.h
|
||||
|
||||
/// <summary>
|
||||
/// Maximum bits in a Huffman code
|
||||
/// </summary>
|
||||
public const int HUFF_MAXBITS = 16;
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZSS
|
||||
|
||||
/// <summary>
|
||||
/// Size of an LZSS window
|
||||
/// </summary>
|
||||
public const int LZSS_WINDOW_SIZE = 4096;
|
||||
|
||||
/// <summary>
|
||||
/// LZSS window fill byte
|
||||
/// </summary>
|
||||
public const byte LZSS_WINDOW_FILL = 0x20;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 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_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 byte LZX_PRETREE_TABLEBITS = 6;
|
||||
public const int LZX_MAINTREE_MAXSYMBOLS = LZX_NUM_CHARS + 290 * 8;
|
||||
public const byte LZX_MAINTREE_TABLEBITS = 12;
|
||||
public const int LZX_LENGTH_MAXSYMBOLS = LZX_NUM_SECONDARY_LENGTHS + 1;
|
||||
public const byte LZX_LENGTH_TABLEBITS = 12;
|
||||
public const int LZX_ALIGNED_MAXSYMBOLS = LZX_ALIGNED_NUM_ELEMENTS;
|
||||
public const byte 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
|
||||
|
||||
#region LZX static data tables
|
||||
|
||||
/* LZX static data tables:
|
||||
*
|
||||
* LZX uses 'position slots' to represent match offsets. For every match,
|
||||
* a small 'position slot' number and a small offset from that slot are
|
||||
* encoded instead of one large offset.
|
||||
*
|
||||
* The number of slots is decided by how many are needed to encode the
|
||||
* largest offset for a given window size. This is easy when the gap between
|
||||
* slots is less than 128Kb, it's a linear relationship. But when extra_bits
|
||||
* reaches its limit of 17 (because LZX can only ensure reading 17 bits of
|
||||
* data at a time), we can only jump 128Kb at a time and have to start
|
||||
* using more and more position slots as each window size doubles.
|
||||
*
|
||||
* position_base[] is an index to the position slot bases
|
||||
*
|
||||
* extra_bits[] states how many bits of offset-from-base data is needed.
|
||||
*
|
||||
* They are calculated as follows:
|
||||
* extra_bits[i] = 0 where i < 4
|
||||
* extra_bits[i] = floor(i/2)-1 where i >= 4 && i < 36
|
||||
* extra_bits[i] = 17 where i >= 36
|
||||
* position_base[0] = 0
|
||||
* position_base[i] = position_base[i-1] + (1 << extra_bits[i-1])
|
||||
*/
|
||||
|
||||
public static readonly uint[] LZXPositionSlots = new uint[11]
|
||||
{
|
||||
30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290
|
||||
};
|
||||
|
||||
public static readonly byte[] LZXExtraBits = new byte[36]
|
||||
{
|
||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
|
||||
9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16
|
||||
};
|
||||
|
||||
public static readonly uint[] LZXPositionBase = new uint[290]
|
||||
{
|
||||
0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512,
|
||||
768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768,
|
||||
49152, 65536, 98304, 131072, 196608, 262144, 393216, 524288, 655360,
|
||||
786432, 917504, 1048576, 1179648, 1310720, 1441792, 1572864, 1703936,
|
||||
1835008, 1966080, 2097152, 2228224, 2359296, 2490368, 2621440, 2752512,
|
||||
2883584, 3014656, 3145728, 3276800, 3407872, 3538944, 3670016, 3801088,
|
||||
3932160, 4063232, 4194304, 4325376, 4456448, 4587520, 4718592, 4849664,
|
||||
4980736, 5111808, 5242880, 5373952, 5505024, 5636096, 5767168, 5898240,
|
||||
6029312, 6160384, 6291456, 6422528, 6553600, 6684672, 6815744, 6946816,
|
||||
7077888, 7208960, 7340032, 7471104, 7602176, 7733248, 7864320, 7995392,
|
||||
8126464, 8257536, 8388608, 8519680, 8650752, 8781824, 8912896, 9043968,
|
||||
9175040, 9306112, 9437184, 9568256, 9699328, 9830400, 9961472, 10092544,
|
||||
10223616, 10354688, 10485760, 10616832, 10747904, 10878976, 11010048,
|
||||
11141120, 11272192, 11403264, 11534336, 11665408, 11796480, 11927552,
|
||||
12058624, 12189696, 12320768, 12451840, 12582912, 12713984, 12845056,
|
||||
12976128, 13107200, 13238272, 13369344, 13500416, 13631488, 13762560,
|
||||
13893632, 14024704, 14155776, 14286848, 14417920, 14548992, 14680064,
|
||||
14811136, 14942208, 15073280, 15204352, 15335424, 15466496, 15597568,
|
||||
15728640, 15859712, 15990784, 16121856, 16252928, 16384000, 16515072,
|
||||
16646144, 16777216, 16908288, 17039360, 17170432, 17301504, 17432576,
|
||||
17563648, 17694720, 17825792, 17956864, 18087936, 18219008, 18350080,
|
||||
18481152, 18612224, 18743296, 18874368, 19005440, 19136512, 19267584,
|
||||
19398656, 19529728, 19660800, 19791872, 19922944, 20054016, 20185088,
|
||||
20316160, 20447232, 20578304, 20709376, 20840448, 20971520, 21102592,
|
||||
21233664, 21364736, 21495808, 21626880, 21757952, 21889024, 22020096,
|
||||
22151168, 22282240, 22413312, 22544384, 22675456, 22806528, 22937600,
|
||||
23068672, 23199744, 23330816, 23461888, 23592960, 23724032, 23855104,
|
||||
23986176, 24117248, 24248320, 24379392, 24510464, 24641536, 24772608,
|
||||
24903680, 25034752, 25165824, 25296896, 25427968, 25559040, 25690112,
|
||||
25821184, 25952256, 26083328, 26214400, 26345472, 26476544, 26607616,
|
||||
26738688, 26869760, 27000832, 27131904, 27262976, 27394048, 27525120,
|
||||
27656192, 27787264, 27918336, 28049408, 28180480, 28311552, 28442624,
|
||||
28573696, 28704768, 28835840, 28966912, 29097984, 29229056, 29360128,
|
||||
29491200, 29622272, 29753344, 29884416, 30015488, 30146560, 30277632,
|
||||
30408704, 30539776, 30670848, 30801920, 30932992, 31064064, 31195136,
|
||||
31326208, 31457280, 31588352, 31719424, 31850496, 31981568, 32112640,
|
||||
32243712, 32374784, 32505856, 32636928, 32768000, 32899072, 33030144,
|
||||
33161216, 33292288, 33423360
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region MSZIP
|
||||
|
||||
public const int MSZIP_FRAME_SIZE = 32768; // Size of LZ history window
|
||||
public const int MSZIP_LITERAL_MAXSYMBOLS = 288; // literal/length huffman tree
|
||||
public const int MSZIP_LITERAL_TABLEBITS = 9;
|
||||
public const int MSZIP_DISTANCE_MAXSYMBOLS = 32; // Distance huffman tree
|
||||
public const int MSZIP_DISTANCE_TABLEBITS = 6;
|
||||
|
||||
// If there are less direct lookup entries than symbols, the longer
|
||||
// code pointers will be <= maxsymbols. This must not happen, or we
|
||||
// will decode entries badly
|
||||
|
||||
//public const int MSZIP_LITERAL_TABLESIZE = (MSZIP_LITERAL_MAXSYMBOLS * 4);
|
||||
public const int MSZIP_LITERAL_TABLESIZE = ((1 << MSZIP_LITERAL_TABLEBITS) + (MSZIP_LITERAL_MAXSYMBOLS * 2));
|
||||
|
||||
//public const int MSZIP_DISTANCE_TABLESIZE = (MSZIP_DISTANCE_MAXSYMBOLS * 4);
|
||||
public const int MSZIP_DISTANCE_TABLESIZE = ((1 << MSZIP_DISTANCE_TABLEBITS) + (MSZIP_DISTANCE_MAXSYMBOLS * 2));
|
||||
|
||||
/// <summary>
|
||||
/// Match lengths for literal codes 257.. 285
|
||||
/// </summary>
|
||||
public static readonly ushort[] LiteralLengths = new ushort[29]
|
||||
{
|
||||
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27,
|
||||
31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Match offsets for distance codes 0 .. 29
|
||||
/// </summary>
|
||||
public static readonly ushort[] DistanceOffsets = new ushort[30]
|
||||
{
|
||||
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385,
|
||||
513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Extra bits required for literal codes 257.. 285
|
||||
/// </summary>
|
||||
public static readonly byte[] LiteralExtraBits = new byte[29]
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2,
|
||||
2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Extra bits required for distance codes 0 .. 29
|
||||
/// </summary>
|
||||
public static readonly byte[] DistanceExtraBits = new byte[30]
|
||||
{
|
||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6,
|
||||
6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The order of the bit length Huffman code lengths
|
||||
/// </summary>
|
||||
public static readonly byte[] BitLengthOrder = new byte[19]
|
||||
{
|
||||
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#region QTM
|
||||
|
||||
public const int QTM_FRAME_SIZE = 32768;
|
||||
|
||||
/* Quantum static data tables:
|
||||
*
|
||||
* Quantum uses 'position slots' to represent match offsets. For every
|
||||
* match, a small 'position slot' number and a small offset from that slot
|
||||
* are encoded instead of one large offset.
|
||||
*
|
||||
* position_base[] is an index to the position slot bases
|
||||
*
|
||||
* extra_bits[] states how many bits of offset-from-base data is needed.
|
||||
*
|
||||
* length_base[] and length_extra[] are equivalent in function, but are
|
||||
* used for encoding selector 6 (variable length match) match lengths,
|
||||
* instead of match offsets.
|
||||
*
|
||||
* They are generated with the following code:
|
||||
* uint i, offset;
|
||||
* for (i = 0, offset = 0; i < 42; i++) {
|
||||
* position_base[i] = offset;
|
||||
* extra_bits[i] = ((i < 2) ? 0 : (i - 2)) >> 1;
|
||||
* offset += 1 << extra_bits[i];
|
||||
* }
|
||||
* for (i = 0, offset = 0; i < 26; i++) {
|
||||
* length_base[i] = offset;
|
||||
* length_extra[i] = (i < 2 ? 0 : i - 2) >> 2;
|
||||
* offset += 1 << length_extra[i];
|
||||
* }
|
||||
* length_base[26] = 254; length_extra[26] = 0;
|
||||
*/
|
||||
|
||||
public static readonly uint[] QTMPositionBase = new uint[42]
|
||||
{
|
||||
0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
|
||||
1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152,
|
||||
65536, 98304, 131072, 196608, 262144, 393216, 524288, 786432, 1048576, 1572864
|
||||
};
|
||||
|
||||
public static readonly byte[] QTMExtraBits = new byte[42]
|
||||
{
|
||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
|
||||
11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19
|
||||
};
|
||||
|
||||
public static readonly byte[] QTMLengthBase = new byte[27]
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 14, 18, 22, 26,
|
||||
30, 38, 46, 54, 62, 78, 94, 110, 126, 158, 190, 222, 254
|
||||
};
|
||||
|
||||
public static readonly byte[] QTMLengthExtra = new byte[27]
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
|
||||
};
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
using System.IO;
|
||||
using static LibMSPackSharp.Constants;
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
@@ -47,39 +48,39 @@ namespace LibMSPackSharp.Compression
|
||||
|
||||
// Reset global state
|
||||
lzh.INIT_BITS();
|
||||
lzh.RESTORE_BITS(out int i_ptr, out int i_end, out uint bit_buffer, out int bits_left);
|
||||
BufferState state = lzh.RESTORE_BITS();
|
||||
|
||||
for (i = 0; i < LZSS.LZSS_WINDOW_SIZE; i++)
|
||||
for (i = 0; i < LZSS_WINDOW_SIZE; i++)
|
||||
{
|
||||
lzh.Window[i] = LZSS.LZSS_WINDOW_FILL;
|
||||
lzh.Window[i] = LZSS_WINDOW_FILL;
|
||||
}
|
||||
|
||||
// Read 6 encoding types (for byte alignment) but only 5 are needed
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
types[i] = (uint)lzh.READ_BITS_SAFE(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
types[i] = (uint)lzh.READ_BITS_SAFE(4, state);
|
||||
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
// Read huffman table symbol lengths and build huffman trees
|
||||
BUILD_TREE(lzh, types[0], lzh.MATCHLEN1_table, lzh.MATCHLEN1_len, KWAJ_TABLEBITS, KWAJ_MATCHLEN1_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
BUILD_TREE(lzh, types[1], lzh.MATCHLEN2_table, lzh.MATCHLEN2_len, KWAJ_TABLEBITS, KWAJ_MATCHLEN2_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
BUILD_TREE(lzh, types[2], lzh.LITLEN_table, lzh.LITLEN_len, KWAJ_TABLEBITS, KWAJ_LITLEN_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
BUILD_TREE(lzh, types[3], lzh.OFFSET_table, lzh.OFFSET_len, KWAJ_TABLEBITS, KWAJ_OFFSET_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
BUILD_TREE(lzh, types[4], lzh.LITERAL_table, lzh.LITERAL_len, KWAJ_TABLEBITS, KWAJ_LITERAL_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
BUILD_TREE(lzh, types[0], lzh.MATCHLEN1_table, lzh.MATCHLEN1_len, KWAJ_TABLEBITS, KWAJ_MATCHLEN1_SYMS, state);
|
||||
BUILD_TREE(lzh, types[1], lzh.MATCHLEN2_table, lzh.MATCHLEN2_len, KWAJ_TABLEBITS, KWAJ_MATCHLEN2_SYMS, state);
|
||||
BUILD_TREE(lzh, types[2], lzh.LITLEN_table, lzh.LITLEN_len, KWAJ_TABLEBITS, KWAJ_LITLEN_SYMS, state);
|
||||
BUILD_TREE(lzh, types[3], lzh.OFFSET_table, lzh.OFFSET_len, KWAJ_TABLEBITS, KWAJ_OFFSET_SYMS, state);
|
||||
BUILD_TREE(lzh, types[4], lzh.LITERAL_table, lzh.LITERAL_len, KWAJ_TABLEBITS, KWAJ_LITERAL_SYMS, state);
|
||||
|
||||
while (lzh.EndOfInput == 0)
|
||||
{
|
||||
if (lit_run != 0)
|
||||
{
|
||||
len = (int)lzh.READ_HUFFSYM_SAFE(lzh.MATCHLEN2_table, lzh.MATCHLEN2_len, KWAJ_MATCHLEN2_TBLSIZE, KWAJ_MATCHLEN2_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
len = (int)lzh.READ_HUFFSYM_SAFE(lzh.MATCHLEN2_table, lzh.MATCHLEN2_len, KWAJ_MATCHLEN2_TBLSIZE, KWAJ_MATCHLEN2_SYMS, state);
|
||||
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = (int)lzh.READ_HUFFSYM_SAFE(lzh.MATCHLEN1_table, lzh.MATCHLEN1_len, KWAJ_MATCHLEN1_TBLSIZE, KWAJ_MATCHLEN1_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
len = (int)lzh.READ_HUFFSYM_SAFE(lzh.MATCHLEN1_table, lzh.MATCHLEN1_len, KWAJ_MATCHLEN1_TBLSIZE, KWAJ_MATCHLEN1_SYMS, state);
|
||||
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
@@ -89,13 +90,13 @@ namespace LibMSPackSharp.Compression
|
||||
len += 2;
|
||||
lit_run = 0; // Not the end of a literal run
|
||||
|
||||
j = (int)lzh.READ_HUFFSYM_SAFE(lzh.OFFSET_table, lzh.OFFSET_len, KWAJ_OFFSET_TBLSIZE, KWAJ_OFFSET_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
j = (int)lzh.READ_HUFFSYM_SAFE(lzh.OFFSET_table, lzh.OFFSET_len, KWAJ_OFFSET_TBLSIZE, KWAJ_OFFSET_SYMS, state);
|
||||
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
offset = j << 6;
|
||||
|
||||
j = (int)lzh.READ_BITS_SAFE(6, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
j = (int)lzh.READ_BITS_SAFE(6, state);
|
||||
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
@@ -115,7 +116,7 @@ namespace LibMSPackSharp.Compression
|
||||
}
|
||||
else
|
||||
{
|
||||
len = (int)lzh.READ_HUFFSYM_SAFE(lzh.LITLEN_table, lzh.LITLEN_len, KWAJ_LITLEN_TBLSIZE, KWAJ_LITLEN_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
len = (int)lzh.READ_HUFFSYM_SAFE(lzh.LITLEN_table, lzh.LITLEN_len, KWAJ_LITLEN_TBLSIZE, KWAJ_LITLEN_SYMS, state);
|
||||
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
@@ -123,7 +124,7 @@ namespace LibMSPackSharp.Compression
|
||||
lit_run = (len == 32) ? 0 : 1; // End of a literal run?
|
||||
while (len-- > 0)
|
||||
{
|
||||
j = (int)lzh.READ_HUFFSYM_SAFE(lzh.LITERAL_table, lzh.LITERAL_len, KWAJ_LITERAL_TBLSIZE, KWAJ_LITERAL_SYMS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
j = (int)lzh.READ_HUFFSYM_SAFE(lzh.LITERAL_table, lzh.LITERAL_len, KWAJ_LITERAL_TBLSIZE, KWAJ_LITERAL_SYMS, state);
|
||||
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
@@ -142,15 +143,19 @@ namespace LibMSPackSharp.Compression
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
private static Error BUILD_TREE(LZHKWAJStream lzh, uint type, ushort[] table, byte[] lengths, int tablebits, int maxsymbols, ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left)
|
||||
private static Error BUILD_TREE(LZHKWAJStream lzh, uint type, ushort[] table, byte[] lengths, int tablebits, int maxsymbols, BufferState state)
|
||||
{
|
||||
lzh.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
|
||||
lzh.STORE_BITS(state);
|
||||
|
||||
Error err = ReadLens(lzh, type, (uint)maxsymbols, lzh.MATCHLEN1_len);
|
||||
if (err != Error.MSPACK_ERR_OK)
|
||||
return err;
|
||||
|
||||
lzh.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left);
|
||||
BufferState temp = lzh.RESTORE_BITS();
|
||||
state.InputPointer = temp.InputPointer;
|
||||
state.InputEnd = temp.InputEnd;
|
||||
state.BitBuffer = temp.BitBuffer;
|
||||
state.BitsLeft = temp.BitsLeft;
|
||||
|
||||
if (!CompressionStream.MakeDecodeTableMSB(maxsymbols, tablebits, lengths, table))
|
||||
return Error.MSPACK_ERR_DATAFORMAT;
|
||||
@@ -162,7 +167,7 @@ namespace LibMSPackSharp.Compression
|
||||
{
|
||||
uint i, c, sel;
|
||||
|
||||
lzh.RESTORE_BITS(out int i_ptr, out int i_end, out uint bit_buffer, out int bits_left);
|
||||
BufferState state = lzh.RESTORE_BITS();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
@@ -177,14 +182,14 @@ namespace LibMSPackSharp.Compression
|
||||
break;
|
||||
|
||||
case 1:
|
||||
c = (uint)lzh.READ_BITS_SAFE(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
c = (uint)lzh.READ_BITS_SAFE(4, state);
|
||||
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
lens[0] = (byte)c;
|
||||
for (i = 1; i < numsyms; i++)
|
||||
{
|
||||
sel = (uint)lzh.READ_BITS_SAFE(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
sel = (uint)lzh.READ_BITS_SAFE(1, state);
|
||||
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
@@ -194,7 +199,7 @@ namespace LibMSPackSharp.Compression
|
||||
}
|
||||
else
|
||||
{
|
||||
sel = (uint)lzh.READ_BITS_SAFE(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
sel = (uint)lzh.READ_BITS_SAFE(1, state);
|
||||
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
@@ -204,7 +209,7 @@ namespace LibMSPackSharp.Compression
|
||||
}
|
||||
else
|
||||
{
|
||||
c = (uint)lzh.READ_BITS_SAFE(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
c = (uint)lzh.READ_BITS_SAFE(4, state);
|
||||
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
@@ -216,20 +221,20 @@ namespace LibMSPackSharp.Compression
|
||||
break;
|
||||
|
||||
case 2:
|
||||
c = (uint)lzh.READ_BITS_SAFE(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
c = (uint)lzh.READ_BITS_SAFE(4, state);
|
||||
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
lens[0] = (byte)c;
|
||||
for (i = 1; i < numsyms; i++)
|
||||
{
|
||||
sel = (uint)lzh.READ_BITS_SAFE(2, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
sel = (uint)lzh.READ_BITS_SAFE(2, state);
|
||||
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
if (sel == 3)
|
||||
{
|
||||
c = (uint)lzh.READ_BITS_SAFE(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
c = (uint)lzh.READ_BITS_SAFE(4, state);
|
||||
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
@@ -246,7 +251,7 @@ namespace LibMSPackSharp.Compression
|
||||
case 3:
|
||||
for (i = 0; i < numsyms; i++)
|
||||
{
|
||||
c = (uint)lzh.READ_BITS_SAFE(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
c = (uint)lzh.READ_BITS_SAFE(4, state);
|
||||
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
@@ -256,7 +261,7 @@ namespace LibMSPackSharp.Compression
|
||||
break;
|
||||
}
|
||||
|
||||
lzh.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
|
||||
lzh.STORE_BITS(state);
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
using static LibMSPackSharp.Constants;
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
@@ -33,7 +34,7 @@ namespace LibMSPackSharp.Compression
|
||||
|
||||
// History window
|
||||
|
||||
public byte[] Window { get; set; } = new byte[LZSS.LZSS_WINDOW_SIZE];
|
||||
public byte[] Window { get; set; } = new byte[LZSS_WINDOW_SIZE];
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -53,10 +54,10 @@ namespace LibMSPackSharp.Compression
|
||||
/// <summary>
|
||||
/// Safely read bits from the buffer
|
||||
/// </summary>
|
||||
public long READ_BITS_SAFE(int nbits, ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left)
|
||||
public long READ_BITS_SAFE(int nbits, BufferState state)
|
||||
{
|
||||
long val = READ_BITS_MSB(nbits, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
if (EndOfInput != 0 && BitsLeft < EndOfInput)
|
||||
long val = READ_BITS_MSB(nbits, state);
|
||||
if (EndOfInput != 0 && BufferState.BitsLeft < EndOfInput)
|
||||
Error = Error.MSPACK_ERR_NOMEMORY;
|
||||
else
|
||||
Error = Error.MSPACK_ERR_OK;
|
||||
@@ -67,10 +68,10 @@ namespace LibMSPackSharp.Compression
|
||||
/// <summary>
|
||||
/// Safely read a symbol from a Huffman tree
|
||||
/// </summary>
|
||||
public long READ_HUFFSYM_SAFE(ushort[] table, byte[] lengths, int tablebits, int maxsymbols, ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left)
|
||||
public long READ_HUFFSYM_SAFE(ushort[] table, byte[] lengths, int tablebits, int maxsymbols, BufferState state)
|
||||
{
|
||||
long val = READ_HUFFSYM_MSB(table, lengths, tablebits, maxsymbols, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
if (EndOfInput != 0 && BitsLeft < EndOfInput)
|
||||
long val = READ_HUFFSYM_MSB(table, lengths, tablebits, maxsymbols, state);
|
||||
if (EndOfInput != 0 && BufferState.BitsLeft < EndOfInput)
|
||||
Error = Error.MSPACK_ERR_NOMEMORY;
|
||||
else
|
||||
Error = Error.MSPACK_ERR_OK;
|
||||
@@ -93,19 +94,19 @@ namespace LibMSPackSharp.Compression
|
||||
public override Error HUFF_ERROR() => Error.MSPACK_ERR_DATAFORMAT;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void READ_BYTES(ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left)
|
||||
public override void READ_BYTES(BufferState state)
|
||||
{
|
||||
if (i_ptr >= i_end)
|
||||
if (state.InputPointer >= state.InputEnd)
|
||||
{
|
||||
ReadInput();
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return;
|
||||
|
||||
i_ptr = InputPointer;
|
||||
i_end = InputEnd;
|
||||
state.InputPointer = BufferState.InputPointer;
|
||||
state.InputEnd = BufferState.InputEnd;
|
||||
}
|
||||
|
||||
INJECT_BITS_MSB(InputBuffer[i_ptr++], 8, ref bit_buffer, ref bits_left);
|
||||
INJECT_BITS_MSB(InputBuffer[state.InputPointer++], 8, state);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -129,15 +130,15 @@ namespace LibMSPackSharp.Compression
|
||||
|
||||
if (read == 0)
|
||||
{
|
||||
InputEnd = 8;
|
||||
BufferState.InputEnd = 8;
|
||||
InputBuffer[0] = 0;
|
||||
read = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Update InputPointer and InputLength
|
||||
InputPointer = 0;
|
||||
InputEnd = read;
|
||||
BufferState.InputPointer = 0;
|
||||
BufferState.InputEnd = read;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,12 @@
|
||||
*/
|
||||
|
||||
using System.IO;
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public class LZSS
|
||||
{
|
||||
#region LZSS compression / decompression definitions
|
||||
|
||||
public const int LZSS_WINDOW_SIZE = 4096;
|
||||
public const byte LZSS_WINDOW_FILL = 0x20;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Decompresses an LZSS stream.
|
||||
///
|
||||
|
||||
799
BurnOutSharp/External/libmspack/Compression/LZX.cs
vendored
799
BurnOutSharp/External/libmspack/Compression/LZX.cs
vendored
@@ -76,142 +76,12 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public class LZX
|
||||
{
|
||||
#region LZX compression / decompression definitions
|
||||
|
||||
// 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_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 byte LZX_PRETREE_TABLEBITS = 6;
|
||||
public const int LZX_MAINTREE_MAXSYMBOLS = LZX_NUM_CHARS + 290 * 8;
|
||||
public const byte LZX_MAINTREE_TABLEBITS = 12;
|
||||
public const int LZX_LENGTH_MAXSYMBOLS = LZX_NUM_SECONDARY_LENGTHS + 1;
|
||||
public const byte LZX_LENGTH_TABLEBITS = 12;
|
||||
public const int LZX_ALIGNED_MAXSYMBOLS = LZX_ALIGNED_NUM_ELEMENTS;
|
||||
public const byte 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
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZX static data tables
|
||||
|
||||
/* LZX static data tables:
|
||||
*
|
||||
* LZX uses 'position slots' to represent match offsets. For every match,
|
||||
* a small 'position slot' number and a small offset from that slot are
|
||||
* encoded instead of one large offset.
|
||||
*
|
||||
* The number of slots is decided by how many are needed to encode the
|
||||
* largest offset for a given window size. This is easy when the gap between
|
||||
* slots is less than 128Kb, it's a linear relationship. But when extra_bits
|
||||
* reaches its limit of 17 (because LZX can only ensure reading 17 bits of
|
||||
* data at a time), we can only jump 128Kb at a time and have to start
|
||||
* using more and more position slots as each window size doubles.
|
||||
*
|
||||
* position_base[] is an index to the position slot bases
|
||||
*
|
||||
* extra_bits[] states how many bits of offset-from-base data is needed.
|
||||
*
|
||||
* They are calculated as follows:
|
||||
* extra_bits[i] = 0 where i < 4
|
||||
* extra_bits[i] = floor(i/2)-1 where i >= 4 && i < 36
|
||||
* extra_bits[i] = 17 where i >= 36
|
||||
* position_base[0] = 0
|
||||
* position_base[i] = position_base[i-1] + (1 << extra_bits[i-1])
|
||||
*/
|
||||
|
||||
private static readonly uint[] position_slots = new uint[11]
|
||||
{
|
||||
30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290
|
||||
};
|
||||
|
||||
private static readonly byte[] extra_bits = new byte[36]
|
||||
{
|
||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
|
||||
9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16
|
||||
};
|
||||
|
||||
private static readonly uint[] position_base = new uint[290]
|
||||
{
|
||||
0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512,
|
||||
768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768,
|
||||
49152, 65536, 98304, 131072, 196608, 262144, 393216, 524288, 655360,
|
||||
786432, 917504, 1048576, 1179648, 1310720, 1441792, 1572864, 1703936,
|
||||
1835008, 1966080, 2097152, 2228224, 2359296, 2490368, 2621440, 2752512,
|
||||
2883584, 3014656, 3145728, 3276800, 3407872, 3538944, 3670016, 3801088,
|
||||
3932160, 4063232, 4194304, 4325376, 4456448, 4587520, 4718592, 4849664,
|
||||
4980736, 5111808, 5242880, 5373952, 5505024, 5636096, 5767168, 5898240,
|
||||
6029312, 6160384, 6291456, 6422528, 6553600, 6684672, 6815744, 6946816,
|
||||
7077888, 7208960, 7340032, 7471104, 7602176, 7733248, 7864320, 7995392,
|
||||
8126464, 8257536, 8388608, 8519680, 8650752, 8781824, 8912896, 9043968,
|
||||
9175040, 9306112, 9437184, 9568256, 9699328, 9830400, 9961472, 10092544,
|
||||
10223616, 10354688, 10485760, 10616832, 10747904, 10878976, 11010048,
|
||||
11141120, 11272192, 11403264, 11534336, 11665408, 11796480, 11927552,
|
||||
12058624, 12189696, 12320768, 12451840, 12582912, 12713984, 12845056,
|
||||
12976128, 13107200, 13238272, 13369344, 13500416, 13631488, 13762560,
|
||||
13893632, 14024704, 14155776, 14286848, 14417920, 14548992, 14680064,
|
||||
14811136, 14942208, 15073280, 15204352, 15335424, 15466496, 15597568,
|
||||
15728640, 15859712, 15990784, 16121856, 16252928, 16384000, 16515072,
|
||||
16646144, 16777216, 16908288, 17039360, 17170432, 17301504, 17432576,
|
||||
17563648, 17694720, 17825792, 17956864, 18087936, 18219008, 18350080,
|
||||
18481152, 18612224, 18743296, 18874368, 19005440, 19136512, 19267584,
|
||||
19398656, 19529728, 19660800, 19791872, 19922944, 20054016, 20185088,
|
||||
20316160, 20447232, 20578304, 20709376, 20840448, 20971520, 21102592,
|
||||
21233664, 21364736, 21495808, 21626880, 21757952, 21889024, 22020096,
|
||||
22151168, 22282240, 22413312, 22544384, 22675456, 22806528, 22937600,
|
||||
23068672, 23199744, 23330816, 23461888, 23592960, 23724032, 23855104,
|
||||
23986176, 24117248, 24248320, 24379392, 24510464, 24641536, 24772608,
|
||||
24903680, 25034752, 25165824, 25296896, 25427968, 25559040, 25690112,
|
||||
25821184, 25952256, 26083328, 26214400, 26345472, 26476544, 26607616,
|
||||
26738688, 26869760, 27000832, 27131904, 27262976, 27394048, 27525120,
|
||||
27656192, 27787264, 27918336, 28049408, 28180480, 28311552, 28442624,
|
||||
28573696, 28704768, 28835840, 28966912, 29097984, 29229056, 29360128,
|
||||
29491200, 29622272, 29753344, 29884416, 30015488, 30146560, 30277632,
|
||||
30408704, 30539776, 30670848, 30801920, 30932992, 31064064, 31195136,
|
||||
31326208, 31457280, 31588352, 31719424, 31850496, 31981568, 32112640,
|
||||
32243712, 32374784, 32505856, 32636928, 32768000, 32899072, 33030144,
|
||||
33161216, 33292288, 33423360
|
||||
};
|
||||
|
||||
private static void ResetState(LZXDStream lzx)
|
||||
{
|
||||
lzx.R0 = 1;
|
||||
lzx.R1 = 1;
|
||||
lzx.R2 = 1;
|
||||
lzx.HeaderRead = 0;
|
||||
lzx.BlockRemaining = 0;
|
||||
lzx.BlockType = LZXBlockType.LZX_BLOCKTYPE_INVALID0;
|
||||
|
||||
// Initialise tables to 0 (because deltas will be applied to them)
|
||||
for (int i = 0; i < LZX_MAINTREE_MAXSYMBOLS; i++)
|
||||
{
|
||||
lzx.MAINTREE_len[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++)
|
||||
{
|
||||
lzx.LENGTH_len[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Allocates and initialises LZX decompression state for decoding an LZX
|
||||
/// stream.
|
||||
@@ -268,9 +138,6 @@ namespace LibMSPackSharp.Compression
|
||||
/// </returns>
|
||||
public static LZXDStream Init(SystemImpl system, FileStream input, FileStream output, int window_bits, int reset_interval, int input_buffer_size, long output_length, bool is_delta)
|
||||
{
|
||||
uint window_size = (uint)(1 << window_bits);
|
||||
LZXDStream lzx;
|
||||
|
||||
if (system == null)
|
||||
return null;
|
||||
|
||||
@@ -299,10 +166,10 @@ namespace LibMSPackSharp.Compression
|
||||
return null;
|
||||
|
||||
// Allocate decompression state
|
||||
lzx = new LZXDStream()
|
||||
LZXDStream lzx = new LZXDStream()
|
||||
{
|
||||
// Allocate decompression window and input buffer
|
||||
Window = new byte[window_size],
|
||||
Window = new byte[1 << window_bits],
|
||||
InputBuffer = new byte[input_buffer_size],
|
||||
|
||||
System = system,
|
||||
@@ -321,15 +188,15 @@ namespace LibMSPackSharp.Compression
|
||||
IntelFileSize = 0,
|
||||
IntelStarted = false,
|
||||
Error = Error.MSPACK_ERR_OK,
|
||||
NumOffsets = position_slots[window_bits - 15] << 3,
|
||||
NumOffsets = LZXPositionSlots[window_bits - 15] << 3,
|
||||
IsDelta = is_delta,
|
||||
|
||||
// e8_buf
|
||||
OutputPointer = 0,
|
||||
OutputEnd = 0,
|
||||
OutputIsE8 = true,
|
||||
};
|
||||
|
||||
ResetState(lzx);
|
||||
lzx.ResetState();
|
||||
lzx.INIT_BITS();
|
||||
|
||||
return lzx;
|
||||
@@ -351,7 +218,7 @@ namespace LibMSPackSharp.Compression
|
||||
/// 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>
|
||||
/// <returns>An error code, or MSPACK_ERR_OK if successful</returns>
|
||||
public static Error SetReferenceData(LZXDStream lzx, SystemImpl system, FileStream input, uint length)
|
||||
{
|
||||
if (lzx == null)
|
||||
@@ -397,7 +264,7 @@ namespace LibMSPackSharp.Compression
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
// See description of outputLength in lzxd_init()
|
||||
// See description of outputLength in Init()
|
||||
public static void SetOutputLength(LZXDStream lzx, long outputLength)
|
||||
{
|
||||
if (lzx != null && outputLength > 0)
|
||||
@@ -435,12 +302,8 @@ namespace LibMSPackSharp.Compression
|
||||
if (lzx == null)
|
||||
return Error.MSPACK_ERR_ARGS;
|
||||
|
||||
int match_length, length_footer, extra, verbatim_bits, bytes_todo;
|
||||
int this_run, main_element, aligned_bits, j, warned = 0;
|
||||
byte[] window, buf = new byte[12];
|
||||
int runsrc, rundest;
|
||||
uint frame_size, end_frame, match_offset, window_posn;
|
||||
uint R0, R1, R2;
|
||||
int warned = 0;
|
||||
byte[] buf = new byte[12];
|
||||
|
||||
// Easy answers
|
||||
if (lzx == null || (out_bytes < 0))
|
||||
@@ -450,32 +313,30 @@ namespace LibMSPackSharp.Compression
|
||||
return lzx.Error;
|
||||
|
||||
// Flush out any stored-up bytes before we begin
|
||||
int i = lzx.OutputEnd - lzx.OutputPointer;
|
||||
if (i > out_bytes)
|
||||
i = (int)out_bytes;
|
||||
int leftover_bytes = lzx.OutputEnd - lzx.OutputPointer;
|
||||
if (leftover_bytes > out_bytes)
|
||||
leftover_bytes = (int)out_bytes;
|
||||
|
||||
if (i != 0)
|
||||
if (leftover_bytes != 0)
|
||||
{
|
||||
try { lzx.System.Write(lzx.OutputFileHandle, lzx.e8_buf, lzx.OutputPointer, i); }
|
||||
try { lzx.System.Write(lzx.OutputFileHandle, lzx.OutputIsE8 ? lzx.E8Buffer : lzx.Window, lzx.OutputPointer, leftover_bytes); }
|
||||
catch { return lzx.Error = Error.MSPACK_ERR_WRITE; }
|
||||
|
||||
lzx.OutputPointer += i;
|
||||
lzx.Offset += i;
|
||||
out_bytes -= i;
|
||||
lzx.OutputPointer += leftover_bytes;
|
||||
lzx.Offset += leftover_bytes;
|
||||
out_bytes -= leftover_bytes;
|
||||
}
|
||||
|
||||
if (out_bytes == 0)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
// Restore local state
|
||||
lzx.RESTORE_BITS(out int i_ptr, out int i_end, out uint bit_buffer, out int bits_left);
|
||||
window = lzx.Window;
|
||||
window_posn = lzx.WindowPosition;
|
||||
R0 = lzx.R0;
|
||||
R1 = lzx.R1;
|
||||
R2 = lzx.R2;
|
||||
BufferState state = lzx.RESTORE_BITS();
|
||||
byte[] window = lzx.Window;
|
||||
int window_posn = lzx.WindowPosition;
|
||||
uint[] R = lzx.R;
|
||||
|
||||
end_frame = (uint)((lzx.Offset + out_bytes) / LZX_FRAME_SIZE) + 1;
|
||||
uint end_frame = (uint)((lzx.Offset + out_bytes) / LZX_FRAME_SIZE) + 1;
|
||||
|
||||
while (lzx.Frame < end_frame)
|
||||
{
|
||||
@@ -494,410 +355,93 @@ namespace LibMSPackSharp.Compression
|
||||
}
|
||||
|
||||
// Re-read the intel header and reset the huffman lengths
|
||||
ResetState(lzx);
|
||||
R0 = lzx.R0;
|
||||
R1 = lzx.R1;
|
||||
R2 = lzx.R2;
|
||||
lzx.ResetState();
|
||||
R = lzx.R;
|
||||
}
|
||||
|
||||
// LZX DELTA format has chunk_size, not present in LZX format
|
||||
if (lzx.IsDelta)
|
||||
{
|
||||
lzx.ENSURE_BITS(16, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
lzx.REMOVE_BITS_MSB(16, ref bit_buffer, ref bits_left);
|
||||
lzx.ENSURE_BITS(16, state);
|
||||
state.REMOVE_BITS_MSB(16);
|
||||
}
|
||||
|
||||
//// Read header if necessary
|
||||
//if (lzx.HeaderRead == 0)
|
||||
//{
|
||||
// // Read 1 bit. If bit=0, intel_filesize = 0.
|
||||
// // If bit=1, read intel filesize (32 bits)
|
||||
// int j = 0;
|
||||
// int i = (int)lzx.READ_BITS_MSB(1, state);
|
||||
|
||||
// if (i != 0)
|
||||
// {
|
||||
// i = (int)lzx.READ_BITS_MSB(16, state);
|
||||
// j = (int)lzx.READ_BITS_MSB(16, state);
|
||||
// }
|
||||
|
||||
// lzx.IntelFileSize = (i << 16) | j;
|
||||
// lzx.HeaderRead = 1;
|
||||
//}
|
||||
|
||||
// Calculate size of frame: all frames are 32k except the final frame
|
||||
// which is 32kb or less. this can only be calculated when lzx.Length
|
||||
// has been filled in.
|
||||
frame_size = LZX_FRAME_SIZE;
|
||||
uint frame_size = LZX_FRAME_SIZE;
|
||||
if (lzx.Length != 0 && (lzx.Length - lzx.Offset) < frame_size)
|
||||
frame_size = (uint)(lzx.Length - lzx.Offset);
|
||||
|
||||
// Decode until one more frame is available
|
||||
bytes_todo = (int)(lzx.FramePosition + frame_size - window_posn);
|
||||
int bytes_todo = (int)(lzx.FramePosition + frame_size - window_posn);
|
||||
while (bytes_todo > 0)
|
||||
{
|
||||
// Initialise new block, if one is needed
|
||||
if (lzx.BlockRemaining == 0)
|
||||
// Realign if previous block was an odd-sized UNCOMPRESSED block
|
||||
if ((lzx.BlockType == LZXBlockType.LZX_BLOCKTYPE_UNCOMPRESSED) && (lzx.BlockLength & 1) != 0)
|
||||
{
|
||||
// Realign if previous block was an odd-sized UNCOMPRESSED block
|
||||
if ((lzx.BlockType == LZXBlockType.LZX_BLOCKTYPE_UNCOMPRESSED) && (lzx.BlockLength & 1) != 0)
|
||||
{
|
||||
lzx.READ_IF_NEEDED(ref i_ptr, ref i_end);
|
||||
if (lzx.Error != Error.MSPACK_ERR_OK)
|
||||
return lzx.Error;
|
||||
lzx.READ_IF_NEEDED(state);
|
||||
if (lzx.Error != Error.MSPACK_ERR_OK)
|
||||
return lzx.Error;
|
||||
|
||||
i_ptr++;
|
||||
}
|
||||
|
||||
// Read block type (3 bits) and block length (24 bits)
|
||||
|
||||
// THIS IS NOT 3 BECAUSE OF OTHER CODE I FOUND
|
||||
lzx.BlockType = (LZXBlockType)lzx.READ_BITS_MSB(3, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
|
||||
// Read header if necessary
|
||||
if (lzx.HeaderRead == 0)
|
||||
{
|
||||
// Read 1 bit. if bit=0, intel_filesize = 0.
|
||||
// if bit=1, read intel filesize (32 bits)
|
||||
j = 0;
|
||||
i = (int)lzx.READ_BITS_MSB(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
i = (int)lzx.READ_BITS_MSB(16, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
j = (int)lzx.READ_BITS_MSB(16, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
}
|
||||
|
||||
lzx.IntelFileSize = (i << 16) | j;
|
||||
lzx.HeaderRead = 1;
|
||||
}
|
||||
|
||||
i = (int)lzx.READ_BITS_MSB(16, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
j = (int)lzx.READ_BITS_MSB(8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
|
||||
lzx.BlockRemaining = lzx.BlockLength = (uint)((i << 8) | j);
|
||||
// Console.WriteLine($"New block t {lzx.BlockType} len {lzx.BlockLength}");
|
||||
|
||||
// Read individual block headers
|
||||
switch (lzx.BlockType)
|
||||
{
|
||||
case LZXBlockType.LZX_BLOCKTYPE_ALIGNED:
|
||||
// Read lengths of and build aligned huffman decoding tree
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
j = (int)lzx.READ_BITS_MSB(16, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
lzx.ALIGNED_len[i] = (byte)j;
|
||||
}
|
||||
|
||||
BUILD_TABLE(lzx, lzx.ALIGNED_table, lzx.ALIGNED_len, LZX_ALIGNED_TABLEBITS, LZX_ALIGNED_MAXSYMBOLS);
|
||||
if (lzx.Error != Error.MSPACK_ERR_OK)
|
||||
return lzx.Error;
|
||||
|
||||
// Read lengths of and build main huffman decoding tree
|
||||
READ_LENGTHS(lzx, lzx.MAINTREE_len, 0, 256, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
if (lzx.Error != Error.MSPACK_ERR_OK)
|
||||
return lzx.Error;
|
||||
|
||||
READ_LENGTHS(lzx, lzx.MAINTREE_len, 256, LZX_NUM_CHARS + lzx.NumOffsets, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
if (lzx.Error != Error.MSPACK_ERR_OK)
|
||||
return lzx.Error;
|
||||
|
||||
BUILD_TABLE(lzx, lzx.MAINTREE_table, lzx.MAINTREE_len, LZX_MAINTREE_TABLEBITS, LZX_MAINTREE_MAXSYMBOLS);
|
||||
if (lzx.Error != Error.MSPACK_ERR_OK)
|
||||
return lzx.Error;
|
||||
|
||||
// If the literal 0xE8 is anywhere in the block...
|
||||
if (lzx.MAINTREE_len[0xE8] != 0)
|
||||
lzx.IntelStarted = true;
|
||||
|
||||
// Read lengths of and build lengths huffman decoding tree
|
||||
READ_LENGTHS(lzx, lzx.LENGTH_len, 0, LZX_NUM_SECONDARY_LENGTHS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
if (lzx.Error != Error.MSPACK_ERR_OK)
|
||||
return lzx.Error;
|
||||
|
||||
BUILD_TABLE_MAYBE_EMPTY(lzx);
|
||||
if (lzx.Error != Error.MSPACK_ERR_OK)
|
||||
return lzx.Error;
|
||||
|
||||
break;
|
||||
|
||||
case LZXBlockType.LZX_BLOCKTYPE_VERBATIM:
|
||||
// Read lengths of and build main huffman decoding tree
|
||||
READ_LENGTHS(lzx, lzx.MAINTREE_len, 0, 256, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
if (lzx.Error != Error.MSPACK_ERR_OK)
|
||||
return lzx.Error;
|
||||
|
||||
READ_LENGTHS(lzx, lzx.MAINTREE_len, 256, LZX_NUM_CHARS + lzx.NumOffsets, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
if (lzx.Error != Error.MSPACK_ERR_OK)
|
||||
return lzx.Error;
|
||||
|
||||
BUILD_TABLE(lzx, lzx.MAINTREE_table, lzx.MAINTREE_len, LZX_MAINTREE_TABLEBITS, LZX_MAINTREE_MAXSYMBOLS);
|
||||
if (lzx.Error != Error.MSPACK_ERR_OK)
|
||||
return lzx.Error;
|
||||
|
||||
// If the literal 0xE8 is anywhere in the block...
|
||||
if (lzx.MAINTREE_len[0xE8] != 0)
|
||||
lzx.IntelStarted = true;
|
||||
|
||||
// Read lengths of and build lengths huffman decoding tree
|
||||
READ_LENGTHS(lzx, lzx.LENGTH_len, 0, LZX_NUM_SECONDARY_LENGTHS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
if (lzx.Error != Error.MSPACK_ERR_OK)
|
||||
return lzx.Error;
|
||||
|
||||
BUILD_TABLE_MAYBE_EMPTY(lzx);
|
||||
if (lzx.Error != Error.MSPACK_ERR_OK)
|
||||
return lzx.Error;
|
||||
|
||||
break;
|
||||
|
||||
case LZXBlockType.LZX_BLOCKTYPE_UNCOMPRESSED:
|
||||
// Because we can't assume otherwise
|
||||
lzx.IntelStarted = true;
|
||||
|
||||
// Read 1-16 (not 0-15) bits to align to bytes
|
||||
if (bits_left == 0)
|
||||
lzx.ENSURE_BITS(16, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
|
||||
bits_left = 0; bit_buffer = 0;
|
||||
|
||||
// Read 12 bytes of stored R0 / R1 / R2 values
|
||||
for (rundest = 0, i = 0; i < 12; i++)
|
||||
{
|
||||
lzx.READ_IF_NEEDED(ref i_ptr, ref i_end);
|
||||
if (lzx.Error != Error.MSPACK_ERR_OK)
|
||||
return lzx.Error;
|
||||
|
||||
buf[rundest++] = lzx.InputBuffer[i_ptr++];
|
||||
}
|
||||
|
||||
R0 = (uint)(buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24));
|
||||
R1 = (uint)(buf[4] | (buf[5] << 8) | (buf[6] << 16) | (buf[7] << 24));
|
||||
R2 = (uint)(buf[8] | (buf[9] << 8) | (buf[10] << 16) | (buf[11] << 24));
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
Console.WriteLine("Bad block type");
|
||||
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
state.InputPointer++;
|
||||
}
|
||||
|
||||
lzx.ReadBlockHeader(buf, ref R, state);
|
||||
if (lzx.Error != Error.MSPACK_ERR_OK)
|
||||
return lzx.Error;
|
||||
|
||||
// Decode more of the block:
|
||||
// run = min(what's available, what's needed)
|
||||
this_run = (int)lzx.BlockRemaining;
|
||||
if (this_run > bytes_todo)
|
||||
this_run = bytes_todo;
|
||||
int this_run = Math.Min(lzx.BlockRemaining, bytes_todo);
|
||||
|
||||
// Assume we decode exactly this_run bytes, for now
|
||||
bytes_todo -= this_run;
|
||||
lzx.BlockRemaining -= (uint)this_run;
|
||||
lzx.BlockRemaining -= this_run;
|
||||
|
||||
// Decode at least this_run bytes
|
||||
switch (lzx.BlockType)
|
||||
{
|
||||
case LZXBlockType.LZX_BLOCKTYPE_ALIGNED:
|
||||
case LZXBlockType.LZX_BLOCKTYPE_VERBATIM:
|
||||
while (this_run > 0)
|
||||
{
|
||||
main_element = (int)lzx.READ_HUFFSYM_MSB(lzx.MAINTREE_table, lzx.MAINTREE_len, LZX_MAINTREE_TABLEBITS, LZX_MAINTREE_MAXSYMBOLS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
if (main_element < LZX_NUM_CHARS)
|
||||
{
|
||||
// Literal: 0 to LZX_NUM_CHARS-1
|
||||
window[window_posn++] = (byte)main_element;
|
||||
this_run--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits))
|
||||
main_element -= LZX_NUM_CHARS;
|
||||
lzx.DecompressBlock(window, ref window_posn, ref this_run, ref R, state);
|
||||
if (lzx.Error != Error.MSPACK_ERR_OK)
|
||||
return lzx.Error;
|
||||
|
||||
// Get match length
|
||||
match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
|
||||
if (match_length == LZX_NUM_PRIMARY_LENGTHS)
|
||||
{
|
||||
if (lzx.LENGTH_empty != 0)
|
||||
{
|
||||
Console.WriteLine("LENGTH symbol needed but tree is empty");
|
||||
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
length_footer = (int)lzx.READ_HUFFSYM_MSB(lzx.LENGTH_table, lzx.LENGTH_len, LZX_LENGTH_TABLEBITS, LZX_LENGTH_MAXSYMBOLS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
match_length += length_footer;
|
||||
}
|
||||
|
||||
match_length += LZX_MIN_MATCH;
|
||||
|
||||
// Get match offset
|
||||
switch ((match_offset = (uint)(main_element >> 3)))
|
||||
{
|
||||
case 0:
|
||||
match_offset = R0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
match_offset = R1;
|
||||
R1 = R0;
|
||||
R0 = match_offset;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
match_offset = R2;
|
||||
R2 = R0;
|
||||
R0 = match_offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (lzx.BlockType == LZXBlockType.LZX_BLOCKTYPE_VERBATIM)
|
||||
{
|
||||
if (match_offset == 3)
|
||||
{
|
||||
match_offset = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
extra = (match_offset >= 36) ? 17 : extra_bits[match_offset];
|
||||
verbatim_bits = (int)lzx.READ_BITS_MSB(extra, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
match_offset = (uint)(position_base[match_offset] - 2 + verbatim_bits);
|
||||
}
|
||||
}
|
||||
|
||||
// LZX_BLOCKTYPE_ALIGNED
|
||||
else
|
||||
{
|
||||
extra = (match_offset >= 36) ? 17 : extra_bits[match_offset];
|
||||
match_offset = position_base[match_offset] - 2;
|
||||
|
||||
// >3: verbatim and aligned bits
|
||||
if (extra > 3)
|
||||
{
|
||||
extra -= 3;
|
||||
verbatim_bits = (int)lzx.READ_BITS_MSB(extra, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
match_offset += (uint)(verbatim_bits << 3);
|
||||
|
||||
aligned_bits = (int)lzx.READ_HUFFSYM_MSB(lzx.ALIGNED_table, lzx.ALIGNED_len, LZX_ALIGNED_TABLEBITS, LZX_ALIGNED_MAXSYMBOLS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
match_offset += (uint)aligned_bits;
|
||||
}
|
||||
|
||||
// 3: aligned bits only
|
||||
else if (extra == 3)
|
||||
{
|
||||
aligned_bits = (int)lzx.READ_HUFFSYM_MSB(lzx.ALIGNED_table, lzx.ALIGNED_len, LZX_ALIGNED_TABLEBITS, LZX_ALIGNED_MAXSYMBOLS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
match_offset += (uint)aligned_bits;
|
||||
}
|
||||
|
||||
// 1-2: verbatim bits only
|
||||
else if (extra > 0)
|
||||
{
|
||||
verbatim_bits = (int)lzx.READ_BITS_MSB(extra, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
match_offset += (uint)verbatim_bits;
|
||||
}
|
||||
|
||||
// 0: not defined in LZX specification!
|
||||
else
|
||||
{
|
||||
match_offset = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Update repeated offset LRU queue
|
||||
R2 = R1; R1 = R0; R0 = match_offset;
|
||||
break;
|
||||
}
|
||||
|
||||
// LZX DELTA uses max match length to signal even longer match
|
||||
if (match_length == LZX_MAX_MATCH && lzx.IsDelta)
|
||||
{
|
||||
int extra_len;
|
||||
|
||||
// 4 entry huffman tree
|
||||
lzx.ENSURE_BITS(3, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
|
||||
// '0' . 8 extra length bits
|
||||
if (lzx.PEEK_BITS_MSB(1, bit_buffer) == 0)
|
||||
{
|
||||
lzx.REMOVE_BITS_MSB(1, ref bit_buffer, ref bits_left);
|
||||
extra_len = (int)lzx.READ_BITS_MSB(8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
}
|
||||
|
||||
// '10' . 10 extra length bits + 0x100
|
||||
else if (lzx.PEEK_BITS_MSB(2, bit_buffer) == 2)
|
||||
{
|
||||
lzx.REMOVE_BITS_MSB(2, ref bit_buffer, ref bits_left);
|
||||
extra_len = (int)lzx.READ_BITS_MSB(10, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
extra_len += 0x100;
|
||||
}
|
||||
|
||||
// '110' . 12 extra length bits + 0x500
|
||||
else if (lzx.PEEK_BITS_MSB(3, bit_buffer) == 6)
|
||||
{
|
||||
lzx.REMOVE_BITS_MSB(3, ref bit_buffer, ref bits_left);
|
||||
extra_len = (int)lzx.READ_BITS_MSB(12, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
extra_len += 0x500;
|
||||
}
|
||||
|
||||
// '111' . 15 extra length bits
|
||||
else
|
||||
{
|
||||
lzx.REMOVE_BITS_MSB(3, ref bit_buffer, ref bits_left);
|
||||
extra_len = (int)lzx.READ_BITS_MSB(15, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
}
|
||||
|
||||
match_length += extra_len;
|
||||
}
|
||||
|
||||
if ((window_posn + match_length) > lzx.WindowSize)
|
||||
{
|
||||
Console.WriteLine("Match ran over window wrap");
|
||||
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
// Copy match
|
||||
rundest = (int)window_posn;
|
||||
i = match_length;
|
||||
|
||||
// Does match offset wrap the window?
|
||||
if (match_offset > window_posn)
|
||||
{
|
||||
if (match_offset > lzx.Offset && (match_offset - window_posn) > lzx.ReferenceDataSize)
|
||||
{
|
||||
Console.WriteLine("Match offset beyond LZX stream");
|
||||
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
// j = length from match offset to end of window
|
||||
j = (int)(match_offset - window_posn);
|
||||
if (j > (int)lzx.WindowSize)
|
||||
{
|
||||
Console.WriteLine("Match offset beyond window boundaries");
|
||||
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
runsrc = (int)(lzx.WindowSize - j);
|
||||
if (j < i)
|
||||
{
|
||||
// If match goes over the window edge, do two copy runs
|
||||
i -= j;
|
||||
while (j-- > 0)
|
||||
{
|
||||
window[rundest++] = window[runsrc++];
|
||||
}
|
||||
|
||||
runsrc = 0;
|
||||
}
|
||||
|
||||
while (i-- > 0)
|
||||
{
|
||||
window[rundest++] = window[runsrc++];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
runsrc = (int)(rundest - match_offset);
|
||||
while (i-- > 0)
|
||||
{
|
||||
window[rundest++] = window[runsrc++];
|
||||
}
|
||||
}
|
||||
|
||||
this_run -= match_length;
|
||||
window_posn += (uint)match_length;
|
||||
}
|
||||
}
|
||||
// If the literal 0xE8 is anywhere in the block...
|
||||
if (lzx.MAINTREE_len[0xE8] != 0)
|
||||
lzx.IntelStarted = true;
|
||||
|
||||
break;
|
||||
|
||||
case LZXBlockType.LZX_BLOCKTYPE_UNCOMPRESSED:
|
||||
// As this_run is limited not to wrap a frame, this also means it
|
||||
// won't wrap the window (as the window is a multiple of 32k)
|
||||
rundest = (int)window_posn;
|
||||
window_posn += (uint)this_run;
|
||||
int rundest = window_posn;
|
||||
window_posn += this_run;
|
||||
while (this_run > 0)
|
||||
{
|
||||
if ((i = i_end - i_ptr) == 0)
|
||||
int i = state.InputEnd - state.InputPointer;
|
||||
if (i == 0)
|
||||
{
|
||||
lzx.READ_IF_NEEDED(ref i_ptr, ref i_end);
|
||||
lzx.READ_IF_NEEDED(state);
|
||||
if (lzx.Error != Error.MSPACK_ERR_OK)
|
||||
return lzx.Error;
|
||||
}
|
||||
@@ -906,13 +450,17 @@ namespace LibMSPackSharp.Compression
|
||||
if (i > this_run)
|
||||
i = this_run;
|
||||
|
||||
Array.Copy(lzx.InputBuffer, i_ptr, window, rundest, i);
|
||||
Array.Copy(lzx.InputBuffer, state.InputPointer, window, rundest, i);
|
||||
|
||||
rundest += i;
|
||||
i_ptr += i;
|
||||
state.InputPointer += i;
|
||||
this_run -= i;
|
||||
}
|
||||
}
|
||||
|
||||
// Because we can't assume otherwise
|
||||
lzx.IntelStarted = true;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -928,7 +476,7 @@ namespace LibMSPackSharp.Compression
|
||||
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
lzx.BlockRemaining -= (uint)-this_run;
|
||||
lzx.BlockRemaining -= -this_run;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -940,10 +488,10 @@ namespace LibMSPackSharp.Compression
|
||||
}
|
||||
|
||||
// Re-align input bitstream
|
||||
if (bits_left > 0)
|
||||
lzx.ENSURE_BITS(16, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
if ((bits_left & 15) != 0)
|
||||
lzx.REMOVE_BITS_MSB(bits_left & 15, ref bit_buffer, ref bits_left);
|
||||
if (state.BitsLeft > 0)
|
||||
lzx.ENSURE_BITS(16, state);
|
||||
if ((state.BitsLeft & 15) != 0)
|
||||
state.REMOVE_BITS_MSB(state.BitsLeft & 15);
|
||||
|
||||
// Check that we've used all of the previous frame first
|
||||
if (lzx.OutputPointer != lzx.OutputEnd)
|
||||
@@ -955,59 +503,24 @@ namespace LibMSPackSharp.Compression
|
||||
// Does this intel block _really_ need decoding?
|
||||
if (lzx.IntelStarted && lzx.IntelFileSize != 0 && (lzx.Frame < 32768) && (frame_size > 10))
|
||||
{
|
||||
int data = 0;
|
||||
int dataend = (int)(frame_size - 10);
|
||||
int curpos = (int)lzx.Offset;
|
||||
int filesize = lzx.IntelFileSize;
|
||||
int abs_off, rel_off;
|
||||
|
||||
// Copy e8 block to the e8 buffer and tweak if needed
|
||||
lzx.OutputPointer = data;
|
||||
Array.Copy(lzx.Window, lzx.FramePosition, lzx.e8_buf, data, frame_size);
|
||||
|
||||
while (data < dataend)
|
||||
{
|
||||
if (lzx.e8_buf[data++] != 0xE8)
|
||||
{
|
||||
curpos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
abs_off = lzx.e8_buf[data + 0] | (lzx.e8_buf[data + 1] << 8) | (lzx.e8_buf[data + 2] << 16) | (lzx.e8_buf[data + 3] << 24);
|
||||
if ((abs_off >= -curpos) && (abs_off < filesize))
|
||||
{
|
||||
rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize;
|
||||
lzx.e8_buf[data + 0] = (byte)rel_off;
|
||||
lzx.e8_buf[data + 1] = (byte)(rel_off >> 8);
|
||||
lzx.e8_buf[data + 2] = (byte)(rel_off >> 16);
|
||||
lzx.e8_buf[data + 3] = (byte)(rel_off >> 24);
|
||||
}
|
||||
|
||||
data += 4;
|
||||
curpos += 5;
|
||||
}
|
||||
|
||||
lzx.OutputEnd = (int)(lzx.OutputPointer + frame_size);
|
||||
|
||||
// Write a frame
|
||||
i = (int)((out_bytes < frame_size) ? out_bytes : frame_size);
|
||||
try { lzx.System.Write(lzx.OutputFileHandle, lzx.e8_buf, lzx.OutputPointer, i); }
|
||||
catch { return lzx.Error = Error.MSPACK_ERR_WRITE; }
|
||||
lzx.UndoE8Preprocessing(frame_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
lzx.OutputIsE8 = false;
|
||||
lzx.OutputPointer = (int)lzx.FramePosition;
|
||||
lzx.OutputEnd = (int)(lzx.OutputPointer + frame_size);
|
||||
|
||||
// Write a frame
|
||||
i = (int)((out_bytes < frame_size) ? out_bytes : frame_size);
|
||||
try { lzx.System.Write(lzx.OutputFileHandle, lzx.Window, lzx.OutputPointer, i); }
|
||||
catch { return lzx.Error = Error.MSPACK_ERR_WRITE; }
|
||||
}
|
||||
|
||||
lzx.OutputPointer += i;
|
||||
lzx.Offset += i;
|
||||
out_bytes -= i;
|
||||
lzx.OutputEnd = (int)(lzx.OutputPointer + frame_size);
|
||||
|
||||
// Write a frame
|
||||
int new_out_bytes = (int)((out_bytes < frame_size) ? out_bytes : frame_size);
|
||||
try { lzx.System.Write(lzx.OutputFileHandle, lzx.OutputIsE8 ? lzx.E8Buffer : lzx.Window, lzx.OutputPointer, new_out_bytes); }
|
||||
catch { return lzx.Error = Error.MSPACK_ERR_WRITE; }
|
||||
|
||||
lzx.OutputPointer += new_out_bytes;
|
||||
lzx.Offset += new_out_bytes;
|
||||
out_bytes -= new_out_bytes;
|
||||
|
||||
// Advance frame start position
|
||||
lzx.FramePosition += frame_size;
|
||||
@@ -1028,131 +541,9 @@ namespace LibMSPackSharp.Compression
|
||||
}
|
||||
|
||||
// Store local state
|
||||
lzx.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
|
||||
lzx.STORE_BITS(state);
|
||||
lzx.WindowPosition = window_posn;
|
||||
lzx.R0 = R0;
|
||||
lzx.R1 = R1;
|
||||
lzx.R2 = R2;
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
private static Error BUILD_TABLE(LZXDStream lzx, ushort[] table, byte[] lengths, int tablebits, int maxsymbols)
|
||||
{
|
||||
if (!CompressionStream.MakeDecodeTableMSB(maxsymbols, tablebits, lengths, table))
|
||||
{
|
||||
Console.WriteLine($"Failed to build table");
|
||||
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
return lzx.Error = Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
private static Error BUILD_TABLE_MAYBE_EMPTY(LZXDStream lzx)
|
||||
{
|
||||
lzx.LENGTH_empty = 0;
|
||||
if (!CompressionStream.MakeDecodeTableMSB(LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS, lzx.LENGTH_len, lzx.LENGTH_table))
|
||||
{
|
||||
for (int i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++)
|
||||
{
|
||||
if (lzx.LENGTH_len[i] > 0)
|
||||
{
|
||||
Console.WriteLine("Failed to build table");
|
||||
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
}
|
||||
|
||||
// Empty tree - allow it, but don't decode symbols with it
|
||||
lzx.LENGTH_empty = 1;
|
||||
}
|
||||
|
||||
return lzx.Error = Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
private static Error READ_LENGTHS(LZXDStream lzx, byte[] lengths, uint first, uint last, ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left)
|
||||
{
|
||||
lzx.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
|
||||
|
||||
if (ReadLens(lzx, lengths, first, last) != Error.MSPACK_ERR_OK)
|
||||
return lzx.Error;
|
||||
|
||||
lzx.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left);
|
||||
return lzx.Error = Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
private static Error ReadLens(LZXDStream lzx, byte[] lens, uint first, uint last)
|
||||
{
|
||||
uint x, y;
|
||||
int z;
|
||||
|
||||
lzx.RESTORE_BITS(out int i_ptr, out int i_end, out uint bit_buffer, out int bits_left);
|
||||
|
||||
// Read lengths for pretree (20 symbols, lengths stored in fixed 4 bits)
|
||||
for (x = 0; x < 20; x++)
|
||||
{
|
||||
y = (uint)lzx.READ_BITS_MSB(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
lzx.PRETREE_len[x] = (byte)y;
|
||||
}
|
||||
|
||||
BUILD_TABLE(lzx, lzx.PRETREE_table, lzx.PRETREE_len, LZX_PRETREE_TABLEBITS, LZX_PRETREE_MAXSYMBOLS);
|
||||
if (lzx.Error != Error.MSPACK_ERR_OK)
|
||||
return lzx.Error;
|
||||
|
||||
for (x = first; x < last;)
|
||||
{
|
||||
z = (int)lzx.READ_HUFFSYM_MSB(lzx.PRETREE_table, lzx.PRETREE_len, LZX_PRETREE_TABLEBITS, LZX_PRETREE_MAXSYMBOLS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
|
||||
// Code = 17, run of ([read 4 bits]+4) zeros
|
||||
if (z == 17)
|
||||
{
|
||||
y = (uint)lzx.READ_BITS_MSB(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
y += 4;
|
||||
while (y-- != 0)
|
||||
{
|
||||
lens[x++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Code = 18, run of ([read 5 bits]+20) zeros
|
||||
else if (z == 18)
|
||||
{
|
||||
y = (uint)lzx.READ_BITS_MSB(5, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
y += 20;
|
||||
while (y-- != 0)
|
||||
{
|
||||
lens[x++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Code = 19, run of ([read 1 bit]+4) [read huffman symbol]
|
||||
else if (z == 19)
|
||||
{
|
||||
y = (uint)lzx.READ_BITS_MSB(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
y += 4;
|
||||
z = (int)lzx.READ_HUFFSYM_MSB(lzx.PRETREE_table, lzx.PRETREE_len, LZX_PRETREE_TABLEBITS, LZX_PRETREE_MAXSYMBOLS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
|
||||
z = lens[x] - z;
|
||||
if (z < 0)
|
||||
z += 17;
|
||||
|
||||
while (y-- != 0)
|
||||
{
|
||||
lens[x++] = (byte)z;
|
||||
}
|
||||
}
|
||||
|
||||
// Code = 0 to 16, delta current length entry
|
||||
else
|
||||
{
|
||||
z = lens[x] - z;
|
||||
if (z < 0)
|
||||
z += 17;
|
||||
|
||||
lens[x++] = (byte)z;
|
||||
}
|
||||
}
|
||||
|
||||
lzx.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
|
||||
lzx.R = R;
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System;
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public class LZXDStream : CompressionStream
|
||||
@@ -49,7 +52,7 @@ namespace LibMSPackSharp.Compression
|
||||
/// <summary>
|
||||
/// Decompression offset within window
|
||||
/// </summary>
|
||||
public uint WindowPosition { get; set; }
|
||||
public int WindowPosition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current frame offset within in window
|
||||
@@ -69,27 +72,17 @@ namespace LibMSPackSharp.Compression
|
||||
/// <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; }
|
||||
public uint[] R { get; set; } = new uint[3];
|
||||
|
||||
/// <summary>
|
||||
/// Uncompressed length of this LZX block
|
||||
/// </summary>
|
||||
public uint BlockLength { get; set; }
|
||||
public int BlockLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Uncompressed bytes still left to decode
|
||||
/// </summary>
|
||||
public uint BlockRemaining { get; set; }
|
||||
public int BlockRemaining { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Magic header value used for transform
|
||||
@@ -118,26 +111,564 @@ namespace LibMSPackSharp.Compression
|
||||
|
||||
#region Huffman code lengths
|
||||
|
||||
public byte[] PRETREE_len { get; set; } = new byte[LZX.LZX_PRETREE_MAXSYMBOLS + LZX.LZX_LENTABLE_SAFETY];
|
||||
public byte[] MAINTREE_len { get; set; } = new byte[LZX.LZX_MAINTREE_MAXSYMBOLS + LZX.LZX_LENTABLE_SAFETY];
|
||||
public byte[] LENGTH_len { get; set; } = new byte[LZX.LZX_LENGTH_MAXSYMBOLS + LZX.LZX_LENTABLE_SAFETY];
|
||||
public byte[] ALIGNED_len { get; set; } = new byte[LZX.LZX_ALIGNED_MAXSYMBOLS + LZX.LZX_LENTABLE_SAFETY];
|
||||
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.LZX_PRETREE_TABLEBITS) + (LZX.LZX_PRETREE_MAXSYMBOLS * 2)];
|
||||
public ushort[] MAINTREE_table { get; set; } = new ushort[(1 << LZX.LZX_MAINTREE_TABLEBITS) + (LZX.LZX_MAINTREE_MAXSYMBOLS * 2)];
|
||||
public ushort[] LENGTH_table { get; set; } = new ushort[(1 << LZX.LZX_LENGTH_TABLEBITS) + (LZX.LZX_LENGTH_MAXSYMBOLS * 2)];
|
||||
public ushort[] ALIGNED_table { get; set; } = new ushort[(1 << LZX.LZX_ALIGNED_TABLEBITS) + (LZX.LZX_ALIGNED_MAXSYMBOLS * 2)];
|
||||
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)];
|
||||
|
||||
#endregion
|
||||
|
||||
public byte LENGTH_empty { get; set; }
|
||||
|
||||
// This is used purely for doing the intel E8 transform
|
||||
public byte[] e8_buf { get; set; } = new byte[LZX.LZX_FRAME_SIZE];
|
||||
public byte[] E8Buffer { get; set; } = new byte[LZX_FRAME_SIZE];
|
||||
|
||||
/// <summary>
|
||||
/// Is the output pointer referring to E8?
|
||||
/// </summary>
|
||||
public bool OutputIsE8 { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Specialty Methods
|
||||
|
||||
public Error DecompressBlock(byte[] window, ref int window_posn, ref int this_run, ref uint[] R, BufferState state)
|
||||
{
|
||||
while (this_run > 0)
|
||||
{
|
||||
int main_element = (int)READ_HUFFSYM_MSB(MAINTREE_table, MAINTREE_len, LZX_MAINTREE_TABLEBITS, LZX_MAINTREE_MAXSYMBOLS, state);
|
||||
if (main_element < LZX_NUM_CHARS)
|
||||
{
|
||||
// Literal: 0 to LZX_NUM_CHARS-1
|
||||
window[window_posn++] = (byte)main_element;
|
||||
this_run--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits))
|
||||
main_element -= LZX_NUM_CHARS;
|
||||
|
||||
// Get match length
|
||||
int match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
|
||||
if (match_length == LZX_NUM_PRIMARY_LENGTHS)
|
||||
{
|
||||
if (LENGTH_empty != 0)
|
||||
{
|
||||
Console.WriteLine("LENGTH symbol needed but tree is empty");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
int length_footer = (int)READ_HUFFSYM_MSB(LENGTH_table, LENGTH_len, LZX_LENGTH_TABLEBITS, LZX_LENGTH_MAXSYMBOLS, state);
|
||||
match_length += length_footer;
|
||||
}
|
||||
|
||||
match_length += LZX_MIN_MATCH;
|
||||
|
||||
// Get match offset
|
||||
uint match_offset = (uint)(main_element >> 3);
|
||||
switch (match_offset)
|
||||
{
|
||||
case 0:
|
||||
match_offset = R[0];
|
||||
break;
|
||||
|
||||
case 1:
|
||||
match_offset = R[1];
|
||||
R[1] = R[0];
|
||||
R[0] = match_offset;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
match_offset = R[2];
|
||||
R[2] = R[0];
|
||||
R[0] = match_offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (BlockType == LZXBlockType.LZX_BLOCKTYPE_VERBATIM)
|
||||
{
|
||||
if (match_offset == 3)
|
||||
{
|
||||
match_offset = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int extra = (match_offset >= 36) ? 17 : LZXExtraBits[match_offset];
|
||||
int verbatim_bits = (int)READ_BITS_MSB(extra, state);
|
||||
match_offset = (uint)(LZXPositionBase[match_offset] - 2 + verbatim_bits);
|
||||
}
|
||||
}
|
||||
|
||||
// LZX_BLOCKTYPE_ALIGNED
|
||||
else
|
||||
{
|
||||
int extra = (match_offset >= 36) ? 17 : LZXExtraBits[match_offset];
|
||||
match_offset = LZXPositionBase[match_offset] - 2;
|
||||
|
||||
// >3: verbatim and aligned bits
|
||||
if (extra > 3)
|
||||
{
|
||||
extra -= 3;
|
||||
int verbatim_bits = (int)READ_BITS_MSB(extra, state);
|
||||
match_offset += (uint)(verbatim_bits << 3);
|
||||
|
||||
int aligned_bits = (int)READ_HUFFSYM_MSB(ALIGNED_table, ALIGNED_len, LZX_ALIGNED_TABLEBITS, LZX_ALIGNED_MAXSYMBOLS, state);
|
||||
match_offset += (uint)aligned_bits;
|
||||
}
|
||||
|
||||
// 3: aligned bits only
|
||||
else if (extra == 3)
|
||||
{
|
||||
int aligned_bits = (int)READ_HUFFSYM_MSB(ALIGNED_table, ALIGNED_len, LZX_ALIGNED_TABLEBITS, LZX_ALIGNED_MAXSYMBOLS, state);
|
||||
match_offset += (uint)aligned_bits;
|
||||
}
|
||||
|
||||
// 1-2: verbatim bits only
|
||||
else if (extra > 0)
|
||||
{
|
||||
int verbatim_bits = (int)READ_BITS_MSB(extra, state);
|
||||
match_offset += (uint)verbatim_bits;
|
||||
}
|
||||
|
||||
// 0: not defined in LZX specification!
|
||||
else
|
||||
{
|
||||
match_offset = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Update repeated offset LRU queue
|
||||
R[2] = R[1]; R[1] = R[0]; R[0] = match_offset;
|
||||
break;
|
||||
}
|
||||
|
||||
// LZX DELTA uses max match length to signal even longer match
|
||||
if (match_length == LZX_MAX_MATCH && IsDelta)
|
||||
{
|
||||
int extra_len;
|
||||
|
||||
// 4 entry huffman tree
|
||||
ENSURE_BITS(3, state);
|
||||
|
||||
// '0' . 8 extra length bits
|
||||
if (PEEK_BITS_MSB(1, state.BitBuffer) == 0)
|
||||
{
|
||||
state.REMOVE_BITS_MSB(1);
|
||||
extra_len = (int)READ_BITS_MSB(8, state);
|
||||
}
|
||||
|
||||
// '10' . 10 extra length bits + 0x100
|
||||
else if (PEEK_BITS_MSB(2, state.BitBuffer) == 2)
|
||||
{
|
||||
state.REMOVE_BITS_MSB(2);
|
||||
extra_len = (int)READ_BITS_MSB(10, state);
|
||||
extra_len += 0x100;
|
||||
}
|
||||
|
||||
// '110' . 12 extra length bits + 0x500
|
||||
else if (PEEK_BITS_MSB(3, state.BitBuffer) == 6)
|
||||
{
|
||||
state.REMOVE_BITS_MSB(3);
|
||||
extra_len = (int)READ_BITS_MSB(12, state);
|
||||
extra_len += 0x500;
|
||||
}
|
||||
|
||||
// '111' . 15 extra length bits
|
||||
else
|
||||
{
|
||||
state.REMOVE_BITS_MSB(3);
|
||||
extra_len = (int)READ_BITS_MSB(15, state);
|
||||
}
|
||||
|
||||
match_length += extra_len;
|
||||
}
|
||||
|
||||
if ((window_posn + match_length) > WindowSize)
|
||||
{
|
||||
Console.WriteLine("Match ran over window wrap");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
// Copy match
|
||||
int rundest = window_posn;
|
||||
int i = match_length;
|
||||
|
||||
// Does match offset wrap the window?
|
||||
if (match_offset > window_posn)
|
||||
{
|
||||
if (match_offset > Offset && (match_offset - window_posn) > ReferenceDataSize)
|
||||
{
|
||||
Console.WriteLine("Match offset beyond LZX stream");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
// j = length from match offset to end of window
|
||||
int j = (int)(match_offset - window_posn);
|
||||
if (j > (int)WindowSize)
|
||||
{
|
||||
Console.WriteLine("Match offset beyond window boundaries");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
int runsrc = (int)(WindowSize - j);
|
||||
if (j < i)
|
||||
{
|
||||
// If match goes over the window edge, do two copy runs
|
||||
i -= j;
|
||||
while (j-- > 0)
|
||||
{
|
||||
window[rundest++] = window[runsrc++];
|
||||
}
|
||||
|
||||
runsrc = 0;
|
||||
}
|
||||
|
||||
while (i-- > 0)
|
||||
{
|
||||
window[rundest++] = window[runsrc++];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int runsrc = (int)(rundest - match_offset);
|
||||
while (i-- > 0)
|
||||
{
|
||||
window[rundest++] = window[runsrc++];
|
||||
}
|
||||
}
|
||||
|
||||
this_run -= match_length;
|
||||
window_posn += match_length;
|
||||
}
|
||||
}
|
||||
|
||||
return Error = Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
public Error ReadBlockHeader(byte[] buffer, ref uint[] R, BufferState state)
|
||||
{
|
||||
ENSURE_BITS(4, state);
|
||||
|
||||
// Read block type (3 bits) and block length (24 bits)
|
||||
byte block_type = (byte)READ_BITS_MSB(3, state);
|
||||
BlockType = (LZXBlockType)block_type;
|
||||
|
||||
// Read the block size
|
||||
int block_size;
|
||||
if (READ_BITS_MSB(1, state) == 1)
|
||||
{
|
||||
block_size = LZX_FRAME_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
int tmp;
|
||||
block_size = 0;
|
||||
|
||||
tmp = (int)READ_BITS_MSB(8, state);
|
||||
block_size |= tmp;
|
||||
tmp = (int)READ_BITS_MSB(8, state);
|
||||
block_size <<= 8;
|
||||
block_size |= tmp;
|
||||
|
||||
if (WindowSize >= 65536)
|
||||
{
|
||||
tmp = (int)READ_BITS_MSB(8, state);
|
||||
block_size <<= 8;
|
||||
block_size |= tmp;
|
||||
}
|
||||
}
|
||||
|
||||
BlockRemaining = BlockLength = block_size;
|
||||
Console.WriteLine($"New block t {BlockType} len {BlockLength}");
|
||||
|
||||
// Read individual block headers
|
||||
switch (BlockType)
|
||||
{
|
||||
case LZXBlockType.LZX_BLOCKTYPE_ALIGNED:
|
||||
// Read lengths of and build aligned huffman decoding tree
|
||||
for (byte i = 0; i < 8; i++)
|
||||
{
|
||||
ALIGNED_len[i] = (byte)READ_BITS_MSB(3, state);
|
||||
}
|
||||
|
||||
BUILD_TABLE(ALIGNED_table, ALIGNED_len, LZX_ALIGNED_TABLEBITS, LZX_ALIGNED_MAXSYMBOLS);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
// Read lengths of and build main huffman decoding tree
|
||||
READ_LENGTHS(MAINTREE_len, 0, 256, state);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
READ_LENGTHS(MAINTREE_len, 256, LZX_NUM_CHARS + NumOffsets, state);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
BUILD_TABLE(MAINTREE_table, MAINTREE_len, LZX_MAINTREE_TABLEBITS, LZX_MAINTREE_MAXSYMBOLS);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
// Read lengths of and build lengths huffman decoding tree
|
||||
READ_LENGTHS(LENGTH_len, 0, LZX_NUM_SECONDARY_LENGTHS, state);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
BUILD_TABLE_MAYBE_EMPTY();
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
break;
|
||||
|
||||
case LZXBlockType.LZX_BLOCKTYPE_VERBATIM:
|
||||
// Read lengths of and build main huffman decoding tree
|
||||
READ_LENGTHS(MAINTREE_len, 0, 256, state);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
READ_LENGTHS(MAINTREE_len, 256, LZX_NUM_CHARS + NumOffsets, state);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
BUILD_TABLE(MAINTREE_table, MAINTREE_len, LZX_MAINTREE_TABLEBITS, LZX_MAINTREE_MAXSYMBOLS);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
// If the literal 0xE8 is anywhere in the block...
|
||||
if (MAINTREE_len[0xE8] != 0)
|
||||
IntelStarted = true;
|
||||
|
||||
// Read lengths of and build lengths huffman decoding tree
|
||||
READ_LENGTHS(LENGTH_len, 0, LZX_NUM_SECONDARY_LENGTHS, state);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
BUILD_TABLE_MAYBE_EMPTY();
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
break;
|
||||
|
||||
case LZXBlockType.LZX_BLOCKTYPE_UNCOMPRESSED:
|
||||
// Read 1-16 (not 0-15) bits to align to bytes
|
||||
if (state.BitsLeft == 0)
|
||||
ENSURE_BITS(16, state);
|
||||
|
||||
state.BitsLeft = 0; state.BitBuffer = 0;
|
||||
|
||||
// Read 12 bytes of stored R[0] / R[1] / R[2] values
|
||||
for (int rundest = 0, k = 0; k < 12; k++)
|
||||
{
|
||||
READ_IF_NEEDED(state);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
buffer[rundest++] = InputBuffer[state.InputPointer++];
|
||||
}
|
||||
|
||||
// TODO: uint[] R should be a part of a state object
|
||||
R[0] = (uint)(buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24));
|
||||
R[1] = (uint)(buffer[4] | (buffer[5] << 8) | (buffer[6] << 16) | (buffer[7] << 24));
|
||||
R[2] = (uint)(buffer[8] | (buffer[9] << 8) | (buffer[10] << 16) | (buffer[11] << 24));
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
Console.WriteLine($"Bad block type: {BlockType}");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
return Error = Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
public Error ReadLens(byte[] lens, uint first, uint last)
|
||||
{
|
||||
BufferState state = RESTORE_BITS();
|
||||
|
||||
// Read lengths for pretree (20 symbols, lengths stored in fixed 4 bits)
|
||||
for (int i = 0; i < LZX_PRETREE_MAXSYMBOLS; i++)
|
||||
{
|
||||
uint y = (uint)READ_BITS_MSB(4, state);
|
||||
PRETREE_len[i] = (byte)y;
|
||||
}
|
||||
|
||||
BUILD_TABLE(PRETREE_table, PRETREE_len, LZX_PRETREE_TABLEBITS, LZX_PRETREE_MAXSYMBOLS);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
for (uint lensPtr = first; lensPtr < last;)
|
||||
{
|
||||
uint num_zeroes, num_same;
|
||||
int tree_code = (int)READ_HUFFSYM_MSB(PRETREE_table, PRETREE_len, LZX_PRETREE_TABLEBITS, LZX_PRETREE_MAXSYMBOLS, state);
|
||||
switch (tree_code)
|
||||
{
|
||||
// Code = 17, run of ([read 4 bits]+4) zeros
|
||||
case 17:
|
||||
num_zeroes = (uint)READ_BITS_MSB(4, state);
|
||||
num_zeroes += 4;
|
||||
while (num_zeroes-- != 0)
|
||||
{
|
||||
lens[lensPtr++] = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Code = 18, run of ([read 5 bits]+20) zeros
|
||||
case 18:
|
||||
num_zeroes = (uint)READ_BITS_MSB(5, state);
|
||||
num_zeroes += 20;
|
||||
while (num_zeroes-- != 0)
|
||||
{
|
||||
lens[lensPtr++] = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Code = 19, run of ([read 1 bit]+4) [read huffman symbol]
|
||||
case 19:
|
||||
num_same = (uint)READ_BITS_MSB(1, state);
|
||||
num_same += 4;
|
||||
|
||||
tree_code = (int)READ_HUFFSYM_MSB(PRETREE_table, PRETREE_len, LZX_PRETREE_TABLEBITS, LZX_PRETREE_MAXSYMBOLS, state);
|
||||
tree_code = lens[lensPtr] - tree_code;
|
||||
if (tree_code < 0)
|
||||
tree_code += 17;
|
||||
|
||||
while (num_same-- != 0)
|
||||
{
|
||||
lens[lensPtr++] = (byte)tree_code;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Code = 0 to 16, delta current length entry
|
||||
default:
|
||||
tree_code = lens[lensPtr] - tree_code;
|
||||
if (tree_code < 0)
|
||||
tree_code += 17;
|
||||
|
||||
lens[lensPtr++] = (byte)tree_code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
STORE_BITS(state);
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
public void ResetState()
|
||||
{
|
||||
R[0] = 1;
|
||||
R[1] = 1;
|
||||
R[2] = 1;
|
||||
HeaderRead = 0;
|
||||
BlockRemaining = 0;
|
||||
BlockType = LZXBlockType.LZX_BLOCKTYPE_INVALID0;
|
||||
|
||||
// Initialise tables to 0 (because deltas will be applied to them)
|
||||
for (int i = 0; i < LZX_MAINTREE_MAXSYMBOLS; i++)
|
||||
{
|
||||
MAINTREE_len[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++)
|
||||
{
|
||||
LENGTH_len[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void UndoE8Preprocessing(uint frame_size)
|
||||
{
|
||||
int data = 0;
|
||||
int dataend = (int)(frame_size - 10);
|
||||
int curpos = (int)Offset;
|
||||
int filesize = IntelFileSize;
|
||||
int abs_off, rel_off;
|
||||
|
||||
// Copy e8 block to the e8 buffer and tweak if needed
|
||||
OutputIsE8 = true;
|
||||
OutputPointer = data;
|
||||
Array.Copy(Window, FramePosition, E8Buffer, data, frame_size);
|
||||
|
||||
while (data < dataend)
|
||||
{
|
||||
if (E8Buffer[data++] != 0xE8)
|
||||
{
|
||||
curpos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
abs_off = E8Buffer[data + 0] | (E8Buffer[data + 1] << 8) | (E8Buffer[data + 2] << 16) | (E8Buffer[data + 3] << 24);
|
||||
if ((abs_off >= -curpos) && (abs_off < filesize))
|
||||
{
|
||||
rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize;
|
||||
E8Buffer[data + 0] = (byte)rel_off;
|
||||
E8Buffer[data + 1] = (byte)(rel_off >> 8);
|
||||
E8Buffer[data + 2] = (byte)(rel_off >> 16);
|
||||
E8Buffer[data + 3] = (byte)(rel_off >> 24);
|
||||
}
|
||||
|
||||
data += 4;
|
||||
curpos += 5;
|
||||
}
|
||||
}
|
||||
|
||||
private Error BUILD_TABLE(ushort[] table, byte[] lengths, int tablebits, int maxsymbols)
|
||||
{
|
||||
if (!MakeDecodeTableMSB(maxsymbols, tablebits, lengths, table))
|
||||
{
|
||||
Console.WriteLine($"Failed to build table");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
return Error = Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
private Error BUILD_TABLE_MAYBE_EMPTY()
|
||||
{
|
||||
LENGTH_empty = 0;
|
||||
if (!MakeDecodeTableMSB(LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS, LENGTH_len, LENGTH_table))
|
||||
{
|
||||
for (int i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++)
|
||||
{
|
||||
if (LENGTH_len[i] > 0)
|
||||
{
|
||||
Console.WriteLine("Failed to build table");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
}
|
||||
|
||||
// Empty tree - allow it, but don't decode symbols with it
|
||||
LENGTH_empty = 1;
|
||||
}
|
||||
|
||||
return Error = Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
private Error READ_LENGTHS(byte[] lengths, uint first, uint last, BufferState state)
|
||||
{
|
||||
STORE_BITS(state);
|
||||
|
||||
if (ReadLens(lengths, first, last) != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
BufferState temp = RESTORE_BITS();
|
||||
state.InputPointer = temp.InputPointer;
|
||||
state.InputEnd = temp.InputEnd;
|
||||
state.BitBuffer = temp.BitBuffer;
|
||||
state.BitsLeft = temp.BitsLeft;
|
||||
|
||||
return Error = Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -145,20 +676,20 @@ namespace LibMSPackSharp.Compression
|
||||
public override Error HUFF_ERROR() => Error.MSPACK_ERR_DECRUNCH;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void READ_BYTES(ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left)
|
||||
public override void READ_BYTES(BufferState state)
|
||||
{
|
||||
READ_IF_NEEDED(ref i_ptr, ref i_end);
|
||||
READ_IF_NEEDED(state);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return;
|
||||
|
||||
byte b0 = InputBuffer[i_ptr++];
|
||||
byte b0 = InputBuffer[state.InputPointer++];
|
||||
|
||||
READ_IF_NEEDED(ref i_ptr, ref i_end);
|
||||
READ_IF_NEEDED(state);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return;
|
||||
|
||||
byte b1 = InputBuffer[i_ptr++];
|
||||
INJECT_BITS_MSB((b1 << 8) | b0, 16, ref bit_buffer, ref bits_left);
|
||||
byte b1 = InputBuffer[state.InputPointer++];
|
||||
INJECT_BITS_MSB((b1 << 8) | b0, 16, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
198
BurnOutSharp/External/libmspack/Compression/MSZIP.cs
vendored
198
BurnOutSharp/External/libmspack/Compression/MSZIP.cs
vendored
@@ -12,75 +12,12 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public class MSZIP
|
||||
{
|
||||
#region MSZIP (deflate) compression / (inflate) decompression definitions
|
||||
|
||||
public const int MSZIP_FRAME_SIZE = 32768; // Size of LZ history window
|
||||
public const int MSZIP_LITERAL_MAXSYMBOLS = 288; // literal/length huffman tree
|
||||
public const int MSZIP_LITERAL_TABLEBITS = 9;
|
||||
public const int MSZIP_DISTANCE_MAXSYMBOLS = 32; // Distance huffman tree
|
||||
public const int MSZIP_DISTANCE_TABLEBITS = 6;
|
||||
|
||||
// If there are less direct lookup entries than symbols, the longer
|
||||
// code pointers will be <= maxsymbols. This must not happen, or we
|
||||
// will decode entries badly
|
||||
|
||||
//public const int MSZIP_LITERAL_TABLESIZE = (MSZIP_LITERAL_MAXSYMBOLS * 4);
|
||||
public const int MSZIP_LITERAL_TABLESIZE = ((1 << MSZIP_LITERAL_TABLEBITS) + (MSZIP_LITERAL_MAXSYMBOLS * 2));
|
||||
|
||||
//public const int MSZIP_DISTANCE_TABLESIZE = (MSZIP_DISTANCE_MAXSYMBOLS * 4);
|
||||
public const int MSZIP_DISTANCE_TABLESIZE = ((1 << MSZIP_DISTANCE_TABLEBITS) + (MSZIP_DISTANCE_MAXSYMBOLS * 2));
|
||||
|
||||
/// <summary>
|
||||
/// Match lengths for literal codes 257.. 285
|
||||
/// </summary>
|
||||
private static readonly ushort[] lit_lengths = new ushort[29]
|
||||
{
|
||||
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27,
|
||||
31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Match offsets for distance codes 0 .. 29
|
||||
/// </summary>
|
||||
private static readonly ushort[] dist_offsets = new ushort[30]
|
||||
{
|
||||
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385,
|
||||
513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Extra bits required for literal codes 257.. 285
|
||||
/// </summary>
|
||||
private static readonly byte[] lit_extrabits = new byte[29]
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2,
|
||||
2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Extra bits required for distance codes 0 .. 29
|
||||
/// </summary>
|
||||
private static readonly byte[] dist_extrabits = new byte[30]
|
||||
{
|
||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6,
|
||||
6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The order of the bit length Huffman code lengths
|
||||
/// </summary>
|
||||
private static readonly byte[] bitlen_order = new byte[19]
|
||||
{
|
||||
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Allocates MS-ZIP decompression stream for decoding the given stream.
|
||||
///
|
||||
@@ -120,12 +57,16 @@ namespace LibMSPackSharp.Compression
|
||||
RepairMode = repair_mode,
|
||||
FlushWindow = FlushWindow,
|
||||
|
||||
InputPointer = 0,
|
||||
InputEnd = 0,
|
||||
OutputPointer = 0,
|
||||
OutputEnd = 0,
|
||||
BitBuffer = 0,
|
||||
BitsLeft = 0,
|
||||
|
||||
BufferState = new BufferState()
|
||||
{
|
||||
InputPointer = 0,
|
||||
InputEnd = 0,
|
||||
BitBuffer = 0,
|
||||
BitsLeft = 0,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -159,7 +100,7 @@ namespace LibMSPackSharp.Compression
|
||||
int bits_left;
|
||||
int i_ptr, i_end;
|
||||
|
||||
int i, state;
|
||||
int i, readState;
|
||||
Error error;
|
||||
|
||||
// Easy answers
|
||||
@@ -188,32 +129,32 @@ namespace LibMSPackSharp.Compression
|
||||
while (out_bytes > 0)
|
||||
{
|
||||
// Unpack another block
|
||||
zip.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left);
|
||||
BufferState state = zip.RESTORE_BITS();
|
||||
|
||||
// Skip to next read 'CK' header
|
||||
i = bits_left & 7;
|
||||
i = state.BitsLeft & 7;
|
||||
|
||||
// Align to bytestream
|
||||
zip.REMOVE_BITS_LSB(i, ref bit_buffer, ref bits_left);
|
||||
state.REMOVE_BITS_LSB(i);
|
||||
|
||||
state = 0;
|
||||
readState = 0;
|
||||
do
|
||||
{
|
||||
i = (int)zip.READ_BITS_LSB(8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
i = (int)zip.READ_BITS_LSB(8, state);
|
||||
|
||||
if (i == 'C')
|
||||
state = 1;
|
||||
else if ((state == 1) && (i == 'K'))
|
||||
state = 2;
|
||||
readState = 1;
|
||||
else if ((readState == 1) && (i == 'K'))
|
||||
readState = 2;
|
||||
else
|
||||
state = 0;
|
||||
} while (state != 2);
|
||||
readState = 0;
|
||||
} while (readState != 2);
|
||||
|
||||
// Inflate a block, repair and realign if necessary
|
||||
zip.WindowPosition = 0;
|
||||
zip.BytesOutput = 0;
|
||||
|
||||
zip.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
|
||||
zip.STORE_BITS(state);
|
||||
|
||||
if ((error = Inflate(zip)) != Error.MSPACK_ERR_OK)
|
||||
{
|
||||
@@ -269,36 +210,31 @@ namespace LibMSPackSharp.Compression
|
||||
/// </summary>
|
||||
public static Error DecompressKWAJ(MSZIPDStream zip)
|
||||
{
|
||||
// For the bit buffer
|
||||
uint bit_buffer;
|
||||
int bits_left;
|
||||
int i_ptr, i_end;
|
||||
|
||||
int i, block_len;
|
||||
Error error;
|
||||
|
||||
// Unpack blocks until block_len == 0
|
||||
for (; ; )
|
||||
{
|
||||
zip.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left);
|
||||
BufferState state = zip.RESTORE_BITS();
|
||||
|
||||
// Align to bytestream, read block_len
|
||||
i = bits_left & 7;
|
||||
zip.REMOVE_BITS_LSB(i, ref bit_buffer, ref bits_left);
|
||||
i = state.BitsLeft & 7;
|
||||
state.REMOVE_BITS_LSB(i);
|
||||
|
||||
block_len = (int)zip.READ_BITS_LSB(8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
i = (int)zip.READ_BITS_LSB(8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
block_len = (int)zip.READ_BITS_LSB(8, state);
|
||||
i = (int)zip.READ_BITS_LSB(8, state);
|
||||
|
||||
block_len |= i << 8;
|
||||
if (block_len == 0)
|
||||
break;
|
||||
|
||||
// Read "CK" header
|
||||
i = (int)zip.READ_BITS_LSB(8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
i = (int)zip.READ_BITS_LSB(8, state);
|
||||
if (i != 'C')
|
||||
return Error.MSPACK_ERR_DATAFORMAT;
|
||||
|
||||
i = (int)zip.READ_BITS_LSB(8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
i = (int)zip.READ_BITS_LSB(8, state);
|
||||
if (i != 'K')
|
||||
return Error.MSPACK_ERR_DATAFORMAT;
|
||||
|
||||
@@ -306,7 +242,7 @@ namespace LibMSPackSharp.Compression
|
||||
zip.WindowPosition = 0;
|
||||
zip.BytesOutput = 0;
|
||||
|
||||
zip.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
|
||||
zip.STORE_BITS(state);
|
||||
|
||||
if ((error = Inflate(zip)) != Error.MSPACK_ERR_OK)
|
||||
{
|
||||
@@ -331,16 +267,16 @@ namespace LibMSPackSharp.Compression
|
||||
byte[] lens = new byte[MSZIP_LITERAL_MAXSYMBOLS + MSZIP_DISTANCE_MAXSYMBOLS];
|
||||
uint lit_codes, dist_codes, code, last_code = 0, bitlen_codes, i, run;
|
||||
|
||||
zip.RESTORE_BITS(out int i_ptr, out int i_end, out uint bit_buffer, out int bits_left);
|
||||
BufferState state = zip.RESTORE_BITS();
|
||||
|
||||
// Read the number of codes
|
||||
lit_codes = (uint)zip.READ_BITS_LSB(5, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
lit_codes = (uint)zip.READ_BITS_LSB(5, state);
|
||||
lit_codes += 257;
|
||||
|
||||
dist_codes = (uint)zip.READ_BITS_LSB(5, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
dist_codes = (uint)zip.READ_BITS_LSB(5, state);
|
||||
dist_codes += 1;
|
||||
|
||||
bitlen_codes = (uint)zip.READ_BITS_LSB(5, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
bitlen_codes = (uint)zip.READ_BITS_LSB(5, state);
|
||||
bitlen_codes += 4;
|
||||
|
||||
if (lit_codes > MSZIP_LITERAL_MAXSYMBOLS)
|
||||
@@ -351,12 +287,12 @@ namespace LibMSPackSharp.Compression
|
||||
// Read in the bit lengths in their unusual order
|
||||
for (i = 0; i < bitlen_codes; i++)
|
||||
{
|
||||
bl_len[bitlen_order[i]] = (byte)zip.READ_BITS_LSB(3, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
bl_len[BitLengthOrder[i]] = (byte)zip.READ_BITS_LSB(3, state);
|
||||
}
|
||||
|
||||
while (i < 19)
|
||||
{
|
||||
bl_len[bitlen_order[i++]] = 0;
|
||||
bl_len[BitLengthOrder[i++]] = 0;
|
||||
}
|
||||
|
||||
// Create decoding table with an immediate lookup
|
||||
@@ -368,9 +304,9 @@ namespace LibMSPackSharp.Compression
|
||||
{
|
||||
// Single-level huffman lookup
|
||||
|
||||
zip.ENSURE_BITS(7, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
code = bl_table[zip.PEEK_BITS_LSB(7, bit_buffer)];
|
||||
zip.REMOVE_BITS_LSB(bl_len[code], ref bit_buffer, ref bits_left);
|
||||
zip.ENSURE_BITS(7, state);
|
||||
code = bl_table[zip.PEEK_BITS_LSB(7, state.BitBuffer)];
|
||||
state.REMOVE_BITS_LSB(bl_len[code]);
|
||||
|
||||
if (code < 16)
|
||||
{
|
||||
@@ -381,19 +317,19 @@ namespace LibMSPackSharp.Compression
|
||||
switch (code)
|
||||
{
|
||||
case 16:
|
||||
run = (uint)zip.READ_BITS_LSB(2, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
run = (uint)zip.READ_BITS_LSB(2, state);
|
||||
run += 3;
|
||||
code = last_code;
|
||||
break;
|
||||
|
||||
case 17:
|
||||
run = (uint)zip.READ_BITS_LSB(3, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
run = (uint)zip.READ_BITS_LSB(3, state);
|
||||
run += 3;
|
||||
code = 0;
|
||||
break;
|
||||
|
||||
case 18:
|
||||
run = (uint)zip.READ_BITS_LSB(7, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
run = (uint)zip.READ_BITS_LSB(7, state);
|
||||
run += 11;
|
||||
code = 0;
|
||||
break;
|
||||
@@ -430,7 +366,7 @@ namespace LibMSPackSharp.Compression
|
||||
zip.DISTANCE_len[i++] = 0;
|
||||
}
|
||||
|
||||
zip.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
|
||||
zip.STORE_BITS(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -444,15 +380,15 @@ namespace LibMSPackSharp.Compression
|
||||
Error err;
|
||||
ushort sym;
|
||||
|
||||
zip.RESTORE_BITS(out int i_ptr, out int i_end, out uint bit_buffer, out int bits_left);
|
||||
BufferState state = zip.RESTORE_BITS();
|
||||
|
||||
do
|
||||
{
|
||||
// Read in last block bit
|
||||
last_block = (uint)zip.READ_BITS_LSB(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
last_block = (uint)zip.READ_BITS_LSB(1, state);
|
||||
|
||||
// Read in block type
|
||||
block_type = (uint)zip.READ_BITS_LSB(2, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
block_type = (uint)zip.READ_BITS_LSB(2, state);
|
||||
|
||||
if (block_type == 0)
|
||||
{
|
||||
@@ -460,29 +396,29 @@ namespace LibMSPackSharp.Compression
|
||||
byte[] lens_buf = new byte[4];
|
||||
|
||||
// Go to byte boundary
|
||||
i = (uint)(bits_left & 7);
|
||||
zip.REMOVE_BITS_LSB((int)i, ref bit_buffer, ref bits_left);
|
||||
i = (uint)(state.BitsLeft & 7);
|
||||
state.REMOVE_BITS_LSB((int)i);
|
||||
|
||||
// Read 4 bytes of data, emptying the bit-buffer if necessary
|
||||
for (i = 0; (bits_left >= 8); i++)
|
||||
for (i = 0; (state.BitsLeft >= 8); i++)
|
||||
{
|
||||
if (i == 4)
|
||||
return Error.INF_ERR_BITBUF;
|
||||
|
||||
lens_buf[i] = (byte)zip.PEEK_BITS_LSB(8, bit_buffer);
|
||||
zip.REMOVE_BITS_LSB(8, ref bit_buffer, ref bits_left);
|
||||
lens_buf[i] = (byte)zip.PEEK_BITS_LSB(8, state.BitBuffer);
|
||||
state.REMOVE_BITS_LSB(8);
|
||||
}
|
||||
|
||||
if (bits_left != 0)
|
||||
if (state.BitsLeft != 0)
|
||||
return Error.INF_ERR_BITBUF;
|
||||
|
||||
while (i < 4)
|
||||
{
|
||||
zip.READ_IF_NEEDED(ref i_ptr, ref i_end);
|
||||
zip.READ_IF_NEEDED(state);
|
||||
if (zip.Error != Error.MSPACK_ERR_OK)
|
||||
return zip.Error;
|
||||
|
||||
lens_buf[i++] = zip.InputBuffer[i_ptr++];
|
||||
lens_buf[i++] = zip.InputBuffer[state.InputPointer++];
|
||||
}
|
||||
|
||||
// Get the length and its complement
|
||||
@@ -496,21 +432,21 @@ namespace LibMSPackSharp.Compression
|
||||
// Read and copy the uncompressed data into the window
|
||||
while (length > 0)
|
||||
{
|
||||
zip.READ_IF_NEEDED(ref i_ptr, ref i_end);
|
||||
zip.READ_IF_NEEDED(state);
|
||||
if (zip.Error != Error.MSPACK_ERR_OK)
|
||||
return zip.Error;
|
||||
|
||||
this_run = length;
|
||||
if (this_run > (uint)(i_end - i_ptr))
|
||||
this_run = (uint)(i_end - i_ptr);
|
||||
if (this_run > (uint)(state.InputEnd - state.InputPointer))
|
||||
this_run = (uint)(state.InputEnd - state.InputPointer);
|
||||
|
||||
if (this_run > (MSZIP_FRAME_SIZE - zip.WindowPosition))
|
||||
this_run = MSZIP_FRAME_SIZE - zip.WindowPosition;
|
||||
|
||||
Array.Copy(zip.InputBuffer, i_ptr, zip.Window, zip.WindowPosition, this_run);
|
||||
Array.Copy(zip.InputBuffer, state.InputPointer, zip.Window, zip.WindowPosition, this_run);
|
||||
|
||||
zip.WindowPosition += this_run;
|
||||
i_ptr += (int)this_run;
|
||||
state.InputPointer += (int)this_run;
|
||||
length -= this_run;
|
||||
|
||||
err = FLUSH_IF_NEEDED(zip);
|
||||
@@ -555,12 +491,12 @@ namespace LibMSPackSharp.Compression
|
||||
else
|
||||
{
|
||||
// Block with dynamic Huffman codes
|
||||
zip.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
|
||||
zip.STORE_BITS(state);
|
||||
|
||||
if ((err = ReadLens(zip)) != Error.MSPACK_ERR_OK)
|
||||
return err;
|
||||
|
||||
zip.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left);
|
||||
state = zip.RESTORE_BITS();
|
||||
}
|
||||
|
||||
// Now huffman lengths are read for either kind of block,
|
||||
@@ -574,7 +510,7 @@ namespace LibMSPackSharp.Compression
|
||||
// Decode forever until end of block code
|
||||
for (; ; )
|
||||
{
|
||||
code = (uint)zip.READ_HUFFSYM_LSB(zip.LITERAL_table, zip.LITERAL_len, MSZIP_LITERAL_TABLEBITS, MSZIP_LITERAL_MAXSYMBOLS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
code = (uint)zip.READ_HUFFSYM_LSB(zip.LITERAL_table, zip.LITERAL_len, MSZIP_LITERAL_TABLEBITS, MSZIP_LITERAL_MAXSYMBOLS, state);
|
||||
|
||||
if (code < 256)
|
||||
{
|
||||
@@ -594,16 +530,16 @@ namespace LibMSPackSharp.Compression
|
||||
if (code >= 29)
|
||||
return Error.INF_ERR_LITCODE; // Codes 286-287 are illegal
|
||||
|
||||
length = (uint)zip.READ_BITS_T_LSB(lit_extrabits[code], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
length += lit_lengths[code];
|
||||
length = (uint)zip.READ_BITS_T_LSB(LiteralExtraBits[code], state);
|
||||
length += LiteralLengths[code];
|
||||
|
||||
code = (uint)zip.READ_HUFFSYM_LSB(zip.DISTANCE_table, zip.DISTANCE_len, MSZIP_DISTANCE_TABLEBITS, MSZIP_DISTANCE_MAXSYMBOLS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
code = (uint)zip.READ_HUFFSYM_LSB(zip.DISTANCE_table, zip.DISTANCE_len, MSZIP_DISTANCE_TABLEBITS, MSZIP_DISTANCE_MAXSYMBOLS, state);
|
||||
|
||||
if (code >= 30)
|
||||
return Error.INF_ERR_DISTCODE;
|
||||
|
||||
distance = (uint)zip.READ_BITS_T_LSB(dist_extrabits[code], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
distance += dist_offsets[code];
|
||||
distance = (uint)zip.READ_BITS_T_LSB(DistanceExtraBits[code], state);
|
||||
distance += DistanceOffsets[code];
|
||||
|
||||
// Match position is window position minus distance. If distance
|
||||
// is more than window position numerically, it must 'wrap
|
||||
@@ -672,7 +608,7 @@ namespace LibMSPackSharp.Compression
|
||||
return Error.INF_ERR_FLUSH;
|
||||
}
|
||||
|
||||
zip.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
|
||||
zip.STORE_BITS(state);
|
||||
|
||||
// Return success
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
@@ -21,7 +22,7 @@ namespace LibMSPackSharp.Compression
|
||||
/// <summary>
|
||||
/// 32kb history window
|
||||
/// </summary>
|
||||
public byte[] Window { get; set; } = new byte[MSZIP.MSZIP_FRAME_SIZE];
|
||||
public byte[] Window { get; set; } = new byte[MSZIP_FRAME_SIZE];
|
||||
|
||||
/// <summary>
|
||||
/// Offset within window
|
||||
@@ -39,15 +40,15 @@ namespace LibMSPackSharp.Compression
|
||||
|
||||
#region Huffman code lengths
|
||||
|
||||
public byte[] LITERAL_len { get; set; } = new byte[MSZIP.MSZIP_LITERAL_MAXSYMBOLS];
|
||||
public byte[] DISTANCE_len { get; set; } = new byte[MSZIP.MSZIP_DISTANCE_MAXSYMBOLS];
|
||||
public byte[] LITERAL_len { get; set; } = new byte[MSZIP_LITERAL_MAXSYMBOLS];
|
||||
public byte[] DISTANCE_len { get; set; } = new byte[MSZIP_DISTANCE_MAXSYMBOLS];
|
||||
|
||||
#endregion
|
||||
|
||||
#region Huffman decoding tables
|
||||
|
||||
public ushort[] LITERAL_table { get; set; } = new ushort[MSZIP.MSZIP_LITERAL_TABLESIZE];
|
||||
public ushort[] DISTANCE_table { get; set; } = new ushort[MSZIP.MSZIP_DISTANCE_TABLESIZE];
|
||||
public ushort[] LITERAL_table { get; set; } = new ushort[MSZIP_LITERAL_TABLESIZE];
|
||||
public ushort[] DISTANCE_table { get; set; } = new ushort[MSZIP_DISTANCE_TABLESIZE];
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -57,13 +58,13 @@ namespace LibMSPackSharp.Compression
|
||||
public override Error HUFF_ERROR() => Error.INF_ERR_HUFFSYM;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void READ_BYTES(ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left)
|
||||
public override void READ_BYTES(BufferState state)
|
||||
{
|
||||
READ_IF_NEEDED(ref i_ptr, ref i_end);
|
||||
READ_IF_NEEDED(state);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return;
|
||||
|
||||
INJECT_BITS_LSB(InputBuffer[i_ptr++], 8, ref bit_buffer, ref bits_left);
|
||||
INJECT_BITS_LSB(InputBuffer[state.InputPointer++], 8, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
117
BurnOutSharp/External/libmspack/Compression/QTM.cs
vendored
117
BurnOutSharp/External/libmspack/Compression/QTM.cs
vendored
@@ -22,67 +22,12 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public class QTM
|
||||
{
|
||||
public const int QTM_FRAME_SIZE = 32768;
|
||||
|
||||
/* Quantum static data tables:
|
||||
*
|
||||
* Quantum uses 'position slots' to represent match offsets. For every
|
||||
* match, a small 'position slot' number and a small offset from that slot
|
||||
* are encoded instead of one large offset.
|
||||
*
|
||||
* position_base[] is an index to the position slot bases
|
||||
*
|
||||
* extra_bits[] states how many bits of offset-from-base data is needed.
|
||||
*
|
||||
* length_base[] and length_extra[] are equivalent in function, but are
|
||||
* used for encoding selector 6 (variable length match) match lengths,
|
||||
* instead of match offsets.
|
||||
*
|
||||
* They are generated with the following code:
|
||||
* uint i, offset;
|
||||
* for (i = 0, offset = 0; i < 42; i++) {
|
||||
* position_base[i] = offset;
|
||||
* extra_bits[i] = ((i < 2) ? 0 : (i - 2)) >> 1;
|
||||
* offset += 1 << extra_bits[i];
|
||||
* }
|
||||
* for (i = 0, offset = 0; i < 26; i++) {
|
||||
* length_base[i] = offset;
|
||||
* length_extra[i] = (i < 2 ? 0 : i - 2) >> 2;
|
||||
* offset += 1 << length_extra[i];
|
||||
* }
|
||||
* length_base[26] = 254; length_extra[26] = 0;
|
||||
*/
|
||||
|
||||
private static readonly uint[] position_base = new uint[42]
|
||||
{
|
||||
0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
|
||||
1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152,
|
||||
65536, 98304, 131072, 196608, 262144, 393216, 524288, 786432, 1048576, 1572864
|
||||
};
|
||||
|
||||
private static readonly byte[] extra_bits = new byte[42]
|
||||
{
|
||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
|
||||
11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19
|
||||
};
|
||||
|
||||
private static readonly byte[] length_base = new byte[27]
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 14, 18, 22, 26,
|
||||
30, 38, 46, 54, 62, 78, 94, 110, 126, 158, 190, 222, 254
|
||||
};
|
||||
|
||||
private static readonly byte[] length_extra = new byte[27]
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// allocates Quantum decompression state for decoding the given stream.
|
||||
///
|
||||
@@ -126,13 +71,17 @@ namespace LibMSPackSharp.Compression
|
||||
HeaderRead = 0,
|
||||
Error = Error.MSPACK_ERR_OK,
|
||||
|
||||
InputPointer = 0,
|
||||
InputEnd = 0,
|
||||
OutputPointer = 0,
|
||||
OutputEnd = 0,
|
||||
EndOfInput = 0,
|
||||
BitsLeft = 0,
|
||||
BitBuffer = 0,
|
||||
|
||||
BufferState = new BufferState()
|
||||
{
|
||||
InputPointer = 0,
|
||||
InputEnd = 0,
|
||||
BitBuffer = 0,
|
||||
BitsLeft = 0,
|
||||
}
|
||||
};
|
||||
|
||||
// Initialise arithmetic coding models
|
||||
@@ -214,7 +163,7 @@ namespace LibMSPackSharp.Compression
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
// Restore local state
|
||||
qtm.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left);
|
||||
BufferState state = qtm.RESTORE_BITS();
|
||||
window = qtm.Window;
|
||||
window_posn = qtm.WindowPosition;
|
||||
frame_todo = qtm.FrameTODO;
|
||||
@@ -230,7 +179,7 @@ namespace LibMSPackSharp.Compression
|
||||
{
|
||||
H = 0xFFFF;
|
||||
L = 0;
|
||||
C = (ushort)qtm.READ_BITS_MSB(16, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
C = (ushort)qtm.READ_BITS_MSB(16, state);
|
||||
qtm.HeaderRead = 1;
|
||||
}
|
||||
|
||||
@@ -244,7 +193,7 @@ namespace LibMSPackSharp.Compression
|
||||
|
||||
while (window_posn < frame_end)
|
||||
{
|
||||
selector = GET_SYMBOL(qtm, qtm.Model7, ref H, ref L, ref C, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
selector = GET_SYMBOL(qtm, qtm.Model7, ref H, ref L, ref C, state);
|
||||
if (selector < 4)
|
||||
{
|
||||
// Literal byte
|
||||
@@ -269,7 +218,7 @@ namespace LibMSPackSharp.Compression
|
||||
break;
|
||||
}
|
||||
|
||||
sym = GET_SYMBOL(qtm, mdl, ref H, ref L, ref C, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
sym = GET_SYMBOL(qtm, mdl, ref H, ref L, ref C, state);
|
||||
window[window_posn++] = (byte)sym;
|
||||
frame_todo--;
|
||||
}
|
||||
@@ -280,29 +229,29 @@ namespace LibMSPackSharp.Compression
|
||||
{
|
||||
// Selector 4 = fixed length match (3 bytes)
|
||||
case 4:
|
||||
sym = GET_SYMBOL(qtm, qtm.Model4, ref H, ref L, ref C, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
extra = (int)qtm.READ_MANY_BITS_MSB(extra_bits[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
match_offset = (uint)(position_base[sym] + extra + 1);
|
||||
sym = GET_SYMBOL(qtm, qtm.Model4, ref H, ref L, ref C, state);
|
||||
extra = (int)qtm.READ_MANY_BITS_MSB(QTMExtraBits[sym], state);
|
||||
match_offset = (uint)(QTMPositionBase[sym] + extra + 1);
|
||||
match_length = 3;
|
||||
break;
|
||||
|
||||
// Selector 5 = fixed length match (4 bytes)
|
||||
case 5:
|
||||
sym = GET_SYMBOL(qtm, qtm.Model5, ref H, ref L, ref C, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
extra = (int)qtm.READ_MANY_BITS_MSB(extra_bits[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
match_offset = (uint)(position_base[sym] + extra + 1);
|
||||
sym = GET_SYMBOL(qtm, qtm.Model5, ref H, ref L, ref C, state);
|
||||
extra = (int)qtm.READ_MANY_BITS_MSB(QTMExtraBits[sym], state);
|
||||
match_offset = (uint)(QTMPositionBase[sym] + extra + 1);
|
||||
match_length = 4;
|
||||
break;
|
||||
|
||||
// Selector 6 = variable length match
|
||||
case 6:
|
||||
sym = GET_SYMBOL(qtm, qtm.Model6Len, ref H, ref L, ref C, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
extra = (int)qtm.READ_MANY_BITS_MSB(length_extra[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
match_length = length_base[sym] + extra + 5;
|
||||
sym = GET_SYMBOL(qtm, qtm.Model6Len, ref H, ref L, ref C, state);
|
||||
extra = (int)qtm.READ_MANY_BITS_MSB(QTMLengthExtra[sym], state);
|
||||
match_length = QTMLengthBase[sym] + extra + 5;
|
||||
|
||||
sym = GET_SYMBOL(qtm, qtm.Model6, ref H, ref L, ref C, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
extra = (int)qtm.READ_MANY_BITS_MSB(extra_bits[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
match_offset = (uint)(position_base[sym] + extra + 1);
|
||||
sym = GET_SYMBOL(qtm, qtm.Model6, ref H, ref L, ref C, state);
|
||||
extra = (int)qtm.READ_MANY_BITS_MSB(QTMExtraBits[sym], state);
|
||||
match_offset = (uint)(QTMPositionBase[sym] + extra + 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -422,15 +371,15 @@ namespace LibMSPackSharp.Compression
|
||||
if (frame_todo == 0)
|
||||
{
|
||||
// Re-align input
|
||||
if ((bits_left & 7) != 0)
|
||||
qtm.REMOVE_BITS_MSB(bits_left & 7, ref bit_buffer, ref bits_left);
|
||||
if ((state.BitsLeft & 7) != 0)
|
||||
state.REMOVE_BITS_MSB(state.BitsLeft & 7);
|
||||
|
||||
// Special Quantum hack -- cabd.c injects a 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.
|
||||
do
|
||||
{
|
||||
i = (int)qtm.READ_BITS_MSB(8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
i = (int)qtm.READ_BITS_MSB(8, state);
|
||||
} while (i != 0xFF);
|
||||
|
||||
qtm.HeaderRead = 0;
|
||||
@@ -470,7 +419,7 @@ namespace LibMSPackSharp.Compression
|
||||
}
|
||||
|
||||
// Store local state
|
||||
qtm.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
|
||||
qtm.STORE_BITS(state);
|
||||
qtm.WindowPosition = window_posn;
|
||||
qtm.FrameTODO = frame_todo;
|
||||
qtm.High = H;
|
||||
@@ -480,7 +429,7 @@ namespace LibMSPackSharp.Compression
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
private static ushort GET_SYMBOL(QTMDStream qtm, QTMDModel model, ref ushort H, ref ushort L, ref ushort C, ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left)
|
||||
private static ushort GET_SYMBOL(QTMDStream qtm, QTMDModel model, ref ushort H, ref ushort L, ref ushort C, BufferState state)
|
||||
{
|
||||
uint range = (uint)((H - L) & 0xFFFF) + 1;
|
||||
ushort symf = (ushort)(((((C - L + 1) * model.Syms[0].CumulativeFrequency) - 1) / range) & 0xFFFF);
|
||||
@@ -527,9 +476,9 @@ namespace LibMSPackSharp.Compression
|
||||
L <<= 1;
|
||||
H = (ushort)((H << 1) | 1);
|
||||
|
||||
qtm.ENSURE_BITS(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
|
||||
C = (ushort)((C << 1) | (qtm.PEEK_BITS_MSB(1, bit_buffer)));
|
||||
qtm.REMOVE_BITS_MSB(1, ref bit_buffer, ref bits_left);
|
||||
qtm.ENSURE_BITS(1, state);
|
||||
C = (ushort)((C << 1) | (qtm.PEEK_BITS_MSB(1, state.BitBuffer)));
|
||||
state.REMOVE_BITS_MSB(1);
|
||||
}
|
||||
|
||||
return temp;
|
||||
|
||||
@@ -130,20 +130,20 @@ namespace LibMSPackSharp.Compression
|
||||
public override Error HUFF_ERROR() => throw new NotImplementedException();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void READ_BYTES(ref int i_ptr, ref int i_end, ref uint bit_buffer, ref int bits_left)
|
||||
public override void READ_BYTES(BufferState state)
|
||||
{
|
||||
READ_IF_NEEDED(ref i_ptr, ref i_end);
|
||||
READ_IF_NEEDED(state);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return;
|
||||
|
||||
byte b0 = InputBuffer[i_ptr++];
|
||||
byte b0 = InputBuffer[state.InputPointer++];
|
||||
|
||||
READ_IF_NEEDED(ref i_ptr, ref i_end);
|
||||
READ_IF_NEEDED(state);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return;
|
||||
|
||||
byte b1 = InputBuffer[i_ptr++];
|
||||
INJECT_BITS_MSB((b0 << 8) | b1, 16, ref bit_buffer, ref bits_left);
|
||||
byte b1 = InputBuffer[state.InputPointer++];
|
||||
INJECT_BITS_MSB((b0 << 8) | b1, 16, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user