Fix libnsgif LWZ decoding buffer awfulness

master
Richard Stanway 2013-07-08 23:12:24 -04:00
parent 72358708c4
commit 1ab300f6fe
2 changed files with 100 additions and 100 deletions

View File

@ -88,10 +88,6 @@
*/
#define GIF_INVALID_FRAME -1
/* Maximum LZW bits available
*/
#define GIF_MAX_LZW 12
/* Transparent colour
*/
#define GIF_TRANSPARENT_COLOUR 0x00
@ -132,30 +128,8 @@ static void gif_init_LZW(gif_animation *gif);
static BOOL gif_next_LZW(gif_animation *gif);
static int gif_next_code(gif_animation *gif, int code_size);
/* General LZW values. They are shared for all GIFs being decoded, and
thus we can't handle progressive decoding efficiently without having
the data for each image which would use an extra 10Kb or so per GIF.
*/
static unsigned char buf[4];
static unsigned char *direct;
static int maskTbl[16] = {0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f,
0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff};
static int table[2][(1 << GIF_MAX_LZW)];
static unsigned char stack[(1 << GIF_MAX_LZW) * 2];
static unsigned char *stack_pointer;
static int code_size, set_code_size;
static int max_code, max_code_size;
static int clear_code, end_code;
static int curbit, lastbit, last_byte;
static int firstcode, oldcode;
static BOOL zero_data_block = FALSE;
static BOOL get_done;
/* Whether to clear the decoded image rather than plot
*/
static BOOL clear_image = FALSE;
const static int maskTbl[16] = {0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f,
0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff};
/** Initialises necessary gif_animation members.
*/
@ -786,7 +760,7 @@ gif_result gif_decode_frame(gif_animation *gif, unsigned int frame) {
return GIF_OK;
}
if ((!clear_image) && ((int)frame == gif->decoded_frame))
if ((!gif->clear_image) && ((int)frame == gif->decoded_frame))
return GIF_OK;
/* Get the start of our frame data and the end of the GIF data
@ -869,7 +843,7 @@ gif_result gif_decode_frame(gif_animation *gif, unsigned int frame) {
goto gif_decode_frame_exit;
}
colour_table = gif->local_colour_table;
if (!clear_image) {
if (!gif->clear_image) {
for (index = 0; index < colour_table_size; index++) {
/* Gif colour map contents are r,g,b.
*
@ -915,7 +889,7 @@ gif_result gif_decode_frame(gif_animation *gif, unsigned int frame) {
/* If we are clearing the image we just clear, if not decode
*/
if (!clear_image) {
if (!gif->clear_image) {
/* Ensure we have enough data for a 1-byte LZW code size + 1-byte gif trailer
*/
if (gif_bytes < 2) {
@ -938,10 +912,10 @@ gif_result gif_decode_frame(gif_animation *gif, unsigned int frame) {
* transparency we likely wouldn't want to do that. */
/* memset((char*)frame_data, colour_table[gif->background_index], gif->width * gif->height * sizeof(int)); */
} else if ((frame != 0) && (gif->frames[frame - 1].disposal_method == GIF_FRAME_CLEAR)) {
clear_image = TRUE;
gif->clear_image = TRUE;
if ((return_value = gif_decode_frame(gif, (frame - 1))) != GIF_OK)
goto gif_decode_frame_exit;
clear_image = FALSE;
gif->clear_image = FALSE;
/* If the previous frame's disposal method requires we restore the previous
* image, find the last image set to "do not dispose" and get that frame data
*/
@ -967,20 +941,20 @@ gif_result gif_decode_frame(gif_animation *gif, unsigned int frame) {
/* Initialise the LZW decoding
*/
set_code_size = gif_data[0];
gif->set_code_size = gif_data[0];
gif->buffer_position = (gif_data - gif->gif_data) + 1;
/* Set our code variables
*/
code_size = set_code_size + 1;
clear_code = (1 << set_code_size);
end_code = clear_code + 1;
max_code_size = clear_code << 1;
max_code = clear_code + 2;
curbit = lastbit = 0;
last_byte = 2;
get_done = FALSE;
direct = buf;
gif->code_size = gif->set_code_size + 1;
gif->clear_code = (1 << gif->set_code_size);
gif->end_code = gif->clear_code + 1;
gif->max_code_size = gif->clear_code << 1;
gif->max_code = gif->clear_code + 2;
gif->curbit = gif->lastbit = 0;
gif->last_byte = 2;
gif->get_done = FALSE;
gif->direct = gif->buf;
gif_init_LZW(gif);
/* Decompress the data
@ -997,13 +971,13 @@ gif_result gif_decode_frame(gif_animation *gif, unsigned int frame) {
*/
x = width;
while (x > 0) {
burst_bytes = (stack_pointer - stack);
burst_bytes = (gif->stack_pointer - gif->stack);
if (burst_bytes > 0) {
if (burst_bytes > x)
burst_bytes = x;
x -= burst_bytes;
while (burst_bytes-- > 0) {
colour = *--stack_pointer;
colour = *--gif->stack_pointer;
if (((gif->frames[frame].transparency) &&
(colour != gif->frames[frame].transparency_index)) ||
(!gif->frames[frame].transparency))
@ -1156,26 +1130,26 @@ void gif_init_LZW(gif_animation *gif) {
int i;
gif->current_error = 0;
if (clear_code >= (1 << GIF_MAX_LZW)) {
stack_pointer = stack;
if (gif->clear_code >= (1 << GIF_MAX_LZW)) {
gif->stack_pointer = gif->stack;
gif->current_error = GIF_FRAME_DATA_ERROR;
return;
}
/* initialise our table */
memset(table, 0x00, (1 << GIF_MAX_LZW) * 8);
for (i = 0; i < clear_code; ++i)
table[1][i] = i;
memset(gif->table, 0x00, (1 << GIF_MAX_LZW) * 8);
for (i = 0; i < gif->clear_code; ++i)
gif->table[1][i] = i;
/* update our LZW parameters */
code_size = set_code_size + 1;
max_code_size = clear_code << 1;
max_code = clear_code + 2;
stack_pointer = stack;
gif->code_size = gif->set_code_size + 1;
gif->max_code_size = gif->clear_code << 1;
gif->max_code = gif->clear_code + 2;
gif->stack_pointer = gif->stack;
do {
firstcode = oldcode = gif_next_code(gif, code_size);
} while (firstcode == clear_code);
*stack_pointer++ =firstcode;
gif->firstcode = gif->oldcode = gif_next_code(gif, gif->code_size);
} while (gif->firstcode == gif->clear_code);
*gif->stack_pointer++ =gif->firstcode;
}
@ -1184,16 +1158,16 @@ static BOOL gif_next_LZW(gif_animation *gif) {
int block_size;
int new_code;
code = gif_next_code(gif, code_size);
code = gif_next_code(gif, gif->code_size);
if (code < 0) {
gif->current_error = code;
return FALSE;
} else if (code == clear_code) {
} else if (code == gif->clear_code) {
gif_init_LZW(gif);
return TRUE;
} else if (code == end_code) {
} else if (code == gif->end_code) {
/* skip to the end of our data so multi-image GIFs work */
if (zero_data_block) {
if (gif->zero_data_block) {
gif->current_error = GIF_FRAME_DATA_ERROR;
return FALSE;
}
@ -1207,42 +1181,42 @@ static BOOL gif_next_LZW(gif_animation *gif) {
}
incode = code;
if (code >= max_code) {
*stack_pointer++ = firstcode;
code = oldcode;
if (code >= gif->max_code) {
*gif->stack_pointer++ = gif->firstcode;
code = gif->oldcode;
}
/* The following loop is the most important in the GIF decoding cycle as every
* single pixel passes through it.
*
* Note: our stack is always big enough to hold a complete decompressed chunk. */
while (code >= clear_code) {
*stack_pointer++ = table[1][code];
new_code = table[0][code];
if (new_code < clear_code) {
* Note: our gif->stack is always big enough to hold a complete decompressed chunk. */
while (code >= gif->clear_code) {
*gif->stack_pointer++ = gif->table[1][code];
new_code = gif->table[0][code];
if (new_code < gif->clear_code) {
code = new_code;
break;
}
*stack_pointer++ = table[1][new_code];
code = table[0][new_code];
*gif->stack_pointer++ = gif->table[1][new_code];
code = gif->table[0][new_code];
if (code == new_code) {
gif->current_error = GIF_FRAME_DATA_ERROR;
return FALSE;
}
}
*stack_pointer++ = firstcode = table[1][code];
*gif->stack_pointer++ = gif->firstcode = gif->table[1][code];
if ((code = max_code) < (1 << GIF_MAX_LZW)) {
table[0][code] = oldcode;
table[1][code] = firstcode;
++max_code;
if ((max_code >= max_code_size) && (max_code_size < (1 << GIF_MAX_LZW))) {
max_code_size = max_code_size << 1;
++code_size;
if ((code = gif->max_code) < (1 << GIF_MAX_LZW)) {
gif->table[0][code] = gif->oldcode;
gif->table[1][code] = gif->firstcode;
++gif->max_code;
if ((gif->max_code >= gif->max_code_size) && (gif->max_code_size < (1 << GIF_MAX_LZW))) {
gif->max_code_size = gif->max_code_size << 1;
++gif->code_size;
}
}
oldcode = incode;
gif->oldcode = incode;
return TRUE;
}
@ -1250,39 +1224,39 @@ static int gif_next_code(gif_animation *gif, int code_size) {
int i, j, end, count, ret;
unsigned char *b;
end = curbit + code_size;
if (end >= lastbit) {
if (get_done)
end = gif->curbit + gif->code_size;
if (end >= gif->lastbit) {
if (gif->get_done)
return GIF_END_OF_FRAME;
buf[0] = direct[last_byte - 2];
buf[1] = direct[last_byte - 1];
gif->buf[0] = gif->direct[gif->last_byte - 2];
gif->buf[1] = gif->direct[gif->last_byte - 1];
/* get the next block */
direct = gif->gif_data + gif->buffer_position;
zero_data_block = ((count = direct[0]) == 0);
gif->direct = gif->gif_data + gif->buffer_position;
gif->zero_data_block = ((count = gif->direct[0]) == 0);
if ((gif->buffer_position + count) >= gif->buffer_size)
return GIF_INSUFFICIENT_FRAME_DATA;
if (count == 0)
get_done = TRUE;
gif->get_done = TRUE;
else {
direct -= 1;
buf[2] = direct[2];
buf[3] = direct[3];
gif->direct -= 1;
gif->buf[2] = gif->direct[2];
gif->buf[3] = gif->direct[3];
}
gif->buffer_position += count + 1;
/* update our variables */
last_byte = 2 + count;
curbit = (curbit - lastbit) + 16;
lastbit = (2 + count) << 3;
end = curbit + code_size;
gif->last_byte = 2 + count;
gif->curbit = (gif->curbit - gif->lastbit) + 16;
gif->lastbit = (2 + count) << 3;
end = gif->curbit + gif->code_size;
}
i = curbit >> 3;
i = gif->curbit >> 3;
if (i < 2)
b = buf;
b = gif->buf;
else
b = direct;
b = gif->direct;
ret = b[i];
j = (end >> 3) - 1;
@ -1291,7 +1265,7 @@ static int gif_next_code(gif_animation *gif, int code_size) {
if (i < j)
ret |= (b[i + 2] << 16);
}
ret = (ret >> (curbit % 8)) & maskTbl[code_size];
curbit += code_size;
ret = (ret >> (gif->curbit % 8)) & maskTbl[gif->code_size];
gif->curbit += gif->code_size;
return ret;
}

View File

@ -42,6 +42,10 @@ typedef enum {
GIF_END_OF_FRAME = -7
} gif_result;
/* Maximum LZW bits available
*/
#define GIF_MAX_LZW 12
/* The GIF frame data
*/
typedef struct gif_frame {
@ -109,6 +113,28 @@ typedef struct gif_animation {
BOOL global_colours; /**< whether the GIF has a global colour table */
unsigned int *global_colour_table; /**< global colour table */
unsigned int *local_colour_table; /**< local colour table */
/* General LZW values. They are NO LONGER shared for all GIFs being decoded BECAUSE
THAT IS A TERRIBLE IDEA TO SAVE 10Kb or so per GIF.
*/
unsigned char buf[4];
unsigned char *direct;
int table[2][(1 << GIF_MAX_LZW)];
unsigned char stack[(1 << GIF_MAX_LZW) * 2];
unsigned char *stack_pointer;
int code_size, set_code_size;
int max_code, max_code_size;
int clear_code, end_code;
int curbit, lastbit, last_byte;
int firstcode, oldcode;
BOOL zero_data_block;
BOOL get_done;
/* Whether to clear the decoded image rather than plot
*/
BOOL clear_image;
} gif_animation;
void gif_create(gif_animation *gif, gif_bitmap_callback_vt *bitmap_callbacks);