summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Drake <tlsa@netsurf-browser.org>2021-04-04 17:38:37 +0100
committerMichael Drake <tlsa@netsurf-browser.org>2021-04-04 22:14:07 +0100
commit3f760807f71ffef44a6ac36d0eb0c09c65ad90ba (patch)
treef7ecd30f7a5bbe5f131b8fddf9259af87a709ff7
parentad9ddb59c4f0607821e52919a5ffdd09a1090a4e (diff)
downloadlibnsgif-3f760807f71ffef44a6ac36d0eb0c09c65ad90ba.tar.gz
libnsgif-3f760807f71ffef44a6ac36d0eb0c09c65ad90ba.tar.bz2
lzw: Return output pointer from decode rather than init.
-rw-r--r--src/libnsgif.c12
-rw-r--r--src/lzw.c74
-rw-r--r--src/lzw.h9
3 files changed, 73 insertions, 22 deletions
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 050a961..60209de 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -654,8 +654,6 @@ gif__decode(gif_animation *gif,
unsigned int *restrict colour_table)
{
unsigned int transparency_index;
- const uint8_t *stack_base;
- const uint8_t *stack_pos;
uint32_t available = 0;
gif_result ret = GIF_OK;
lzw_result res;
@@ -663,7 +661,7 @@ gif__decode(gif_animation *gif,
/* Initialise the LZW decoding */
res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
gif->buffer_size, gif->buffer_position,
- minimum_code_size, &stack_base);
+ minimum_code_size);
if (res != LZW_OK) {
return gif_error_from_lzw(res);
}
@@ -672,7 +670,6 @@ gif__decode(gif_animation *gif,
gif->frames[frame].transparency_index :
GIF_NO_TRANSPARENCY;
- stack_pos = stack_base;
for (unsigned int y = 0; y < height; y++) {
unsigned int x;
unsigned int decode_y;
@@ -687,9 +684,11 @@ gif__decode(gif_animation *gif,
x = width;
while (x > 0) {
+ const uint8_t *uncompressed;
unsigned row_available;
if (available == 0) {
- res = lzw_decode(gif->lzw_ctx, &available);
+ res = lzw_decode(gif->lzw_ctx,
+ &uncompressed, &available);
if (res != LZW_OK) {
/* Unexpected end of frame, try to recover */
if (res == LZW_OK_EOD) {
@@ -699,7 +698,6 @@ gif__decode(gif_animation *gif,
}
break;
}
- stack_pos = stack_base;
}
row_available = x < available ? x : available;
@@ -707,7 +705,7 @@ gif__decode(gif_animation *gif,
available -= row_available;
while (row_available-- > 0) {
register unsigned int colour;
- colour = *stack_pos++;
+ colour = *uncompressed++;
if (colour != transparency_index) {
*frame_scanline = colour_table[colour];
}
diff --git a/src/lzw.c b/src/lzw.c
index d3e0dcf..8c8911a 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -82,6 +82,9 @@ struct lzw_ctx {
uint32_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. */
+
/** Output value stack. */
uint8_t stack_base[LZW_DICTIONARY_ENTRY_MAX];
@@ -241,8 +244,7 @@ lzw_result lzw_decode_init(
const uint8_t *compressed_data,
uint32_t compressed_data_len,
uint32_t compressed_data_pos,
- uint8_t minimum_code_size,
- const uint8_t ** const stack_base_out)
+ uint8_t minimum_code_size)
{
struct lzw_table_entry *table = ctx->table;
@@ -264,6 +266,8 @@ lzw_result lzw_decode_init(
ctx->clear_code = (1 << minimum_code_size) + 0;
ctx->eoi_code = (1 << minimum_code_size) + 1;
+ ctx->output_left = 0;
+
/* Initialise the standard table entries */
for (uint32_t i = 0; i < ctx->clear_code; ++i) {
table[i].first = i;
@@ -274,7 +278,6 @@ lzw_result lzw_decode_init(
lzw__clear_table(ctx);
ctx->prev_code = ctx->clear_code;
- *stack_base_out = ctx->stack_base;
return LZW_OK;
}
@@ -306,11 +309,31 @@ static inline void lzw__table_add_entry(
* \return Number of pixel values written.
*/
static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
- uint32_t code)
+ void *buffer,
+ uint32_t length,
+ uint32_t used,
+ uint32_t code,
+ uint32_t left)
{
- uint8_t *stack_pos = ctx->stack_base;
+ uint8_t *stack_pos = (uint8_t *)buffer + used;
struct lzw_table_entry * const table = ctx->table;
- uint32_t count = table[code].count;
+ uint32_t space = length - used;
+ uint32_t count = left;
+
+ if (count > space) {
+ left = count - space;
+ count = space;
+ } else {
+ left = 0;
+ }
+
+ ctx->output_code = code;
+ ctx->output_left = left;
+
+ for (unsigned i = left; i != 0; i--) {
+ struct lzw_table_entry *entry = table + code;
+ code = entry->extends;
+ }
stack_pos += count;
for (unsigned i = count; i != 0; i--) {
@@ -322,9 +345,28 @@ static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
return count;
}
-/* Exported function, documented in lzw.h */
-lzw_result lzw_decode(struct lzw_ctx *ctx,
- uint32_t *written)
+/**
+ * Fill the LZW stack with decompressed data
+ *
+ * Ensure anything on the stack is used before calling this, as anything
+ * on the stack before this call will be trampled.
+ *
+ * \param[in] ctx LZW reading context, updated.
+ * \param[out] written Returns the number of values written.
+ * Use with `stack_base_out` value from previous
+ * lzw_decode_init() call.
+ * \return LZW_OK on success, or appropriate error code otherwise.
+ */
+static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
+ void *buffer,
+ uint32_t length,
+ uint32_t (*write_pixels)(struct lzw_ctx *ctx,
+ void *buffer,
+ uint32_t length,
+ uint32_t used,
+ uint32_t code,
+ uint32_t left),
+ uint32_t *used)
{
lzw_result res;
uint32_t code;
@@ -362,7 +404,8 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
}
}
- *written += lzw__write_pixels(ctx, code);
+ *used += write_pixels(ctx, buffer, length, *used, code,
+ ctx->table[code].count);
}
/* Store details of this code as "previous code" to the context. */
@@ -372,3 +415,14 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
return LZW_OK;
}
+
+/* Exported function, documented in lzw.h */
+lzw_result lzw_decode(struct lzw_ctx *ctx,
+ const uint8_t ** const data,
+ uint32_t *used)
+{
+ *used = 0;
+ *data = ctx->stack_base;
+ return lzw__decode(ctx, ctx->stack_base, sizeof(ctx->stack_base),
+ lzw__write_pixels, used);
+}
diff --git a/src/lzw.h b/src/lzw.h
index a4a58fc..2e82869 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -74,8 +74,7 @@ lzw_result lzw_decode_init(
const uint8_t *compressed_data,
uint32_t compressed_data_len,
uint32_t compressed_data_pos,
- uint8_t minimum_code_size,
- const uint8_t ** const stack_base_out);
+ uint8_t minimum_code_size);
/**
* Fill the LZW stack with decompressed data
@@ -89,8 +88,8 @@ lzw_result lzw_decode_init(
* lzw_decode_init() call.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
-lzw_result lzw_decode(
- struct lzw_ctx *ctx,
- uint32_t *written);
+lzw_result lzw_decode(struct lzw_ctx *ctx,
+ const uint8_t ** const data,
+ uint32_t *used);
#endif