128 lines
3.5 KiB
C
128 lines
3.5 KiB
C
// infuncmp.c
|
|
|
|
// Decodes uncompressed blocks
|
|
|
|
#include "inflate.h"
|
|
#include "infmacro.h"
|
|
|
|
|
|
// Returns whether there are >= n valid bits in the bit buffer
|
|
#define ASSERT_BITS_IN_BIT_BUFFER(n) (context->bitcount + 16 >= (n))
|
|
|
|
|
|
static int twoBytesToInt(byte a, byte b)
|
|
{
|
|
return (((int) a) & 255) | ((((int) b) & 255) << 8);
|
|
}
|
|
|
|
|
|
static void dumpBits(t_decoder_context *context, int n)
|
|
{
|
|
context->bitbuf >>= n;
|
|
context->bitcount -= n;
|
|
}
|
|
|
|
|
|
// retrieve n bits from the bit buffer, and dump them when done
|
|
// n can be up to 16
|
|
static int getBits(t_decoder_context *context, int n)
|
|
{
|
|
int result;
|
|
|
|
context->bitcount -= n;
|
|
result = (context->bitbuf & g_BitMask[n]);
|
|
context->bitbuf >>= n;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
BOOL decodeUncompressedBlock(t_decoder_context *context, BOOL *end_of_block)
|
|
{
|
|
unsigned int unc_len, complement;
|
|
|
|
*end_of_block = FALSE;
|
|
|
|
if (context->state == STATE_DECODING_UNCOMPRESSED)
|
|
{
|
|
unc_len = context->state_loop_counter;
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
|
|
if (context->state == STATE_UNCOMPRESSED_ALIGNING)
|
|
{
|
|
// Right now we have between 0 and 32 bits in bitbuf
|
|
|
|
// However, we must flush to a byte boundary
|
|
if ((context->bitcount & 7) != 0)
|
|
{
|
|
int result;
|
|
|
|
result = getBits(context, (context->bitcount & 7));
|
|
|
|
// Since this is supposed to be padding, we should read all zeroes,
|
|
// however, it's not really specified in the spec that they have to
|
|
// be zeroes, so don't count this as an error
|
|
}
|
|
|
|
// Now we have exactly 0, 8, 16, 24, or 32 bits in the bit buffer
|
|
context->state = STATE_UNCOMPRESSED_1;
|
|
}
|
|
|
|
// Now we need to read 4 bytes from the input - however, some of these bytes may
|
|
// be inside our bit buffer, so take them from there first
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (context->state == STATE_UNCOMPRESSED_1 + i)
|
|
{
|
|
if (ASSERT_BITS_IN_BIT_BUFFER(8))
|
|
{
|
|
context->unc_buffer[i] = (byte) ((context->bitbuf) & 255);
|
|
context->bitbuf >>= 8;
|
|
context->bitcount -= 8;
|
|
}
|
|
else
|
|
{
|
|
if (INPUT_EOF())
|
|
return TRUE;
|
|
|
|
context->unc_buffer[i] = *context->input_curpos++;
|
|
}
|
|
|
|
context->state++;
|
|
}
|
|
}
|
|
|
|
unc_len = twoBytesToInt(context->unc_buffer[0], context->unc_buffer[1]);
|
|
complement = twoBytesToInt(context->unc_buffer[2], context->unc_buffer[3]);
|
|
|
|
// make sure complement matches
|
|
if ((unsigned short) unc_len != (unsigned short) (~complement))
|
|
return FALSE; // error!
|
|
}
|
|
|
|
// BUGBUG Make this into a memory copy loop for speed!
|
|
while (unc_len > 0 && context->input_curpos < context->end_input_buffer && context->output_curpos < context->end_output_buffer)
|
|
{
|
|
unc_len--;
|
|
*context->output_curpos++ = context->window[context->bufpos++] = *context->input_curpos++;
|
|
context->bufpos &= WINDOW_MASK;
|
|
}
|
|
|
|
// More bytes left to compress in this block?
|
|
if (unc_len != 0)
|
|
{
|
|
context->state = STATE_DECODING_UNCOMPRESSED;
|
|
context->state_loop_counter = unc_len;
|
|
}
|
|
else
|
|
{
|
|
// Done with this block, need to re-init bit buffer for next block
|
|
context->state = STATE_READING_BFINAL_NEED_TO_INIT_BITBUF;
|
|
*end_of_block = TRUE;
|
|
}
|
|
|
|
return TRUE;
|
|
} |