windows-nt/Source/XPSP1/NT/enduser/stuff/itss/lzx/decoder/decblk.c
2020-09-26 16:20:57 +08:00

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;
}