/* * enctree.c * * Encode trees into output data */ #define EXT extern #include "encoder.h" /* * Encode a tree */ static void WriteRepTree( t_encoder_context *context, byte *pLen, byte *pLastLen, int Num ) { int i; int j; int Same; ushort SmallFreq[2*24]; ushort MiniCode[24]; char MiniLen[24]; char k; byte temp_store; byte * z=context->enc_output_buffer_curpos; static const byte Modulo17Lookup[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; memset(SmallFreq, 0, sizeof(SmallFreq)); temp_store = pLen[Num]; pLen[Num] = 123; for (i = 0; i < Num; i++) { Same = 0; /* Count the number of consecutive elements which have the same length */ /* No need to check against array boundary, because the last element has */ /* a nonsense value */ for (j = i+1; pLen[j] == pLen[i]; j++) Same++; /* If more than 3, compress this information */ if (Same >= TREE_ENC_REP_MIN) { /* Special case if they're zeroes */ if (!pLen[i]) { if (Same > TREE_ENC_REP_MIN + TREE_ENC_REP_ZERO_FIRST + TREE_ENC_REP_ZERO_SECOND - 1) Same = TREE_ENC_REP_MIN + TREE_ENC_REP_ZERO_FIRST + TREE_ENC_REP_ZERO_SECOND - 1; if (Same <= TREE_ENC_REP_MIN + TREE_ENC_REP_ZERO_FIRST - 1) SmallFreq[17]++; else SmallFreq[18]++; } else { if (Same > TREE_ENC_REP_MIN + TREE_ENC_REP_SAME_FIRST - 1) Same = TREE_ENC_REP_MIN + TREE_ENC_REP_SAME_FIRST - 1; SmallFreq[ Modulo17Lookup[ pLastLen[i]-pLen[i]+17 ] ]++; SmallFreq[19]++; } i += Same-1; } else SmallFreq[ Modulo17Lookup[ pLastLen[i]-pLen[i]+17 ] ]++; } make_tree( context, 20, SmallFreq, (byte *) MiniLen, MiniCode, true ); /* max 10 byte output overrun */ for (i = 0; i < 20; i++) { output_bits(context, 4, MiniLen[i]); } /* Output original tree with new code */ for (i = 0; i < Num; i++) { Same = 0; /* Count the number of consecutive elements which have the same length */ /* No need to check against array boundary, because the last element has */ /* a nonsense value */ for (j = i+1; pLen[j] == pLen[i]; j++) Same++; /* If more than 3, we can do something */ if (Same >= TREE_ENC_REP_MIN) { if (!pLen[i]) /* Zeroes */ { if (Same > TREE_ENC_REP_MIN + TREE_ENC_REP_ZERO_FIRST + TREE_ENC_REP_ZERO_SECOND - 1) Same = TREE_ENC_REP_MIN + TREE_ENC_REP_ZERO_FIRST + TREE_ENC_REP_ZERO_SECOND - 1; if (Same <= TREE_ENC_REP_MIN + TREE_ENC_REP_ZERO_FIRST - 1) k = 17; else k = 18; } else { if (Same > TREE_ENC_REP_MIN + TREE_ENC_REP_SAME_FIRST - 1) Same = TREE_ENC_REP_MIN + TREE_ENC_REP_SAME_FIRST - 1; k = 19; } } else k = Modulo17Lookup[ pLastLen[i]-pLen[i]+17 ]; output_bits(context, MiniLen[k], MiniCode[k]); if (k == 17) { output_bits(context, TREE_ENC_REPZ_FIRST_EXTRA_BITS, Same-TREE_ENC_REP_MIN); i += Same-1; } else if (k == 18) { output_bits(context, TREE_ENC_REPZ_SECOND_EXTRA_BITS, Same-(TREE_ENC_REP_MIN+TREE_ENC_REP_ZERO_FIRST)); i += Same-1; } else if (k == 19) { output_bits(context, TREE_ENC_REP_SAME_EXTRA_BITS, Same-TREE_ENC_REP_MIN); k = Modulo17Lookup[ pLastLen[i]-pLen[i]+17 ]; output_bits(context, MiniLen[k], MiniCode[k]); i += Same-1; } } pLen[Num] = temp_store; memcpy(pLastLen, pLen, Num); } void create_trees(t_encoder_context *context, bool generate_codes) { /* * Assumption: We can trash PtrLen[NUM_CHARS+(NUM_POSITION_SLOTS*NUM_LENGTHS))], since * we allocated space for it earlier */ make_tree( context, NUM_CHARS+(context->enc_num_position_slots*(NUM_PRIMARY_LENGTHS+1)), context->enc_main_tree_freq, context->enc_main_tree_len, context->enc_main_tree_code, generate_codes ); make_tree( context, NUM_SECONDARY_LENGTHS, context->enc_secondary_tree_freq, context->enc_secondary_tree_len, context->enc_secondary_tree_code, generate_codes ); make_tree( context, ALIGNED_NUM_ELEMENTS, context->enc_aligned_tree_freq, context->enc_aligned_tree_len, context->enc_aligned_tree_code, true ); } void fix_tree_cost_estimates(t_encoder_context *context) { /* * We're only creating trees for estimation purposes and we do not * want to encode the tree. However, the following loops will set * the frequency zero tree element lengths to values other than * zero, so that the optimal encoder won't get confused when it * tries to estimate the number of bits it would take to output an * element. * * We also set the bit lengths of match length 2's further away * than MAX_LENGTH_TWO_OFFSET to a large number, so that the * optimal parser will never select such matches. */ ulong i; /* Set zero lengths to some value */ for (i = 0; i< NUM_CHARS; i++) { if (context->enc_main_tree_len[i] == 0) context->enc_main_tree_len[i] = 11; } for (; i < NUM_CHARS+(context->enc_num_position_slots*(NUM_PRIMARY_LENGTHS+1)); i++) { if (context->enc_main_tree_len[i] == 0) context->enc_main_tree_len[i] = 12; } for (i = 0; i < NUM_SECONDARY_LENGTHS; i++) { if (context->enc_secondary_tree_len[i] == 0) context->enc_secondary_tree_len[i] = 8; } prevent_far_matches(context); } void prevent_far_matches(t_encoder_context *context) { ulong i; /* * Set far match length 2's to a high value so they will never * be chosen. * * See description of MAX_GROWTH in encdefs.h */ for ( i = MP_SLOT(MAX_LENGTH_TWO_OFFSET); i < context->enc_num_position_slots; i++ ) { context->enc_main_tree_len[NUM_CHARS + (i << NL_SHIFT)] = 100; } } /* * Encode the trees * * Assumes trees have already been created with create_trees(). * * Warning, do not call update_tree_cost_estimates() before encoding * the trees, since that routine trashes some of the tree elements. */ void encode_trees(t_encoder_context *context) { WriteRepTree( context, context->enc_main_tree_len, context->enc_main_tree_prev_len, NUM_CHARS ); WriteRepTree( context, &context->enc_main_tree_len[NUM_CHARS], &context->enc_main_tree_prev_len[NUM_CHARS], context->enc_num_position_slots * (NUM_PRIMARY_LENGTHS+1) ); WriteRepTree( context, context->enc_secondary_tree_len, context->enc_secondary_tree_prev_len, NUM_SECONDARY_LENGTHS ); } void encode_aligned_tree(t_encoder_context *context) { int i; make_tree( context, ALIGNED_NUM_ELEMENTS, context->enc_aligned_tree_freq, context->enc_aligned_tree_len, context->enc_aligned_tree_code, true ); /* Output original tree with new code */ for (i = 0; i < 8; i++) { output_bits(context, 3, context->enc_aligned_tree_len[i]); } }