libnsgif: branch tlsa/lzw-optimise updated. release/0.2.1-43-gfada1a8
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/libnsgif.git/shortlog/fada1a850cb1e88b9c19...
...commit http://git.netsurf-browser.org/libnsgif.git/commit/fada1a850cb1e88b9c19e4...
...tree http://git.netsurf-browser.org/libnsgif.git/tree/fada1a850cb1e88b9c19e450...
The branch, tlsa/lzw-optimise has been updated
via fada1a850cb1e88b9c19e45029092311ab7f869c (commit)
from 9be2acf63d9f293d0ca1321dfd985889bce4e37d (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=fada1a850cb1e88b9c...
commit fada1a850cb1e88b9c19e45029092311ab7f869c
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
lzw: Optimisation: Pre-multiply relative offsets by struct size.
diff --git a/src/lzw.c b/src/lzw.c
index 59c74a6..fe79556 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -364,7 +364,7 @@ static inline void lzw__table_add_entry(
entry->value = code;
entry->first = ctx->prev_code_first;
entry->count = ctx->prev_code_count + 1;
- entry->extends = ctx->table_size - ctx->prev_code;
+ entry->extends = (ctx->table_size - ctx->prev_code) * sizeof(*entry);
ctx->table_size++;
}
@@ -444,6 +444,19 @@ static inline lzw_result lzw__decode(
}
/**
+ * Get the LZW table entry that the given entry extends.
+ *
+ * \param[in] entry The starting entry/
+ * \return new table entry.
+ */
+static inline const struct lzw_table_entry *lzw__entry_get_extends(
+ const struct lzw_table_entry *entry)
+{
+ return (const struct lzw_table_entry *)
+ (((const uint8_t *)(entry)) - entry->extends);
+}
+
+/**
* Write values for this code to the output stack.
*
* If there isn't enough space in the output stack, this function will write
@@ -483,13 +496,13 @@ static inline uint32_t lzw__write_fn(struct lzw_ctx *ctx,
/* Skip over any values we don't have space for. */
for (unsigned i = left; i != 0; i--) {
- entry -= entry->extends;
+ entry = lzw__entry_get_extends(entry);
}
output_pos += count;
for (unsigned i = count; i != 0; i--) {
*--output_pos = entry->value;
- entry -= entry->extends;
+ entry = lzw__entry_get_extends(entry);
}
return count;
@@ -561,7 +574,7 @@ static inline uint32_t lzw__map_write_fn(struct lzw_ctx *ctx,
ctx->output_left = left;
for (unsigned i = left; i != 0; i--) {
- entry -= entry->extends;
+ entry = lzw__entry_get_extends(entry);
}
output_pos += count;
@@ -571,12 +584,12 @@ static inline uint32_t lzw__map_write_fn(struct lzw_ctx *ctx,
if (entry->value != ctx->transparency_idx) {
*output_pos = ctx->colour_map[entry->value];
}
- entry -= entry->extends;
+ entry = lzw__entry_get_extends(entry);
}
} else {
for (unsigned i = count; i != 0; i--) {
*--output_pos = ctx->colour_map[entry->value];
- entry -= entry->extends;
+ entry = lzw__entry_get_extends(entry);
}
}
-----------------------------------------------------------------------
Summary of changes:
src/lzw.c | 25 +++++++++++++++++++------
1 file changed, 19 insertions(+), 6 deletions(-)
diff --git a/src/lzw.c b/src/lzw.c
index 59c74a6..fe79556 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -364,7 +364,7 @@ static inline void lzw__table_add_entry(
entry->value = code;
entry->first = ctx->prev_code_first;
entry->count = ctx->prev_code_count + 1;
- entry->extends = ctx->table_size - ctx->prev_code;
+ entry->extends = (ctx->table_size - ctx->prev_code) * sizeof(*entry);
ctx->table_size++;
}
@@ -444,6 +444,19 @@ static inline lzw_result lzw__decode(
}
/**
+ * Get the LZW table entry that the given entry extends.
+ *
+ * \param[in] entry The starting entry/
+ * \return new table entry.
+ */
+static inline const struct lzw_table_entry *lzw__entry_get_extends(
+ const struct lzw_table_entry *entry)
+{
+ return (const struct lzw_table_entry *)
+ (((const uint8_t *)(entry)) - entry->extends);
+}
+
+/**
* Write values for this code to the output stack.
*
* If there isn't enough space in the output stack, this function will write
@@ -483,13 +496,13 @@ static inline uint32_t lzw__write_fn(struct lzw_ctx *ctx,
/* Skip over any values we don't have space for. */
for (unsigned i = left; i != 0; i--) {
- entry -= entry->extends;
+ entry = lzw__entry_get_extends(entry);
}
output_pos += count;
for (unsigned i = count; i != 0; i--) {
*--output_pos = entry->value;
- entry -= entry->extends;
+ entry = lzw__entry_get_extends(entry);
}
return count;
@@ -561,7 +574,7 @@ static inline uint32_t lzw__map_write_fn(struct lzw_ctx *ctx,
ctx->output_left = left;
for (unsigned i = left; i != 0; i--) {
- entry -= entry->extends;
+ entry = lzw__entry_get_extends(entry);
}
output_pos += count;
@@ -571,12 +584,12 @@ static inline uint32_t lzw__map_write_fn(struct lzw_ctx *ctx,
if (entry->value != ctx->transparency_idx) {
*output_pos = ctx->colour_map[entry->value];
}
- entry -= entry->extends;
+ entry = lzw__entry_get_extends(entry);
}
} else {
for (unsigned i = count; i != 0; i--) {
*--output_pos = ctx->colour_map[entry->value];
- entry -= entry->extends;
+ entry = lzw__entry_get_extends(entry);
}
}
--
NetSurf GIF Decoder
1 year, 8 months
libnsgif: branch tlsa/lzw-optimise created. release/0.2.1-42-g9be2acf
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/libnsgif.git/shortlog/9be2acf63d9f293d0ca1...
...commit http://git.netsurf-browser.org/libnsgif.git/commit/9be2acf63d9f293d0ca132...
...tree http://git.netsurf-browser.org/libnsgif.git/tree/9be2acf63d9f293d0ca1321d...
The branch, tlsa/lzw-optimise has been created
at 9be2acf63d9f293d0ca1321dfd985889bce4e37d (commit)
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=9be2acf63d9f293d0c...
commit 9be2acf63d9f293d0ca1321dfd985889bce4e37d
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
lzw: Use relative offset to next output entry, rather than absolute.
diff --git a/src/lzw.c b/src/lzw.c
index 710895e..59c74a6 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -364,7 +364,7 @@ static inline void lzw__table_add_entry(
entry->value = code;
entry->first = ctx->prev_code_first;
entry->count = ctx->prev_code_count + 1;
- entry->extends = ctx->prev_code;
+ entry->extends = ctx->table_size - ctx->prev_code;
ctx->table_size++;
}
@@ -467,7 +467,7 @@ static inline uint32_t lzw__write_fn(struct lzw_ctx *ctx,
uint16_t left)
{
uint8_t *restrict output_pos = (uint8_t *)output_data + output_used;
- const struct lzw_table_entry * const table = ctx->table;
+ const struct lzw_table_entry *entry = ctx->table + code;
uint32_t space = output_length - output_used;
uint16_t count = left;
@@ -483,15 +483,13 @@ static inline uint32_t lzw__write_fn(struct lzw_ctx *ctx,
/* Skip over any values we don't have space for. */
for (unsigned i = left; i != 0; i--) {
- const struct lzw_table_entry *entry = table + code;
- code = entry->extends;
+ entry -= entry->extends;
}
output_pos += count;
for (unsigned i = count; i != 0; i--) {
- const struct lzw_table_entry *entry = table + code;
*--output_pos = entry->value;
- code = entry->extends;
+ entry -= entry->extends;
}
return count;
@@ -548,7 +546,7 @@ static inline uint32_t lzw__map_write_fn(struct lzw_ctx *ctx,
uint16_t left)
{
uint32_t *restrict output_pos = (uint32_t *)output_data + output_used;
- const struct lzw_table_entry * const table = ctx->table;
+ const struct lzw_table_entry *entry = ctx->table + code;
uint32_t space = output_length - output_used;
uint16_t count = left;
@@ -563,25 +561,22 @@ static inline uint32_t lzw__map_write_fn(struct lzw_ctx *ctx,
ctx->output_left = left;
for (unsigned i = left; i != 0; i--) {
- const struct lzw_table_entry *entry = table + code;
- code = entry->extends;
+ entry -= entry->extends;
}
output_pos += count;
if (ctx->has_transparency) {
for (unsigned i = count; i != 0; i--) {
- const struct lzw_table_entry *entry = table + code;
--output_pos;
if (entry->value != ctx->transparency_idx) {
*output_pos = ctx->colour_map[entry->value];
}
- code = entry->extends;
+ entry -= entry->extends;
}
} else {
for (unsigned i = count; i != 0; i--) {
- const struct lzw_table_entry *entry = table + code;
*--output_pos = ctx->colour_map[entry->value];
- code = entry->extends;
+ entry -= entry->extends;
}
}
-----------------------------------------------------------------------
--
NetSurf GIF Decoder
1 year, 8 months
libnsgif: branch master updated. release/0.2.1-41-ga507bb7
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/libnsgif.git/shortlog/a507bb77e88a3e8c4b65...
...commit http://git.netsurf-browser.org/libnsgif.git/commit/a507bb77e88a3e8c4b654a...
...tree http://git.netsurf-browser.org/libnsgif.git/tree/a507bb77e88a3e8c4b654a6d...
The branch, master has been updated
via a507bb77e88a3e8c4b654a6d7fb7351db8a3ec32 (commit)
via aaca45d709e628860020f1c423f013e08cdf4e3b (commit)
via 35dd8d132bf4c5433ac1e358cf26b987f566fd23 (commit)
via 58c6e9393a794556bc3a192ce8227400d275d4e0 (commit)
via 84211ade387da05c766b94a435c3bac3e8199976 (commit)
from f29bbfbc5cbfe36a0f4f98d84bf1f84d6e4ee1d4 (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=a507bb77e88a3e8c4b...
commit a507bb77e88a3e8c4b654a6d7fb7351db8a3ec32
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
test: Print filename of any gif that errors.
diff --git a/test/runtest.sh b/test/runtest.sh
index fd5a32b..06eaef4 100755
--- a/test/runtest.sh
+++ b/test/runtest.sh
@@ -54,6 +54,7 @@ for GIF in $(ls ${GIFTESTS});do
ECODE=$?
if [ "${ECODE}" -gt 127 ];then
GIFTESTERRC=$((GIFTESTERRC+1))
+ echo "Error ${GIF}"
else
if [ "${ECODE}" -gt 0 ];then
GIFTESTFAILC=$((GIFTESTFAILC+1))
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=aaca45d709e6288600...
commit aaca45d709e628860020f1c423f013e08cdf4e3b
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
gif: Optimise opaque gifs on the complex decode path.
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 24dbf7d..2bea30e 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -688,13 +688,21 @@ gif__decode_complex(gif_animation *gif,
row_available = x < available ? x : available;
x -= row_available;
available -= row_available;
- while (row_available-- > 0) {
- register unsigned int colour;
- colour = *uncompressed++;
- if (colour != transparency_index) {
- *frame_scanline = colour_table[colour];
+ if (transparency_index > 0xFF) {
+ while (row_available-- > 0) {
+ *frame_scanline++ =
+ colour_table[*uncompressed++];
+ }
+ } else {
+ while (row_available-- > 0) {
+ register unsigned int colour;
+ colour = *uncompressed++;
+ if (colour != transparency_index) {
+ *frame_scanline =
+ colour_table[colour];
+ }
+ frame_scanline++;
}
- frame_scanline++;
}
}
}
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=35dd8d132bf4c5433a...
commit 35dd8d132bf4c5433ac1e358cf26b987f566fd23
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
lzw: Optimise mapped output for frames without transparency.
diff --git a/src/lzw.c b/src/lzw.c
index babe485..710895e 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -568,13 +568,21 @@ static inline uint32_t lzw__map_write_fn(struct lzw_ctx *ctx,
}
output_pos += count;
- for (unsigned i = count; i != 0; i--) {
- const struct lzw_table_entry *entry = table + code;
- --output_pos;
- if (entry->value != ctx->transparency_idx) {
- *output_pos = ctx->colour_map[entry->value];
+ if (ctx->has_transparency) {
+ for (unsigned i = count; i != 0; i--) {
+ const struct lzw_table_entry *entry = table + code;
+ --output_pos;
+ if (entry->value != ctx->transparency_idx) {
+ *output_pos = ctx->colour_map[entry->value];
+ }
+ code = entry->extends;
+ }
+ } else {
+ for (unsigned i = count; i != 0; i--) {
+ const struct lzw_table_entry *entry = table + code;
+ *--output_pos = ctx->colour_map[entry->value];
+ code = entry->extends;
}
- code = entry->extends;
}
return count;
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=58c6e9393a794556bc...
commit 58c6e9393a794556bc3a192ce8227400d275d4e0
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
lzw: Rework API for separate init for map/non-map decode functions.
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 5fa9cb6..24dbf7d 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -554,6 +554,8 @@ static gif_result gif_error_from_lzw(lzw_result l_res)
[LZW_BAD_ICODE] = GIF_FRAME_DATA_ERROR,
[LZW_BAD_CODE] = GIF_FRAME_DATA_ERROR,
};
+ assert(l_res != LZW_BAD_PARAM);
+ assert(l_res != LZW_NO_COLOUR);
return g_res[l_res];
}
@@ -643,9 +645,8 @@ gif__decode_complex(gif_animation *gif,
lzw_result res;
/* Initialise the LZW decoding */
- res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
- gif->buffer_size, gif->buffer_position,
- minimum_code_size);
+ res = lzw_decode_init(gif->lzw_ctx, minimum_code_size,
+ gif->gif_data, gif->buffer_size, gif->buffer_position);
if (res != LZW_OK) {
return gif_error_from_lzw(res);
}
@@ -680,7 +681,7 @@ gif__decode_complex(gif_animation *gif,
}
break;
}
- res = lzw_decode_continuous(gif->lzw_ctx,
+ res = lzw_decode(gif->lzw_ctx,
&uncompressed, &available);
}
@@ -715,23 +716,22 @@ gif__decode_simple(gif_animation *gif,
gif_result ret = GIF_OK;
lzw_result res;
+ transparency_index = gif->frames[frame].transparency ?
+ gif->frames[frame].transparency_index :
+ GIF_NO_TRANSPARENCY;
+
/* Initialise the LZW decoding */
- res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
- gif->buffer_size, gif->buffer_position,
- minimum_code_size);
+ res = lzw_decode_init_map(gif->lzw_ctx,
+ minimum_code_size, transparency_index, colour_table,
+ gif->gif_data, gif->buffer_size, gif->buffer_position);
if (res != LZW_OK) {
return gif_error_from_lzw(res);
}
- transparency_index = gif->frames[frame].transparency ?
- gif->frames[frame].transparency_index :
- GIF_NO_TRANSPARENCY;
-
frame_data += (offset_y * gif->width);
while (pixels > 0) {
- res = lzw_decode_map_continuous(gif->lzw_ctx,
- transparency_index, colour_table,
+ res = lzw_decode_map(gif->lzw_ctx,
frame_data, pixels, &written);
pixels -= written;
frame_data += written;
diff --git a/src/lzw.c b/src/lzw.c
index a243ddb..babe485 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -68,31 +68,32 @@ struct lzw_table_entry {
struct lzw_ctx {
struct lzw_read_ctx input; /**< Input reading context */
- uint32_t prev_code; /**< Code read from input previously. */
- uint32_t prev_code_first; /**< First value of previous code. */
- uint32_t prev_code_count; /**< Total values for previous code. */
+ uint16_t prev_code; /**< Code read from input previously. */
+ uint16_t prev_code_first; /**< First value of previous code. */
+ uint16_t prev_code_count; /**< Total values for previous code. */
- uint32_t initial_code_size; /**< Starting LZW code size. */
+ uint8_t initial_code_size; /**< Starting LZW code size. */
- uint32_t code_size; /**< Current LZW code size. */
- uint32_t code_max; /**< Max code value for current code size. */
+ uint8_t code_size; /**< Current LZW code size. */
+ uint16_t code_max; /**< Max code value for current code size. */
- uint32_t clear_code; /**< Special Clear code value */
- uint32_t eoi_code; /**< Special End of Information code value */
+ uint16_t clear_code; /**< Special Clear code value */
+ uint16_t eoi_code; /**< Special End of Information code value */
- uint32_t table_size; /**< Next position in table to fill. */
+ uint16_t table_size; /**< Next position in table to fill. */
- uint32_t output_code; /**< Code that has been partially output. */
- uint32_t output_left; /**< Number of values left for output_code. */
+ uint16_t output_code; /**< Code that has been partially output. */
+ uint16_t output_left; /**< Number of values left for output_code. */
- uint32_t transparency_idx; /**< Index representing transparency. */
- uint32_t *restrict colour_map; /**< Index to pixel colour mapping */
-
- /** Output value stack. */
- uint8_t stack_base[LZW_TABLE_ENTRY_MAX];
+ bool has_transparency; /**< Whether the image is opaque. */
+ uint8_t transparency_idx; /**< Index representing transparency. */
+ const uint32_t *restrict colour_map; /**< Index to colour mapping. */
/** LZW code table. Generated during decode. */
struct lzw_table_entry table[LZW_TABLE_ENTRY_MAX];
+
+ /** Output value stack. */
+ uint8_t stack_base[LZW_TABLE_ENTRY_MAX];
};
@@ -165,8 +166,8 @@ static lzw_result lzw__block_advance(struct lzw_read_ctx *restrict ctx)
*/
static inline lzw_result lzw__read_code(
struct lzw_read_ctx *restrict ctx,
- uint32_t code_size,
- uint32_t *restrict code_out)
+ uint16_t code_size,
+ uint16_t *restrict code_out)
{
uint32_t code = 0;
uint32_t current_bit = ctx->sb_bit & 0x7;
@@ -232,9 +233,9 @@ static inline lzw_result lzw__read_code(
*/
static inline lzw_result lzw__handle_clear(
struct lzw_ctx *ctx,
- uint32_t *code_out)
+ uint16_t *code_out)
{
- uint32_t code;
+ uint16_t code;
/* Reset table building context */
ctx->code_size = ctx->initial_code_size;
@@ -259,27 +260,26 @@ static inline lzw_result lzw__handle_clear(
return LZW_OK;
}
-
/* Exported function, documented in lzw.h */
lzw_result lzw_decode_init(
struct lzw_ctx *ctx,
- const uint8_t *compressed_data,
- uint32_t compressed_data_len,
- uint32_t compressed_data_pos,
- uint8_t minimum_code_size)
+ uint8_t minimum_code_size,
+ const uint8_t *input_data,
+ uint32_t input_length,
+ uint32_t input_pos)
{
struct lzw_table_entry *table = ctx->table;
lzw_result res;
- uint32_t code;
+ uint16_t code;
if (minimum_code_size >= LZW_CODE_MAX) {
return LZW_BAD_ICODE;
}
/* Initialise the input reading context */
- ctx->input.data = compressed_data;
- ctx->input.data_len = compressed_data_len;
- ctx->input.data_sb_next = compressed_data_pos;
+ ctx->input.data = input_data;
+ ctx->input.data_len = input_length;
+ ctx->input.data_sb_next = input_pos;
ctx->input.sb_bit = 0;
ctx->input.sb_bit_count = 0;
@@ -293,7 +293,7 @@ lzw_result lzw_decode_init(
ctx->output_left = 0;
/* Initialise the standard table entries */
- for (uint32_t i = 0; i < ctx->clear_code; ++i) {
+ for (uint16_t i = 0; i < ctx->clear_code; i++) {
table[i].first = i;
table[i].value = i;
table[i].count = 1;
@@ -313,6 +313,39 @@ lzw_result lzw_decode_init(
ctx->output_code = code;
ctx->output_left = 1;
+ ctx->has_transparency = false;
+ ctx->transparency_idx = 0;
+ ctx->colour_map = NULL;
+
+ return LZW_OK;
+}
+
+/* Exported function, documented in lzw.h */
+lzw_result lzw_decode_init_map(
+ struct lzw_ctx *ctx,
+ uint8_t minimum_code_size,
+ uint32_t transparency_idx,
+ const uint32_t *colour_table,
+ const uint8_t *input_data,
+ uint32_t input_length,
+ uint32_t input_pos)
+{
+ lzw_result res;
+
+ if (colour_table == NULL) {
+ return LZW_BAD_PARAM;
+ }
+
+ res = lzw_decode_init(ctx, minimum_code_size,
+ input_data, input_length, input_pos);
+ if (res != LZW_OK) {
+ return res;
+ }
+
+ ctx->has_transparency = (transparency_idx <= 0xFF);
+ ctx->transparency_idx = transparency_idx;
+ ctx->colour_map = colour_table;
+
return LZW_OK;
}
@@ -324,7 +357,7 @@ lzw_result lzw_decode_init(
*/
static inline void lzw__table_add_entry(
struct lzw_ctx *ctx,
- uint32_t code)
+ uint16_t code)
{
struct lzw_table_entry *entry = &ctx->table[ctx->table_size];
@@ -338,30 +371,31 @@ static inline void lzw__table_add_entry(
typedef uint32_t (*lzw_writer_fn)(
struct lzw_ctx *ctx,
- void *restrict output,
- uint32_t length,
- uint32_t used,
- uint32_t code,
- uint32_t left);
+ void *restrict output_data,
+ uint32_t output_length,
+ uint32_t output_pos,
+ uint16_t code,
+ uint16_t left);
/**
* Get the next LZW code and write its value(s) to output buffer.
*
- * \param[in] ctx LZW reading context, updated.
- * \param[in] output Array to write output values into.
- * \param[in] length Size of output array.
- * \param[in] write_pixels Function for writing pixels to output.
- * \param[in,out] used Number of values written. Updated on exit.
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] write_fn Function for writing pixels to output.
+ * \param[in] output_data Array to write output values into.
+ * \param[in] output_length Size of output array.
+ * \param[in,out] output_written Number of values written. Updated on exit.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
-static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
- void *restrict output,
- uint32_t length,
- lzw_writer_fn write_pixels,
- uint32_t *restrict used)
+static inline lzw_result lzw__decode(
+ struct lzw_ctx *ctx,
+ lzw_writer_fn write_fn,
+ void *restrict output_data,
+ uint32_t output_length,
+ uint32_t *restrict output_written)
{
lzw_result res;
- uint32_t code;
+ uint16_t code;
/* Get a new code from the input */
res = lzw__read_code(&ctx->input, ctx->code_size, &code);
@@ -385,7 +419,7 @@ static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
}
} else if (ctx->table_size < LZW_TABLE_ENTRY_MAX) {
- uint32_t size = ctx->table_size;
+ uint16_t size = ctx->table_size;
lzw__table_add_entry(ctx, (code < size) ?
ctx->table[code].first :
ctx->prev_code_first);
@@ -397,8 +431,9 @@ static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
}
}
- *used += write_pixels(ctx, output, length, *used, code,
- ctx->table[code].count);
+ *output_written += write_fn(ctx,
+ output_data, output_length, *output_written,
+ code, ctx->table[code].count);
/* Store details of this code as "previous code" to the context. */
ctx->prev_code_first = ctx->table[code].first;
@@ -416,25 +451,25 @@ static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
* this call, then there is more data for this code left to output. The code
* is stored to the context as `ctx->output_code`.
*
- * \param[in] ctx LZW reading context, updated.
- * \param[in] output Array to write output values into.
- * \param[in] length Size of output array.
- * \param[in] used Current position in output array.
- * \param[in] code LZW code to output values for.
- * \param[in] left Number of values remaining to output for this value.
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] output_data Array to write output values into.
+ * \param[in] output_length length Size of output array.
+ * \param[in] output_used Current position in output array.
+ * \param[in] code LZW code to output values for.
+ * \param[in] left Number of values remaining to output for this code.
* \return Number of pixel values written.
*/
-static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
- void *restrict output,
- uint32_t length,
- uint32_t used,
- uint32_t code,
- uint32_t left)
+static inline uint32_t lzw__write_fn(struct lzw_ctx *ctx,
+ void *restrict output_data,
+ uint32_t output_length,
+ uint32_t output_used,
+ uint16_t code,
+ uint16_t left)
{
- uint8_t *restrict output_pos = (uint8_t *)output + used;
+ uint8_t *restrict output_pos = (uint8_t *)output_data + output_used;
const struct lzw_table_entry * const table = ctx->table;
- uint32_t space = length - used;
- uint32_t count = left;
+ uint32_t space = output_length - output_used;
+ uint16_t count = left;
if (count > space) {
left = count - space;
@@ -463,23 +498,24 @@ static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
}
/* Exported function, documented in lzw.h */
-lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
- const uint8_t *restrict *const restrict data,
- uint32_t *restrict used)
+lzw_result lzw_decode(struct lzw_ctx *ctx,
+ const uint8_t *restrict *const restrict output_data,
+ uint32_t *restrict output_written)
{
- *used = 0;
- *data = ctx->stack_base;
+ const uint32_t output_length = sizeof(ctx->stack_base);
+
+ *output_written = 0;
+ *output_data = ctx->stack_base;
if (ctx->output_left != 0) {
- *used += lzw__write_pixels(ctx,
- ctx->stack_base, sizeof(ctx->stack_base), *used,
+ *output_written += lzw__write_fn(ctx,
+ ctx->stack_base, output_length, *output_written,
ctx->output_code, ctx->output_left);
}
- while (*used != sizeof(ctx->stack_base)) {
- lzw_result res = lzw__decode(ctx,
- ctx->stack_base, sizeof(ctx->stack_base),
- lzw__write_pixels, used);
+ while (*output_written != output_length) {
+ lzw_result res = lzw__decode(ctx, lzw__write_fn,
+ ctx->stack_base, output_length, output_written);
if (res != LZW_OK) {
return res;
}
@@ -489,32 +525,32 @@ lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
}
/**
- * Write colour mapped values for this code to the output stack.
+ * Write colour mapped values for this code to the output.
*
* If there isn't enough space in the output stack, this function will write
* the as many as it can into the output. If `ctx->output_left > 0` after
* this call, then there is more data for this code left to output. The code
* is stored to the context as `ctx->output_code`.
*
- * \param[in] ctx LZW reading context, updated.
- * \param[in] output Array to write output values into.
- * \param[in] length Size of output array.
- * \param[in] used Current position in output array.
- * \param[in] code LZW code to output values for.
- * \param[in] left Number of values remaining to output for this value.
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] output_data Array to write output values into.
+ * \param[in] output_length Size of output array.
+ * \param[in] output_used Current position in output array.
+ * \param[in] code LZW code to output values for.
+ * \param[in] left Number of values remaining to output for code.
* \return Number of pixel values written.
*/
-static inline uint32_t lzw__write_pixels_map(struct lzw_ctx *ctx,
- void *restrict buffer,
- uint32_t length,
- uint32_t used,
- uint32_t code,
- uint32_t left)
+static inline uint32_t lzw__map_write_fn(struct lzw_ctx *ctx,
+ void *restrict output_data,
+ uint32_t output_length,
+ uint32_t output_used,
+ uint16_t code,
+ uint16_t left)
{
- uint32_t *restrict stack_pos = (uint32_t *)buffer + used;
+ uint32_t *restrict output_pos = (uint32_t *)output_data + output_used;
const struct lzw_table_entry * const table = ctx->table;
- uint32_t space = length - used;
- uint32_t count = left;
+ uint32_t space = output_length - output_used;
+ uint16_t count = left;
if (count > space) {
left = count - space;
@@ -531,12 +567,12 @@ static inline uint32_t lzw__write_pixels_map(struct lzw_ctx *ctx,
code = entry->extends;
}
- stack_pos += count;
+ output_pos += count;
for (unsigned i = count; i != 0; i--) {
const struct lzw_table_entry *entry = table + code;
- --stack_pos;
+ --output_pos;
if (entry->value != ctx->transparency_idx) {
- *stack_pos = ctx->colour_map[entry->value];
+ *output_pos = ctx->colour_map[entry->value];
}
code = entry->extends;
}
@@ -545,26 +581,26 @@ static inline uint32_t lzw__write_pixels_map(struct lzw_ctx *ctx,
}
/* Exported function, documented in lzw.h */
-lzw_result lzw_decode_map_continuous(struct lzw_ctx *ctx,
- uint32_t transparency_idx,
- uint32_t *restrict colour_map,
- uint32_t *restrict data,
- uint32_t length,
- uint32_t *restrict used)
+lzw_result lzw_decode_map(struct lzw_ctx *ctx,
+ uint32_t *restrict output_data,
+ uint32_t output_length,
+ uint32_t *restrict output_written)
{
- *used = 0;
+ *output_written = 0;
- ctx->transparency_idx = transparency_idx;
- ctx->colour_map = colour_map;
+ if (ctx->colour_map == NULL) {
+ return LZW_NO_COLOUR;
+ }
if (ctx->output_left != 0) {
- *used += lzw__write_pixels_map(ctx, data, length, *used,
+ *output_written += lzw__map_write_fn(ctx,
+ output_data, output_length, *output_written,
ctx->output_code, ctx->output_left);
}
- while (*used != length) {
- lzw_result res = lzw__decode(ctx, data, length,
- lzw__write_pixels_map, used);
+ while (*output_written != output_length) {
+ lzw_result res = lzw__decode(ctx, lzw__map_write_fn,
+ output_data, output_length, output_written);
if (res != LZW_OK) {
return res;
}
diff --git a/src/lzw.h b/src/lzw.h
index a227163..4549c60 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -16,7 +16,6 @@
* Decoder for GIF LZW data.
*/
-
/** Maximum LZW code size in bits */
#define LZW_CODE_MAX 12
@@ -32,7 +31,9 @@ typedef enum lzw_result {
LZW_NO_MEM, /**< Error: Out of memory */
LZW_NO_DATA, /**< Error: Out of data */
LZW_EOI_CODE, /**< Error: End of Information code */
+ LZW_NO_COLOUR, /**< Error: No colour map provided. */
LZW_BAD_ICODE, /**< Error: Bad initial LZW code */
+ LZW_BAD_PARAM, /**< Error: Bad function parameter. */
LZW_BAD_CODE, /**< Error: Bad LZW code */
} lzw_result;
@@ -58,62 +59,81 @@ void lzw_context_destroy(
/**
* Initialise an LZW decompression context for decoding.
*
- * Caller owns neither `stack_base_out` or `stack_pos_out`.
- *
- * \param[in] ctx The LZW decompression context to initialise.
- * \param[in] compressed_data The compressed data.
- * \param[in] compressed_data_len Byte length of compressed data.
- * \param[in] compressed_data_pos Start position in data. Must be position
- * of a size byte at sub-block start.
- * \param[in] minimum_code_size The LZW Minimum Code Size.
- * \param[out] stack_base_out Returns base of decompressed data stack.
+ * \param[in] ctx The LZW decompression context to initialise.
+ * \param[in] minimum_code_size The LZW Minimum Code Size.
+ * \param[in] input_data The compressed data.
+ * \param[in] input_length Byte length of compressed data.
+ * \param[in] input_pos Start position in data. Must be position
+ * of a size byte at sub-block start.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
lzw_result lzw_decode_init(
struct lzw_ctx *ctx,
- const uint8_t *compressed_data,
- uint32_t compressed_data_len,
- uint32_t compressed_data_pos,
- uint8_t minimum_code_size);
+ uint8_t minimum_code_size,
+ const uint8_t *input_data,
+ uint32_t input_length,
+ uint32_t input_pos);
/**
- * Read input codes until end of lzw context owned output buffer.
+ * Read input codes until end of LZW context owned output buffer.
*
* Ensure anything in output is used before calling this, as anything
- * on the there before this call will be trampled.
+ * there before this call will be trampled.
*
- * \param[in] ctx LZW reading context, updated.
- * \param[out] data Returns pointer to array of output values.
- * \param[out] used Returns the number of values written to data.
+ * \param[in] ctx LZW reading context, updated.
+ * \param[out] output_data Returns pointer to array of output values.
+ * \param[out] output_written Returns the number of values written to data.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
-lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
- const uint8_t *restrict *const restrict data,
- uint32_t *restrict used);
+lzw_result lzw_decode(struct lzw_ctx *ctx,
+ const uint8_t *restrict *const restrict output_data,
+ uint32_t *restrict output_written);
/**
- * Read LZW codes into client buffer, mapping output to colours.
- *
- * Ensure anything in output is used before calling this, as anything
- * on the there before this call will be trampled.
+ * Initialise an LZW decompression context for decoding to colour map values.
*
* For transparency to work correctly, the given client buffer must have
* the values from the previous frame. The transparency_idx should be a value
* of 256 or above, if the frame does not have transparency.
*
- * \param[in] ctx LZW reading context, updated.
- * \param[in] transparency_idx Index representing transparency.
- * \param[in] colour_map Index to pixel colour mapping
- * \param[in] data Client buffer to fill with colour mapped values.
- * \param[in] length Size of output array.
- * \param[out] used Returns the number of values written to data.
+ * \param[in] ctx The LZW decompression context to initialise.
+ * \param[in] minimum_code_size The LZW Minimum Code Size.
+ * \param[in] transparency_idx Index representing transparency.
+ * \param[in] colour_table Index to pixel colour mapping.
+ * \param[in] input_data The compressed data.
+ * \param[in] input_length Byte length of compressed data.
+ * \param[in] input_pos Start position in data. Must be position
+ * of a size byte at sub-block start.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
-lzw_result lzw_decode_map_continuous(struct lzw_ctx *ctx,
+lzw_result lzw_decode_init_map(
+ struct lzw_ctx *ctx,
+ uint8_t minimum_code_size,
uint32_t transparency_idx,
- uint32_t *restrict colour_table,
- uint32_t *restrict data,
- uint32_t length,
- uint32_t *restrict used);
+ const uint32_t *colour_table,
+ const uint8_t *input_data,
+ uint32_t input_length,
+ uint32_t input_pos);
+
+/**
+ * Read LZW codes into client buffer, mapping output to colours.
+ *
+ * The context must have been initialised using \ref lzw_decode_init_map
+ * before calling this function, in order to provide the colour mapping table
+ * and any transparency index.
+ *
+ * Ensure anything in output is used before calling this, as anything
+ * there before this call will be trampled.
+ *
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] output_data Client buffer to fill with colour mapped values.
+ * \param[in] output_length Size of output array.
+ * \param[out] output_written Returns the number of values written to data.
+ * \return LZW_OK on success, or appropriate error code otherwise.
+ */
+lzw_result lzw_decode_map(struct lzw_ctx *ctx,
+ uint32_t *restrict output_data,
+ uint32_t output_length,
+ uint32_t *restrict output_written);
#endif
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=84211ade387da05c76...
commit 84211ade387da05c766b94a435c3bac3e8199976
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
lzw: Decode until end of space in output buffer.
diff --git a/src/lzw.c b/src/lzw.c
index c865b8d..a243ddb 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -562,7 +562,7 @@ lzw_result lzw_decode_map_continuous(struct lzw_ctx *ctx,
ctx->output_code, ctx->output_left);
}
- while (*used != sizeof(ctx->stack_base)) {
+ while (*used != length) {
lzw_result res = lzw__decode(ctx, data, length,
lzw__write_pixels_map, used);
if (res != LZW_OK) {
-----------------------------------------------------------------------
Summary of changes:
src/libnsgif.c | 46 ++++++----
src/lzw.c | 268 ++++++++++++++++++++++++++++++++-----------------------
src/lzw.h | 94 +++++++++++--------
test/runtest.sh | 1 +
4 files changed, 241 insertions(+), 168 deletions(-)
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 5fa9cb6..2bea30e 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -554,6 +554,8 @@ static gif_result gif_error_from_lzw(lzw_result l_res)
[LZW_BAD_ICODE] = GIF_FRAME_DATA_ERROR,
[LZW_BAD_CODE] = GIF_FRAME_DATA_ERROR,
};
+ assert(l_res != LZW_BAD_PARAM);
+ assert(l_res != LZW_NO_COLOUR);
return g_res[l_res];
}
@@ -643,9 +645,8 @@ gif__decode_complex(gif_animation *gif,
lzw_result res;
/* Initialise the LZW decoding */
- res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
- gif->buffer_size, gif->buffer_position,
- minimum_code_size);
+ res = lzw_decode_init(gif->lzw_ctx, minimum_code_size,
+ gif->gif_data, gif->buffer_size, gif->buffer_position);
if (res != LZW_OK) {
return gif_error_from_lzw(res);
}
@@ -680,20 +681,28 @@ gif__decode_complex(gif_animation *gif,
}
break;
}
- res = lzw_decode_continuous(gif->lzw_ctx,
+ res = lzw_decode(gif->lzw_ctx,
&uncompressed, &available);
}
row_available = x < available ? x : available;
x -= row_available;
available -= row_available;
- while (row_available-- > 0) {
- register unsigned int colour;
- colour = *uncompressed++;
- if (colour != transparency_index) {
- *frame_scanline = colour_table[colour];
+ if (transparency_index > 0xFF) {
+ while (row_available-- > 0) {
+ *frame_scanline++ =
+ colour_table[*uncompressed++];
+ }
+ } else {
+ while (row_available-- > 0) {
+ register unsigned int colour;
+ colour = *uncompressed++;
+ if (colour != transparency_index) {
+ *frame_scanline =
+ colour_table[colour];
+ }
+ frame_scanline++;
}
- frame_scanline++;
}
}
}
@@ -715,23 +724,22 @@ gif__decode_simple(gif_animation *gif,
gif_result ret = GIF_OK;
lzw_result res;
+ transparency_index = gif->frames[frame].transparency ?
+ gif->frames[frame].transparency_index :
+ GIF_NO_TRANSPARENCY;
+
/* Initialise the LZW decoding */
- res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
- gif->buffer_size, gif->buffer_position,
- minimum_code_size);
+ res = lzw_decode_init_map(gif->lzw_ctx,
+ minimum_code_size, transparency_index, colour_table,
+ gif->gif_data, gif->buffer_size, gif->buffer_position);
if (res != LZW_OK) {
return gif_error_from_lzw(res);
}
- transparency_index = gif->frames[frame].transparency ?
- gif->frames[frame].transparency_index :
- GIF_NO_TRANSPARENCY;
-
frame_data += (offset_y * gif->width);
while (pixels > 0) {
- res = lzw_decode_map_continuous(gif->lzw_ctx,
- transparency_index, colour_table,
+ res = lzw_decode_map(gif->lzw_ctx,
frame_data, pixels, &written);
pixels -= written;
frame_data += written;
diff --git a/src/lzw.c b/src/lzw.c
index c865b8d..710895e 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -68,31 +68,32 @@ struct lzw_table_entry {
struct lzw_ctx {
struct lzw_read_ctx input; /**< Input reading context */
- uint32_t prev_code; /**< Code read from input previously. */
- uint32_t prev_code_first; /**< First value of previous code. */
- uint32_t prev_code_count; /**< Total values for previous code. */
+ uint16_t prev_code; /**< Code read from input previously. */
+ uint16_t prev_code_first; /**< First value of previous code. */
+ uint16_t prev_code_count; /**< Total values for previous code. */
- uint32_t initial_code_size; /**< Starting LZW code size. */
+ uint8_t initial_code_size; /**< Starting LZW code size. */
- uint32_t code_size; /**< Current LZW code size. */
- uint32_t code_max; /**< Max code value for current code size. */
+ uint8_t code_size; /**< Current LZW code size. */
+ uint16_t code_max; /**< Max code value for current code size. */
- uint32_t clear_code; /**< Special Clear code value */
- uint32_t eoi_code; /**< Special End of Information code value */
+ uint16_t clear_code; /**< Special Clear code value */
+ uint16_t eoi_code; /**< Special End of Information code value */
- uint32_t table_size; /**< Next position in table to fill. */
+ uint16_t table_size; /**< Next position in table to fill. */
- uint32_t output_code; /**< Code that has been partially output. */
- uint32_t output_left; /**< Number of values left for output_code. */
+ uint16_t output_code; /**< Code that has been partially output. */
+ uint16_t output_left; /**< Number of values left for output_code. */
- uint32_t transparency_idx; /**< Index representing transparency. */
- uint32_t *restrict colour_map; /**< Index to pixel colour mapping */
-
- /** Output value stack. */
- uint8_t stack_base[LZW_TABLE_ENTRY_MAX];
+ bool has_transparency; /**< Whether the image is opaque. */
+ uint8_t transparency_idx; /**< Index representing transparency. */
+ const uint32_t *restrict colour_map; /**< Index to colour mapping. */
/** LZW code table. Generated during decode. */
struct lzw_table_entry table[LZW_TABLE_ENTRY_MAX];
+
+ /** Output value stack. */
+ uint8_t stack_base[LZW_TABLE_ENTRY_MAX];
};
@@ -165,8 +166,8 @@ static lzw_result lzw__block_advance(struct lzw_read_ctx *restrict ctx)
*/
static inline lzw_result lzw__read_code(
struct lzw_read_ctx *restrict ctx,
- uint32_t code_size,
- uint32_t *restrict code_out)
+ uint16_t code_size,
+ uint16_t *restrict code_out)
{
uint32_t code = 0;
uint32_t current_bit = ctx->sb_bit & 0x7;
@@ -232,9 +233,9 @@ static inline lzw_result lzw__read_code(
*/
static inline lzw_result lzw__handle_clear(
struct lzw_ctx *ctx,
- uint32_t *code_out)
+ uint16_t *code_out)
{
- uint32_t code;
+ uint16_t code;
/* Reset table building context */
ctx->code_size = ctx->initial_code_size;
@@ -259,27 +260,26 @@ static inline lzw_result lzw__handle_clear(
return LZW_OK;
}
-
/* Exported function, documented in lzw.h */
lzw_result lzw_decode_init(
struct lzw_ctx *ctx,
- const uint8_t *compressed_data,
- uint32_t compressed_data_len,
- uint32_t compressed_data_pos,
- uint8_t minimum_code_size)
+ uint8_t minimum_code_size,
+ const uint8_t *input_data,
+ uint32_t input_length,
+ uint32_t input_pos)
{
struct lzw_table_entry *table = ctx->table;
lzw_result res;
- uint32_t code;
+ uint16_t code;
if (minimum_code_size >= LZW_CODE_MAX) {
return LZW_BAD_ICODE;
}
/* Initialise the input reading context */
- ctx->input.data = compressed_data;
- ctx->input.data_len = compressed_data_len;
- ctx->input.data_sb_next = compressed_data_pos;
+ ctx->input.data = input_data;
+ ctx->input.data_len = input_length;
+ ctx->input.data_sb_next = input_pos;
ctx->input.sb_bit = 0;
ctx->input.sb_bit_count = 0;
@@ -293,7 +293,7 @@ lzw_result lzw_decode_init(
ctx->output_left = 0;
/* Initialise the standard table entries */
- for (uint32_t i = 0; i < ctx->clear_code; ++i) {
+ for (uint16_t i = 0; i < ctx->clear_code; i++) {
table[i].first = i;
table[i].value = i;
table[i].count = 1;
@@ -313,6 +313,39 @@ lzw_result lzw_decode_init(
ctx->output_code = code;
ctx->output_left = 1;
+ ctx->has_transparency = false;
+ ctx->transparency_idx = 0;
+ ctx->colour_map = NULL;
+
+ return LZW_OK;
+}
+
+/* Exported function, documented in lzw.h */
+lzw_result lzw_decode_init_map(
+ struct lzw_ctx *ctx,
+ uint8_t minimum_code_size,
+ uint32_t transparency_idx,
+ const uint32_t *colour_table,
+ const uint8_t *input_data,
+ uint32_t input_length,
+ uint32_t input_pos)
+{
+ lzw_result res;
+
+ if (colour_table == NULL) {
+ return LZW_BAD_PARAM;
+ }
+
+ res = lzw_decode_init(ctx, minimum_code_size,
+ input_data, input_length, input_pos);
+ if (res != LZW_OK) {
+ return res;
+ }
+
+ ctx->has_transparency = (transparency_idx <= 0xFF);
+ ctx->transparency_idx = transparency_idx;
+ ctx->colour_map = colour_table;
+
return LZW_OK;
}
@@ -324,7 +357,7 @@ lzw_result lzw_decode_init(
*/
static inline void lzw__table_add_entry(
struct lzw_ctx *ctx,
- uint32_t code)
+ uint16_t code)
{
struct lzw_table_entry *entry = &ctx->table[ctx->table_size];
@@ -338,30 +371,31 @@ static inline void lzw__table_add_entry(
typedef uint32_t (*lzw_writer_fn)(
struct lzw_ctx *ctx,
- void *restrict output,
- uint32_t length,
- uint32_t used,
- uint32_t code,
- uint32_t left);
+ void *restrict output_data,
+ uint32_t output_length,
+ uint32_t output_pos,
+ uint16_t code,
+ uint16_t left);
/**
* Get the next LZW code and write its value(s) to output buffer.
*
- * \param[in] ctx LZW reading context, updated.
- * \param[in] output Array to write output values into.
- * \param[in] length Size of output array.
- * \param[in] write_pixels Function for writing pixels to output.
- * \param[in,out] used Number of values written. Updated on exit.
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] write_fn Function for writing pixels to output.
+ * \param[in] output_data Array to write output values into.
+ * \param[in] output_length Size of output array.
+ * \param[in,out] output_written Number of values written. Updated on exit.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
-static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
- void *restrict output,
- uint32_t length,
- lzw_writer_fn write_pixels,
- uint32_t *restrict used)
+static inline lzw_result lzw__decode(
+ struct lzw_ctx *ctx,
+ lzw_writer_fn write_fn,
+ void *restrict output_data,
+ uint32_t output_length,
+ uint32_t *restrict output_written)
{
lzw_result res;
- uint32_t code;
+ uint16_t code;
/* Get a new code from the input */
res = lzw__read_code(&ctx->input, ctx->code_size, &code);
@@ -385,7 +419,7 @@ static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
}
} else if (ctx->table_size < LZW_TABLE_ENTRY_MAX) {
- uint32_t size = ctx->table_size;
+ uint16_t size = ctx->table_size;
lzw__table_add_entry(ctx, (code < size) ?
ctx->table[code].first :
ctx->prev_code_first);
@@ -397,8 +431,9 @@ static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
}
}
- *used += write_pixels(ctx, output, length, *used, code,
- ctx->table[code].count);
+ *output_written += write_fn(ctx,
+ output_data, output_length, *output_written,
+ code, ctx->table[code].count);
/* Store details of this code as "previous code" to the context. */
ctx->prev_code_first = ctx->table[code].first;
@@ -416,25 +451,25 @@ static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
* this call, then there is more data for this code left to output. The code
* is stored to the context as `ctx->output_code`.
*
- * \param[in] ctx LZW reading context, updated.
- * \param[in] output Array to write output values into.
- * \param[in] length Size of output array.
- * \param[in] used Current position in output array.
- * \param[in] code LZW code to output values for.
- * \param[in] left Number of values remaining to output for this value.
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] output_data Array to write output values into.
+ * \param[in] output_length length Size of output array.
+ * \param[in] output_used Current position in output array.
+ * \param[in] code LZW code to output values for.
+ * \param[in] left Number of values remaining to output for this code.
* \return Number of pixel values written.
*/
-static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
- void *restrict output,
- uint32_t length,
- uint32_t used,
- uint32_t code,
- uint32_t left)
+static inline uint32_t lzw__write_fn(struct lzw_ctx *ctx,
+ void *restrict output_data,
+ uint32_t output_length,
+ uint32_t output_used,
+ uint16_t code,
+ uint16_t left)
{
- uint8_t *restrict output_pos = (uint8_t *)output + used;
+ uint8_t *restrict output_pos = (uint8_t *)output_data + output_used;
const struct lzw_table_entry * const table = ctx->table;
- uint32_t space = length - used;
- uint32_t count = left;
+ uint32_t space = output_length - output_used;
+ uint16_t count = left;
if (count > space) {
left = count - space;
@@ -463,23 +498,24 @@ static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
}
/* Exported function, documented in lzw.h */
-lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
- const uint8_t *restrict *const restrict data,
- uint32_t *restrict used)
+lzw_result lzw_decode(struct lzw_ctx *ctx,
+ const uint8_t *restrict *const restrict output_data,
+ uint32_t *restrict output_written)
{
- *used = 0;
- *data = ctx->stack_base;
+ const uint32_t output_length = sizeof(ctx->stack_base);
+
+ *output_written = 0;
+ *output_data = ctx->stack_base;
if (ctx->output_left != 0) {
- *used += lzw__write_pixels(ctx,
- ctx->stack_base, sizeof(ctx->stack_base), *used,
+ *output_written += lzw__write_fn(ctx,
+ ctx->stack_base, output_length, *output_written,
ctx->output_code, ctx->output_left);
}
- while (*used != sizeof(ctx->stack_base)) {
- lzw_result res = lzw__decode(ctx,
- ctx->stack_base, sizeof(ctx->stack_base),
- lzw__write_pixels, used);
+ while (*output_written != output_length) {
+ lzw_result res = lzw__decode(ctx, lzw__write_fn,
+ ctx->stack_base, output_length, output_written);
if (res != LZW_OK) {
return res;
}
@@ -489,32 +525,32 @@ lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
}
/**
- * Write colour mapped values for this code to the output stack.
+ * Write colour mapped values for this code to the output.
*
* If there isn't enough space in the output stack, this function will write
* the as many as it can into the output. If `ctx->output_left > 0` after
* this call, then there is more data for this code left to output. The code
* is stored to the context as `ctx->output_code`.
*
- * \param[in] ctx LZW reading context, updated.
- * \param[in] output Array to write output values into.
- * \param[in] length Size of output array.
- * \param[in] used Current position in output array.
- * \param[in] code LZW code to output values for.
- * \param[in] left Number of values remaining to output for this value.
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] output_data Array to write output values into.
+ * \param[in] output_length Size of output array.
+ * \param[in] output_used Current position in output array.
+ * \param[in] code LZW code to output values for.
+ * \param[in] left Number of values remaining to output for code.
* \return Number of pixel values written.
*/
-static inline uint32_t lzw__write_pixels_map(struct lzw_ctx *ctx,
- void *restrict buffer,
- uint32_t length,
- uint32_t used,
- uint32_t code,
- uint32_t left)
+static inline uint32_t lzw__map_write_fn(struct lzw_ctx *ctx,
+ void *restrict output_data,
+ uint32_t output_length,
+ uint32_t output_used,
+ uint16_t code,
+ uint16_t left)
{
- uint32_t *restrict stack_pos = (uint32_t *)buffer + used;
+ uint32_t *restrict output_pos = (uint32_t *)output_data + output_used;
const struct lzw_table_entry * const table = ctx->table;
- uint32_t space = length - used;
- uint32_t count = left;
+ uint32_t space = output_length - output_used;
+ uint16_t count = left;
if (count > space) {
left = count - space;
@@ -531,40 +567,48 @@ static inline uint32_t lzw__write_pixels_map(struct lzw_ctx *ctx,
code = entry->extends;
}
- stack_pos += count;
- for (unsigned i = count; i != 0; i--) {
- const struct lzw_table_entry *entry = table + code;
- --stack_pos;
- if (entry->value != ctx->transparency_idx) {
- *stack_pos = ctx->colour_map[entry->value];
+ output_pos += count;
+ if (ctx->has_transparency) {
+ for (unsigned i = count; i != 0; i--) {
+ const struct lzw_table_entry *entry = table + code;
+ --output_pos;
+ if (entry->value != ctx->transparency_idx) {
+ *output_pos = ctx->colour_map[entry->value];
+ }
+ code = entry->extends;
+ }
+ } else {
+ for (unsigned i = count; i != 0; i--) {
+ const struct lzw_table_entry *entry = table + code;
+ *--output_pos = ctx->colour_map[entry->value];
+ code = entry->extends;
}
- code = entry->extends;
}
return count;
}
/* Exported function, documented in lzw.h */
-lzw_result lzw_decode_map_continuous(struct lzw_ctx *ctx,
- uint32_t transparency_idx,
- uint32_t *restrict colour_map,
- uint32_t *restrict data,
- uint32_t length,
- uint32_t *restrict used)
+lzw_result lzw_decode_map(struct lzw_ctx *ctx,
+ uint32_t *restrict output_data,
+ uint32_t output_length,
+ uint32_t *restrict output_written)
{
- *used = 0;
+ *output_written = 0;
- ctx->transparency_idx = transparency_idx;
- ctx->colour_map = colour_map;
+ if (ctx->colour_map == NULL) {
+ return LZW_NO_COLOUR;
+ }
if (ctx->output_left != 0) {
- *used += lzw__write_pixels_map(ctx, data, length, *used,
+ *output_written += lzw__map_write_fn(ctx,
+ output_data, output_length, *output_written,
ctx->output_code, ctx->output_left);
}
- while (*used != sizeof(ctx->stack_base)) {
- lzw_result res = lzw__decode(ctx, data, length,
- lzw__write_pixels_map, used);
+ while (*output_written != output_length) {
+ lzw_result res = lzw__decode(ctx, lzw__map_write_fn,
+ output_data, output_length, output_written);
if (res != LZW_OK) {
return res;
}
diff --git a/src/lzw.h b/src/lzw.h
index a227163..4549c60 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -16,7 +16,6 @@
* Decoder for GIF LZW data.
*/
-
/** Maximum LZW code size in bits */
#define LZW_CODE_MAX 12
@@ -32,7 +31,9 @@ typedef enum lzw_result {
LZW_NO_MEM, /**< Error: Out of memory */
LZW_NO_DATA, /**< Error: Out of data */
LZW_EOI_CODE, /**< Error: End of Information code */
+ LZW_NO_COLOUR, /**< Error: No colour map provided. */
LZW_BAD_ICODE, /**< Error: Bad initial LZW code */
+ LZW_BAD_PARAM, /**< Error: Bad function parameter. */
LZW_BAD_CODE, /**< Error: Bad LZW code */
} lzw_result;
@@ -58,62 +59,81 @@ void lzw_context_destroy(
/**
* Initialise an LZW decompression context for decoding.
*
- * Caller owns neither `stack_base_out` or `stack_pos_out`.
- *
- * \param[in] ctx The LZW decompression context to initialise.
- * \param[in] compressed_data The compressed data.
- * \param[in] compressed_data_len Byte length of compressed data.
- * \param[in] compressed_data_pos Start position in data. Must be position
- * of a size byte at sub-block start.
- * \param[in] minimum_code_size The LZW Minimum Code Size.
- * \param[out] stack_base_out Returns base of decompressed data stack.
+ * \param[in] ctx The LZW decompression context to initialise.
+ * \param[in] minimum_code_size The LZW Minimum Code Size.
+ * \param[in] input_data The compressed data.
+ * \param[in] input_length Byte length of compressed data.
+ * \param[in] input_pos Start position in data. Must be position
+ * of a size byte at sub-block start.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
lzw_result lzw_decode_init(
struct lzw_ctx *ctx,
- const uint8_t *compressed_data,
- uint32_t compressed_data_len,
- uint32_t compressed_data_pos,
- uint8_t minimum_code_size);
+ uint8_t minimum_code_size,
+ const uint8_t *input_data,
+ uint32_t input_length,
+ uint32_t input_pos);
/**
- * Read input codes until end of lzw context owned output buffer.
+ * Read input codes until end of LZW context owned output buffer.
*
* Ensure anything in output is used before calling this, as anything
- * on the there before this call will be trampled.
+ * there before this call will be trampled.
*
- * \param[in] ctx LZW reading context, updated.
- * \param[out] data Returns pointer to array of output values.
- * \param[out] used Returns the number of values written to data.
+ * \param[in] ctx LZW reading context, updated.
+ * \param[out] output_data Returns pointer to array of output values.
+ * \param[out] output_written Returns the number of values written to data.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
-lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
- const uint8_t *restrict *const restrict data,
- uint32_t *restrict used);
+lzw_result lzw_decode(struct lzw_ctx *ctx,
+ const uint8_t *restrict *const restrict output_data,
+ uint32_t *restrict output_written);
/**
- * Read LZW codes into client buffer, mapping output to colours.
- *
- * Ensure anything in output is used before calling this, as anything
- * on the there before this call will be trampled.
+ * Initialise an LZW decompression context for decoding to colour map values.
*
* For transparency to work correctly, the given client buffer must have
* the values from the previous frame. The transparency_idx should be a value
* of 256 or above, if the frame does not have transparency.
*
- * \param[in] ctx LZW reading context, updated.
- * \param[in] transparency_idx Index representing transparency.
- * \param[in] colour_map Index to pixel colour mapping
- * \param[in] data Client buffer to fill with colour mapped values.
- * \param[in] length Size of output array.
- * \param[out] used Returns the number of values written to data.
+ * \param[in] ctx The LZW decompression context to initialise.
+ * \param[in] minimum_code_size The LZW Minimum Code Size.
+ * \param[in] transparency_idx Index representing transparency.
+ * \param[in] colour_table Index to pixel colour mapping.
+ * \param[in] input_data The compressed data.
+ * \param[in] input_length Byte length of compressed data.
+ * \param[in] input_pos Start position in data. Must be position
+ * of a size byte at sub-block start.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
-lzw_result lzw_decode_map_continuous(struct lzw_ctx *ctx,
+lzw_result lzw_decode_init_map(
+ struct lzw_ctx *ctx,
+ uint8_t minimum_code_size,
uint32_t transparency_idx,
- uint32_t *restrict colour_table,
- uint32_t *restrict data,
- uint32_t length,
- uint32_t *restrict used);
+ const uint32_t *colour_table,
+ const uint8_t *input_data,
+ uint32_t input_length,
+ uint32_t input_pos);
+
+/**
+ * Read LZW codes into client buffer, mapping output to colours.
+ *
+ * The context must have been initialised using \ref lzw_decode_init_map
+ * before calling this function, in order to provide the colour mapping table
+ * and any transparency index.
+ *
+ * Ensure anything in output is used before calling this, as anything
+ * there before this call will be trampled.
+ *
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] output_data Client buffer to fill with colour mapped values.
+ * \param[in] output_length Size of output array.
+ * \param[out] output_written Returns the number of values written to data.
+ * \return LZW_OK on success, or appropriate error code otherwise.
+ */
+lzw_result lzw_decode_map(struct lzw_ctx *ctx,
+ uint32_t *restrict output_data,
+ uint32_t output_length,
+ uint32_t *restrict output_written);
#endif
diff --git a/test/runtest.sh b/test/runtest.sh
index fd5a32b..06eaef4 100755
--- a/test/runtest.sh
+++ b/test/runtest.sh
@@ -54,6 +54,7 @@ for GIF in $(ls ${GIFTESTS});do
ECODE=$?
if [ "${ECODE}" -gt 127 ];then
GIFTESTERRC=$((GIFTESTERRC+1))
+ echo "Error ${GIF}"
else
if [ "${ECODE}" -gt 0 ];then
GIFTESTFAILC=$((GIFTESTFAILC+1))
--
NetSurf GIF Decoder
1 year, 8 months