Nearly finish demacroificiation

This commit is contained in:
Matt Nadareski
2022-05-24 00:47:09 -07:00
parent 21ecaca761
commit 4316427980
9 changed files with 409 additions and 982 deletions

View File

@@ -17,6 +17,8 @@ namespace LibMSPackSharp.Compression
{
public abstract class CompressionStream : BaseDecompressState
{
#region Constants
/// <summary>
/// Number of bits in a character
/// </summary>
@@ -27,6 +29,13 @@ namespace LibMSPackSharp.Compression
/// </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; }
@@ -363,7 +372,7 @@ namespace LibMSPackSharp.Compression
// TODO: These should be in a separate file
#region ReadHuff Methods
public const int HUFF_MAXBITS = 16;
#region Common
/// <summary>
/// This function was originally coded by David Tritscher.
@@ -379,6 +388,7 @@ namespace LibMSPackSharp.Compression
/// Should be ((1<<nbits) + (nsyms*2)) in length.
/// </param>
/// <returns>true for OK or false for error</returns>
/// <remarks>TODO: Split into MSB and LSB variants</remarks>
public static bool MakeDecodeTable(int nsyms, int nbits, byte[] length, ushort[] table, bool msb)
{
ushort sym, next_symbol;
@@ -535,6 +545,87 @@ namespace LibMSPackSharp.Compression
return pos == table_mask;
}
/// <summary>
/// Per compression error code for decoding failure
/// </summary>
public abstract Error HUFF_ERROR();
#endregion
#region MSB
/// <summary>
/// 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)
{
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)];
if (sym >= maxsymbols)
HUFF_TRAVERSE_MSB(ref sym, table, tablebits, maxsymbols, bit_buffer);
REMOVE_BITS_MSB(lengths[sym], ref bit_buffer, ref bits_left);
return sym;
}
/// <summary>
/// Traverse for a single symbol
/// </summary>
private void HUFF_TRAVERSE_MSB(ref ushort sym, ushort[] table, int tablebits, int maxsymbols, uint bit_buffer)
{
int i = 1 << (BITBUF_WIDTH - tablebits);
do
{
if ((i >>= 1) == 0)
{
Error = HUFF_ERROR();
return;
}
sym = table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)];
} while (sym >= maxsymbols);
}
#endregion
#region LSB
/// <summary>
/// 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)
{
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)];
if (sym >= maxsymbols)
HUFF_TRAVERSE_LSB(ref sym, table, tablebits, maxsymbols, bit_buffer);
REMOVE_BITS_LSB(lengths[sym], ref bit_buffer, ref bits_left);
return sym;
}
/// <summary>
/// Traverse for a single symbol
/// </summary>
private void HUFF_TRAVERSE_LSB(ref ushort sym, ushort[] table, int tablebits, int maxsymbols, uint bit_buffer)
{
int i = tablebits - 1;
do
{
if (i++ > HUFF_MAXBITS)
{
Error = HUFF_ERROR();
return;
}
sym = table[(sym << 1) | ((bit_buffer >> i) & 1)];
} while (sym >= maxsymbols);
}
#endregion
#endregion
}
}

View File

@@ -8,7 +8,6 @@
*/
using System.IO;
using LibMSPackSharp.KWAJ;
using static LibMSPackSharp.Constants;
namespace LibMSPackSharp.Compression
@@ -42,10 +41,8 @@ namespace LibMSPackSharp.Compression
public static Error Decompress(LZHKWAJStream lzh)
{
int i;
ushort sym;
int lit_run = 0;
int j, pos = 0, len, offset;
Error err;
uint[] types = new uint[6];
// Reset global state
@@ -60,151 +57,31 @@ namespace LibMSPackSharp.Compression
// Read 6 encoding types (for byte alignment) but only 5 are needed
for (i = 0; i < 6; i++)
{
//READ_BITS_SAFE(types[i], 4)
{
types[i] = (uint)lzh.READ_BITS_MSB(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput)
return Error.MSPACK_ERR_OK;
}
types[i] = (uint)lzh.READ_BITS_SAFE(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
return Error.MSPACK_ERR_OK;
}
// Read huffman table symbol lengths and build huffman trees
//BUILD_TREE(MATCHLEN1, types[0])
{
lzh.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
err = ReadLens(lzh, types[0], KWAJ_MATCHLEN1_SYMS, 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);
if (!CompressionStream.MakeDecodeTable(KWAJ_MATCHLEN1_SYMS, KWAJ_TABLEBITS, lzh.MATCHLEN1_len, lzh.MATCHLEN1_table, msb: true))
return Error.MSPACK_ERR_DATAFORMAT;
}
//BUILD_TREE(MATCHLEN2, types[1])
{
lzh.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
err = ReadLens(lzh, types[1], KWAJ_MATCHLEN2_SYMS, lzh.MATCHLEN2_len);
if (err != Error.MSPACK_ERR_OK)
return err;
lzh.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left);
if (!CompressionStream.MakeDecodeTable(KWAJ_MATCHLEN2_SYMS, KWAJ_TABLEBITS, lzh.MATCHLEN2_len, lzh.MATCHLEN2_table, msb: true))
return Error.MSPACK_ERR_DATAFORMAT;
}
//BUILD_TREE(LITLEN, types[2])
{
lzh.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
err = ReadLens(lzh, types[2], KWAJ_LITLEN_SYMS, lzh.LITLEN_len);
if (err != Error.MSPACK_ERR_OK)
return err;
lzh.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left);
if (!CompressionStream.MakeDecodeTable(KWAJ_LITLEN_SYMS, KWAJ_TABLEBITS, lzh.LITLEN_len, lzh.LITLEN_table, msb: true))
return Error.MSPACK_ERR_DATAFORMAT;
}
//BUILD_TREE(OFFSET, types[3])
{
lzh.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
err = ReadLens(lzh, types[3], KWAJ_OFFSET_SYMS, lzh.OFFSET_len);
if (err != Error.MSPACK_ERR_OK)
return err;
lzh.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left);
if (!CompressionStream.MakeDecodeTable(KWAJ_OFFSET_SYMS, KWAJ_TABLEBITS, lzh.OFFSET_len, lzh.OFFSET_table, msb: true))
return Error.MSPACK_ERR_DATAFORMAT;
}
//BUILD_TREE(LITERAL, types[4])
{
lzh.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
err = ReadLens(lzh, types[4], KWAJ_LITERAL_SYMS, lzh.LITERAL_len);
if (err != Error.MSPACK_ERR_OK)
return err;
lzh.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left);
if (!CompressionStream.MakeDecodeTable(KWAJ_LITERAL_SYMS, KWAJ_TABLEBITS, lzh.LITERAL_len, lzh.LITERAL_table, msb: true))
return Error.MSPACK_ERR_DATAFORMAT;
}
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);
while (lzh.EndOfInput == 0)
{
if (lit_run != 0)
{
//READ_HUFFSYM_SAFE(MATCHLEN2, len)
{
//READ_HUFFSYM(MATCHLEN2, len)
{
lzh.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
sym = lzh.MATCHLEN2_table[lzh.PEEK_BITS_MSB(KWAJ_TABLEBITS, bit_buffer)];
if (sym >= KWAJ_MATCHLEN2_SYMS)
{
//HUFF_TRAVERSE(MATCHLEN2)
{
i = 1 << (CompressionStream.BITBUF_WIDTH - KWAJ_TABLEBITS);
do
{
if ((i >>= 1) == 0)
return Error.MSPACK_ERR_DATAFORMAT;
sym = lzh.MATCHLEN2_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)];
} while (sym >= KWAJ_MATCHLEN2_SYMS);
}
}
(len) = sym;
i = lzh.MATCHLEN2_len[sym];
lzh.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left);
}
if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput)
return Error.MSPACK_ERR_OK;
}
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);
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
return Error.MSPACK_ERR_OK;
}
else
{
//READ_HUFFSYM_SAFE(MATCHLEN1, len)
{
//READ_HUFFSYM(MATCHLEN1, len)
{
lzh.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
sym = lzh.MATCHLEN1_table[lzh.PEEK_BITS_MSB(KWAJ_TABLEBITS, bit_buffer)];
if (sym >= KWAJ_MATCHLEN1_SYMS)
{
//HUFF_TRAVERSE(MATCHLEN1)
{
i = 1 << (CompressionStream.BITBUF_WIDTH - KWAJ_TABLEBITS);
do
{
if ((i >>= 1) == 0)
return Error.MSPACK_ERR_DATAFORMAT;
sym = lzh.MATCHLEN1_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)];
} while (sym >= KWAJ_MATCHLEN1_SYMS);
}
}
(len) = sym;
i = lzh.MATCHLEN1_len[sym];
lzh.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left);
}
if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput)
return Error.MSPACK_ERR_OK;
}
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);
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
return Error.MSPACK_ERR_OK;
}
if (len > 0)
@@ -212,44 +89,15 @@ namespace LibMSPackSharp.Compression
len += 2;
lit_run = 0; // Not the end of a literal run
//READ_HUFFSYM_SAFE(OFFSET, j)
{
//READ_HUFFSYM(OFFSET, j)
{
lzh.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
sym = lzh.OFFSET_table[lzh.PEEK_BITS_MSB(KWAJ_TABLEBITS, bit_buffer)];
if (sym >= KWAJ_OFFSET_SYMS)
{
//HUFF_TRAVERSE(OFFSET)
{
i = 1 << (CompressionStream.BITBUF_WIDTH - KWAJ_TABLEBITS);
do
{
if ((i >>= 1) == 0)
return Error.MSPACK_ERR_DATAFORMAT;
sym = lzh.OFFSET_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)];
} while (sym >= KWAJ_OFFSET_SYMS);
}
}
(j) = sym;
i = lzh.OFFSET_len[sym];
lzh.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left);
}
if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput)
return Error.MSPACK_ERR_OK;
}
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);
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
return Error.MSPACK_ERR_OK;
offset = j << 6;
//READ_BITS_SAFE(j, 6)
{
j = (int)lzh.READ_BITS_MSB(6, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput)
return Error.MSPACK_ERR_OK;
}
j = (int)lzh.READ_BITS_SAFE(6, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
return Error.MSPACK_ERR_OK;
offset |= j;
@@ -257,12 +105,9 @@ namespace LibMSPackSharp.Compression
while (len-- > 0)
{
lzh.Window[pos] = lzh.Window[(pos + 4096 - offset) & 4095];
//WRITE_BYTE
{
if (lzh.System.Write(lzh.OutputFileHandle, lzh.Window, pos, 1) != 1)
return Error.MSPACK_ERR_WRITE;
}
lzh.WRITE_BYTE(pos);
if (lzh.Error != Error.MSPACK_ERR_OK)
return lzh.Error;
pos++;
pos &= 4095;
@@ -270,78 +115,24 @@ namespace LibMSPackSharp.Compression
}
else
{
//READ_HUFFSYM_SAFE(LITLEN, len)
{
//READ_HUFFSYM(LITLEN, len)
{
lzh.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
sym = lzh.LITLEN_table[lzh.PEEK_BITS_MSB(KWAJ_TABLEBITS, bit_buffer)];
if (sym >= KWAJ_LITLEN_SYMS)
{
//HUFF_TRAVERSE(tbl)
{
i = 1 << (CompressionStream.BITBUF_WIDTH - KWAJ_TABLEBITS);
do
{
if ((i >>= 1) == 0)
return Error.MSPACK_ERR_DATAFORMAT;
sym = lzh.LITLEN_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)];
} while (sym >= KWAJ_LITLEN_SYMS);
}
}
(len) = sym;
i = lzh.LITLEN_len[sym];
lzh.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left);
}
if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput)
return Error.MSPACK_ERR_OK;
}
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);
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
return Error.MSPACK_ERR_OK;
len++;
lit_run = (len == 32) ? 0 : 1; // End of a literal run?
while (len-- > 0)
{
//READ_HUFFSYM_SAFE(LITERAL, j)
{
//READ_HUFFSYM(LITERAL, j)
{
lzh.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
sym = lzh.LITERAL_table[lzh.PEEK_BITS_MSB(KWAJ_TABLEBITS, bit_buffer)];
if (sym >= KWAJ_LITERAL_SYMS)
{
//HUFF_TRAVERSE(LITERAL)
{
i = 1 << (CompressionStream.BITBUF_WIDTH - KWAJ_TABLEBITS);
do
{
if ((i >>= 1) == 0)
return Error.MSPACK_ERR_DATAFORMAT;
sym = lzh.LITERAL_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)];
} while (sym >= KWAJ_LITERAL_SYMS);
}
}
(j) = sym;
i = lzh.LITERAL_len[sym];
lzh.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left);
}
if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput)
return Error.MSPACK_ERR_OK;
}
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);
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
return Error.MSPACK_ERR_OK;
// Copy as output and into the ring buffer
lzh.Window[pos] = (byte)j;
//WRITE_BYTE
{
if (lzh.System.Write(lzh.OutputFileHandle, lzh.Window, pos, 1) != 1)
return Error.MSPACK_ERR_WRITE;
}
lzh.WRITE_BYTE(pos);
if (lzh.Error != Error.MSPACK_ERR_OK)
return lzh.Error;
pos++; pos &= 4095;
}
@@ -351,16 +142,28 @@ namespace LibMSPackSharp.Compression
return Error.MSPACK_ERR_OK;
}
private static Error ReadLens(LZHKWAJStream lzh, uint type, uint numsyms, byte[] lens)
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)
{
uint bit_buffer;
int bits_left;
int i_ptr, i_end;
uint i, c, sel;
Error err;
lzh.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
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);
if (!CompressionStream.MakeDecodeTable(maxsymbols, tablebits, lengths, table, msb: true))
return Error.MSPACK_ERR_DATAFORMAT;
return Error.MSPACK_ERR_OK;
}
private static Error ReadLens(LZHKWAJStream lzh, uint type, uint numsyms, byte[] lens)
{
uint i, c, sel;
lzh.RESTORE_BITS(out int i_ptr, out int i_end, out uint bit_buffer, out int bits_left);
switch (type)
{
case 0:
@@ -374,22 +177,16 @@ namespace LibMSPackSharp.Compression
break;
case 1:
//READ_BITS_SAFE(c, 4)
{
c = (uint)lzh.READ_BITS_MSB(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput)
return Error.MSPACK_ERR_OK;
}
c = (uint)lzh.READ_BITS_SAFE(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
return Error.MSPACK_ERR_OK;
lens[0] = (byte)c;
for (i = 1; i < numsyms; i++)
{
//READ_BITS_SAFE(sel, 1)
{
sel = (uint)lzh.READ_BITS_MSB(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput)
return Error.MSPACK_ERR_OK;
}
sel = (uint)lzh.READ_BITS_SAFE(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
return Error.MSPACK_ERR_OK;
if (sel == 0)
{
@@ -397,12 +194,9 @@ namespace LibMSPackSharp.Compression
}
else
{
//READ_BITS_SAFE(sel, 1)
{
sel = (uint)lzh.READ_BITS_MSB(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput)
return Error.MSPACK_ERR_OK;
}
sel = (uint)lzh.READ_BITS_SAFE(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
return Error.MSPACK_ERR_OK;
if (sel == 0)
{
@@ -410,12 +204,9 @@ namespace LibMSPackSharp.Compression
}
else
{
//READ_BITS_SAFE(c, 4)
{
c = (uint)lzh.READ_BITS_MSB(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput)
return Error.MSPACK_ERR_OK;
}
c = (uint)lzh.READ_BITS_SAFE(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
return Error.MSPACK_ERR_OK;
lens[i] = (byte)c;
}
@@ -425,31 +216,22 @@ namespace LibMSPackSharp.Compression
break;
case 2:
//READ_BITS_SAFE(c, 4)
{
c = (uint)lzh.READ_BITS_MSB(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput)
return Error.MSPACK_ERR_OK;
}
c = (uint)lzh.READ_BITS_SAFE(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
return Error.MSPACK_ERR_OK;
lens[0] = (byte)c;
for (i = 1; i < numsyms; i++)
{
//READ_BITS_SAFE(sel, 2)
{
sel = (uint)lzh.READ_BITS_MSB(2, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput)
return Error.MSPACK_ERR_OK;
}
sel = (uint)lzh.READ_BITS_SAFE(2, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
return Error.MSPACK_ERR_OK;
if (sel == 3)
{
//READ_BITS_SAFE(c, 4)
{
c = (uint)lzh.READ_BITS_MSB(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput)
return Error.MSPACK_ERR_OK;
}
c = (uint)lzh.READ_BITS_SAFE(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
return Error.MSPACK_ERR_OK;
}
else
{
@@ -464,12 +246,9 @@ namespace LibMSPackSharp.Compression
case 3:
for (i = 0; i < numsyms; i++)
{
//READ_BITS_SAFE(c, 4)
{
c = (uint)lzh.READ_BITS_MSB(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.EndOfInput != 0 && bits_left < lzh.EndOfInput)
return Error.MSPACK_ERR_OK;
}
c = (uint)lzh.READ_BITS_SAFE(4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (lzh.Error == Error.MSPACK_ERR_NOMEMORY)
return Error.MSPACK_ERR_OK;
lens[i] = (byte)c;
}

View File

@@ -37,6 +37,61 @@ namespace LibMSPackSharp.Compression
#endregion
#region Specialty Methods
/* In the KWAJ LZH format, there is no special 'eof' marker, it just
* ends. Depending on how many bits are left in the final byte when
* the stream ends, that might be enough to start another literal or
* match. The only easy way to detect that we've come to an end is to
* guard all bit-reading. We allow fake bits to be read once we reach
* the end of the stream, but we check if we then consumed any of
* those fake bits, after doing the READ_BITS / READ_HUFFSYM. This
* isn't how the default readbits.h read_input() works (it simply lets
* 2 fake bytes in then stops), so we implement our own.
*/
/// <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)
{
long val = READ_BITS_MSB(nbits, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (EndOfInput != 0 && BitsLeft < EndOfInput)
Error = Error.MSPACK_ERR_NOMEMORY;
else
Error = Error.MSPACK_ERR_OK;
return val;
}
/// <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)
{
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)
Error = Error.MSPACK_ERR_NOMEMORY;
else
Error = Error.MSPACK_ERR_OK;
return val;
}
/// <summary>
/// Write a single byte to the output stream
/// </summary>
public void WRITE_BYTE(int pos)
{
if (System.Write(OutputFileHandle, Window, pos, 1) != 1)
Error = Error.MSPACK_ERR_WRITE;
}
#endregion
/// <inheritdoc/>
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)
{

View File

@@ -435,12 +435,6 @@ namespace LibMSPackSharp.Compression
if (lzx == null)
return Error.MSPACK_ERR_ARGS;
// Bitstream and huffman reading variables
uint bit_buffer;
int bits_left, i;
int i_ptr, i_end;
ushort sym;
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];
@@ -456,7 +450,7 @@ namespace LibMSPackSharp.Compression
return lzx.Error;
// Flush out any stored-up bytes before we begin
i = lzx.OutputEnd - lzx.OutputPointer;
int i = lzx.OutputEnd - lzx.OutputPointer;
if (i > out_bytes)
i = (int)out_bytes;
@@ -474,7 +468,7 @@ namespace LibMSPackSharp.Compression
return Error.MSPACK_ERR_OK;
// Restore local state
lzx.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left);
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;
@@ -577,149 +571,64 @@ namespace LibMSPackSharp.Compression
lzx.ALIGNED_len[i] = (byte)j;
}
//BUILD_TABLE(ALIGNED)
{
if (!CompressionStream.MakeDecodeTable(LZX_ALIGNED_MAXSYMBOLS, LZX_ALIGNED_TABLEBITS, lzx.ALIGNED_len, lzx.ALIGNED_table, msb: true))
{
Console.WriteLine($"Failed to build ALIGNED table");
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
}
}
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(MAINTREE, 0, 256)
{
lzx.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
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;
if (ReadLens(lzx, lzx.MAINTREE_len, (0), (uint)(256)) != Error.MSPACK_ERR_OK)
return lzx.Error;
lzx.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left);
}
//READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + lzx.NumOffsets)
{
lzx.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
if (ReadLens(lzx, lzx.MAINTREE_len, (256), (uint)(LZX_NUM_CHARS + lzx.NumOffsets)) != Error.MSPACK_ERR_OK)
return lzx.Error;
lzx.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left);
}
//BUILD_TABLE(MAINTREE)
{
if (!CompressionStream.MakeDecodeTable(LZX_MAINTREE_MAXSYMBOLS, LZX_MAINTREE_TABLEBITS, lzx.MAINTREE_len, lzx.MAINTREE_table, msb: true))
{
Console.WriteLine($"Failed to build MAINTREE table");
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
}
}
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;
//READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS)
{
lzx.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
if (ReadLens(lzx, lzx.LENGTH_len, (0), (uint)(LZX_NUM_SECONDARY_LENGTHS)) != Error.MSPACK_ERR_OK)
return lzx.Error;
lzx.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left);
}
//BUILD_TABLE_MAYBE_EMPTY(LENGTH)
{
lzx.LENGTH_empty = 0;
if (!CompressionStream.MakeDecodeTable(LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS, lzx.LENGTH_len, lzx.LENGTH_table, msb: true))
{
for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++)
{
if (lzx.LENGTH_len[i] > 0)
{
Console.WriteLine("Failed to build TBL table");
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
}
}
// Empty tree - allow it, but don't decode symbols with it
lzx.LENGTH_empty = 1;
}
}
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(MAINTREE, 0, 256)
{
lzx.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
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;
if (ReadLens(lzx, lzx.MAINTREE_len, (0), (uint)(256)) != Error.MSPACK_ERR_OK)
return lzx.Error;
lzx.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left);
}
//READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + lzx.NumOffsets)
{
lzx.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
if (ReadLens(lzx, lzx.MAINTREE_len, (256), (uint)(LZX_NUM_CHARS + lzx.NumOffsets)) != Error.MSPACK_ERR_OK)
return lzx.Error;
lzx.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left);
}
//BUILD_TABLE(MAINTREE)
{
if (!CompressionStream.MakeDecodeTable(LZX_MAINTREE_MAXSYMBOLS, LZX_MAINTREE_TABLEBITS, lzx.MAINTREE_len, lzx.MAINTREE_table, msb: true))
{
Console.WriteLine($"Failed to build MAINTREE table");
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
}
}
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;
//READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS)
{
lzx.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
if (ReadLens(lzx, lzx.LENGTH_len, (0), (uint)(LZX_NUM_SECONDARY_LENGTHS)) != Error.MSPACK_ERR_OK)
return lzx.Error;
lzx.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left);
}
//BUILD_TABLE_MAYBE_EMPTY(LENGTH)
{
lzx.LENGTH_empty = 0;
if (!CompressionStream.MakeDecodeTable(LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS, lzx.LENGTH_len, lzx.LENGTH_table, msb: true))
{
for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++)
{
if (lzx.LENGTH_len[i] > 0)
{
Console.WriteLine("Failed to build TBL table");
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
}
}
// Empty tree - allow it, but don't decode symbols with it
lzx.LENGTH_empty = 1;
}
}
BUILD_TABLE_MAYBE_EMPTY(lzx);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
break;
@@ -772,30 +681,7 @@ namespace LibMSPackSharp.Compression
case LZXBlockType.LZX_BLOCKTYPE_VERBATIM:
while (this_run > 0)
{
//READ_HUFFSYM(MAINTREE, main_element)
{
lzx.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
sym = lzx.MAINTREE_table[lzx.PEEK_BITS_MSB(LZX_MAINTREE_TABLEBITS, bit_buffer)];
if (sym >= LZX_MAINTREE_MAXSYMBOLS)
{
//HUFF_TRAVERSE(MAINTREE)
{
i = 1 << (CompressionStream.BITBUF_WIDTH - LZX_MAINTREE_TABLEBITS);
do
{
if ((i >>= 1) == 0)
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
sym = lzx.MAINTREE_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)];
} while (sym >= LZX_MAINTREE_MAXSYMBOLS);
}
}
(main_element) = sym;
i = lzx.MAINTREE_len[sym];
lzx.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left);
}
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
@@ -817,30 +703,7 @@ namespace LibMSPackSharp.Compression
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
}
//READ_HUFFSYM(LENGTH, length_footer)
{
lzx.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
sym = lzx.LENGTH_table[lzx.PEEK_BITS_MSB(LZX_LENGTH_TABLEBITS, bit_buffer)];
if (sym >= LZX_LENGTH_MAXSYMBOLS)
{
//HUFF_TRAVERSE(LENGTH)
{
i = 1 << (CompressionStream.BITBUF_WIDTH - LZX_LENGTH_TABLEBITS);
do
{
if ((i >>= 1) == 0)
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
sym = lzx.LENGTH_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)];
} while (sym >= LZX_LENGTH_MAXSYMBOLS);
}
}
(length_footer) = sym;
i = lzx.LENGTH_len[sym];
lzx.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left);
}
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;
}
@@ -893,60 +756,14 @@ namespace LibMSPackSharp.Compression
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);
//READ_HUFFSYM(ALIGNED, aligned_bits)
{
lzx.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
sym = lzx.ALIGNED_table[lzx.PEEK_BITS_MSB(LZX_ALIGNED_TABLEBITS, bit_buffer)];
if (sym >= LZX_ALIGNED_MAXSYMBOLS)
{
//HUFF_TRAVERSE(ALIGNED)
{
i = 1 << (CompressionStream.BITBUF_WIDTH - LZX_ALIGNED_TABLEBITS);
do
{
if ((i >>= 1) == 0)
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
sym = lzx.ALIGNED_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)];
} while (sym >= LZX_ALIGNED_MAXSYMBOLS);
}
}
(aligned_bits) = sym;
i = lzx.ALIGNED_len[sym];
lzx.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left);
}
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)
{
//READ_HUFFSYM(ALIGNED, aligned_bits)
{
lzx.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
sym = lzx.ALIGNED_table[lzx.PEEK_BITS_MSB(LZX_ALIGNED_TABLEBITS, bit_buffer)];
if (sym >= LZX_ALIGNED_MAXSYMBOLS)
{
//HUFF_TRAVERSE(ALIGNED)
{
i = 1 << (CompressionStream.BITBUF_WIDTH - LZX_ALIGNED_TABLEBITS);
do
{
if ((i >>= 1) == 0)
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
sym = lzx.ALIGNED_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)];
} while (sym >= LZX_ALIGNED_MAXSYMBOLS);
}
}
(aligned_bits) = sym;
i = lzx.ALIGNED_len[sym];
lzx.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left);
}
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;
}
@@ -1220,18 +1037,55 @@ namespace LibMSPackSharp.Compression
return Error.MSPACK_ERR_OK;
}
private static Error BUILD_TABLE(LZXDStream lzx, ushort[] table, byte[] lengths, int tablebits, int maxsymbols)
{
if (!CompressionStream.MakeDecodeTable(maxsymbols, tablebits, lengths, table, msb: true))
{
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.MakeDecodeTable(LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS, lzx.LENGTH_len, lzx.LENGTH_table, msb: true))
{
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)
{
// Bit buffer and huffman symbol decode variables
uint bit_buffer;
int bits_left, i;
ushort sym;
int i_ptr, i_end;
uint x, y;
int z;
lzx.RESTORE_BITS(out i_ptr, out i_end, out bit_buffer, out bits_left);
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++)
@@ -1240,40 +1094,13 @@ namespace LibMSPackSharp.Compression
lzx.PRETREE_len[x] = (byte)y;
}
//BUILD_TABLE(PRETREE)
{
if (!CompressionStream.MakeDecodeTable(LZX_PRETREE_MAXSYMBOLS, LZX_PRETREE_TABLEBITS, lzx.PRETREE_len, lzx.PRETREE_table, msb: true))
{
Console.WriteLine($"failed to build PRETREE table");
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
}
}
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;)
{
//READ_HUFFSYM(PRETREE, z)
{
lzx.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
sym = lzx.PRETREE_table[lzx.PEEK_BITS_MSB(LZX_PRETREE_TABLEBITS, bit_buffer)];
if (sym >= LZX_PRETREE_MAXSYMBOLS)
{
//HUFF_TRAVERSE(PRETREE)
{
i = 1 << (CompressionStream.BITBUF_WIDTH - LZX_PRETREE_TABLEBITS);
do
{
if ((i >>= 1) == 0)
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
sym = lzx.PRETREE_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)];
} while (sym >= LZX_PRETREE_MAXSYMBOLS);
}
}
(z) = sym;
i = lzx.PRETREE_len[sym];
lzx.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left);
}
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)
@@ -1302,30 +1129,7 @@ namespace LibMSPackSharp.Compression
{
y = (uint)lzx.READ_BITS_MSB(1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
y += 4;
//READ_HUFFSYM(PRETREE, z)
{
lzx.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
sym = lzx.PRETREE_table[lzx.PEEK_BITS_MSB(LZX_PRETREE_TABLEBITS, bit_buffer)];
if (sym >= LZX_PRETREE_MAXSYMBOLS)
{
//HUFF_TRAVERSE(PRETREE)
{
i = 1 << (CompressionStream.BITBUF_WIDTH - LZX_PRETREE_TABLEBITS);
do
{
if ((i >>= 1) == 0)
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
sym = lzx.PRETREE_table[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)];
} while (sym >= LZX_PRETREE_MAXSYMBOLS);
}
}
(z) = sym;
i = lzx.PRETREE_len[sym];
lzx.REMOVE_BITS_MSB(i, ref bit_buffer, ref bits_left);
}
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)

View File

@@ -141,6 +141,9 @@ namespace LibMSPackSharp.Compression
#endregion
/// <inheritdoc/>
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)
{

View File

@@ -12,7 +12,6 @@
using System;
using System.IO;
using static LibMSPackSharp.Compression.Constants;
namespace LibMSPackSharp.Compression
{
@@ -289,7 +288,7 @@ namespace LibMSPackSharp.Compression
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 |= i << 8;
if (block_len == 0)
break;
@@ -514,16 +513,9 @@ namespace LibMSPackSharp.Compression
i_ptr += (int)this_run;
length -= this_run;
//FLUSH_IF_NEEDED
{
if (zip.WindowPosition == MSZIP_FRAME_SIZE)
{
if (zip.FlushWindow(zip, MSZIP_FRAME_SIZE) != Error.MSPACK_ERR_OK)
return Error.INF_ERR_FLUSH;
zip.WindowPosition = 0;
}
}
err = FLUSH_IF_NEEDED(zip);
if (err != Error.MSPACK_ERR_OK)
return err;
}
}
else if ((block_type == 1) || (block_type == 2))
@@ -582,44 +574,14 @@ namespace LibMSPackSharp.Compression
// Decode forever until end of block code
for (; ; )
{
//READ_HUFFSYM(LITERAL, code)
{
zip.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
sym = zip.LITERAL_table[zip.PEEK_BITS_LSB(MSZIP_LITERAL_TABLEBITS, bit_buffer)];
if (sym >= MSZIP_LITERAL_MAXSYMBOLS)
{
//HUFF_TRAVERSE(LITERAL)
{
i = MSZIP_LITERAL_TABLEBITS - 1;
do
{
if (i++ > CompressionStream.HUFF_MAXBITS)
return Error.INF_ERR_HUFFSYM;
sym = zip.LITERAL_table[(sym << 1) | ((bit_buffer >> (int)i) & 1)];
} while (sym >= MSZIP_LITERAL_MAXSYMBOLS);
}
}
(code) = sym;
i = zip.LITERAL_len[sym];
zip.REMOVE_BITS_LSB((int)i, ref bit_buffer, ref bits_left);
}
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);
if (code < 256)
{
zip.Window[zip.WindowPosition++] = (byte)code;
//FLUSH_IF_NEEDED
{
if (zip.WindowPosition == MSZIP_FRAME_SIZE)
{
if (zip.FlushWindow(zip, MSZIP_FRAME_SIZE) != Error.MSPACK_ERR_OK)
return Error.INF_ERR_FLUSH;
zip.WindowPosition = 0;
}
}
err = FLUSH_IF_NEEDED(zip);
if (err != Error.MSPACK_ERR_OK)
return err;
}
else if (code == 256)
{
@@ -635,29 +597,7 @@ namespace LibMSPackSharp.Compression
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];
//READ_HUFFSYM(DISTANCE, code)
{
zip.ENSURE_BITS(CompressionStream.HUFF_MAXBITS, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
sym = zip.DISTANCE_table[zip.PEEK_BITS_LSB(MSZIP_DISTANCE_TABLEBITS, bit_buffer)];
if (sym >= MSZIP_DISTANCE_MAXSYMBOLS)
{
//HUFF_TRAVERSE(DISTANCE)
{
i = MSZIP_DISTANCE_TABLEBITS - 1;
do
{
if (i++ > CompressionStream.HUFF_MAXBITS)
return Error.INF_ERR_HUFFSYM;
sym = zip.DISTANCE_table[(sym << 1) | ((bit_buffer >> (int)i) & 1)];
} while (sym >= MSZIP_DISTANCE_MAXSYMBOLS);
}
}
(code) = sym;
i = zip.DISTANCE_len[sym];
zip.REMOVE_BITS_LSB((int)i, ref bit_buffer, ref bits_left);
}
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);
if (code >= 30)
return Error.INF_ERR_DISTCODE;
@@ -678,17 +618,9 @@ namespace LibMSPackSharp.Compression
{
zip.Window[zip.WindowPosition++] = zip.Window[match_posn++];
match_posn &= MSZIP_FRAME_SIZE - 1;
//FLUSH_IF_NEEDED
{
if (zip.WindowPosition == MSZIP_FRAME_SIZE)
{
if (zip.FlushWindow(zip, MSZIP_FRAME_SIZE) != Error.MSPACK_ERR_OK)
return Error.INF_ERR_FLUSH;
zip.WindowPosition = 0;
}
}
err = FLUSH_IF_NEEDED(zip);
if (err != Error.MSPACK_ERR_OK)
return err;
}
}
else
@@ -716,16 +648,9 @@ namespace LibMSPackSharp.Compression
if (match_posn == MSZIP_FRAME_SIZE)
match_posn = 0;
//FLUSH_IF_NEEDED
{
if (zip.WindowPosition == MSZIP_FRAME_SIZE)
{
if (zip.FlushWindow(zip, MSZIP_FRAME_SIZE) != Error.MSPACK_ERR_OK)
return Error.INF_ERR_FLUSH;
zip.WindowPosition = 0;
}
}
err = FLUSH_IF_NEEDED(zip);
if (err != Error.MSPACK_ERR_OK)
return err;
} while (length > 0);
}
@@ -753,6 +678,19 @@ namespace LibMSPackSharp.Compression
return Error.MSPACK_ERR_OK;
}
private static Error FLUSH_IF_NEEDED(MSZIPDStream zip)
{
if (zip.WindowPosition == MSZIP_FRAME_SIZE)
{
if (zip.FlushWindow(zip, MSZIP_FRAME_SIZE) != Error.MSPACK_ERR_OK)
return Error.INF_ERR_FLUSH;
zip.WindowPosition = 0;
}
return Error.MSPACK_ERR_OK;
}
/// <summary>
/// inflate() calls this whenever the window should be flushed. As
/// MSZIP only expands to the size of the window, the implementation used

View File

@@ -53,6 +53,9 @@ namespace LibMSPackSharp.Compression
#endregion
/// <inheritdoc/>
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)
{

View File

@@ -244,58 +244,7 @@ namespace LibMSPackSharp.Compression
while (window_posn < frame_end)
{
//GET_SYMBOL(qtm.Model7, var)
{
range = (uint)((H - L) & 0xFFFF) + 1;
symf = (ushort)(((((C - L + 1) * qtm.Model7.Syms[0].CumulativeFrequency) - 1) / range) & 0xFFFF);
for (i = 1; i < qtm.Model7.Entries; i++)
{
if (qtm.Model7.Syms[i].CumulativeFrequency <= symf)
break;
}
(selector) = qtm.Model7.Syms[i - 1].Sym;
range = (uint)(H - L) + 1;
symf = qtm.Model7.Syms[0].CumulativeFrequency;
H = (ushort)(L + ((qtm.Model7.Syms[i - 1].CumulativeFrequency * range) / symf) - 1);
L = (ushort)(L + ((qtm.Model7.Syms[i].CumulativeFrequency * range) / symf));
do
{
qtm.Model7.Syms[--i].CumulativeFrequency += 8;
} while (i > 0);
if (qtm.Model7.Syms[0].CumulativeFrequency > 3800)
UpdateModel(qtm.Model7);
while (true)
{
if ((L & 0x8000) != (H & 0x8000))
{
if ((L & 0x4000) != 0 && (H & 0x4000) == 0)
{
// Underflow case
C ^= 0x4000;
L &= 0x3FFF;
H |= 0x4000;
}
else
{
break;
}
}
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);
}
}
selector = GET_SYMBOL(qtm, qtm.Model7, ref H, ref L, ref C, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (selector < 4)
{
// Literal byte
@@ -320,58 +269,7 @@ namespace LibMSPackSharp.Compression
break;
}
//GET_SYMBOL(mdl, sym)
{
range = (uint)((H - L) & 0xFFFF) + 1;
symf = (ushort)(((((C - L + 1) * mdl.Syms[0].CumulativeFrequency) - 1) / range) & 0xFFFF);
for (i = 1; i < mdl.Entries; i++)
{
if (mdl.Syms[i].CumulativeFrequency <= symf)
break;
}
(sym) = mdl.Syms[i - 1].Sym;
range = (uint)(H - L) + 1;
symf = mdl.Syms[0].CumulativeFrequency;
H = (ushort)(L + ((mdl.Syms[i - 1].CumulativeFrequency * range) / symf) - 1);
L = (ushort)(L + ((mdl.Syms[i].CumulativeFrequency * range) / symf));
do
{
mdl.Syms[--i].CumulativeFrequency += 8;
} while (i > 0);
if (mdl.Syms[0].CumulativeFrequency > 3800)
UpdateModel(mdl);
while (true)
{
if ((L & 0x8000) != (H & 0x8000))
{
if ((L & 0x4000) != 0 && (H & 0x4000) == 0)
{
// Underflow case
C ^= 0x4000;
L &= 0x3FFF;
H |= 0x4000;
}
else
{
break;
}
}
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);
}
}
sym = GET_SYMBOL(qtm, mdl, ref H, ref L, ref C, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
window[window_posn++] = (byte)sym;
frame_todo--;
}
@@ -382,58 +280,7 @@ namespace LibMSPackSharp.Compression
{
// Selector 4 = fixed length match (3 bytes)
case 4:
//GET_SYMBOL(qtm.Model4, sym)
{
range = (uint)((H - L) & 0xFFFF) + 1;
symf = (ushort)(((((C - L + 1) * qtm.Model4.Syms[0].CumulativeFrequency) - 1) / range) & 0xFFFF);
for (i = 1; i < qtm.Model4.Entries; i++)
{
if (qtm.Model4.Syms[i].CumulativeFrequency <= symf)
break;
}
(sym) = qtm.Model4.Syms[i - 1].Sym;
range = (uint)(H - L) + 1;
symf = qtm.Model4.Syms[0].CumulativeFrequency;
H = (ushort)(L + ((qtm.Model4.Syms[i - 1].CumulativeFrequency * range) / symf) - 1);
L = (ushort)(L + ((qtm.Model4.Syms[i].CumulativeFrequency * range) / symf));
do
{
qtm.Model4.Syms[--i].CumulativeFrequency += 8;
} while (i > 0);
if (qtm.Model4.Syms[0].CumulativeFrequency > 3800)
UpdateModel(qtm.Model4);
while (true)
{
if ((L & 0x8000) != (H & 0x8000))
{
if ((L & 0x4000) != 0 && (H & 0x4000) == 0)
{
// Underflow case
C ^= 0x4000;
L &= 0x3FFF;
H |= 0x4000;
}
else
{
break;
}
}
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);
}
}
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);
match_length = 3;
@@ -441,58 +288,7 @@ namespace LibMSPackSharp.Compression
// Selector 5 = fixed length match (4 bytes)
case 5:
//GET_SYMBOL(qtm.Model5, sym)
{
range = (uint)((H - L) & 0xFFFF) + 1;
symf = (ushort)(((((C - L + 1) * qtm.Model5.Syms[0].CumulativeFrequency) - 1) / range) & 0xFFFF);
for (i = 1; i < qtm.Model5.Entries; i++)
{
if (qtm.Model5.Syms[i].CumulativeFrequency <= symf)
break;
}
(sym) = qtm.Model5.Syms[i - 1].Sym;
range = (uint)(H - L) + 1;
symf = qtm.Model5.Syms[0].CumulativeFrequency;
H = (ushort)(L + ((qtm.Model5.Syms[i - 1].CumulativeFrequency * range) / symf) - 1);
L = (ushort)(L + ((qtm.Model5.Syms[i].CumulativeFrequency * range) / symf));
do
{
qtm.Model5.Syms[--i].CumulativeFrequency += 8;
} while (i > 0);
if (qtm.Model5.Syms[0].CumulativeFrequency > 3800)
UpdateModel(qtm.Model5);
while (true)
{
if ((L & 0x8000) != (H & 0x8000))
{
if ((L & 0x4000) != 0 && (H & 0x4000) == 0)
{
// Underflow case
C ^= 0x4000;
L &= 0x3FFF;
H |= 0x4000;
}
else
{
break;
}
}
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);
}
}
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);
match_length = 4;
@@ -500,113 +296,11 @@ namespace LibMSPackSharp.Compression
// Selector 6 = variable length match
case 6:
//GET_SYMBOL(qtm.Model6Len, sym)
{
range = (uint)((H - L) & 0xFFFF) + 1;
symf = (ushort)(((((C - L + 1) * qtm.Model6Len.Syms[0].CumulativeFrequency) - 1) / range) & 0xFFFF);
for (i = 1; i < qtm.Model6Len.Entries; i++)
{
if (qtm.Model6Len.Syms[i].CumulativeFrequency <= symf)
break;
}
(sym) = qtm.Model6Len.Syms[i - 1].Sym;
range = (uint)(H - L) + 1;
symf = qtm.Model6Len.Syms[0].CumulativeFrequency;
H = (ushort)(L + ((qtm.Model6Len.Syms[i - 1].CumulativeFrequency * range) / symf) - 1);
L = (ushort)(L + ((qtm.Model6Len.Syms[i].CumulativeFrequency * range) / symf));
do
{
qtm.Model6Len.Syms[--i].CumulativeFrequency += 8;
} while (i > 0);
if (qtm.Model6Len.Syms[0].CumulativeFrequency > 3800)
UpdateModel(qtm.Model6Len);
while (true)
{
if ((L & 0x8000) != (H & 0x8000))
{
if ((L & 0x4000) != 0 && (H & 0x4000) == 0)
{
// Underflow case
C ^= 0x4000;
L &= 0x3FFF;
H |= 0x4000;
}
else
{
break;
}
}
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);
}
}
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;
//GET_SYMBOL(qtm.Model6, sym)
{
range = (uint)((H - L) & 0xFFFF) + 1;
symf = (ushort)(((((C - L + 1) * qtm.Model6.Syms[0].CumulativeFrequency) - 1) / range) & 0xFFFF);
for (i = 1; i < qtm.Model6.Entries; i++)
{
if (qtm.Model6.Syms[i].CumulativeFrequency <= symf)
break;
}
(sym) = qtm.Model6.Syms[i - 1].Sym;
range = (uint)(H - L) + 1;
symf = qtm.Model6.Syms[0].CumulativeFrequency;
H = (ushort)(L + ((qtm.Model6.Syms[i - 1].CumulativeFrequency * range) / symf) - 1);
L = (ushort)(L + ((qtm.Model6.Syms[i].CumulativeFrequency * range) / symf));
do
{
qtm.Model6.Syms[--i].CumulativeFrequency += 8;
} while (i > 0);
if (qtm.Model6.Syms[0].CumulativeFrequency > 3800)
UpdateModel(qtm.Model6);
while (true)
{
if ((L & 0x8000) != (H & 0x8000))
{
if ((L & 0x4000) != 0 && (H & 0x4000) == 0)
{
// Underflow case
C ^= 0x4000;
L &= 0x3FFF;
H |= 0x4000;
}
else
{
break;
}
}
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);
}
}
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);
break;
@@ -786,6 +480,61 @@ 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)
{
uint range = (uint)((H - L) & 0xFFFF) + 1;
ushort symf = (ushort)(((((C - L + 1) * model.Syms[0].CumulativeFrequency) - 1) / range) & 0xFFFF);
int i = 1;
for (; i < model.Entries; i++)
{
if (model.Syms[i].CumulativeFrequency <= symf)
break;
}
ushort temp = model.Syms[i - 1].Sym;
range = (uint)(H - L) + 1;
symf = model.Syms[0].CumulativeFrequency;
H = (ushort)(L + ((model.Syms[i - 1].CumulativeFrequency * range) / symf) - 1);
L = (ushort)(L + ((model.Syms[i].CumulativeFrequency * range) / symf));
do
{
model.Syms[--i].CumulativeFrequency += 8;
} while (i > 0);
if (model.Syms[0].CumulativeFrequency > 3800)
UpdateModel(model);
while (true)
{
if ((L & 0x8000) != (H & 0x8000))
{
if ((L & 0x4000) != 0 && (H & 0x4000) == 0)
{
// Underflow case
C ^= 0x4000;
L &= 0x3FFF;
H |= 0x4000;
}
else
{
break;
}
}
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);
}
return temp;
}
private static void UpdateModel(QTMDModel model)
{
QTMDModelSym tmp;

View File

@@ -10,6 +10,8 @@
* For further details, see the file COPYING.LIB distributed with libmspack
*/
using System;
namespace LibMSPackSharp.Compression
{
public class QTMDStream : CompressionStream
@@ -124,6 +126,9 @@ namespace LibMSPackSharp.Compression
#endregion
/// <inheritdoc/>
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)
{