windows-nt/Source/XPSP1/NT/base/mspatch/lzx/decoder/decalign.c
2020-09-26 16:20:57 +08:00

452 lines
14 KiB
C

/*
* decalign.c
*
* Decoding aligned offset block
*/
#include "decoder.h"
static long special_decode_aligned_block(t_decoder_context *context, long bufpos, int amount_to_decode)
{
ulong match_pos;
ulong temp_pos;
long bufpos_end;
int match_length;
int c;
ulong dec_bitbuf;
char dec_bitcount;
byte *dec_input_curpos;
byte *dec_end_input_pos;
byte *dec_mem_window;
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
*/
DECODE_MAIN_TREE(c);
if ((c -= NUM_CHARS) < 0)
{
#ifdef TRACING
TracingLiteral(bufpos, (byte) c);
#endif
dec_mem_window[bufpos] = (byte) c;
dec_mem_window[context->dec_window_size + bufpos] = (byte) c;
bufpos++;
}
else
{
/*
* Get match length slot
*/
if ((match_length = c & NUM_PRIMARY_LENGTHS) == NUM_PRIMARY_LENGTHS)
{
DECODE_LEN_TREE_NOEOFCHECK(match_length);
}
/*
* Get match position slot
*/
m = c >> NL_SHIFT;
if (m > 2)
{
if (dec_extra_bits[ m ] >= 3)
{
if (dec_extra_bits[m]-3)
{
/* no need to getbits17 */
GET_BITS_NOEOFCHECK(dec_extra_bits[ m ] - 3, temp_pos);
}
else
{
temp_pos = 0;
}
match_pos = MP_POS_minus2[m] + (temp_pos << 3);
DECODE_ALIGNED_NOEOFCHECK(temp_pos);
match_pos += temp_pos;
}
else
{
if (dec_extra_bits[m])
{
GET_BITS_NOEOFCHECK(dec_extra_bits[ m ], match_pos);
match_pos += MP_POS_minus2[m];
}
else
{
match_pos = 1; // MP_POS_minus2[m==3];
}
}
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
{
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_length += MIN_MATCH;
#ifdef EXTRALONGMATCHES
if ( match_length == MAX_MATCH ) {
//
// Fetch extra match length in addition to MAX_MATCH, which
// is encoded like this:
//
// 0xxxxxxxx (8-bit value)
// 10xxxxxxxxxx (10-bit value plus 2^8)
// 110xxxxxxxxxxxx (12-bit value plus 2^8 plus 2^10)
// 111xxxxxxxxxxxxxxx (15-bit value)
//
// 15 bits is the largest possible because a match cannot
// span a 32K boundary.
//
// We know we'll read at least 9 bits, so read 9 bits first
// and then determine how many additional to read based on
// the first 3 bits of that.
//
ULONG ExtraMatchLength;
ULONG ExtraMatchLengthResidue;
GET_BITS_NOEOFCHECK( 9, ExtraMatchLength );
if ( ExtraMatchLength & ( 1 << 8 )) {
if ( ExtraMatchLength & ( 1 << 7 )) {
if ( ExtraMatchLength & ( 1 << 6 )) {
//
// First 3 bits are '111', so that means remaining
// 6 bits are the first 6 bits of the 15 bit value
// meaning we must read 9 more bits.
//
ExtraMatchLength = ( ExtraMatchLength & (( 1 << 6 ) - 1 )) << 9;
GET_BITS_NOEOFCHECK( 9, ExtraMatchLengthResidue );
ExtraMatchLength |= ExtraMatchLengthResidue;
}
else {
//
// First 3 bits are '110', so that means remaining
// 6 bits are the first 6 bits of the 12 bit value
// meaning we must read 6 more bits. Then we add
// 2^8 plus 2^10 to the value.
//
ExtraMatchLength = ( ExtraMatchLength & (( 1 << 6 ) - 1 )) << 6;
GET_BITS_NOEOFCHECK( 6, ExtraMatchLengthResidue );
ExtraMatchLength |= ExtraMatchLengthResidue;
ExtraMatchLength += ( 1 << 8 ) + ( 1 << 10 );
}
}
else {
//
// First 2 bits are '10', so that means remaining
// 7 bits are the first 7 bits of the 10 bit value
// meaning we must read 3 more bits. Then we add
// 2^8 to the value.
//
ExtraMatchLength = ( ExtraMatchLength & (( 1 << 7 ) - 1 )) << 3;
GET_BITS_NOEOFCHECK( 3, ExtraMatchLengthResidue );
ExtraMatchLength |= ExtraMatchLengthResidue;
ExtraMatchLength += ( 1 << 8 );
}
}
else {
//
// First bit is a '0', so that means remaining 8 bits are
// the 8 bit value to add to the match length. No need to
// mask off the leading '0'.
//
}
match_length += ExtraMatchLength;
}
#endif
#ifdef TRACING
TracingMatch(bufpos,
bufpos-match_pos,
context->dec_window_size,
match_length,
m);
#endif
do
{
dec_mem_window[bufpos] = dec_mem_window[(bufpos-match_pos) & context->dec_window_mask];
if (bufpos < MAX_MATCH)
dec_mem_window[context->dec_window_size+bufpos] = 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;
}
#ifndef ASM_DECODE_ALIGNED_OFFSET_BLOCK
long fast_decode_aligned_offset_block(t_decoder_context *context, long bufpos, int amount_to_decode)
{
ulong match_pos;
ulong temp_pos;
long bufpos_end;
long decode_residue;
int match_length;
int c;
ulong dec_bitbuf;
char dec_bitcount;
byte *dec_input_curpos;
byte *dec_end_input_pos;
byte *dec_mem_window;
ulong match_ptr;
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
*/
DECODE_MAIN_TREE(c);
if ((c -= NUM_CHARS) < 0)
{
#ifdef TRACING
TracingLiteral(bufpos, (byte) c);
#endif
dec_mem_window[bufpos++] = (byte) c;
}
else
{
/*
* Get match length slot
*/
if ((match_length = c & NUM_PRIMARY_LENGTHS) == NUM_PRIMARY_LENGTHS)
{
DECODE_LEN_TREE_NOEOFCHECK(match_length);
}
/*
* Get match position slot
*/
m = c >> NL_SHIFT;
if (m > 2)
{
if (dec_extra_bits[ m ] >= 3)
{
if (dec_extra_bits[m]-3)
{
/* no need to getbits17 */
GET_BITS_NOEOFCHECK(dec_extra_bits[ m ] - 3, temp_pos);
}
else
{
temp_pos = 0;
}
match_pos = MP_POS_minus2[m] + (temp_pos << 3);
DECODE_ALIGNED_NOEOFCHECK(temp_pos);
match_pos += temp_pos;
}
else
{
if (dec_extra_bits[m])
{
GET_BITS_NOEOFCHECK(dec_extra_bits[ m ], match_pos);
match_pos += MP_POS_minus2[m];
}
else
{
match_pos = MP_POS_minus2[m];
}
}
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
{
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_length += MIN_MATCH;
match_ptr = (bufpos - match_pos) & context->dec_window_mask;
#ifdef EXTRALONGMATCHES
if ( match_length == MAX_MATCH ) {
//
// See detailed explanation above.
//
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
do
{
dec_mem_window[bufpos++] = 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
int decode_aligned_offset_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_aligned_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_aligned_offset_block(context, BufPos, amount_to_decode);
}