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