Huffman tree implement MSZIP (nw)

This commit is contained in:
Matt Nadareski
2022-05-21 21:47:54 -07:00
parent e45b593c7b
commit b69c5cf928
2 changed files with 109 additions and 81 deletions

View File

@@ -167,84 +167,7 @@ namespace LibMSPackSharp.Compression
// TODO: These should be in a separate file
#region ReadHuff Methods
private const int HUFF_MAXBITS = 16;
/// <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 int READ_HUFFSYM(ushort[] decodingTable, ref uint var, int tablebits, byte[] lengthTable, int maxsymbols, ref int i, ref int i_ptr, ref int i_end, ref int bits_left, ref uint bit_buffer, bool msb)
{
// ENSURE_BITS(HUFF_MAXBITS)
while (bits_left < HUFF_MAXBITS)
{
READ_BYTES;
}
if (Error != Error.MSPACK_ERR_OK)
return (int)Error;
int peek;
if (msb)
peek = (int)(bit_buffer >> (BITBUF_WIDTH - (tablebits)));
else
peek = (int)(bit_buffer & ((1 << (tablebits)) - 1));
ushort sym = decodingTable[peek];
if (sym >= maxsymbols)
{
int ret = HUFF_TRAVERSE(decodingTable, tablebits, maxsymbols, ref i, ref sym, bit_buffer, msb);
if (ret != 0)
return ret;
}
var = sym;
i = lengthTable[sym];
// REMOVE_BITS(i);
if (msb)
{
bit_buffer <<= i;
bits_left -= i;
}
else
{
bit_buffer >>= i;
bits_left -= i;
}
return (int)Error.MSPACK_ERR_OK;
}
public int HUFF_TRAVERSE(ushort[] decodingTable, int tablebits, int maxsymbols, ref int i, ref ushort sym, uint bit_buffer, bool msb)
{
if (msb)
{
i = 1 << (BITBUF_WIDTH - tablebits);
do
{
if ((i >>= 1) == 0)
return HUFF_ERROR();
sym = decodingTable[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)];
} while (sym >= maxsymbols);
}
else
{
i = tablebits - 1;
do
{
if (i++ > HUFF_MAXBITS)
return HUFF_ERROR();
try { sym = decodingTable[(sym << 1) | ((bit_buffer >> i) & 1)]; } catch { }
} while (sym >= maxsymbols);
}
return (int)Error.MSPACK_ERR_OK;
}
public abstract int HUFF_ERROR();
public const int HUFF_MAXBITS = 16;
/// <summary>
/// This function was originally coded by David Tritscher.

View File

@@ -962,7 +962,6 @@ namespace LibMSPackSharp.Compression
/// <summary>
/// A clean implementation of RFC 1951 / inflate
/// </summary>
// TODO: Huffman tree implementation
private static Error Inflate(MSZIPDStream zip)
{
uint last_block, block_type, distance, length, this_run, i;
@@ -1228,7 +1227,60 @@ namespace LibMSPackSharp.Compression
// Decode forever until end of block code
for (; ; )
{
READ_HUFFSYM(LITERAL, code);
//READ_HUFFSYM(LITERAL, code)
{
//ENSURE_BITS(CompressionStream.HUFF_MAXBITS)
{
while (bits_left < (CompressionStream.HUFF_MAXBITS))
{
//READ_BYTES
{
//READ_IF_NEEDED
{
if (i_ptr >= i_end)
{
if (zip.ReadInput() != Error.MSPACK_ERR_OK)
return zip.Error;
i_ptr = zip.InputPointer;
i_end = zip.InputLength;
}
}
//INJECT_BITS(zip.InputBuffer[i_ptr++], 8)
{
bit_buffer |= (uint)((zip.InputBuffer[i_ptr++]) << bits_left);
bits_left += (8);
}
}
}
}
sym = zip.LITERAL_table[(bit_buffer & ((1 << (MSZIP_LITERAL_TABLEBITS)) - 1))]; //PEEK_BITS(TABLEBITS(LITERAL))
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];
//REMOVE_BITS(i)
{
bit_buffer >>= (int)(i);
bits_left -= (int)(i);
}
}
if (code < 256)
{
@@ -1296,7 +1348,60 @@ namespace LibMSPackSharp.Compression
length += lit_lengths[code];
READ_HUFFSYM(DISTANCE, code);
//READ_HUFFSYM(DISTANCE, var)
{
//ENSURE_BITS(CompressionStream.HUFF_MAXBITS)
{
while (bits_left < (CompressionStream.HUFF_MAXBITS))
{
//READ_BYTES
{
//READ_IF_NEEDED
{
if (i_ptr >= i_end)
{
if (zip.ReadInput() != Error.MSPACK_ERR_OK)
return zip.Error;
i_ptr = zip.InputPointer;
i_end = zip.InputLength;
}
}
//INJECT_BITS(zip.InputBuffer[i_ptr++], 8)
{
bit_buffer |= (uint)((zip.InputBuffer[i_ptr++]) << bits_left);
bits_left += (8);
}
}
}
}
sym = zip.DISTANCE_table[(bit_buffer & ((1 << (MSZIP_DISTANCE_TABLEBITS)) - 1))]; //PEEK_BITS(TABLEBITS(DISTANCE))
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];
//REMOVE_BITS(i)
{
bit_buffer >>= (int)(i);
bits_left -= (int)(i);
}
}
if (code >= 30)
return Error.INF_ERR_DISTCODE;