Gitweb links:
...log
http://git.netsurf-browser.org/libnsgif.git/shortlog/aa6d8064c05f5a45132b...
...commit
http://git.netsurf-browser.org/libnsgif.git/commit/aa6d8064c05f5a45132b15...
...tree
http://git.netsurf-browser.org/libnsgif.git/tree/aa6d8064c05f5a45132b154c...
The branch, master has been updated
via aa6d8064c05f5a45132b154c266b5e2360a84dff (commit)
via 5c5ae3e63a28b5222874017f7ec12d62403063bb (commit)
via f4ccd56c717d4ee3f2f2a0791b5f8134d8a1645e (commit)
via a1617883903bf102af5d6712c9812261efe1ccb9 (commit)
via 83442501788be224b9da56c3c837a9024795ca8c (commit)
from abc6a95ad6a8fd14cce943b4f9643b0a2ad175b4 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=aa6d8064c05f5a4513...
commit aa6d8064c05f5a45132b154c266b5e2360a84dff
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
make the mast table read only data in the only place it is used
diff --git a/src/libnsgif.c b/src/libnsgif.c
index dc2aabb..b6d69e4 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -69,7 +69,6 @@
struct lzw_s {
unsigned char buf[4];
unsigned char *direct;
- int maskTbl[16];
int table[2][(1 << GIF_MAX_LZW)];
unsigned char stack[(1 << GIF_MAX_LZW) * 2];
unsigned char *stack_pointer;
@@ -95,20 +94,28 @@ struct lzw_s {
* each image which would use an extra 10Kb or so per GIF.
*/
static struct lzw_s lzw_params = {
- .maskTbl = {
- 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f,
- 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff
- },
.zero_data_block = false,
};
static struct lzw_s *lzw = &lzw_params;
-
+/**
+ * get the next LZW code from the GIF
+ *
+ * reads codes from the input data stream coping with GIF data sub blocking
+ *
+ * \param gif The GIF context
+ * \param code_size The number of bitsin the current LZW code
+ * \return The next code to process or error return code
+ */
static int gif_next_code(gif_animation *gif, int code_size)
{
int i, j, end, count, ret;
unsigned char *b;
+ static const int maskTbl[16] = {
+ 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f,
+ 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff
+ };
end = lzw->curbit + code_size;
if (end >= lzw->lastbit) {
@@ -123,10 +130,13 @@ static int gif_next_code(gif_animation *gif, int code_size)
if (gif->buffer_position >= gif->buffer_size) {
return GIF_INSUFFICIENT_FRAME_DATA;
}
- lzw->zero_data_block = ((count = lzw->direct[0]) == 0);
+
+ count = lzw->direct[0];
+ lzw->zero_data_block = (count == 0);
if ((gif->buffer_position + count) >= gif->buffer_size) {
return GIF_INSUFFICIENT_FRAME_DATA;
}
+
if (count == 0) {
lzw->get_done = true;
} else {
@@ -161,14 +171,18 @@ static int gif_next_code(gif_animation *gif, int code_size)
ret |= (b[i + 2] << 16);
}
}
- ret = (ret >> (lzw->curbit % 8)) & lzw->maskTbl[code_size];
+ ret = (ret >> (lzw->curbit % 8)) & maskTbl[code_size];
lzw->curbit += code_size;
+
return ret;
}
/**
* Clear LZW code dictionary
+ *
+ * \param gif The GIF context.
+ * \return GIF_OK or error code.
*/
static gif_result gif_clear_codes_LZW(gif_animation *gif)
{
@@ -207,6 +221,12 @@ static gif_result gif_clear_codes_LZW(gif_animation *gif)
}
+/**
+ * fill the LZW stack with decompressed data
+ *
+ * \param gif The GIF context.
+ * \return true on sucessful decode of the next LZW code else false.
+ */
static bool gif_next_LZW(gif_animation *gif)
{
int code, incode;
@@ -256,7 +276,7 @@ static bool gif_next_LZW(gif_animation *gif)
/* The following loop is the most important in the GIF decoding cycle
* as every single pixel passes through it.
*
- * Note: our lzw->stack is always big enough to hold a complete decompressed
+ * Note: our stack is always big enough to hold a complete decompressed
* chunk.
*/
while (code >= lzw->clear_code) {
@@ -291,7 +311,8 @@ static bool gif_next_LZW(gif_animation *gif)
}
*lzw->stack_pointer++ = lzw->firstcode = lzw->table[1][code];
- if ((code = lzw->max_code) < (1 << GIF_MAX_LZW)) {
+ code = lzw->max_code;
+ if (code < (1 << GIF_MAX_LZW)) {
lzw->table[0][code] = lzw->oldcode;
lzw->table[1][code] = lzw->firstcode;
++lzw->max_code;
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=5c5ae3e63a28b52228...
commit 5c5ae3e63a28b5222874017f7ec12d62403063bb
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
remove forward declarations
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 9f9bd8d..dc2aabb 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -62,16 +62,10 @@
#define GIF_BLOCK_TERMINATOR 0x00
#define GIF_TRAILER 0x3b
+/** standard GIF header size */
#define GIF_STANDARD_HEADER_SIZE 13
-/* Internal GIF routines */
-static gif_result gif_initialise_sprite(gif_animation *gif, unsigned int width, unsigned
int height);
-static gif_result gif_initialise_frame(gif_animation *gif);
-static gif_result gif_initialise_frame_extensions(gif_animation *gif, const int frame);
-static gif_result gif_skip_frame_extensions(gif_animation *gif);
-static unsigned int gif_interlaced_line(int height, int y);
-
-
+/** LZW parameters */
struct lzw_s {
unsigned char buf[4];
unsigned char *direct;
@@ -358,6 +352,131 @@ gif_initialise_sprite(gif_animation *gif,
/**
+ * Attempts to initialise the frame's extensions
+ *
+ * \param gif The animation context
+ * \param frame The frame number
+ * @return GIF_INSUFFICIENT_FRAME_DATA for insufficient data to complete the
+ * frame GIF_OK for successful initialisation.
+ */
+static gif_result
+gif_initialise_frame_extensions(gif_animation *gif, const int frame)
+{
+ unsigned char *gif_data, *gif_end;
+ int gif_bytes;
+ unsigned int block_size;
+
+ /* Get our buffer position etc. */
+ gif_data = (unsigned char *)(gif->gif_data + gif->buffer_position);
+ gif_end = (unsigned char *)(gif->gif_data + gif->buffer_size);
+
+ /* Initialise the extensions */
+ while (gif_data < gif_end && gif_data[0] == GIF_EXTENSION_INTRODUCER)
{
+ ++gif_data;
+ if ((gif_bytes = (gif_end - gif_data)) < 1) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+
+ /* Switch on extension label */
+ switch (gif_data[0]) {
+ case GIF_EXTENSION_GRAPHIC_CONTROL:
+ /* 6-byte Graphic Control Extension is:
+ *
+ * +0 CHAR Graphic Control Label
+ * +1 CHAR Block Size
+ * +2 CHAR __Packed Fields__
+ * 3BITS Reserved
+ * 3BITS Disposal Method
+ * 1BIT User Input Flag
+ * 1BIT Transparent Color Flag
+ * +3 SHORT Delay Time
+ * +5 CHAR Transparent Color Index
+ */
+ if (gif_bytes < 6) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+
+ gif->frames[frame].frame_delay = gif_data[3] | (gif_data[4]
<< 8);
+ if (gif_data[2] & GIF_TRANSPARENCY_MASK) {
+ gif->frames[frame].transparency = true;
+ gif->frames[frame].transparency_index = gif_data[5];
+ }
+ gif->frames[frame].disposal_method = ((gif_data[2] &
GIF_DISPOSAL_MASK) >> 2);
+ /* I have encountered documentation and GIFs in the
+ * wild that use 0x04 to restore the previous frame,
+ * rather than the officially documented 0x03. I
+ * believe some (older?) software may even actually
+ * export this way. We handle this as a type of
+ * "quirks" mode.
+ */
+ if (gif->frames[frame].disposal_method ==
GIF_FRAME_QUIRKS_RESTORE) {
+ gif->frames[frame].disposal_method =
GIF_FRAME_RESTORE;
+ }
+ gif_data += (2 + gif_data[1]);
+ break;
+
+ case GIF_EXTENSION_APPLICATION:
+ /* 14-byte+ Application Extension is:
+ *
+ * +0 CHAR Application Extension Label
+ * +1 CHAR Block Size
+ * +2 8CHARS Application Identifier
+ * +10 3CHARS Appl. Authentication Code
+ * +13 1-256 Application Data (Data sub-blocks)
+ */
+ if (gif_bytes < 17) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ if ((gif_data[1] == 0x0b) &&
+ (strncmp((const char *) gif_data + 2,
+ "NETSCAPE2.0", 11) == 0) &&
+ (gif_data[13] == 0x03) &&
+ (gif_data[14] == 0x01)) {
+ gif->loop_count = gif_data[15] | (gif_data[16]
<< 8);
+ }
+ gif_data += (2 + gif_data[1]);
+ break;
+
+ case GIF_EXTENSION_COMMENT:
+ /* Move the pointer to the first data sub-block Skip 1
+ * byte for the extension label
+ */
+ ++gif_data;
+ break;
+
+ default:
+ /* Move the pointer to the first data sub-block Skip 2
+ * bytes for the extension label and size fields Skip
+ * the extension size itself
+ */
+ if (gif_bytes < 2) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ gif_data += (2 + gif_data[1]);
+ }
+
+ /* Repeatedly skip blocks until we get a zero block or run out
+ * of data This data is ignored by this gif decoder
+ */
+ gif_bytes = (gif_end - gif_data);
+ block_size = 0;
+ while (gif_data < gif_end && gif_data[0] !=
GIF_BLOCK_TERMINATOR) {
+ block_size = gif_data[0] + 1;
+ if ((gif_bytes -= block_size) < 0) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ gif_data += block_size;
+ }
+ ++gif_data;
+ }
+
+ /* Set buffer position and return */
+ gif->buffer_position = (gif_data - gif->gif_data);
+ return GIF_OK;
+}
+
+
+/**
* Attempts to initialise the next frame
*
* \param gif The animation context
@@ -593,129 +712,6 @@ static gif_result gif_initialise_frame(gif_animation *gif)
}
-/**
- * Attempts to initialise the frame's extensions
- *
- * \param gif The animation context
- * \param frame The frame number
- * @return GIF_INSUFFICIENT_FRAME_DATA for insufficient data to complete the
- * frame GIF_OK for successful initialisation.
- */
-static gif_result
-gif_initialise_frame_extensions(gif_animation *gif, const int frame)
-{
- unsigned char *gif_data, *gif_end;
- int gif_bytes;
- unsigned int block_size;
-
- /* Get our buffer position etc. */
- gif_data = (unsigned char *)(gif->gif_data + gif->buffer_position);
- gif_end = (unsigned char *)(gif->gif_data + gif->buffer_size);
-
- /* Initialise the extensions */
- while (gif_data < gif_end && gif_data[0] == GIF_EXTENSION_INTRODUCER)
{
- ++gif_data;
- if ((gif_bytes = (gif_end - gif_data)) < 1) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
-
- /* Switch on extension label */
- switch (gif_data[0]) {
- case GIF_EXTENSION_GRAPHIC_CONTROL:
- /* 6-byte Graphic Control Extension is:
- *
- * +0 CHAR Graphic Control Label
- * +1 CHAR Block Size
- * +2 CHAR __Packed Fields__
- * 3BITS Reserved
- * 3BITS Disposal Method
- * 1BIT User Input Flag
- * 1BIT Transparent Color Flag
- * +3 SHORT Delay Time
- * +5 CHAR Transparent Color Index
- */
- if (gif_bytes < 6) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
-
- gif->frames[frame].frame_delay = gif_data[3] | (gif_data[4]
<< 8);
- if (gif_data[2] & GIF_TRANSPARENCY_MASK) {
- gif->frames[frame].transparency = true;
- gif->frames[frame].transparency_index = gif_data[5];
- }
- gif->frames[frame].disposal_method = ((gif_data[2] &
GIF_DISPOSAL_MASK) >> 2);
- /* I have encountered documentation and GIFs in the
- * wild that use 0x04 to restore the previous frame,
- * rather than the officially documented 0x03. I
- * believe some (older?) software may even actually
- * export this way. We handle this as a type of
- * "quirks" mode.
- */
- if (gif->frames[frame].disposal_method ==
GIF_FRAME_QUIRKS_RESTORE) {
- gif->frames[frame].disposal_method =
GIF_FRAME_RESTORE;
- }
- gif_data += (2 + gif_data[1]);
- break;
-
- case GIF_EXTENSION_APPLICATION:
- /* 14-byte+ Application Extension is:
- *
- * +0 CHAR Application Extension Label
- * +1 CHAR Block Size
- * +2 8CHARS Application Identifier
- * +10 3CHARS Appl. Authentication Code
- * +13 1-256 Application Data (Data sub-blocks)
- */
- if (gif_bytes < 17) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- if ((gif_data[1] == 0x0b) &&
- (strncmp((const char *) gif_data + 2,
- "NETSCAPE2.0", 11) == 0) &&
- (gif_data[13] == 0x03) &&
- (gif_data[14] == 0x01)) {
- gif->loop_count = gif_data[15] | (gif_data[16]
<< 8);
- }
- gif_data += (2 + gif_data[1]);
- break;
-
- case GIF_EXTENSION_COMMENT:
- /* Move the pointer to the first data sub-block Skip 1
- * byte for the extension label
- */
- ++gif_data;
- break;
-
- default:
- /* Move the pointer to the first data sub-block Skip 2
- * bytes for the extension label and size fields Skip
- * the extension size itself
- */
- if (gif_bytes < 2) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- gif_data += (2 + gif_data[1]);
- }
-
- /* Repeatedly skip blocks until we get a zero block or run out
- * of data This data is ignored by this gif decoder
- */
- gif_bytes = (gif_end - gif_data);
- block_size = 0;
- while (gif_data < gif_end && gif_data[0] !=
GIF_BLOCK_TERMINATOR) {
- block_size = gif_data[0] + 1;
- if ((gif_bytes -= block_size) < 0) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- gif_data += block_size;
- }
- ++gif_data;
- }
-
- /* Set buffer position and return */
- gif->buffer_position = (gif_data - gif->gif_data);
- return GIF_OK;
-}
/**
@@ -1278,7 +1274,7 @@ gif_result gif_initialise(gif_animation *gif, size_t size, unsigned
char *data)
* termination block) Although generally useless, the GIF
* specification does not expressly prohibit this
*/
- if (gif->buffer_size == 14) {
+ if (gif->buffer_size == (GIF_STANDARD_HEADER_SIZE + 1)) {
if (gif_data[0] == GIF_TRAILER) {
return GIF_OK;
} else {
@@ -1286,7 +1282,7 @@ gif_result gif_initialise(gif_animation *gif, size_t size, unsigned
char *data)
}
}
- /* Initialise enough workspace for 4 frames initially */
+ /* Initialise enough workspace for a frame */
if ((gif->frames = (gif_frame *)malloc(sizeof(gif_frame))) == NULL) {
gif_finalise(gif);
return GIF_INSUFFICIENT_MEMORY;
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=f4ccd56c717d4ee3f2...
commit f4ccd56c717d4ee3f2f2a0791b5f8134d8a1645e
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
fix the colour table size check to be correct
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 8422563..9f9bd8d 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -62,6 +62,8 @@
#define GIF_BLOCK_TERMINATOR 0x00
#define GIF_TRAILER 0x3b
+#define GIF_STANDARD_HEADER_SIZE 13
+
/* Internal GIF routines */
static gif_result gif_initialise_sprite(gif_animation *gif, unsigned int width, unsigned
int height);
static gif_result gif_initialise_frame(gif_animation *gif);
@@ -1310,7 +1312,7 @@ gif_result gif_initialise(gif_animation *gif, size_t size, unsigned
char *data)
if (gif->global_colour_table[0] == GIF_PROCESS_COLOURS) {
/* Check for a global colour map signified by bit 7 */
if (gif->global_colours) {
- if (gif->buffer_size < (gif->colour_table_size * 3 +
12)) {
+ if (gif->buffer_size < (gif->colour_table_size * 3 +
GIF_STANDARD_HEADER_SIZE)) {
return GIF_INSUFFICIENT_DATA;
}
for (index = 0; index < gif->colour_table_size; index++) {
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=a1617883903bf102af...
commit a1617883903bf102af5d6712c9812261efe1ccb9
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
fix buffer overrun due to LZW code clearing
The LZW code clearing function was not dealing with errors when
obtaining the next code from the gif. this resulted in input buffer
overruns and occasional segmentation faults.
diff --git a/src/libnsgif.c b/src/libnsgif.c
index f241145..8422563 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -177,6 +177,7 @@ static int gif_next_code(gif_animation *gif, int code_size)
static gif_result gif_clear_codes_LZW(gif_animation *gif)
{
int i;
+ int code;
if (lzw->clear_code >= (1 << GIF_MAX_LZW)) {
lzw->stack_pointer = lzw->stack;
@@ -197,8 +198,13 @@ static gif_result gif_clear_codes_LZW(gif_animation *gif)
/* process repeated clear codes */
do {
- lzw->firstcode = lzw->oldcode = gif_next_code(gif,
lzw->code_size);
- } while (lzw->firstcode == lzw->clear_code);
+ code = gif_next_code(gif, lzw->code_size);
+ if (code < 0) {
+ return code;
+ }
+ } while (code == lzw->clear_code);
+ lzw->firstcode = lzw->oldcode = code;
+
*lzw->stack_pointer++ = lzw->firstcode;
return GIF_OK;
@@ -219,6 +225,9 @@ static bool gif_next_LZW(gif_animation *gif)
if (code == lzw->clear_code) {
gif->current_error = gif_clear_codes_LZW(gif);
+ if (gif->current_error != GIF_OK) {
+ return false;
+ }
return true;
}
@@ -1053,6 +1062,9 @@ gif_internal_decode_frame(gif_animation *gif,
lzw->get_done = false;
lzw->direct = lzw->buf;
gif->current_error = gif_clear_codes_LZW(gif);
+ if (gif->current_error != GIF_OK) {
+ return gif->current_error;
+ }
/* Decompress the data */
for (y = 0; y < height; y++) {
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=83442501788be224b9...
commit 83442501788be224b9da56c3c837a9024795ca8c
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
move lzw parameters to a struct
Make all the lzw parameters members of a structure instead of being
random globals. This allows for a future change to making the library
safe when decompressing multiple GIF.
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 412c67a..f241145 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -69,32 +69,236 @@ static gif_result gif_initialise_frame_extensions(gif_animation *gif,
const int
static gif_result gif_skip_frame_extensions(gif_animation *gif);
static unsigned int gif_interlaced_line(int height, int y);
-/* Internal LZW routines */
-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);
+
+struct lzw_s {
+ unsigned char buf[4];
+ unsigned char *direct;
+ int maskTbl[16];
+ 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;
+ int oldcode;
+
+ bool zero_data_block;
+ bool get_done;
+};
+
/* 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] = {
+static struct lzw_s lzw_params = {
+ .maskTbl = {
0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f,
0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff
+ },
+ .zero_data_block = false,
};
-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;
+static struct lzw_s *lzw = &lzw_params;
+
+
+static int gif_next_code(gif_animation *gif, int code_size)
+{
+ int i, j, end, count, ret;
+ unsigned char *b;
+
+ end = lzw->curbit + code_size;
+ if (end >= lzw->lastbit) {
+ if (lzw->get_done) {
+ return GIF_END_OF_FRAME;
+ }
+ lzw->buf[0] = lzw->direct[lzw->last_byte - 2];
+ lzw->buf[1] = lzw->direct[lzw->last_byte - 1];
+
+ /* get the next block */
+ lzw->direct = gif->gif_data + gif->buffer_position;
+ if (gif->buffer_position >= gif->buffer_size) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ lzw->zero_data_block = ((count = lzw->direct[0]) == 0);
+ if ((gif->buffer_position + count) >= gif->buffer_size) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ if (count == 0) {
+ lzw->get_done = true;
+ } else {
+ if (gif->buffer_position + 3 >= gif->buffer_size) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ lzw->direct -= 1;
+ lzw->buf[2] = lzw->direct[2];
+ lzw->buf[3] = lzw->direct[3];
+ }
+ gif->buffer_position += count + 1;
+
+ /* update our variables */
+ lzw->last_byte = 2 + count;
+ lzw->curbit = (lzw->curbit - lzw->lastbit) + 16;
+ lzw->lastbit = (2 + count) << 3;
+ end = lzw->curbit + code_size;
+ }
+
+ i = lzw->curbit >> 3;
+ if (i < 2) {
+ b = lzw->buf;
+ } else {
+ b = lzw->direct;
+ }
+
+ ret = b[i];
+ j = (end >> 3) - 1;
+ if (i <= j) {
+ ret |= (b[i + 1] << 8);
+ if (i < j) {
+ ret |= (b[i + 2] << 16);
+ }
+ }
+ ret = (ret >> (lzw->curbit % 8)) & lzw->maskTbl[code_size];
+ lzw->curbit += code_size;
+ return ret;
+}
+
+
+/**
+ * Clear LZW code dictionary
+ */
+static gif_result gif_clear_codes_LZW(gif_animation *gif)
+{
+ int i;
+
+ if (lzw->clear_code >= (1 << GIF_MAX_LZW)) {
+ lzw->stack_pointer = lzw->stack;
+ return GIF_FRAME_DATA_ERROR;
+ }
+
+ /* initialise our table */
+ memset(lzw->table, 0x00, (1 << GIF_MAX_LZW) * 8);
+ for (i = 0; i < lzw->clear_code; ++i) {
+ lzw->table[1][i] = i;
+ }
+
+ /* reset LZW parameters */
+ lzw->code_size = lzw->set_code_size + 1;
+ lzw->max_code_size = lzw->clear_code << 1;
+ lzw->max_code = lzw->clear_code + 2;
+ lzw->stack_pointer = lzw->stack;
+
+ /* process repeated clear codes */
+ do {
+ lzw->firstcode = lzw->oldcode = gif_next_code(gif,
lzw->code_size);
+ } while (lzw->firstcode == lzw->clear_code);
+ *lzw->stack_pointer++ = lzw->firstcode;
+
+ return GIF_OK;
+}
+
+
+static bool gif_next_LZW(gif_animation *gif)
+{
+ int code, incode;
+ int block_size;
+ int new_code;
+
+ code = gif_next_code(gif, lzw->code_size);
+ if (code < 0) {
+ gif->current_error = code;
+ return false;
+ }
+
+ if (code == lzw->clear_code) {
+ gif->current_error = gif_clear_codes_LZW(gif);
+ return true;
+ }
+
+ if (code == lzw->end_code) {
+ /* skip to the end of our data so multi-image GIFs work */
+ if (lzw->zero_data_block) {
+ gif->current_error = GIF_FRAME_DATA_ERROR;
+ return false;
+ }
+ block_size = 0;
+ while (block_size != 1 &&
+ gif->buffer_position < gif->buffer_size) {
+ block_size = gif->gif_data[gif->buffer_position] + 1;
+ gif->buffer_position += block_size;
+ }
+ gif->current_error = GIF_FRAME_DATA_ERROR;
+ return false;
+ }
+
+ incode = code;
+ if (code >= lzw->max_code) {
+ if (lzw->stack_pointer >= lzw->stack + ((1 << GIF_MAX_LZW)
* 2)) {
+ gif->current_error = GIF_FRAME_DATA_ERROR;
+ return false;
+ }
+ *lzw->stack_pointer++ = lzw->firstcode;
+ code = lzw->oldcode;
+ }
+
+ /* The following loop is the most important in the GIF decoding cycle
+ * as every single pixel passes through it.
+ *
+ * Note: our lzw->stack is always big enough to hold a complete decompressed
+ * chunk.
+ */
+ while (code >= lzw->clear_code) {
+ if (lzw->stack_pointer >= lzw->stack + ((1 << GIF_MAX_LZW)
* 2) ||
+ code >= (1 << GIF_MAX_LZW)) {
+ gif->current_error = GIF_FRAME_DATA_ERROR;
+ return false;
+ }
+ *lzw->stack_pointer++ = lzw->table[1][code];
+ new_code = lzw->table[0][code];
+ if (new_code < lzw->clear_code) {
+ code = new_code;
+ break;
+ }
+
+ if (lzw->stack_pointer >= lzw->stack + ((1 << GIF_MAX_LZW)
* 2) ||
+ new_code >= (1 << GIF_MAX_LZW)) {
+ gif->current_error = GIF_FRAME_DATA_ERROR;
+ return false;
+ }
+ *lzw->stack_pointer++ = lzw->table[1][new_code];
+ code = lzw->table[0][new_code];
+ if (code == new_code) {
+ gif->current_error = GIF_FRAME_DATA_ERROR;
+ return false;
+ }
+ }
+
+ if (lzw->stack_pointer >= lzw->stack + ((1 << GIF_MAX_LZW) * 2))
{
+ gif->current_error = GIF_FRAME_DATA_ERROR;
+ return false;
+ }
+ *lzw->stack_pointer++ = lzw->firstcode = lzw->table[1][code];
+
+ if ((code = lzw->max_code) < (1 << GIF_MAX_LZW)) {
+ lzw->table[0][code] = lzw->oldcode;
+ lzw->table[1][code] = lzw->firstcode;
+ ++lzw->max_code;
+ if ((lzw->max_code >= lzw->max_code_size) &&
+ (lzw->max_code_size < (1 << GIF_MAX_LZW))) {
+ lzw->max_code_size = lzw->max_code_size << 1;
+ ++lzw->code_size;
+ }
+ }
+ lzw->oldcode = incode;
+ return true;
+}
/**
@@ -585,189 +789,7 @@ static unsigned int gif_interlaced_line(int height, int y) {
}
-/**
- * Initialise LZW decoding
- */
-void gif_init_LZW(gif_animation *gif)
-{
- int i;
-
- gif->current_error = 0;
- if (clear_code >= (1 << GIF_MAX_LZW)) {
- stack_pointer = 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;
- }
-
- /* update our LZW parameters */
- code_size = set_code_size + 1;
- max_code_size = clear_code << 1;
- max_code = clear_code + 2;
- stack_pointer = stack;
- do {
- firstcode = oldcode = gif_next_code(gif, code_size);
- } while (firstcode == clear_code);
- *stack_pointer++ =firstcode;
-}
-
-
-static bool gif_next_LZW(gif_animation *gif)
-{
- int code, incode;
- int block_size;
- int new_code;
- code = gif_next_code(gif, code_size);
- if (code < 0) {
- gif->current_error = code;
- return false;
- } else if (code == clear_code) {
- gif_init_LZW(gif);
- return true;
- } else if (code == end_code) {
- /* skip to the end of our data so multi-image GIFs work */
- if (zero_data_block) {
- gif->current_error = GIF_FRAME_DATA_ERROR;
- return false;
- }
- block_size = 0;
- while (block_size != 1 &&
- gif->buffer_position < gif->buffer_size) {
- block_size = gif->gif_data[gif->buffer_position] + 1;
- gif->buffer_position += block_size;
- }
- gif->current_error = GIF_FRAME_DATA_ERROR;
- return false;
- }
-
- incode = code;
- if (code >= max_code) {
- if (stack_pointer >= stack + ((1 << GIF_MAX_LZW) * 2)) {
- gif->current_error = GIF_FRAME_DATA_ERROR;
- return false;
- }
- *stack_pointer++ = firstcode;
- code = 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) {
- if (stack_pointer >= stack + ((1 << GIF_MAX_LZW) * 2) ||
- code >= (1 << GIF_MAX_LZW)) {
- gif->current_error = GIF_FRAME_DATA_ERROR;
- return false;
- }
- *stack_pointer++ = table[1][code];
- new_code = table[0][code];
- if (new_code < clear_code) {
- code = new_code;
- break;
- }
-
- if (stack_pointer >= stack + ((1 << GIF_MAX_LZW) * 2) ||
- new_code >= (1 << GIF_MAX_LZW)) {
- gif->current_error = GIF_FRAME_DATA_ERROR;
- return false;
- }
- *stack_pointer++ = table[1][new_code];
- code = table[0][new_code];
- if (code == new_code) {
- gif->current_error = GIF_FRAME_DATA_ERROR;
- return false;
- }
- }
-
- if (stack_pointer >= stack + ((1 << GIF_MAX_LZW) * 2)) {
- gif->current_error = GIF_FRAME_DATA_ERROR;
- return false;
- }
- *stack_pointer++ = firstcode = 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;
- }
- }
- oldcode = incode;
- return true;
-}
-
-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) {
- return GIF_END_OF_FRAME;
- }
- buf[0] = direct[last_byte - 2];
- buf[1] = direct[last_byte - 1];
-
- /* get the next block */
- direct = gif->gif_data + gif->buffer_position;
- if (gif->buffer_position >= gif->buffer_size) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- zero_data_block = ((count = direct[0]) == 0);
- if ((gif->buffer_position + count) >= gif->buffer_size) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- if (count == 0) {
- get_done = true;
- } else {
- if (gif->buffer_position + 3 >= gif->buffer_size) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- direct -= 1;
- buf[2] = direct[2];
- buf[3] = 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;
- }
-
- i = curbit >> 3;
- if (i < 2) {
- b = buf;
- } else {
- b = direct;
- }
-
- ret = b[i];
- j = (end >> 3) - 1;
- if (i <= j) {
- ret |= (b[i + 1] << 8);
- if (i < j) {
- ret |= (b[i + 2] << 16);
- }
- }
- ret = (ret >> (curbit % 8)) & maskTbl[code_size];
- curbit += code_size;
- return ret;
-}
/**
@@ -1017,20 +1039,20 @@ gif_internal_decode_frame(gif_animation *gif,
gif->decoded_frame = frame;
/* Initialise the LZW decoding */
- set_code_size = gif_data[0];
+ lzw->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_init_LZW(gif);
+ lzw->code_size = lzw->set_code_size + 1;
+ lzw->clear_code = (1 << lzw->set_code_size);
+ lzw->end_code = lzw->clear_code + 1;
+ lzw->max_code_size = lzw->clear_code << 1;
+ lzw->max_code = lzw->clear_code + 2;
+ lzw->curbit = lzw->lastbit = 0;
+ lzw->last_byte = 2;
+ lzw->get_done = false;
+ lzw->direct = lzw->buf;
+ gif->current_error = gif_clear_codes_LZW(gif);
/* Decompress the data */
for (y = 0; y < height; y++) {
@@ -1047,14 +1069,14 @@ gif_internal_decode_frame(gif_animation *gif,
*/
x = width;
while (x > 0) {
- burst_bytes = (stack_pointer - stack);
+ burst_bytes = (lzw->stack_pointer - lzw->stack);
if (burst_bytes > 0) {
if (burst_bytes > x) {
burst_bytes = x;
}
x -= burst_bytes;
while (burst_bytes-- > 0) {
- colour = *--stack_pointer;
+ colour = *--lzw->stack_pointer;
if (((gif->frames[frame].transparency)
&&
(colour !=
gif->frames[frame].transparency_index)) ||
(!gif->frames[frame].transparency)) {
-----------------------------------------------------------------------
Summary of changes:
src/libnsgif.c | 763 ++++++++++++++++++++++++++++++--------------------------
1 file changed, 408 insertions(+), 355 deletions(-)
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 412c67a..b6d69e4 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -62,39 +62,269 @@
#define GIF_BLOCK_TERMINATOR 0x00
#define GIF_TRAILER 0x3b
-/* Internal GIF routines */
-static gif_result gif_initialise_sprite(gif_animation *gif, unsigned int width, unsigned
int height);
-static gif_result gif_initialise_frame(gif_animation *gif);
-static gif_result gif_initialise_frame_extensions(gif_animation *gif, const int frame);
-static gif_result gif_skip_frame_extensions(gif_animation *gif);
-static unsigned int gif_interlaced_line(int height, int y);
-
-/* Internal LZW routines */
-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);
+/** standard GIF header size */
+#define GIF_STANDARD_HEADER_SIZE 13
+
+/** LZW parameters */
+struct lzw_s {
+ 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;
+ int oldcode;
+
+ bool zero_data_block;
+ bool get_done;
+};
+
/* 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 struct lzw_s lzw_params = {
+ .zero_data_block = false,
};
-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;
+static struct lzw_s *lzw = &lzw_params;
+
+/**
+ * get the next LZW code from the GIF
+ *
+ * reads codes from the input data stream coping with GIF data sub blocking
+ *
+ * \param gif The GIF context
+ * \param code_size The number of bitsin the current LZW code
+ * \return The next code to process or error return code
+ */
+static int gif_next_code(gif_animation *gif, int code_size)
+{
+ int i, j, end, count, ret;
+ unsigned char *b;
+ static const int maskTbl[16] = {
+ 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f,
+ 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff
+ };
+
+ end = lzw->curbit + code_size;
+ if (end >= lzw->lastbit) {
+ if (lzw->get_done) {
+ return GIF_END_OF_FRAME;
+ }
+ lzw->buf[0] = lzw->direct[lzw->last_byte - 2];
+ lzw->buf[1] = lzw->direct[lzw->last_byte - 1];
+
+ /* get the next block */
+ lzw->direct = gif->gif_data + gif->buffer_position;
+ if (gif->buffer_position >= gif->buffer_size) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+
+ count = lzw->direct[0];
+ lzw->zero_data_block = (count == 0);
+ if ((gif->buffer_position + count) >= gif->buffer_size) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+
+ if (count == 0) {
+ lzw->get_done = true;
+ } else {
+ if (gif->buffer_position + 3 >= gif->buffer_size) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ lzw->direct -= 1;
+ lzw->buf[2] = lzw->direct[2];
+ lzw->buf[3] = lzw->direct[3];
+ }
+ gif->buffer_position += count + 1;
+
+ /* update our variables */
+ lzw->last_byte = 2 + count;
+ lzw->curbit = (lzw->curbit - lzw->lastbit) + 16;
+ lzw->lastbit = (2 + count) << 3;
+ end = lzw->curbit + code_size;
+ }
+
+ i = lzw->curbit >> 3;
+ if (i < 2) {
+ b = lzw->buf;
+ } else {
+ b = lzw->direct;
+ }
+
+ ret = b[i];
+ j = (end >> 3) - 1;
+ if (i <= j) {
+ ret |= (b[i + 1] << 8);
+ if (i < j) {
+ ret |= (b[i + 2] << 16);
+ }
+ }
+ ret = (ret >> (lzw->curbit % 8)) & maskTbl[code_size];
+ lzw->curbit += code_size;
+
+ return ret;
+}
+
+
+/**
+ * Clear LZW code dictionary
+ *
+ * \param gif The GIF context.
+ * \return GIF_OK or error code.
+ */
+static gif_result gif_clear_codes_LZW(gif_animation *gif)
+{
+ int i;
+ int code;
+
+ if (lzw->clear_code >= (1 << GIF_MAX_LZW)) {
+ lzw->stack_pointer = lzw->stack;
+ return GIF_FRAME_DATA_ERROR;
+ }
+
+ /* initialise our table */
+ memset(lzw->table, 0x00, (1 << GIF_MAX_LZW) * 8);
+ for (i = 0; i < lzw->clear_code; ++i) {
+ lzw->table[1][i] = i;
+ }
+
+ /* reset LZW parameters */
+ lzw->code_size = lzw->set_code_size + 1;
+ lzw->max_code_size = lzw->clear_code << 1;
+ lzw->max_code = lzw->clear_code + 2;
+ lzw->stack_pointer = lzw->stack;
+
+ /* process repeated clear codes */
+ do {
+ code = gif_next_code(gif, lzw->code_size);
+ if (code < 0) {
+ return code;
+ }
+ } while (code == lzw->clear_code);
+ lzw->firstcode = lzw->oldcode = code;
+
+ *lzw->stack_pointer++ = lzw->firstcode;
+
+ return GIF_OK;
+}
+
+
+/**
+ * fill the LZW stack with decompressed data
+ *
+ * \param gif The GIF context.
+ * \return true on sucessful decode of the next LZW code else false.
+ */
+static bool gif_next_LZW(gif_animation *gif)
+{
+ int code, incode;
+ int block_size;
+ int new_code;
+
+ code = gif_next_code(gif, lzw->code_size);
+ if (code < 0) {
+ gif->current_error = code;
+ return false;
+ }
+
+ if (code == lzw->clear_code) {
+ gif->current_error = gif_clear_codes_LZW(gif);
+ if (gif->current_error != GIF_OK) {
+ return false;
+ }
+ return true;
+ }
+
+ if (code == lzw->end_code) {
+ /* skip to the end of our data so multi-image GIFs work */
+ if (lzw->zero_data_block) {
+ gif->current_error = GIF_FRAME_DATA_ERROR;
+ return false;
+ }
+ block_size = 0;
+ while (block_size != 1 &&
+ gif->buffer_position < gif->buffer_size) {
+ block_size = gif->gif_data[gif->buffer_position] + 1;
+ gif->buffer_position += block_size;
+ }
+ gif->current_error = GIF_FRAME_DATA_ERROR;
+ return false;
+ }
+
+ incode = code;
+ if (code >= lzw->max_code) {
+ if (lzw->stack_pointer >= lzw->stack + ((1 << GIF_MAX_LZW)
* 2)) {
+ gif->current_error = GIF_FRAME_DATA_ERROR;
+ return false;
+ }
+ *lzw->stack_pointer++ = lzw->firstcode;
+ code = lzw->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 >= lzw->clear_code) {
+ if (lzw->stack_pointer >= lzw->stack + ((1 << GIF_MAX_LZW)
* 2) ||
+ code >= (1 << GIF_MAX_LZW)) {
+ gif->current_error = GIF_FRAME_DATA_ERROR;
+ return false;
+ }
+ *lzw->stack_pointer++ = lzw->table[1][code];
+ new_code = lzw->table[0][code];
+ if (new_code < lzw->clear_code) {
+ code = new_code;
+ break;
+ }
+
+ if (lzw->stack_pointer >= lzw->stack + ((1 << GIF_MAX_LZW)
* 2) ||
+ new_code >= (1 << GIF_MAX_LZW)) {
+ gif->current_error = GIF_FRAME_DATA_ERROR;
+ return false;
+ }
+ *lzw->stack_pointer++ = lzw->table[1][new_code];
+ code = lzw->table[0][new_code];
+ if (code == new_code) {
+ gif->current_error = GIF_FRAME_DATA_ERROR;
+ return false;
+ }
+ }
+
+ if (lzw->stack_pointer >= lzw->stack + ((1 << GIF_MAX_LZW) * 2))
{
+ gif->current_error = GIF_FRAME_DATA_ERROR;
+ return false;
+ }
+ *lzw->stack_pointer++ = lzw->firstcode = lzw->table[1][code];
+
+ code = lzw->max_code;
+ if (code < (1 << GIF_MAX_LZW)) {
+ lzw->table[0][code] = lzw->oldcode;
+ lzw->table[1][code] = lzw->firstcode;
+ ++lzw->max_code;
+ if ((lzw->max_code >= lzw->max_code_size) &&
+ (lzw->max_code_size < (1 << GIF_MAX_LZW))) {
+ lzw->max_code_size = lzw->max_code_size << 1;
+ ++lzw->code_size;
+ }
+ }
+ lzw->oldcode = incode;
+ return true;
+}
/**
@@ -130,14 +360,139 @@ gif_initialise_sprite(gif_animation *gif,
return GIF_INSUFFICIENT_MEMORY;
}
- assert(gif->bitmap_callbacks.bitmap_destroy);
- gif->bitmap_callbacks.bitmap_destroy(gif->frame_image);
- gif->frame_image = buffer;
- gif->width = max_width;
- gif->height = max_height;
-
- /* Invalidate our currently decoded image */
- gif->decoded_frame = GIF_INVALID_FRAME;
+ assert(gif->bitmap_callbacks.bitmap_destroy);
+ gif->bitmap_callbacks.bitmap_destroy(gif->frame_image);
+ gif->frame_image = buffer;
+ gif->width = max_width;
+ gif->height = max_height;
+
+ /* Invalidate our currently decoded image */
+ gif->decoded_frame = GIF_INVALID_FRAME;
+ return GIF_OK;
+}
+
+
+/**
+ * Attempts to initialise the frame's extensions
+ *
+ * \param gif The animation context
+ * \param frame The frame number
+ * @return GIF_INSUFFICIENT_FRAME_DATA for insufficient data to complete the
+ * frame GIF_OK for successful initialisation.
+ */
+static gif_result
+gif_initialise_frame_extensions(gif_animation *gif, const int frame)
+{
+ unsigned char *gif_data, *gif_end;
+ int gif_bytes;
+ unsigned int block_size;
+
+ /* Get our buffer position etc. */
+ gif_data = (unsigned char *)(gif->gif_data + gif->buffer_position);
+ gif_end = (unsigned char *)(gif->gif_data + gif->buffer_size);
+
+ /* Initialise the extensions */
+ while (gif_data < gif_end && gif_data[0] == GIF_EXTENSION_INTRODUCER)
{
+ ++gif_data;
+ if ((gif_bytes = (gif_end - gif_data)) < 1) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+
+ /* Switch on extension label */
+ switch (gif_data[0]) {
+ case GIF_EXTENSION_GRAPHIC_CONTROL:
+ /* 6-byte Graphic Control Extension is:
+ *
+ * +0 CHAR Graphic Control Label
+ * +1 CHAR Block Size
+ * +2 CHAR __Packed Fields__
+ * 3BITS Reserved
+ * 3BITS Disposal Method
+ * 1BIT User Input Flag
+ * 1BIT Transparent Color Flag
+ * +3 SHORT Delay Time
+ * +5 CHAR Transparent Color Index
+ */
+ if (gif_bytes < 6) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+
+ gif->frames[frame].frame_delay = gif_data[3] | (gif_data[4]
<< 8);
+ if (gif_data[2] & GIF_TRANSPARENCY_MASK) {
+ gif->frames[frame].transparency = true;
+ gif->frames[frame].transparency_index = gif_data[5];
+ }
+ gif->frames[frame].disposal_method = ((gif_data[2] &
GIF_DISPOSAL_MASK) >> 2);
+ /* I have encountered documentation and GIFs in the
+ * wild that use 0x04 to restore the previous frame,
+ * rather than the officially documented 0x03. I
+ * believe some (older?) software may even actually
+ * export this way. We handle this as a type of
+ * "quirks" mode.
+ */
+ if (gif->frames[frame].disposal_method ==
GIF_FRAME_QUIRKS_RESTORE) {
+ gif->frames[frame].disposal_method =
GIF_FRAME_RESTORE;
+ }
+ gif_data += (2 + gif_data[1]);
+ break;
+
+ case GIF_EXTENSION_APPLICATION:
+ /* 14-byte+ Application Extension is:
+ *
+ * +0 CHAR Application Extension Label
+ * +1 CHAR Block Size
+ * +2 8CHARS Application Identifier
+ * +10 3CHARS Appl. Authentication Code
+ * +13 1-256 Application Data (Data sub-blocks)
+ */
+ if (gif_bytes < 17) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ if ((gif_data[1] == 0x0b) &&
+ (strncmp((const char *) gif_data + 2,
+ "NETSCAPE2.0", 11) == 0) &&
+ (gif_data[13] == 0x03) &&
+ (gif_data[14] == 0x01)) {
+ gif->loop_count = gif_data[15] | (gif_data[16]
<< 8);
+ }
+ gif_data += (2 + gif_data[1]);
+ break;
+
+ case GIF_EXTENSION_COMMENT:
+ /* Move the pointer to the first data sub-block Skip 1
+ * byte for the extension label
+ */
+ ++gif_data;
+ break;
+
+ default:
+ /* Move the pointer to the first data sub-block Skip 2
+ * bytes for the extension label and size fields Skip
+ * the extension size itself
+ */
+ if (gif_bytes < 2) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ gif_data += (2 + gif_data[1]);
+ }
+
+ /* Repeatedly skip blocks until we get a zero block or run out
+ * of data This data is ignored by this gif decoder
+ */
+ gif_bytes = (gif_end - gif_data);
+ block_size = 0;
+ while (gif_data < gif_end && gif_data[0] !=
GIF_BLOCK_TERMINATOR) {
+ block_size = gif_data[0] + 1;
+ if ((gif_bytes -= block_size) < 0) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ gif_data += block_size;
+ }
+ ++gif_data;
+ }
+
+ /* Set buffer position and return */
+ gif->buffer_position = (gif_data - gif->gif_data);
return GIF_OK;
}
@@ -378,129 +733,6 @@ static gif_result gif_initialise_frame(gif_animation *gif)
}
-/**
- * Attempts to initialise the frame's extensions
- *
- * \param gif The animation context
- * \param frame The frame number
- * @return GIF_INSUFFICIENT_FRAME_DATA for insufficient data to complete the
- * frame GIF_OK for successful initialisation.
- */
-static gif_result
-gif_initialise_frame_extensions(gif_animation *gif, const int frame)
-{
- unsigned char *gif_data, *gif_end;
- int gif_bytes;
- unsigned int block_size;
-
- /* Get our buffer position etc. */
- gif_data = (unsigned char *)(gif->gif_data + gif->buffer_position);
- gif_end = (unsigned char *)(gif->gif_data + gif->buffer_size);
-
- /* Initialise the extensions */
- while (gif_data < gif_end && gif_data[0] == GIF_EXTENSION_INTRODUCER)
{
- ++gif_data;
- if ((gif_bytes = (gif_end - gif_data)) < 1) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
-
- /* Switch on extension label */
- switch (gif_data[0]) {
- case GIF_EXTENSION_GRAPHIC_CONTROL:
- /* 6-byte Graphic Control Extension is:
- *
- * +0 CHAR Graphic Control Label
- * +1 CHAR Block Size
- * +2 CHAR __Packed Fields__
- * 3BITS Reserved
- * 3BITS Disposal Method
- * 1BIT User Input Flag
- * 1BIT Transparent Color Flag
- * +3 SHORT Delay Time
- * +5 CHAR Transparent Color Index
- */
- if (gif_bytes < 6) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
-
- gif->frames[frame].frame_delay = gif_data[3] | (gif_data[4]
<< 8);
- if (gif_data[2] & GIF_TRANSPARENCY_MASK) {
- gif->frames[frame].transparency = true;
- gif->frames[frame].transparency_index = gif_data[5];
- }
- gif->frames[frame].disposal_method = ((gif_data[2] &
GIF_DISPOSAL_MASK) >> 2);
- /* I have encountered documentation and GIFs in the
- * wild that use 0x04 to restore the previous frame,
- * rather than the officially documented 0x03. I
- * believe some (older?) software may even actually
- * export this way. We handle this as a type of
- * "quirks" mode.
- */
- if (gif->frames[frame].disposal_method ==
GIF_FRAME_QUIRKS_RESTORE) {
- gif->frames[frame].disposal_method =
GIF_FRAME_RESTORE;
- }
- gif_data += (2 + gif_data[1]);
- break;
-
- case GIF_EXTENSION_APPLICATION:
- /* 14-byte+ Application Extension is:
- *
- * +0 CHAR Application Extension Label
- * +1 CHAR Block Size
- * +2 8CHARS Application Identifier
- * +10 3CHARS Appl. Authentication Code
- * +13 1-256 Application Data (Data sub-blocks)
- */
- if (gif_bytes < 17) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- if ((gif_data[1] == 0x0b) &&
- (strncmp((const char *) gif_data + 2,
- "NETSCAPE2.0", 11) == 0) &&
- (gif_data[13] == 0x03) &&
- (gif_data[14] == 0x01)) {
- gif->loop_count = gif_data[15] | (gif_data[16]
<< 8);
- }
- gif_data += (2 + gif_data[1]);
- break;
-
- case GIF_EXTENSION_COMMENT:
- /* Move the pointer to the first data sub-block Skip 1
- * byte for the extension label
- */
- ++gif_data;
- break;
-
- default:
- /* Move the pointer to the first data sub-block Skip 2
- * bytes for the extension label and size fields Skip
- * the extension size itself
- */
- if (gif_bytes < 2) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- gif_data += (2 + gif_data[1]);
- }
-
- /* Repeatedly skip blocks until we get a zero block or run out
- * of data This data is ignored by this gif decoder
- */
- gif_bytes = (gif_end - gif_data);
- block_size = 0;
- while (gif_data < gif_end && gif_data[0] !=
GIF_BLOCK_TERMINATOR) {
- block_size = gif_data[0] + 1;
- if ((gif_bytes -= block_size) < 0) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- gif_data += block_size;
- }
- ++gif_data;
- }
-
- /* Set buffer position and return */
- gif->buffer_position = (gif_data - gif->gif_data);
- return GIF_OK;
-}
/**
@@ -585,189 +817,7 @@ static unsigned int gif_interlaced_line(int height, int y) {
}
-/**
- * Initialise LZW decoding
- */
-void gif_init_LZW(gif_animation *gif)
-{
- int i;
-
- gif->current_error = 0;
- if (clear_code >= (1 << GIF_MAX_LZW)) {
- stack_pointer = 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;
- }
-
- /* update our LZW parameters */
- code_size = set_code_size + 1;
- max_code_size = clear_code << 1;
- max_code = clear_code + 2;
- stack_pointer = stack;
- do {
- firstcode = oldcode = gif_next_code(gif, code_size);
- } while (firstcode == clear_code);
- *stack_pointer++ =firstcode;
-}
-
-
-static bool gif_next_LZW(gif_animation *gif)
-{
- int code, incode;
- int block_size;
- int new_code;
-
- code = gif_next_code(gif, code_size);
- if (code < 0) {
- gif->current_error = code;
- return false;
- } else if (code == clear_code) {
- gif_init_LZW(gif);
- return true;
- } else if (code == end_code) {
- /* skip to the end of our data so multi-image GIFs work */
- if (zero_data_block) {
- gif->current_error = GIF_FRAME_DATA_ERROR;
- return false;
- }
- block_size = 0;
- while (block_size != 1 &&
- gif->buffer_position < gif->buffer_size) {
- block_size = gif->gif_data[gif->buffer_position] + 1;
- gif->buffer_position += block_size;
- }
- gif->current_error = GIF_FRAME_DATA_ERROR;
- return false;
- }
-
- incode = code;
- if (code >= max_code) {
- if (stack_pointer >= stack + ((1 << GIF_MAX_LZW) * 2)) {
- gif->current_error = GIF_FRAME_DATA_ERROR;
- return false;
- }
- *stack_pointer++ = firstcode;
- code = 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) {
- if (stack_pointer >= stack + ((1 << GIF_MAX_LZW) * 2) ||
- code >= (1 << GIF_MAX_LZW)) {
- gif->current_error = GIF_FRAME_DATA_ERROR;
- return false;
- }
- *stack_pointer++ = table[1][code];
- new_code = table[0][code];
- if (new_code < clear_code) {
- code = new_code;
- break;
- }
-
- if (stack_pointer >= stack + ((1 << GIF_MAX_LZW) * 2) ||
- new_code >= (1 << GIF_MAX_LZW)) {
- gif->current_error = GIF_FRAME_DATA_ERROR;
- return false;
- }
- *stack_pointer++ = table[1][new_code];
- code = table[0][new_code];
- if (code == new_code) {
- gif->current_error = GIF_FRAME_DATA_ERROR;
- return false;
- }
- }
-
- if (stack_pointer >= stack + ((1 << GIF_MAX_LZW) * 2)) {
- gif->current_error = GIF_FRAME_DATA_ERROR;
- return false;
- }
- *stack_pointer++ = firstcode = 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;
- }
- }
- oldcode = incode;
- return true;
-}
-
-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) {
- return GIF_END_OF_FRAME;
- }
- buf[0] = direct[last_byte - 2];
- buf[1] = direct[last_byte - 1];
-
- /* get the next block */
- direct = gif->gif_data + gif->buffer_position;
- if (gif->buffer_position >= gif->buffer_size) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- zero_data_block = ((count = direct[0]) == 0);
- if ((gif->buffer_position + count) >= gif->buffer_size) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- if (count == 0) {
- get_done = true;
- } else {
- if (gif->buffer_position + 3 >= gif->buffer_size) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- direct -= 1;
- buf[2] = direct[2];
- buf[3] = 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;
- }
-
- i = curbit >> 3;
- if (i < 2) {
- b = buf;
- } else {
- b = direct;
- }
- ret = b[i];
- j = (end >> 3) - 1;
- if (i <= j) {
- ret |= (b[i + 1] << 8);
- if (i < j) {
- ret |= (b[i + 2] << 16);
- }
- }
- ret = (ret >> (curbit % 8)) & maskTbl[code_size];
- curbit += code_size;
- return ret;
-}
/**
@@ -1017,20 +1067,23 @@ gif_internal_decode_frame(gif_animation *gif,
gif->decoded_frame = frame;
/* Initialise the LZW decoding */
- set_code_size = gif_data[0];
+ lzw->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_init_LZW(gif);
+ lzw->code_size = lzw->set_code_size + 1;
+ lzw->clear_code = (1 << lzw->set_code_size);
+ lzw->end_code = lzw->clear_code + 1;
+ lzw->max_code_size = lzw->clear_code << 1;
+ lzw->max_code = lzw->clear_code + 2;
+ lzw->curbit = lzw->lastbit = 0;
+ lzw->last_byte = 2;
+ lzw->get_done = false;
+ lzw->direct = lzw->buf;
+ gif->current_error = gif_clear_codes_LZW(gif);
+ if (gif->current_error != GIF_OK) {
+ return gif->current_error;
+ }
/* Decompress the data */
for (y = 0; y < height; y++) {
@@ -1047,14 +1100,14 @@ gif_internal_decode_frame(gif_animation *gif,
*/
x = width;
while (x > 0) {
- burst_bytes = (stack_pointer - stack);
+ burst_bytes = (lzw->stack_pointer - lzw->stack);
if (burst_bytes > 0) {
if (burst_bytes > x) {
burst_bytes = x;
}
x -= burst_bytes;
while (burst_bytes-- > 0) {
- colour = *--stack_pointer;
+ colour = *--lzw->stack_pointer;
if (((gif->frames[frame].transparency)
&&
(colour !=
gif->frames[frame].transparency_index)) ||
(!gif->frames[frame].transparency)) {
@@ -1242,7 +1295,7 @@ gif_result gif_initialise(gif_animation *gif, size_t size, unsigned
char *data)
* termination block) Although generally useless, the GIF
* specification does not expressly prohibit this
*/
- if (gif->buffer_size == 14) {
+ if (gif->buffer_size == (GIF_STANDARD_HEADER_SIZE + 1)) {
if (gif_data[0] == GIF_TRAILER) {
return GIF_OK;
} else {
@@ -1250,7 +1303,7 @@ gif_result gif_initialise(gif_animation *gif, size_t size, unsigned
char *data)
}
}
- /* Initialise enough workspace for 4 frames initially */
+ /* Initialise enough workspace for a frame */
if ((gif->frames = (gif_frame *)malloc(sizeof(gif_frame))) == NULL) {
gif_finalise(gif);
return GIF_INSUFFICIENT_MEMORY;
@@ -1276,7 +1329,7 @@ gif_result gif_initialise(gif_animation *gif, size_t size, unsigned
char *data)
if (gif->global_colour_table[0] == GIF_PROCESS_COLOURS) {
/* Check for a global colour map signified by bit 7 */
if (gif->global_colours) {
- if (gif->buffer_size < (gif->colour_table_size * 3 +
12)) {
+ if (gif->buffer_size < (gif->colour_table_size * 3 +
GIF_STANDARD_HEADER_SIZE)) {
return GIF_INSUFFICIENT_DATA;
}
for (index = 0; index < gif->colour_table_size; index++) {
--
NetSurf GIF Decoder