400 lines
13 KiB
C
400 lines
13 KiB
C
|
/*
|
||
|
* decverb.c
|
||
|
*
|
||
|
* Decoding verbatim-bit blocks
|
||
|
*/
|
||
|
#include "decoder.h"
|
||
|
|
||
|
|
||
|
static long special_decode_verbatim_block(
|
||
|
t_decoder_context *context,
|
||
|
long BufPos,
|
||
|
int amount_to_decode
|
||
|
)
|
||
|
{
|
||
|
ulong match_pos;
|
||
|
long bufpos_end;
|
||
|
int match_length;
|
||
|
int c;
|
||
|
ulong dec_bitbuf;
|
||
|
byte *dec_input_curpos;
|
||
|
byte *dec_end_input_pos;
|
||
|
byte *dec_mem_window;
|
||
|
char dec_bitcount;
|
||
|
ulong m;
|
||
|
|
||
|
/*
|
||
|
* Store commonly used variables locally
|
||
|
*/
|
||
|
dec_bitcount = context->dec_bitcount;
|
||
|
dec_bitbuf = context->dec_bitbuf;
|
||
|
dec_input_curpos = context->dec_input_curpos;
|
||
|
dec_end_input_pos = context->dec_end_input_pos;
|
||
|
dec_mem_window = context->dec_mem_window;
|
||
|
|
||
|
bufpos_end = BufPos + amount_to_decode;
|
||
|
|
||
|
/*
|
||
|
* We may overflow by up to MAX_MATCH
|
||
|
*/
|
||
|
while (BufPos < bufpos_end)
|
||
|
{
|
||
|
/* decode an item from the main tree */
|
||
|
DECODE_MAIN_TREE(c);
|
||
|
|
||
|
if ((c -= NUM_CHARS) < 0)
|
||
|
{
|
||
|
/* it's a character */
|
||
|
/* note: c - 256 == c if c is a byte */
|
||
|
#ifdef TRACING
|
||
|
TracingLiteral(BufPos, (byte) c);
|
||
|
#endif
|
||
|
context->dec_mem_window[BufPos] = (byte) c;
|
||
|
|
||
|
/* we know BufPos < bufpos_end here, so no need to check for overflow */
|
||
|
context->dec_mem_window[context->dec_window_size+BufPos] = (byte) c;
|
||
|
BufPos++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* get match length header */
|
||
|
if ((match_length = c & NUM_PRIMARY_LENGTHS) == NUM_PRIMARY_LENGTHS)
|
||
|
{
|
||
|
/* get match length footer if necessary */
|
||
|
DECODE_LEN_TREE_NOEOFCHECK(match_length);
|
||
|
}
|
||
|
|
||
|
/* get match position slot */
|
||
|
m = c >> NL_SHIFT;
|
||
|
|
||
|
/* read any extra bits for the match position */
|
||
|
if (m > 2)
|
||
|
{
|
||
|
if (m > 3) /* dec_extra_bits[m] != 0 */
|
||
|
{
|
||
|
GET_BITS17_NOEOFCHECK(dec_extra_bits[ m ], match_pos);
|
||
|
match_pos += MP_POS_minus2[m];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
match_pos = 1; // MP_POS_minus2[3];
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Add match base to "extra bits". Our match base
|
||
|
* table has 2 subtracted from all the elements.
|
||
|
*
|
||
|
* This is because encoded positions 0,1,2 denote
|
||
|
* repeated offsets. Encoded position 3 denotes
|
||
|
* a match 1 character away, 4 encodes 2 away, etc.
|
||
|
* Hence the subtraction of 2, which has been
|
||
|
* incorporated into the table.
|
||
|
*/
|
||
|
|
||
|
/* update LRU repeated offset list */
|
||
|
context->dec_last_matchpos_offset[2] = context->dec_last_matchpos_offset[1];
|
||
|
context->dec_last_matchpos_offset[1] = context->dec_last_matchpos_offset[0];
|
||
|
context->dec_last_matchpos_offset[0] = match_pos;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* positions 0, 1, 2 denote repeated offsets */
|
||
|
match_pos = context->dec_last_matchpos_offset[m];
|
||
|
|
||
|
if (m)
|
||
|
{
|
||
|
context->dec_last_matchpos_offset[m] = context->dec_last_matchpos_offset[0];
|
||
|
context->dec_last_matchpos_offset[0] = match_pos;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* match lengths range from 2...257 */
|
||
|
match_length += MIN_MATCH;
|
||
|
|
||
|
#ifdef EXTRALONGMATCHES
|
||
|
|
||
|
if ( match_length == MAX_MATCH ) {
|
||
|
|
||
|
//
|
||
|
// See detailed explanation in decalign.c
|
||
|
//
|
||
|
|
||
|
ULONG ExtraMatchLength, ExtraMatchLengthResidue;
|
||
|
|
||
|
GET_BITS_NOEOFCHECK( 9, ExtraMatchLength );
|
||
|
|
||
|
if ( ExtraMatchLength & ( 1 << 8 )) {
|
||
|
if ( ExtraMatchLength & ( 1 << 7 )) {
|
||
|
if ( ExtraMatchLength & ( 1 << 6 )) {
|
||
|
ExtraMatchLength = ( ExtraMatchLength & (( 1 << 6 ) - 1 )) << 9;
|
||
|
GET_BITS_NOEOFCHECK( 9, ExtraMatchLengthResidue );
|
||
|
ExtraMatchLength |= ExtraMatchLengthResidue;
|
||
|
}
|
||
|
else {
|
||
|
ExtraMatchLength = ( ExtraMatchLength & (( 1 << 6 ) - 1 )) << 6;
|
||
|
GET_BITS_NOEOFCHECK( 6, ExtraMatchLengthResidue );
|
||
|
ExtraMatchLength |= ExtraMatchLengthResidue;
|
||
|
ExtraMatchLength += ( 1 << 8 ) + ( 1 << 10 );
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
ExtraMatchLength = ( ExtraMatchLength & (( 1 << 7 ) - 1 )) << 3;
|
||
|
GET_BITS_NOEOFCHECK( 3, ExtraMatchLengthResidue );
|
||
|
ExtraMatchLength |= ExtraMatchLengthResidue;
|
||
|
ExtraMatchLength += ( 1 << 8 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
match_length += ExtraMatchLength;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#ifdef TRACING
|
||
|
TracingMatch(BufPos,
|
||
|
BufPos - match_pos,
|
||
|
context->dec_window_size,
|
||
|
match_length,
|
||
|
m);
|
||
|
#endif
|
||
|
|
||
|
/* copy match data */
|
||
|
do
|
||
|
{
|
||
|
context->dec_mem_window[BufPos] = context->dec_mem_window[(BufPos-match_pos) & context->dec_window_mask];
|
||
|
|
||
|
/* replicate bytes */
|
||
|
if (BufPos < MAX_MATCH) // what does this do? Does it need to be more than MAX_MATCH now?
|
||
|
context->dec_mem_window[context->dec_window_size+BufPos] = context->dec_mem_window[BufPos];
|
||
|
|
||
|
BufPos++;
|
||
|
} while (--match_length > 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
context->dec_bitcount = dec_bitcount;
|
||
|
context->dec_bitbuf = dec_bitbuf;
|
||
|
context->dec_input_curpos = dec_input_curpos;
|
||
|
|
||
|
return BufPos;
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef ASM_DECODE_VERBATIM_BLOCK
|
||
|
|
||
|
long __cdecl fast_decode_verbatim_block(
|
||
|
t_decoder_context *context,
|
||
|
long BufPos,
|
||
|
int amount_to_decode
|
||
|
);
|
||
|
|
||
|
#else /* !ASM_DECODE_VERBATIM_BLOCK */
|
||
|
|
||
|
long fast_decode_verbatim_block(t_decoder_context *context, long BufPos, int amount_to_decode)
|
||
|
{
|
||
|
ulong match_pos;
|
||
|
ulong match_ptr;
|
||
|
long bufpos_end;
|
||
|
long decode_residue;
|
||
|
int match_length;
|
||
|
int c;
|
||
|
ulong dec_bitbuf;
|
||
|
byte *dec_input_curpos;
|
||
|
byte *dec_end_input_pos;
|
||
|
byte *dec_mem_window;
|
||
|
char dec_bitcount;
|
||
|
ulong m;
|
||
|
|
||
|
/*
|
||
|
* Store commonly used variables locally
|
||
|
*/
|
||
|
dec_bitcount = context->dec_bitcount;
|
||
|
dec_bitbuf = context->dec_bitbuf;
|
||
|
dec_input_curpos = context->dec_input_curpos;
|
||
|
dec_end_input_pos = context->dec_end_input_pos;
|
||
|
dec_mem_window = context->dec_mem_window;
|
||
|
|
||
|
bufpos_end = BufPos + amount_to_decode;
|
||
|
|
||
|
while (BufPos < bufpos_end)
|
||
|
{
|
||
|
/* decode an item from the main tree */
|
||
|
DECODE_MAIN_TREE(c);
|
||
|
|
||
|
if ((c -= NUM_CHARS) < 0)
|
||
|
{
|
||
|
/* it's a character */
|
||
|
/* note: c - 256 == c if c is a byte */
|
||
|
#ifdef TRACING
|
||
|
TracingLiteral(BufPos, (byte) c);
|
||
|
#endif
|
||
|
context->dec_mem_window[BufPos++] = (byte) c;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* get match length header */
|
||
|
if ((match_length = c & NUM_PRIMARY_LENGTHS) == NUM_PRIMARY_LENGTHS)
|
||
|
{
|
||
|
/* get match length footer if necessary */
|
||
|
DECODE_LEN_TREE_NOEOFCHECK(match_length);
|
||
|
}
|
||
|
|
||
|
/* get match position slot */
|
||
|
m = c >> NL_SHIFT;
|
||
|
|
||
|
/* read any extra bits for the match position */
|
||
|
if (m > 2)
|
||
|
{
|
||
|
if (m > 3) /* dec_extra_bits[m] != 0 */
|
||
|
{
|
||
|
GET_BITS17_NOEOFCHECK(dec_extra_bits[ m ], match_pos);
|
||
|
match_pos += MP_POS_minus2[m];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
match_pos = MP_POS_minus2[3];
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Add match base to "extra bits". Our match base
|
||
|
* table has 2 subtracted from all the elements.
|
||
|
*
|
||
|
* This is because encoded positions 0,1,2 denote
|
||
|
* repeated offsets. Encoded position 3 denotes
|
||
|
* a match 1 character away, 4 encodes 2 away, etc.
|
||
|
* Hence the subtraction of 2, which has been
|
||
|
* incorporated into the table.
|
||
|
*/
|
||
|
|
||
|
/* update LRU repeated offset list */
|
||
|
context->dec_last_matchpos_offset[2] = context->dec_last_matchpos_offset[1];
|
||
|
context->dec_last_matchpos_offset[1] = context->dec_last_matchpos_offset[0];
|
||
|
context->dec_last_matchpos_offset[0] = match_pos;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* positions 0, 1, 2 denote repeated offsets */
|
||
|
match_pos = context->dec_last_matchpos_offset[m];
|
||
|
|
||
|
if (m)
|
||
|
{
|
||
|
context->dec_last_matchpos_offset[m] = context->dec_last_matchpos_offset[0];
|
||
|
context->dec_last_matchpos_offset[0] = match_pos;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* match lengths range from 2...257 */
|
||
|
match_length += MIN_MATCH;
|
||
|
|
||
|
#ifdef EXTRALONGMATCHES
|
||
|
|
||
|
if ( match_length == MAX_MATCH ) {
|
||
|
|
||
|
//
|
||
|
// See detailed explanation in decalign.c
|
||
|
//
|
||
|
|
||
|
ULONG ExtraMatchLength, ExtraMatchLengthResidue;
|
||
|
|
||
|
GET_BITS_NOEOFCHECK( 9, ExtraMatchLength );
|
||
|
|
||
|
if ( ExtraMatchLength & ( 1 << 8 )) {
|
||
|
if ( ExtraMatchLength & ( 1 << 7 )) {
|
||
|
if ( ExtraMatchLength & ( 1 << 6 )) {
|
||
|
ExtraMatchLength = ( ExtraMatchLength & (( 1 << 6 ) - 1 )) << 9;
|
||
|
GET_BITS_NOEOFCHECK( 9, ExtraMatchLengthResidue );
|
||
|
ExtraMatchLength |= ExtraMatchLengthResidue;
|
||
|
}
|
||
|
else {
|
||
|
ExtraMatchLength = ( ExtraMatchLength & (( 1 << 6 ) - 1 )) << 6;
|
||
|
GET_BITS_NOEOFCHECK( 6, ExtraMatchLengthResidue );
|
||
|
ExtraMatchLength |= ExtraMatchLengthResidue;
|
||
|
ExtraMatchLength += ( 1 << 8 ) + ( 1 << 10 );
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
ExtraMatchLength = ( ExtraMatchLength & (( 1 << 7 ) - 1 )) << 3;
|
||
|
GET_BITS_NOEOFCHECK( 3, ExtraMatchLengthResidue );
|
||
|
ExtraMatchLength |= ExtraMatchLengthResidue;
|
||
|
ExtraMatchLength += ( 1 << 8 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
match_length += ExtraMatchLength;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
match_ptr = (BufPos - match_pos) & context->dec_window_mask;
|
||
|
|
||
|
#ifdef TRACING
|
||
|
TracingMatch(BufPos,
|
||
|
BufPos - match_pos,
|
||
|
context->dec_window_size,
|
||
|
match_length,
|
||
|
m);
|
||
|
#endif
|
||
|
|
||
|
/* copy match data */
|
||
|
|
||
|
do
|
||
|
{
|
||
|
context->dec_mem_window[BufPos++] = context->dec_mem_window[match_ptr++];
|
||
|
} while (--match_length > 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
context->dec_bitcount = dec_bitcount;
|
||
|
context->dec_bitbuf = dec_bitbuf;
|
||
|
context->dec_input_curpos = dec_input_curpos;
|
||
|
|
||
|
/* should be zero */
|
||
|
decode_residue = BufPos - bufpos_end;
|
||
|
|
||
|
BufPos &= context->dec_window_mask;
|
||
|
context->dec_bufpos = BufPos;
|
||
|
|
||
|
return decode_residue;
|
||
|
}
|
||
|
#endif /* ASM_DECODE_VERBATIM_BLOCK */
|
||
|
|
||
|
|
||
|
int decode_verbatim_block(t_decoder_context *context, long BufPos, int amount_to_decode)
|
||
|
{
|
||
|
/*
|
||
|
* Special case code when BufPos is near the beginning of the window;
|
||
|
* we must properly update our MAX_MATCH wrapper bytes.
|
||
|
*/
|
||
|
if (BufPos < MAX_MATCH)
|
||
|
{
|
||
|
long new_bufpos;
|
||
|
long amount_to_slowly_decode;
|
||
|
|
||
|
amount_to_slowly_decode = min(MAX_MATCH-BufPos, amount_to_decode);
|
||
|
|
||
|
/*
|
||
|
* It's ok to end up decoding more than we wanted if we
|
||
|
* restricted it to decoding only MAX_MATCH; there's
|
||
|
* no guarantee a match doesn't straddle MAX_MATCH
|
||
|
*/
|
||
|
new_bufpos = special_decode_verbatim_block(
|
||
|
context,
|
||
|
BufPos,
|
||
|
amount_to_slowly_decode
|
||
|
);
|
||
|
|
||
|
amount_to_decode -= (new_bufpos-BufPos);
|
||
|
|
||
|
context->dec_bufpos = BufPos = new_bufpos;
|
||
|
|
||
|
/*
|
||
|
* Note: if amount_to_decode < 0 then we're in trouble
|
||
|
*/
|
||
|
if (amount_to_decode <= 0)
|
||
|
return amount_to_decode;
|
||
|
}
|
||
|
|
||
|
return fast_decode_verbatim_block(context, BufPos, amount_to_decode);
|
||
|
}
|
||
|
|