diff options
author | Michael Drake <tlsa@netsurf-browser.org> | 2021-04-04 17:38:37 +0100 |
---|---|---|
committer | Michael Drake <tlsa@netsurf-browser.org> | 2021-04-04 22:14:07 +0100 |
commit | 3f760807f71ffef44a6ac36d0eb0c09c65ad90ba (patch) | |
tree | f7ecd30f7a5bbe5f131b8fddf9259af87a709ff7 | |
parent | ad9ddb59c4f0607821e52919a5ffdd09a1090a4e (diff) | |
download | libnsgif-3f760807f71ffef44a6ac36d0eb0c09c65ad90ba.tar.gz libnsgif-3f760807f71ffef44a6ac36d0eb0c09c65ad90ba.tar.bz2 |
lzw: Return output pointer from decode rather than init.
-rw-r--r-- | src/libnsgif.c | 12 | ||||
-rw-r--r-- | src/lzw.c | 74 | ||||
-rw-r--r-- | src/lzw.h | 9 |
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]; } @@ -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); +} @@ -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 |