windows-nt/Source/XPSP1/NT/enduser/stuff/itss/lzx/decoder/decverb.c
2020-09-26 16:20:57 +08:00

299 lines
7.6 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;
char 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 */
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;
/* 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)
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 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;
char 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 */
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;
match_ptr = (BufPos - match_pos) & context->dec_window_mask;
/* 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 = (((MAX_MATCH-BufPos) < (amount_to_decode)) ? (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);
}