675 lines
19 KiB
C
675 lines
19 KiB
C
|
|
||
|
// infdyna.c
|
||
|
|
||
|
// Decompress a dynamically compressed block
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <crtdbg.h>
|
||
|
#include "inflate.h"
|
||
|
#include "infmacro.h"
|
||
|
#include "maketbl.h"
|
||
|
|
||
|
|
||
|
#define OUTPUT_EOF() (output_curpos >= context->end_output_buffer)
|
||
|
|
||
|
|
||
|
// This is the slow version, which worries about the input running out or the output
|
||
|
// running out. The trick here is to not read any more bytes than we need to; theoretically
|
||
|
// the "end of block" code could be 1 bit, so we cannot always assume that it is ok to fill
|
||
|
// the bit buffer with 16 bits right before a table decode.
|
||
|
|
||
|
BOOL DecodeDynamicBlock(t_decoder_context *context, BOOL *end_of_block_code_seen)
|
||
|
{
|
||
|
const byte * input_ptr;
|
||
|
const byte * end_input_buffer;
|
||
|
byte * output_curpos;
|
||
|
byte * window;
|
||
|
unsigned long bufpos;
|
||
|
unsigned long bitbuf;
|
||
|
int bitcount;
|
||
|
int length;
|
||
|
long dist_code;
|
||
|
unsigned long offset;
|
||
|
t_decoder_state old_state;
|
||
|
BYTE fCanTryFastEncoder = TRUE;
|
||
|
|
||
|
*end_of_block_code_seen = FALSE;
|
||
|
|
||
|
|
||
|
// Store these variables locally for speed
|
||
|
|
||
|
top:
|
||
|
output_curpos = context->output_curpos;
|
||
|
|
||
|
window = context->window;
|
||
|
bufpos = context->bufpos;
|
||
|
|
||
|
end_input_buffer = context->end_input_buffer;
|
||
|
|
||
|
LOAD_BITBUF_VARS();
|
||
|
|
||
|
_ASSERT(bitcount >= -16);
|
||
|
|
||
|
old_state = context->state;
|
||
|
context->state = STATE_DECODE_TOP; // reset state
|
||
|
|
||
|
switch (old_state)
|
||
|
{
|
||
|
case STATE_DECODE_TOP:
|
||
|
break;
|
||
|
|
||
|
case STATE_HAVE_INITIAL_LENGTH:
|
||
|
length = context->length;
|
||
|
goto reenter_state_have_initial_length;
|
||
|
|
||
|
case STATE_HAVE_FULL_LENGTH:
|
||
|
length = context->length;
|
||
|
goto reenter_state_have_full_length;
|
||
|
|
||
|
case STATE_HAVE_DIST_CODE:
|
||
|
length = context->length;
|
||
|
dist_code = context->dist_code;
|
||
|
goto reenter_state_have_dist_code;
|
||
|
|
||
|
case STATE_INTERRUPTED_MATCH:
|
||
|
length = context->length;
|
||
|
offset = context->offset;
|
||
|
goto reenter_state_interrupted_match;
|
||
|
|
||
|
default:
|
||
|
_ASSERT(0); // error, invalid state!
|
||
|
}
|
||
|
|
||
|
do
|
||
|
{
|
||
|
|
||
|
// The first time we're at the top of this loop, check whether we can use the
|
||
|
// fast encoder; we will do this if the input and output buffers are nowhere
|
||
|
// near the end, which allows the fast encoder to be a little more relaxed
|
||
|
// about checking for these conditions
|
||
|
|
||
|
// If we cannot enter the fast encoder when we first check, then we will not
|
||
|
// be able to enter it again while we're in this function (the amount of
|
||
|
// input/output available is not going to get any larger), so don't check
|
||
|
// again.
|
||
|
|
||
|
if (fCanTryFastEncoder)
|
||
|
{
|
||
|
if (context->output_curpos + MAX_MATCH < context->end_output_buffer &&
|
||
|
context->input_curpos + 12 < context->end_input_buffer)
|
||
|
{
|
||
|
SAVE_BITBUF_VARS();
|
||
|
context->output_curpos = output_curpos;
|
||
|
context->bufpos = bufpos;
|
||
|
|
||
|
if (FastDecodeDynamicBlock(context, end_of_block_code_seen) == FALSE)
|
||
|
return FALSE;
|
||
|
|
||
|
if (*end_of_block_code_seen)
|
||
|
return TRUE;
|
||
|
|
||
|
goto top;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// don't check again
|
||
|
fCanTryFastEncoder = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// decode an element from the main tree
|
||
|
|
||
|
|
||
|
// we must have at least 1 bit available
|
||
|
_ASSERT(bitcount >= -16);
|
||
|
|
||
|
if (bitcount == -16)
|
||
|
{
|
||
|
if (input_ptr >= end_input_buffer)
|
||
|
break;
|
||
|
|
||
|
bitbuf |= ((*input_ptr++) << (bitcount+16));
|
||
|
bitcount += 8;
|
||
|
}
|
||
|
|
||
|
retry_decode_literal:
|
||
|
|
||
|
// assert that at least 1 bit is present
|
||
|
_ASSERT(bitcount > -16);
|
||
|
|
||
|
// decode an element from the literal tree
|
||
|
length = context->literal_table[bitbuf & LITERAL_TABLE_MASK];
|
||
|
|
||
|
while (length < 0)
|
||
|
{
|
||
|
unsigned long mask = 1 << LITERAL_TABLE_BITS;
|
||
|
do
|
||
|
{
|
||
|
length = -length;
|
||
|
if ((bitbuf & mask) == 0)
|
||
|
length = context->literal_left[length];
|
||
|
else
|
||
|
length = context->literal_right[length];
|
||
|
mask <<= 1;
|
||
|
} while (length < 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
// If this code is longer than the # bits we had in the bit buffer (i.e.
|
||
|
// we read only part of the code - but enough to know that it's too long),
|
||
|
// read more bits and retry
|
||
|
|
||
|
if (context->literal_tree_code_length[length] > (bitcount+16))
|
||
|
{
|
||
|
// if we run out of bits, break
|
||
|
if (input_ptr >= end_input_buffer)
|
||
|
break;
|
||
|
|
||
|
bitbuf |= ((*input_ptr++) << (bitcount+16));
|
||
|
bitcount += 8;
|
||
|
goto retry_decode_literal;
|
||
|
}
|
||
|
|
||
|
DUMPBITS(context->literal_tree_code_length[length]);
|
||
|
_ASSERT(bitcount >= -16);
|
||
|
|
||
|
|
||
|
// Is it a character or a match?
|
||
|
|
||
|
if (length < 256)
|
||
|
{
|
||
|
// it's an unmatched symbol
|
||
|
window[bufpos] = *output_curpos++ = (byte) length;
|
||
|
bufpos = (bufpos + 1) & WINDOW_MASK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// it's a match
|
||
|
int extra_bits;
|
||
|
|
||
|
length -= 257;
|
||
|
|
||
|
// if value was 256, that was the end-of-block code
|
||
|
if (length < 0)
|
||
|
{
|
||
|
*end_of_block_code_seen = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// Get match length
|
||
|
|
||
|
|
||
|
|
||
|
// These matches are by far the most common case.
|
||
|
|
||
|
if (length < 8)
|
||
|
{
|
||
|
// no extra bits
|
||
|
|
||
|
// match length = 3,4,5,6,7,8,9,10
|
||
|
length += 3;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int extra_bits;
|
||
|
|
||
|
reenter_state_have_initial_length:
|
||
|
|
||
|
extra_bits = g_ExtraLengthBits[length];
|
||
|
|
||
|
if (extra_bits > 0)
|
||
|
{
|
||
|
// make sure we have this many bits in the bit buffer
|
||
|
if (extra_bits > bitcount + 16)
|
||
|
{
|
||
|
// if we run out of bits, break
|
||
|
if (input_ptr >= end_input_buffer)
|
||
|
{
|
||
|
context->state = STATE_HAVE_INITIAL_LENGTH;
|
||
|
context->length = length;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
bitbuf |= ((*input_ptr++) << (bitcount+16));
|
||
|
bitcount += 8;
|
||
|
|
||
|
// extra_length_bits will be no more than 5, so we need to read at
|
||
|
// most one byte of input to satisfy this request
|
||
|
}
|
||
|
|
||
|
length = g_LengthBase[length] + (bitbuf & g_BitMask[extra_bits]);
|
||
|
|
||
|
DUMPBITS(extra_bits);
|
||
|
_ASSERT(bitcount >= -16);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/*
|
||
|
* we know length > 8 and extra_bits == 0, there the length must be 258
|
||
|
*/
|
||
|
length = 258; /* g_LengthBase[length]; */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Get match distance
|
||
|
|
||
|
|
||
|
// decode distance code
|
||
|
reenter_state_have_full_length:
|
||
|
|
||
|
// we must have at least 1 bit available
|
||
|
if (bitcount == -16)
|
||
|
{
|
||
|
if (input_ptr >= end_input_buffer)
|
||
|
{
|
||
|
context->state = STATE_HAVE_FULL_LENGTH;
|
||
|
context->length = length;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
bitbuf |= ((*input_ptr++) << (bitcount+16));
|
||
|
bitcount += 8;
|
||
|
}
|
||
|
|
||
|
|
||
|
retry_decode_distance:
|
||
|
|
||
|
// assert that at least 1 bit is present
|
||
|
_ASSERT(bitcount > -16);
|
||
|
|
||
|
dist_code = context->distance_table[bitbuf & DISTANCE_TABLE_MASK];
|
||
|
|
||
|
while (dist_code < 0)
|
||
|
{
|
||
|
unsigned long mask = 1 << DISTANCE_TABLE_BITS;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
dist_code = -dist_code;
|
||
|
|
||
|
if ((bitbuf & mask) == 0)
|
||
|
dist_code = context->distance_left[dist_code];
|
||
|
else
|
||
|
dist_code = context->distance_right[dist_code];
|
||
|
|
||
|
mask <<= 1;
|
||
|
} while (dist_code < 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
// If this code is longer than the # bits we had in the bit buffer (i.e.
|
||
|
// we read only part of the code - but enough to know that it's too long),
|
||
|
// read more bits and retry
|
||
|
|
||
|
if (context->distance_tree_code_length[dist_code] > (bitcount+16))
|
||
|
{
|
||
|
// if we run out of bits, break
|
||
|
if (input_ptr >= end_input_buffer)
|
||
|
{
|
||
|
context->state = STATE_HAVE_FULL_LENGTH;
|
||
|
context->length = length;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
bitbuf |= ((*input_ptr++) << (bitcount+16));
|
||
|
bitcount += 8;
|
||
|
|
||
|
_ASSERT(bitcount >= -16);
|
||
|
goto retry_decode_distance;
|
||
|
}
|
||
|
|
||
|
|
||
|
DUMPBITS(context->distance_tree_code_length[dist_code]);
|
||
|
|
||
|
// To avoid a table lookup we note that for dist_code >= 2,
|
||
|
// extra_bits = (dist_code-2) >> 1
|
||
|
|
||
|
// Old (intuitive) way of doing this:
|
||
|
// offset = distance_base_position[dist_code] +
|
||
|
// getBits(extra_distance_bits[dist_code]);
|
||
|
|
||
|
reenter_state_have_dist_code:
|
||
|
|
||
|
_ASSERT(bitcount >= -16);
|
||
|
|
||
|
extra_bits = (dist_code-2) >> 1;
|
||
|
|
||
|
if (extra_bits > 0)
|
||
|
{
|
||
|
// make sure we have this many bits in the bit buffer
|
||
|
if (extra_bits > bitcount + 16)
|
||
|
{
|
||
|
// if we run out of bits, break
|
||
|
if (input_ptr >= end_input_buffer)
|
||
|
{
|
||
|
context->state = STATE_HAVE_DIST_CODE;
|
||
|
context->length = length;
|
||
|
context->dist_code = dist_code;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
bitbuf |= ((*input_ptr++) << (bitcount+16));
|
||
|
bitcount += 8;
|
||
|
|
||
|
// extra_length_bits can be > 8, so check again
|
||
|
if (extra_bits > bitcount + 16)
|
||
|
{
|
||
|
// if we run out of bits, break
|
||
|
if (input_ptr >= end_input_buffer)
|
||
|
{
|
||
|
context->state = STATE_HAVE_DIST_CODE;
|
||
|
context->length = length;
|
||
|
context->dist_code = dist_code;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
bitbuf |= ((*input_ptr++) << (bitcount+16));
|
||
|
bitcount += 8;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
offset = g_DistanceBasePosition[dist_code] + (bitbuf & g_BitMask[extra_bits]);
|
||
|
|
||
|
DUMPBITS(extra_bits);
|
||
|
_ASSERT(bitcount >= -16);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
offset = dist_code + 1;
|
||
|
}
|
||
|
|
||
|
// copy remaining byte(s) of match
|
||
|
reenter_state_interrupted_match:
|
||
|
|
||
|
do
|
||
|
{
|
||
|
window[bufpos] = *output_curpos++ = window[(bufpos - offset) & WINDOW_MASK];
|
||
|
bufpos = (bufpos + 1) & WINDOW_MASK;
|
||
|
|
||
|
if (--length == 0)
|
||
|
break;
|
||
|
|
||
|
} while (output_curpos < context->end_output_buffer);
|
||
|
|
||
|
if (length > 0)
|
||
|
{
|
||
|
context->state = STATE_INTERRUPTED_MATCH;
|
||
|
context->length = length;
|
||
|
context->offset = offset;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// it's "<=" because we end when we received the end-of-block code,
|
||
|
// not when we fill up the output, however, this will catch cases
|
||
|
// of corrupted data where there is no end-of-output code
|
||
|
} while (output_curpos < context->end_output_buffer);
|
||
|
|
||
|
_ASSERT(bitcount >= -16);
|
||
|
|
||
|
SAVE_BITBUF_VARS();
|
||
|
|
||
|
context->output_curpos = output_curpos;
|
||
|
context->bufpos = bufpos;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// This is the fast version, which assumes that, at the top of the loop:
|
||
|
|
||
|
// 1. There are at least 12 bytes of input available at the top of the loop (so that we don't
|
||
|
// have to check input EOF several times in the middle of the loop)
|
||
|
|
||
|
// and
|
||
|
|
||
|
// 2. There are at least MAX_MATCH bytes of output available (so that we don't have to check
|
||
|
// for output EOF while we're copying matches)
|
||
|
|
||
|
// The state must also be STATE_DECODE_TOP on entering and exiting this function
|
||
|
|
||
|
BOOL FastDecodeDynamicBlock(t_decoder_context *context, BOOL *end_of_block_code_seen)
|
||
|
{
|
||
|
const byte * input_ptr;
|
||
|
const byte * end_input_buffer;
|
||
|
byte * output_curpos;
|
||
|
byte * window;
|
||
|
unsigned long bufpos;
|
||
|
unsigned long bitbuf;
|
||
|
int bitcount;
|
||
|
int length;
|
||
|
long dist_code;
|
||
|
unsigned long offset;
|
||
|
|
||
|
*end_of_block_code_seen = FALSE;
|
||
|
|
||
|
|
||
|
// Store these variables locally for speed
|
||
|
|
||
|
output_curpos = context->output_curpos;
|
||
|
|
||
|
window = context->window;
|
||
|
bufpos = context->bufpos;
|
||
|
|
||
|
end_input_buffer = context->end_input_buffer;
|
||
|
|
||
|
LOAD_BITBUF_VARS();
|
||
|
|
||
|
_ASSERT(context->state == STATE_DECODE_TOP);
|
||
|
_ASSERT(input_ptr + 12 < end_input_buffer);
|
||
|
_ASSERT(output_curpos + MAX_MATCH < context->end_output_buffer);
|
||
|
|
||
|
// make sure there are at least 16 bits in the bit buffer
|
||
|
while (bitcount <= 0)
|
||
|
{
|
||
|
bitbuf |= ((*input_ptr++) << (bitcount+16));
|
||
|
bitcount += 8;
|
||
|
}
|
||
|
|
||
|
do
|
||
|
{
|
||
|
|
||
|
// decode an element from the main tree
|
||
|
|
||
|
|
||
|
// decode an element from the literal tree
|
||
|
length = context->literal_table[bitbuf & LITERAL_TABLE_MASK];
|
||
|
|
||
|
while (length < 0)
|
||
|
{
|
||
|
unsigned long mask = 1 << LITERAL_TABLE_BITS;
|
||
|
do
|
||
|
{
|
||
|
length = -length;
|
||
|
if ((bitbuf & mask) == 0)
|
||
|
length = context->literal_left[length];
|
||
|
else
|
||
|
length = context->literal_right[length];
|
||
|
mask <<= 1;
|
||
|
} while (length < 0);
|
||
|
}
|
||
|
|
||
|
DUMPBITS(context->literal_tree_code_length[length]);
|
||
|
|
||
|
if (bitcount <= 0)
|
||
|
{
|
||
|
bitbuf |= ((*input_ptr++) << (bitcount+16));
|
||
|
bitcount += 8;
|
||
|
|
||
|
if (bitcount <= 0)
|
||
|
{
|
||
|
bitbuf |= ((*input_ptr++) << (bitcount+16));
|
||
|
bitcount += 8;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Is it a character or a match?
|
||
|
|
||
|
if (length < 256)
|
||
|
{
|
||
|
// it's an unmatched symbol
|
||
|
window[bufpos] = *output_curpos++ = (byte) length;
|
||
|
bufpos = (bufpos + 1) & WINDOW_MASK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// it's a match
|
||
|
int extra_bits;
|
||
|
|
||
|
length -= 257;
|
||
|
|
||
|
// if value was 256, that was the end-of-block code
|
||
|
if (length < 0)
|
||
|
{
|
||
|
*end_of_block_code_seen = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// Get match length
|
||
|
|
||
|
|
||
|
|
||
|
// These matches are by far the most common case.
|
||
|
|
||
|
if (length < 8)
|
||
|
{
|
||
|
// no extra bits
|
||
|
|
||
|
// match length = 3,4,5,6,7,8,9,10
|
||
|
length += 3;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int extra_bits;
|
||
|
|
||
|
extra_bits = g_ExtraLengthBits[length];
|
||
|
|
||
|
if (extra_bits > 0)
|
||
|
{
|
||
|
length = g_LengthBase[length] + (bitbuf & g_BitMask[extra_bits]);
|
||
|
|
||
|
DUMPBITS(extra_bits);
|
||
|
|
||
|
if (bitcount <= 0)
|
||
|
{
|
||
|
bitbuf |= ((*input_ptr++) << (bitcount+16));
|
||
|
bitcount += 8;
|
||
|
|
||
|
if (bitcount <= 0)
|
||
|
{
|
||
|
bitbuf |= ((*input_ptr++) << (bitcount+16));
|
||
|
bitcount += 8;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/*
|
||
|
* we know length > 8 and extra_bits == 0, there the length must be 258
|
||
|
*/
|
||
|
length = 258; /* g_LengthBase[length]; */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Get match distance
|
||
|
|
||
|
|
||
|
// decode distance code
|
||
|
dist_code = context->distance_table[bitbuf & DISTANCE_TABLE_MASK];
|
||
|
|
||
|
while (dist_code < 0)
|
||
|
{
|
||
|
unsigned long mask = 1 << DISTANCE_TABLE_BITS;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
dist_code = -dist_code;
|
||
|
|
||
|
if ((bitbuf & mask) == 0)
|
||
|
dist_code = context->distance_left[dist_code];
|
||
|
else
|
||
|
dist_code = context->distance_right[dist_code];
|
||
|
|
||
|
mask <<= 1;
|
||
|
} while (dist_code < 0);
|
||
|
}
|
||
|
|
||
|
DUMPBITS(context->distance_tree_code_length[dist_code]);
|
||
|
|
||
|
if (bitcount <= 0)
|
||
|
{
|
||
|
bitbuf |= ((*input_ptr++) << (bitcount+16));
|
||
|
bitcount += 8;
|
||
|
|
||
|
if (bitcount <= 0)
|
||
|
{
|
||
|
bitbuf |= ((*input_ptr++) << (bitcount+16));
|
||
|
bitcount += 8;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// To avoid a table lookup we note that for dist_code >= 2,
|
||
|
// extra_bits = (dist_code-2) >> 1
|
||
|
|
||
|
// Old (intuitive) way of doing this:
|
||
|
// offset = distance_base_position[dist_code] +
|
||
|
// getBits(extra_distance_bits[dist_code]);
|
||
|
extra_bits = (dist_code-2) >> 1;
|
||
|
|
||
|
if (extra_bits > 0)
|
||
|
{
|
||
|
offset = g_DistanceBasePosition[dist_code] + (bitbuf & g_BitMask[extra_bits]);
|
||
|
|
||
|
DUMPBITS(extra_bits);
|
||
|
|
||
|
if (bitcount <= 0)
|
||
|
{
|
||
|
bitbuf |= ((*input_ptr++) << (bitcount+16));
|
||
|
bitcount += 8;
|
||
|
|
||
|
if (bitcount <= 0)
|
||
|
{
|
||
|
bitbuf |= ((*input_ptr++) << (bitcount+16));
|
||
|
bitcount += 8;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
offset = dist_code + 1;
|
||
|
}
|
||
|
|
||
|
// copy remaining byte(s) of match
|
||
|
do
|
||
|
{
|
||
|
window[bufpos] = *output_curpos++ = window[(bufpos - offset) & WINDOW_MASK];
|
||
|
bufpos = (bufpos + 1) & WINDOW_MASK;
|
||
|
} while (--length != 0);
|
||
|
}
|
||
|
} while ((input_ptr + 12 < end_input_buffer) && (output_curpos + MAX_MATCH < context->end_output_buffer));
|
||
|
|
||
|
// make sure there are at least 16 bits in the bit buffer
|
||
|
while (bitcount <= 0)
|
||
|
{
|
||
|
bitbuf |= ((*input_ptr++) << (bitcount+16));
|
||
|
bitcount += 8;
|
||
|
}
|
||
|
|
||
|
SAVE_BITBUF_VARS();
|
||
|
|
||
|
context->output_curpos = output_curpos;
|
||
|
context->bufpos = bufpos;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|