You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
298 lines
6.8 KiB
298 lines
6.8 KiB
//
|
|
// inftree.c
|
|
//
|
|
// Reads the tree for a dynamic block
|
|
//
|
|
#include <crtdbg.h>
|
|
#include "inflate.h"
|
|
#include "infmacro.h"
|
|
#include "maketbl.h"
|
|
|
|
|
|
//
|
|
// Decode an element from the pre-tree
|
|
//
|
|
static int decodePretreeElement(t_decoder_context *context)
|
|
{
|
|
int element;
|
|
|
|
retry:
|
|
element = context->pretree_table[context->bitbuf & PRETREE_TABLE_MASK];
|
|
|
|
while (element < 0)
|
|
{
|
|
unsigned long mask = 1 << PRETREE_TABLE_BITS;
|
|
|
|
do
|
|
{
|
|
element = -element;
|
|
|
|
if ((context->bitbuf & mask) == 0)
|
|
element = context->pretree_left[element];
|
|
else
|
|
element = context->pretree_right[element];
|
|
|
|
mask <<= 1;
|
|
} while (element < 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),
|
|
// return -1.
|
|
//
|
|
if (context->pretree_code_length[element] > (context->bitcount+16))
|
|
{
|
|
// if we run out of bits, return -1
|
|
if (context->input_curpos >= context->end_input_buffer)
|
|
return -1;
|
|
|
|
context->bitbuf |= ((*context->input_curpos++) << (context->bitcount+16));
|
|
context->bitcount += 8;
|
|
goto retry;
|
|
}
|
|
|
|
dumpBits(context, context->pretree_code_length[element]);
|
|
|
|
return element;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Dilemma:
|
|
//
|
|
// This code runs slowly because bitcount and bitbuf are accessed through the context,
|
|
// not as local variables. However, if they were made into local variables, the code
|
|
// size would be massively increased. Luckily the speed of this code isn't so important
|
|
// compared to that of decodeCompressedBlock().
|
|
//
|
|
BOOL readDynamicBlockHeader(t_decoder_context *context)
|
|
{
|
|
int i;
|
|
int code;
|
|
|
|
#define NUM_CODE_LENGTH_ORDER_CODES (sizeof(g_CodeOrder)/sizeof(g_CodeOrder[0]))
|
|
// make sure extern g_CodeOrder[] declared with array size!
|
|
|
|
switch (context->state)
|
|
{
|
|
case STATE_READING_NUM_LIT_CODES:
|
|
goto reenter_state_reading_num_lit_codes;
|
|
|
|
case STATE_READING_NUM_DIST_CODES:
|
|
goto reenter_state_reading_num_dist_codes;
|
|
|
|
case STATE_READING_NUM_CODE_LENGTH_CODES:
|
|
goto reenter_state_reading_num_code_length_codes;
|
|
|
|
case STATE_READING_CODE_LENGTH_CODES:
|
|
{
|
|
i = context->state_loop_counter;
|
|
goto reenter_state_reading_code_length_codes;
|
|
}
|
|
|
|
case STATE_READING_TREE_CODES_BEFORE:
|
|
{
|
|
i = context->state_loop_counter;
|
|
goto reenter_state_reading_tree_codes_before;
|
|
}
|
|
|
|
case STATE_READING_TREE_CODES_AFTER:
|
|
{
|
|
i = context->state_loop_counter;
|
|
code = context->state_code;
|
|
goto reenter_state_reading_tree_codes_after;
|
|
}
|
|
|
|
default:
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
reenter_state_reading_num_lit_codes:
|
|
|
|
if (ensureBitsContext(context, 5) == FALSE)
|
|
{
|
|
context->state = STATE_READING_NUM_LIT_CODES;
|
|
return TRUE;
|
|
}
|
|
|
|
context->num_literal_codes = getBits(context, 5) + 257;
|
|
|
|
|
|
|
|
reenter_state_reading_num_dist_codes:
|
|
|
|
if (ensureBitsContext(context, 5) == FALSE)
|
|
{
|
|
context->state = STATE_READING_NUM_DIST_CODES;
|
|
return TRUE;
|
|
}
|
|
|
|
context->num_dist_codes = getBits(context, 5) + 1;
|
|
|
|
|
|
|
|
reenter_state_reading_num_code_length_codes:
|
|
|
|
if (ensureBitsContext(context, 4) == FALSE)
|
|
{
|
|
context->state = STATE_READING_NUM_CODE_LENGTH_CODES;
|
|
return TRUE;
|
|
}
|
|
|
|
context->num_code_length_codes = getBits(context, 4) + 4;
|
|
|
|
|
|
|
|
for (i = 0; i < context->num_code_length_codes; i++)
|
|
{
|
|
|
|
reenter_state_reading_code_length_codes:
|
|
|
|
if (ensureBitsContext(context, 3) == FALSE)
|
|
{
|
|
context->state = STATE_READING_CODE_LENGTH_CODES;
|
|
context->state_loop_counter = i;
|
|
return TRUE;
|
|
}
|
|
|
|
context->pretree_code_length[ g_CodeOrder[i] ] = (byte) getBits(context, 3);
|
|
}
|
|
|
|
for (i = context->num_code_length_codes; i < NUM_CODE_LENGTH_ORDER_CODES; i++)
|
|
context->pretree_code_length[ g_CodeOrder[i] ] = 0;
|
|
|
|
if (makeTable(
|
|
NUM_PRETREE_ELEMENTS,
|
|
PRETREE_TABLE_BITS,
|
|
context->pretree_code_length,
|
|
context->pretree_table,
|
|
context->pretree_left,
|
|
context->pretree_right
|
|
) == FALSE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
context->temp_code_array_size = context->num_literal_codes + context->num_dist_codes;
|
|
|
|
|
|
for (i = 0; i < context->temp_code_array_size; )
|
|
{
|
|
|
|
reenter_state_reading_tree_codes_before:
|
|
|
|
_ASSERT(context->bitcount >= -16);
|
|
|
|
if (context->bitcount == -16)
|
|
{
|
|
if (context->input_curpos >= context->end_input_buffer)
|
|
{
|
|
context->state = STATE_READING_TREE_CODES_BEFORE;
|
|
context->state_loop_counter = i;
|
|
return TRUE;
|
|
}
|
|
|
|
context->bitbuf |= ((*context->input_curpos++) << (context->bitcount+16));
|
|
context->bitcount += 8;
|
|
}
|
|
|
|
code = decodePretreeElement(context);
|
|
|
|
if (code < 0)
|
|
{
|
|
context->state = STATE_READING_TREE_CODES_BEFORE;
|
|
context->state_loop_counter = i;
|
|
return TRUE;
|
|
}
|
|
|
|
reenter_state_reading_tree_codes_after:
|
|
|
|
if (code <= 15)
|
|
{
|
|
context->temp_code_list[i++] = (unsigned char) code;
|
|
}
|
|
else
|
|
{
|
|
int repeat_count, j;
|
|
|
|
//
|
|
// If the code is > 15 it means there is a repeat count of 2, 3, or 7 bits
|
|
//
|
|
if (ensureBitsContext(context, 7) == FALSE)
|
|
{
|
|
context->state = STATE_READING_TREE_CODES_AFTER;
|
|
context->state_code = (unsigned char) code;
|
|
context->state_loop_counter = i;
|
|
return TRUE;
|
|
}
|
|
|
|
if (code == 16)
|
|
{
|
|
byte prev_code;
|
|
|
|
// can't have "prev code" on first code
|
|
if (i == 0)
|
|
return FALSE;
|
|
|
|
prev_code = context->temp_code_list[i-1];
|
|
|
|
repeat_count = getBits(context, 2) + 3;
|
|
|
|
if (i + repeat_count > context->temp_code_array_size)
|
|
return FALSE;
|
|
|
|
for (j = 0; j < repeat_count; j++)
|
|
context->temp_code_list[i++] = prev_code;
|
|
}
|
|
else if (code == 17)
|
|
{
|
|
repeat_count = getBits(context, 3) + 3;
|
|
|
|
if (i + repeat_count > context->temp_code_array_size)
|
|
return FALSE;
|
|
|
|
for (j = 0; j < repeat_count; j++)
|
|
context->temp_code_list[i++] = 0;
|
|
}
|
|
else // code == 18
|
|
{
|
|
repeat_count = getBits(context, 7) + 11;
|
|
|
|
if (i + repeat_count > context->temp_code_array_size)
|
|
return FALSE;
|
|
|
|
for (j = 0; j < repeat_count; j++)
|
|
context->temp_code_list[i++] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create literal and distance tables
|
|
//
|
|
memcpy(context->literal_tree_code_length, context->temp_code_list, context->num_literal_codes);
|
|
|
|
for (i = context->num_literal_codes; i < MAX_LITERAL_TREE_ELEMENTS; i++)
|
|
context->literal_tree_code_length[i] = 0;
|
|
|
|
for (i = 0; i < context->num_dist_codes; i++)
|
|
context->distance_tree_code_length[i] = context->temp_code_list[i + context->num_literal_codes];
|
|
|
|
for (i = context->num_dist_codes; i < MAX_DIST_TREE_ELEMENTS; i++)
|
|
context->distance_tree_code_length[i] = 0;
|
|
|
|
//
|
|
// Make sure there is an end-of-block code, otherwise how could we ever end?
|
|
//
|
|
if (context->literal_tree_code_length[END_OF_BLOCK_CODE] == 0)
|
|
return FALSE;
|
|
|
|
context->state = STATE_DECODE_TOP;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|