// // optblock.c // // Outputting blocks // #include "deflate.h" #include #include #include #include "maketbl.h" // // Decode a recorded literal // #define DECODE_LITERAL(slot) \ slot = encoder->recording_literal_tree_table[read_bitbuf & REC_LITERALS_DECODING_TABLE_MASK]; \ while (slot < 0) \ { \ unsigned long mask = 1 << REC_LITERALS_DECODING_TABLE_BITS; \ do \ { \ slot = -slot; \ if ((read_bitbuf & mask) == 0) \ slot = encoder->recording_literal_tree_left[slot]; \ else \ slot = encoder->recording_literal_tree_right[slot]; \ mask <<= 1; \ } while (slot < 0); \ } // // Decode a recorded distance slot // #define DECODE_POS_SLOT(slot) \ slot = encoder->recording_dist_tree_table[read_bitbuf & REC_DISTANCES_DECODING_TABLE_MASK]; \ while (slot < 0) \ { \ unsigned long mask = 1 << REC_DISTANCES_DECODING_TABLE_BITS; \ do \ { \ slot = -slot; \ if ((read_bitbuf & mask) == 0) \ slot = encoder->recording_dist_tree_left[slot]; \ else \ slot = encoder->recording_dist_tree_right[slot]; \ mask <<= 1; \ } while (slot < 0); \ } // // Remove count bits from the bit buffer // #define DUMP_READBUF_BITS(count) \ read_bitbuf >>= count; \ read_bitcount -= count; // // Read more bits into the read buffer if our bit buffer if we need to // #define CHECK_MORE_READBUF() \ if (read_bitcount <= 0) \ { \ read_bitbuf |= ((*read_bufptr++) << (read_bitcount+16)); \ read_bitcount += 8; \ if (read_bitcount <= 0) \ { \ read_bitbuf |= ((*read_bufptr++) << (read_bitcount+16)); \ read_bitcount += 8; \ } \ } // output an element from the literal tree #define OUTPUT_LITERAL(element) \ { \ _ASSERT(encoder->literal_tree_len[element] != 0); \ outputBits(context, encoder->literal_tree_len[element], encoder->literal_tree_code[element]); \ } // output an element from the distance tree #define OUTPUT_DIST_SLOT(element) \ { \ _ASSERT(encoder->dist_tree_len[element] != 0); \ outputBits(context, encoder->dist_tree_len[element], encoder->dist_tree_code[element]); \ } // // Output a dynamic block // static BOOL OptimalEncoderOutputDynamicBlock(t_encoder_context *context) { unsigned long read_bitbuf; int read_bitcount; byte * read_bufptr; t_optimal_encoder *encoder = context->optimal_encoder; if (context->state == STATE_NORMAL) { // // If we haven't started to output a block yet // read_bufptr = encoder->lit_dist_buffer; read_bitbuf = 0; read_bitcount = -16; read_bitbuf |= ((*read_bufptr++) << (read_bitcount+16)); read_bitcount += 8; read_bitbuf |= ((*read_bufptr++) << (read_bitcount+16)); read_bitcount += 8; context->outputting_block_bitbuf = read_bitbuf; context->outputting_block_bitcount = read_bitcount; context->outputting_block_bufptr = read_bufptr; outputBits(context, 1, 0); // "final" block flag outputBits(context, 2, BLOCKTYPE_DYNAMIC); context->state = STATE_OUTPUTTING_TREE_STRUCTURE; } if (context->state == STATE_OUTPUTTING_TREE_STRUCTURE) { // // Make sure there is enough room to output the entire tree structure at once // if (context->output_curpos > context->output_endpos - MAX_TREE_DATA_SIZE) { _ASSERT(0); // not enough room to output tree structure, fatal error! return FALSE; } outputTreeStructure(context, encoder->literal_tree_len, encoder->dist_tree_len); context->state = STATE_OUTPUTTING_BLOCK; } _ASSERT(context->state == STATE_OUTPUTTING_BLOCK); // load state into local variables read_bufptr = context->outputting_block_bufptr; read_bitbuf = context->outputting_block_bitbuf; read_bitcount = context->outputting_block_bitcount; // output literals while (context->outputting_block_current_literal < context->outputting_block_num_literals) { int literal; // break when we get near the end of our output buffer if (context->output_curpos >= context->output_near_end_threshold) break; DECODE_LITERAL(literal); DUMP_READBUF_BITS(encoder->recording_literal_tree_len[literal]); CHECK_MORE_READBUF(); if (literal < NUM_CHARS) { // it's a char OUTPUT_LITERAL(literal); } else { // it's a match int len_slot, pos_slot, extra_pos_bits; // literal == len_slot + (NUM_CHARS+1) _ASSERT(literal != END_OF_BLOCK_CODE); OUTPUT_LITERAL(literal); len_slot = literal - (NUM_CHARS+1); // // extra_length_bits[len_slot] > 0 when len_slot >= 8 // (except when length is MAX_MATCH). // if (len_slot >= 8) { int extra_bits = g_ExtraLengthBits[len_slot]; if (extra_bits > 0) { unsigned int extra_data = read_bitbuf & ((1 << extra_bits)-1); outputBits(context, extra_bits, extra_data); DUMP_READBUF_BITS(extra_bits); CHECK_MORE_READBUF(); } } DECODE_POS_SLOT(pos_slot); DUMP_READBUF_BITS(encoder->recording_dist_tree_len[pos_slot]); CHECK_MORE_READBUF(); _ASSERT(pos_slot < 30); OUTPUT_DIST_SLOT(pos_slot); extra_pos_bits = g_ExtraDistanceBits[pos_slot]; if (extra_pos_bits > 0) { unsigned int extra_data = read_bitbuf & ((1 << extra_pos_bits)-1); outputBits(context, extra_pos_bits, extra_data); DUMP_READBUF_BITS(extra_pos_bits); CHECK_MORE_READBUF(); } } context->outputting_block_current_literal++; } // did we output all of our literals without running out of output space? if (context->outputting_block_current_literal >= context->outputting_block_num_literals) { // output the code signifying end-of-block OUTPUT_LITERAL(END_OF_BLOCK_CODE); // reset state context->state = STATE_NORMAL; } else { context->outputting_block_bitbuf = read_bitbuf; context->outputting_block_bitcount = read_bitcount; context->outputting_block_bufptr = read_bufptr; context->state = STATE_OUTPUTTING_BLOCK; } return TRUE; } // // Output a block. This routine will resume outputting a block that was already being // output if state != STATE_NORMAL. // BOOL OptimalEncoderOutputBlock(t_encoder_context *context) { t_optimal_encoder *encoder = context->optimal_encoder; _ASSERT(encoder != NULL); // // The tree creation routines cannot >= 65536 literals. // _ASSERT(context->outputting_block_num_literals < 65536); if (context->state == STATE_NORMAL) { // // Start outputting literals and distances from the beginning // context->outputting_block_current_literal = 0; // // Nothing to output? Then return // if (context->outputting_block_num_literals == 0) return TRUE; // make decoding table so that we can decode recorded items makeTable( MAX_LITERAL_TREE_ELEMENTS, REC_LITERALS_DECODING_TABLE_BITS, encoder->recording_literal_tree_len, encoder->recording_literal_tree_table, encoder->recording_literal_tree_left, encoder->recording_literal_tree_right ); makeTable( MAX_DIST_TREE_ELEMENTS, REC_DISTANCES_DECODING_TABLE_BITS, encoder->recording_dist_tree_len, encoder->recording_dist_tree_table, encoder->recording_dist_tree_left, encoder->recording_dist_tree_right ); // now make the trees used for encoding makeTree( MAX_LITERAL_TREE_ELEMENTS, 15, encoder->literal_tree_freq, encoder->literal_tree_code, encoder->literal_tree_len ); makeTree( MAX_DIST_TREE_ELEMENTS, 15, encoder->dist_tree_freq, encoder->dist_tree_code, encoder->dist_tree_len ); } // // Try outputting as a dynamic block // if (OptimalEncoderOutputDynamicBlock(context) == FALSE) { return FALSE; } if (context->state == STATE_NORMAL) { encoder->recording_bufptr = context->optimal_encoder->lit_dist_buffer; encoder->recording_bitbuf = 0; encoder->recording_bitcount = 0; context->outputting_block_num_literals = 0; // make sure there are no zero frequency items NormaliseFrequencies(encoder->literal_tree_freq, encoder->dist_tree_freq); // make tree for recording new items makeTree( MAX_DIST_TREE_ELEMENTS, RECORDING_DIST_MAX_CODE_LEN, encoder->dist_tree_freq, encoder->recording_dist_tree_code, encoder->recording_dist_tree_len ); makeTree( MAX_LITERAL_TREE_ELEMENTS, RECORDING_LIT_MAX_CODE_LEN, encoder->literal_tree_freq, encoder->recording_literal_tree_code, encoder->recording_literal_tree_len ); OptimalEncoderZeroFrequencyCounts(encoder); } return TRUE; }