|
|
/*
* output.c * * General outputting routines */ #include "deflate.h"
#include <string.h>
#include <stdio.h>
#include <crtdbg.h>
//
// Output an element from the pre-tree
//
#define OUTPUT_PRETREE_ELEMENT(element) \
_ASSERT(pretree_len[element] != 0); \ outputBits(context, pretree_len[element], pretree_code[element]);
//
// Output the tree structure for a dynamic block
//
void outputTreeStructure(t_encoder_context *context, const BYTE *literal_tree_len, const BYTE *dist_tree_len) { int hdist, hlit, combined_tree_elements, i, pass; USHORT pretree_freq[NUM_PRETREE_ELEMENTS*2]; USHORT pretree_code[NUM_PRETREE_ELEMENTS]; byte pretree_len[NUM_PRETREE_ELEMENTS];
//
// combined literal + distance length code array for outputting the trees
// in compressed form
//
// +3 is so we can overflow the array when performing run length encoding
// (dummy values are inserted at the end so that run length encoding fails
// before falling off the end of the array)
//
BYTE lens[MAX_LITERAL_TREE_ELEMENTS + MAX_DIST_TREE_ELEMENTS + 3];
//
// Calculate HDIST
//
for (hdist = MAX_DIST_TREE_ELEMENTS - 1; hdist >= 1; hdist--) { if (dist_tree_len[hdist] != 0) break; }
hdist++;
//
// Calculate HLIT
//
for (hlit = MAX_LITERAL_TREE_ELEMENTS - 1; hlit >= 257; hlit--) { if (literal_tree_len[hlit] != 0) break; }
hlit++;
//
// Now initialise the array to have all of the hlit and hdist codes
// in it
//
combined_tree_elements = hdist + hlit;
memcpy(lens, literal_tree_len, hlit); memcpy(&lens[hlit], dist_tree_len, hdist);
//
// Stick in some dummy values at the end so that we don't overflow the
// array when comparing
//
for (i = combined_tree_elements; i < sizeof(lens); i++) lens[i] = -1;
for (i = 0; i < NUM_PRETREE_ELEMENTS; i++) pretree_freq[i] = 0;
//
// Output the bitlengths in compressed (run length encoded) form.
//
// Make two passes; on the first pass count the various codes, create
// the tree and output it, on the second pass output the codes using
// the tree.
//
for (pass = 0; pass < 2; pass++) { int cur_element;
// are we outputting during this pass?
BOOL outputting = (pass == 1);
cur_element = 0;
while (cur_element < combined_tree_elements) { int curlen = lens[cur_element]; int run_length;
//
// See how many consecutive elements have the same value
//
// This won't run off the end of the array; it will hit the -1's
// we stored there
//
for (run_length = cur_element+1; lens[run_length] == curlen; run_length++) ;
run_length -= cur_element;
//
// For non-zero codes need 4 identical in a row (original code
// plus 3 repeats). We decrement the run_length by one if the
// code is not zero, since we don't count the first (original)
// code in this case.
//
// For zero codes, need 3 zeroes in a row.
//
if (curlen != 0) run_length--;
if (run_length < 3) { if (outputting) { OUTPUT_PRETREE_ELEMENT(curlen); } else pretree_freq[curlen]++;
cur_element++; } else { //
// Elements with zero values are encoded specially
//
if (curlen == 0) { //
// Do we use code 17 (3-10 repeated zeroes) or
// code 18 (11-138 repeated zeroes)?
//
if (run_length <= 10) { // code 17
if (outputting) { OUTPUT_PRETREE_ELEMENT(17); outputBits(context, 3, run_length - 3); } else { pretree_freq[17]++; } } else { // code 18
if (run_length > 138) run_length = 138;
if (outputting) { OUTPUT_PRETREE_ELEMENT(18); outputBits(context, 7, run_length - 11); } else { pretree_freq[18]++; } }
cur_element += run_length; } else { //
// Number of lengths actually encoded. This may end up
// being less than run_length if we have a run length of
// 7 (6 + 1 [which cannot be encoded with a code 16])
//
int run_length_encoded = 0;
// curlen != 0
// can output 3...6 repeats of a non-zero code, so split
// longer runs into short ones (if possible)
// remember to output the code itself first!
if (outputting) { OUTPUT_PRETREE_ELEMENT(curlen);
while (run_length >= 3) { int this_run = (run_length <= 6) ? run_length : 6;
OUTPUT_PRETREE_ELEMENT(16); outputBits(context, 2, this_run - 3);
run_length_encoded += this_run; run_length -= this_run; } } else { pretree_freq[curlen]++;
while (run_length >= 3) { int this_run = (run_length <= 6) ? run_length : 6;
pretree_freq[16]++;
run_length_encoded += this_run; run_length -= this_run; } }
// +1 for the original code itself
cur_element += (run_length_encoded+1); } } }
//
// If this is the first pass, create the pretree from the
// frequency data and output it, as well as the values of
// HLIT, HDIST, HDCLEN (# pretree codes used)
//
if (pass == 0) { int hclen, i;
makeTree( NUM_PRETREE_ELEMENTS, 7, pretree_freq, pretree_code, pretree_len );
//
// Calculate HCLEN
//
for (hclen = NUM_PRETREE_ELEMENTS-1; hclen >= 4; hclen--) { if (pretree_len[ g_CodeOrder[hclen] ] != 0) break; } hclen++;
//
// Dynamic block header
//
outputBits(context, 5, hlit - 257); outputBits(context, 5, hdist - 1); outputBits(context, 4, hclen - 4);
for (i = 0; i < hclen; i++) { outputBits(context, 3, pretree_len[g_CodeOrder[i]]); } } } }
//
// bitwise i/o
//
void flushOutputBitBuffer(t_encoder_context *context) { if (context->bitcount > 0) { int prev_bitcount = context->bitcount; outputBits(context, 16 - context->bitcount, 0);
// backtrack if we have to; ZIP is byte aligned, not 16-bit word aligned
if (prev_bitcount <= 8) context->output_curpos--; } }
//
// Does not check for output overflow, so make sure to call checkOutputOverflow()
// often enough!
//
void outputBits(t_encoder_context *context, int n, int x) { _ASSERT(context->output_curpos < context->output_endpos-1); _ASSERT(n > 0 && n <= 16);
context->bitbuf |= (x << context->bitcount); context->bitcount += n;
if (context->bitcount >= 16) { *context->output_curpos++ = (BYTE) context->bitbuf; *context->output_curpos++ = (BYTE) (context->bitbuf >> 8);
context->bitbuf >>= 16; context->bitcount -= 16; } }
// initialise the bit buffer
void InitBitBuffer(t_encoder_context *context) { context->bitbuf = 0; context->bitcount = 0; }
void OutputBlock(t_encoder_context *context) { _ASSERT(context->std_encoder != NULL || context->optimal_encoder != NULL); // we never call OutputBlock() with the fast encoder
_ASSERT(context->fast_encoder == NULL);
if (context->std_encoder != NULL) StdEncoderOutputBlock(context); else if (context->optimal_encoder != NULL) OptimalEncoderOutputBlock(context); }
void FlushRecordingBuffer(t_encoder_context *context) { _ASSERT(context->std_encoder != NULL || context->optimal_encoder != NULL); _ASSERT(context->fast_encoder == NULL); // fast encoder does not record
if (context->std_encoder != NULL) { *context->std_encoder->recording_bufptr++ = (BYTE) context->std_encoder->recording_bitbuf; *context->std_encoder->recording_bufptr++ = (BYTE) (context->std_encoder->recording_bitbuf >> 8); } else if (context->optimal_encoder != NULL) { *context->optimal_encoder->recording_bufptr++ = (BYTE) context->optimal_encoder->recording_bitbuf; *context->optimal_encoder->recording_bufptr++ = (BYTE) (context->optimal_encoder->recording_bitbuf >> 8); } }
|