// // deftree.c // // Tree creation for the compressor // #include "deflate.h" #include #include // // MAX_LITERAL_TREE elements is the largest number of elements that will ever be passed // in to this routine // typedef struct { // Made left_right a single long array for performance reasons. We always access them // one after the other, so there is no disadvantage. // left[] in lower 16 bits, right[] in upper 16 bits // short left[2*MAX_LITERAL_TREE_ELEMENTS]; // short right[2*MAX_LITERAL_TREE_ELEMENTS]; unsigned long left_right[2*MAX_LITERAL_TREE_ELEMENTS]; int heap[MAX_LITERAL_TREE_ELEMENTS+1]; int num_elements; // Maximum allowable code length (7 for pre-tree, 15 for other trees) int max_code_length; unsigned short *freq; // passed in as parameter unsigned short *code; // passed in as parameter short * sortptr; int depth; int heapsize; int len_cnt[17]; } t_tree_context; static void countLen(t_tree_context *context, int i) /* call with i = root */ { if (i < context->num_elements) { // check for max code length allowed context->len_cnt[(context->depth < context->max_code_length) ? context->depth : context->max_code_length]++; } else { unsigned long lr_value = context->left_right[i]; context->depth++; countLen(context, lr_value & 65535); // formerly left[i] countLen(context, lr_value >> 16); // formerly right[i] context->depth--; } } static void makeLen(t_tree_context *context, int root, BYTE *len) { int k; int cum; int i; for (i = 0; i <= 16; i++) context->len_cnt[i] = 0; countLen(context, root); cum = 0; for (i = context->max_code_length; i > 0; i--) cum += (context->len_cnt[i] << (context->max_code_length - i)); while (cum != (1 << context->max_code_length)) { context->len_cnt[context->max_code_length]--; for (i = context->max_code_length-1; i > 0; i--) { if (context->len_cnt[i] != 0) { context->len_cnt[i]--; context->len_cnt[i+1] += 2; break; } } cum--; } for (i = 16; i > 0; i--) { k = context->len_cnt[i]; while (--k >= 0) len[ *context->sortptr++ ] = (byte) i; } } /* priority queue; send i-th entry down heap */ static void downHeap(t_tree_context *context, int i) { int j, k; k = context->heap[i]; while ((j = (i<<1)) <= context->heapsize) { if (j < context->heapsize && context->freq[context->heap[j]] > context->freq[context->heap[j + 1]]) j++; if (context->freq[k] <= context->freq[context->heap[j]]) break; context->heap[i] = context->heap[j]; i = j; } context->heap[i] = k; } // // Reverse the bits, len > 0 // static unsigned int bitReverse(unsigned int code, int len) { unsigned int new_code = 0; do { new_code |= (code & 1); new_code <<= 1; code >>= 1; } while (--len > 0); return new_code >> 1; } void makeCode(int num_elements, const int *len_cnt, const BYTE *len, USHORT *code) { int start[18]; int i; start[1] = 0; for (i = 1; i <= 16; i++) start[i + 1] = (start[i] + len_cnt[i]) << 1; for (i = 0; i < num_elements; i++) { unsigned int unreversed_code; unreversed_code = start[len[i]]++; code[i] = (USHORT) bitReverse(unreversed_code, len[i]); } } void makeTree( int num_elements, int max_code_length, unsigned short * freq, unsigned short * code, byte * len ) { t_tree_context tree; int k; int avail; int i; _ASSERT(num_elements <= MAX_LITERAL_TREE_ELEMENTS); // init tree context tree.depth = 0; tree.freq = freq; tree.code = code; tree.num_elements = num_elements; tree.max_code_length = max_code_length; avail = num_elements; tree.heapsize = 0; tree.heap[1] = 0; for (i = 0; i < tree.num_elements; i++) { len[i] = 0; if (tree.freq[i] != 0) tree.heap[++tree.heapsize] = i; } // // Less than 2 elements in the tree? // if (tree.heapsize < 2) { if (tree.heapsize == 0) { // // No elements in the tree? // // Then insert two fake elements and retry. // tree.freq[0] = 1; tree.freq[1] = 1; } else { // // One element in the tree, so add a fake code // // If our only element is element #0 (heap[1] == 0), then // make element #1 have a frequency of 1. // // Else make element #0 have a frequency of 1. // if (tree.heap[1] == 0) tree.freq[1] = 1; else tree.freq[0] = 1; } // // Retry with these new frequencies // makeTree(num_elements, max_code_length, freq, code, len); return; } for (i = tree.heapsize >> 1; i >= 1; i--) downHeap(&tree, i); /* make priority queue */ tree.sortptr = tree.code; do { int i, j; /* while queue has at least two entries */ i = tree.heap[1]; /* take out least-freq entry */ if (i < tree.num_elements) *tree.sortptr++ = (short) i; tree.heap[1] = tree.heap[tree.heapsize--]; downHeap(&tree, 1); j = tree.heap[1]; /* next least-freq entry */ if (j < tree.num_elements) *tree.sortptr++ = (short) j; k = avail++; /* generate new node */ tree.freq[k] = tree.freq[i] + tree.freq[j]; tree.heap[1] = k; downHeap(&tree, 1); /* put into queue */ // tree.left[k] = (short) i; // tree.right[k] = (short) j; tree.left_right[k] = (j << 16) | i; } while (tree.heapsize > 1); tree.sortptr = tree.code; makeLen(&tree, k, len); makeCode(num_elements, tree.len_cnt, len, code); }