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