229 lines
5.7 KiB
C
229 lines
5.7 KiB
C
/*
|
|
* decblk.c
|
|
*
|
|
* main decoder module
|
|
*/
|
|
#include "decoder.h"
|
|
|
|
|
|
/* local function prototypes */
|
|
static int decode_block(
|
|
t_decoder_context *context,
|
|
lzx_block_type block_type,
|
|
long bufpos,
|
|
long amount_to_decode
|
|
);
|
|
|
|
|
|
/*
|
|
* Decode a block type
|
|
*/
|
|
static int decode_block(
|
|
t_decoder_context *context,
|
|
lzx_block_type block_type,
|
|
long bufpos,
|
|
long amount_to_decode
|
|
)
|
|
{
|
|
int result;
|
|
|
|
if (block_type == BLOCKTYPE_ALIGNED)
|
|
result = decode_aligned_offset_block(context, bufpos, (int) amount_to_decode);
|
|
else if (block_type == BLOCKTYPE_VERBATIM)
|
|
result = decode_verbatim_block(context, bufpos, (int) amount_to_decode);
|
|
else if (block_type == BLOCKTYPE_UNCOMPRESSED)
|
|
result = decode_uncompressed_block(context, bufpos, (int) amount_to_decode);
|
|
else /* no other block types exist */
|
|
result = -1;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Main decode entrypoint
|
|
*/
|
|
long NEAR decode_data(t_decoder_context *context, long bytes_to_decode)
|
|
{
|
|
ulong amount_can_decode;
|
|
long total_decoded;
|
|
|
|
total_decoded = 0;
|
|
|
|
while (bytes_to_decode > 0)
|
|
{
|
|
if (context->dec_decoder_state == DEC_STATE_START_NEW_BLOCK)
|
|
{
|
|
ulong temp1;
|
|
ulong temp2;
|
|
ulong temp3;
|
|
bool do_translation;
|
|
|
|
/*
|
|
* If this is the first time this group, then get the
|
|
* file size for translation.
|
|
*/
|
|
if (context->dec_first_time_this_group)
|
|
{
|
|
context->dec_first_time_this_group = false;
|
|
|
|
do_translation = (bool) getbits(context, 1);
|
|
|
|
if (do_translation)
|
|
{
|
|
ulong high, low;
|
|
|
|
high = getbits(context, 16);
|
|
low = getbits(context, 16);
|
|
context->dec_current_file_size = (high<<16)|low;
|
|
}
|
|
else
|
|
{
|
|
context->dec_current_file_size = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If the last block we decoded was uncompressed, then
|
|
* we need to skip the pad byte (if it exists), and
|
|
* initialise the decoder's bit buffer
|
|
*/
|
|
if (context->dec_block_type == BLOCKTYPE_UNCOMPRESSED)
|
|
{
|
|
/*
|
|
* If block size was odd, a pad byte is required
|
|
*/
|
|
if (context->dec_original_block_size & 1)
|
|
{
|
|
if (context->dec_input_curpos < context->dec_end_input_pos)
|
|
context->dec_input_curpos++;
|
|
}
|
|
|
|
/* so that initialise_decoder_bitbuf() will succeed */
|
|
context->dec_block_type = BLOCKTYPE_INVALID;
|
|
|
|
initialise_decoder_bitbuf(context);
|
|
}
|
|
|
|
/* get the block type */
|
|
context->dec_block_type = (lzx_block_type) getbits(context, 3);
|
|
|
|
/* get size of block (in uncompressed bytes) to decode */
|
|
temp1 = getbits(context, 8);
|
|
temp2 = getbits(context, 8);
|
|
temp3 = getbits(context, 8);
|
|
|
|
/*
|
|
* How large is the block we're going to decode?
|
|
* It can be from 0...16777215 bytes (16MB)
|
|
*/
|
|
context->dec_block_size =
|
|
context->dec_original_block_size = (temp1<<16) + (temp2<<8) + (temp3);
|
|
|
|
/* if block is an aligned type, read the aligned offset tree */
|
|
if (context->dec_block_type == BLOCKTYPE_ALIGNED)
|
|
read_aligned_offset_tree(context);
|
|
|
|
/* read trees */
|
|
if (context->dec_block_type == BLOCKTYPE_VERBATIM ||
|
|
context->dec_block_type == BLOCKTYPE_ALIGNED)
|
|
{
|
|
/* backup old trees */
|
|
memcpy(
|
|
context->dec_main_tree_prev_len,
|
|
context->dec_main_tree_len,
|
|
MAIN_TREE_ELEMENTS
|
|
);
|
|
|
|
memcpy(
|
|
context->dec_secondary_length_tree_prev_len,
|
|
context->dec_secondary_length_tree_len,
|
|
NUM_SECONDARY_LENGTHS
|
|
);
|
|
|
|
read_main_and_secondary_trees(context);
|
|
}
|
|
else if (context->dec_block_type == BLOCKTYPE_UNCOMPRESSED)
|
|
{
|
|
if (handle_beginning_of_uncompressed_block(context) == false)
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
/* no other block types are supported at this time */
|
|
return -1;
|
|
}
|
|
|
|
context->dec_decoder_state = DEC_STATE_DECODING_DATA;
|
|
}
|
|
|
|
/*
|
|
* Keep decoding until the whole block has been decoded
|
|
*/
|
|
while ((context->dec_block_size > 0) && (bytes_to_decode > 0))
|
|
{
|
|
int decode_residue;
|
|
|
|
amount_can_decode = (((context->dec_block_size) < (bytes_to_decode)) ? (context->dec_block_size) : (bytes_to_decode));
|
|
|
|
/* shouldn't happen */
|
|
if (amount_can_decode == 0)
|
|
return -1;
|
|
|
|
decode_residue = decode_block(
|
|
context,
|
|
context->dec_block_type,
|
|
context->dec_bufpos,
|
|
amount_can_decode
|
|
);
|
|
|
|
/*
|
|
* We should have decoded exactly the amount we wanted,
|
|
* since the encoder makes sure that no matches span 32K
|
|
* boundaries.
|
|
*
|
|
* If the data was corrupted, it's possible that we decoded
|
|
* up to MAX_MATCH bytes more than we wanted to.
|
|
*/
|
|
if (decode_residue != 0)
|
|
{
|
|
/* error, we didn't decode what we wanted! */
|
|
return -1;
|
|
}
|
|
|
|
context->dec_block_size -= amount_can_decode;
|
|
bytes_to_decode -= amount_can_decode;
|
|
total_decoded += amount_can_decode;
|
|
}
|
|
|
|
if (context->dec_block_size == 0)
|
|
{
|
|
context->dec_decoder_state = DEC_STATE_START_NEW_BLOCK;
|
|
}
|
|
|
|
if (bytes_to_decode == 0)
|
|
{
|
|
initialise_decoder_bitbuf(context);
|
|
}
|
|
}
|
|
|
|
#ifdef BIT16
|
|
copy_data_to_output(
|
|
context,
|
|
total_decoded,
|
|
context->dec_output_buffer
|
|
);
|
|
#else
|
|
copy_data_to_output(
|
|
context,
|
|
total_decoded,
|
|
context->dec_bufpos ?
|
|
&context->dec_mem_window[context->dec_bufpos - total_decoded] :
|
|
&context->dec_mem_window[context->dec_window_size - total_decoded]
|
|
);
|
|
#endif
|
|
|
|
return total_decoded;
|
|
}
|