Windows2000/private/inet/urlmon/compress/gzip/optblock.c
2020-09-30 17:12:32 +02:00

353 lines
9.6 KiB
C

// optblock.c
// Outputting blocks
#include "deflate.h"
#include <string.h>
#include <stdio.h>
#include <crtdbg.h>
#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;
}