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