lzw: Return output array from decode function instead of init.

This commit is contained in:
Michael Drake 2021-04-05 10:11:07 +01:00 committed by Michael Drake
parent 01fde32f99
commit abd8619bef
3 changed files with 50 additions and 31 deletions

View File

@ -634,8 +634,6 @@ gif__decode(gif_animation *gif,
unsigned int *restrict colour_table) unsigned int *restrict colour_table)
{ {
unsigned int transparency_index; unsigned int transparency_index;
const uint8_t *stack_base;
const uint8_t *stack_pos;
uint32_t available = 0; uint32_t available = 0;
gif_result ret = GIF_OK; gif_result ret = GIF_OK;
lzw_result res; lzw_result res;
@ -643,7 +641,7 @@ gif__decode(gif_animation *gif,
/* Initialise the LZW decoding */ /* Initialise the LZW decoding */
res = lzw_decode_init(gif->lzw_ctx, gif->gif_data, res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
gif->buffer_size, gif->buffer_position, gif->buffer_size, gif->buffer_position,
minimum_code_size, &stack_base); minimum_code_size);
if (res != LZW_OK) { if (res != LZW_OK) {
return gif_error_from_lzw(res); return gif_error_from_lzw(res);
} }
@ -652,7 +650,6 @@ gif__decode(gif_animation *gif,
gif->frames[frame].transparency_index : gif->frames[frame].transparency_index :
GIF_NO_TRANSPARENCY; GIF_NO_TRANSPARENCY;
stack_pos = stack_base;
for (unsigned int y = 0; y < height; y++) { for (unsigned int y = 0; y < height; y++) {
unsigned int x; unsigned int x;
unsigned int decode_y; unsigned int decode_y;
@ -667,9 +664,11 @@ gif__decode(gif_animation *gif,
x = width; x = width;
while (x > 0) { while (x > 0) {
const uint8_t *uncompressed;
unsigned row_available; unsigned row_available;
if (available == 0) { if (available == 0) {
res = lzw_decode(gif->lzw_ctx, &available); res = lzw_decode(gif->lzw_ctx,
&uncompressed, &available);
if (res != LZW_OK) { if (res != LZW_OK) {
/* Unexpected end of frame, try to recover */ /* Unexpected end of frame, try to recover */
if (res == LZW_OK_EOD) { if (res == LZW_OK_EOD) {
@ -679,7 +678,6 @@ gif__decode(gif_animation *gif,
} }
break; break;
} }
stack_pos = stack_base;
} }
row_available = x < available ? x : available; row_available = x < available ? x : available;
@ -687,7 +685,7 @@ gif__decode(gif_animation *gif,
available -= row_available; available -= row_available;
while (row_available-- > 0) { while (row_available-- > 0) {
register unsigned int colour; register unsigned int colour;
colour = *stack_pos++; colour = *uncompressed++;
if (colour != transparency_index) { if (colour != transparency_index) {
*frame_scanline = colour_table[colour]; *frame_scanline = colour_table[colour];
} }

View File

@ -241,8 +241,7 @@ lzw_result lzw_decode_init(
const uint8_t *compressed_data, const uint8_t *compressed_data,
uint32_t compressed_data_len, uint32_t compressed_data_len,
uint32_t compressed_data_pos, uint32_t compressed_data_pos,
uint8_t minimum_code_size, uint8_t minimum_code_size)
const uint8_t ** const stack_base_out)
{ {
struct lzw_table_entry *table = ctx->table; struct lzw_table_entry *table = ctx->table;
@ -274,7 +273,6 @@ lzw_result lzw_decode_init(
lzw__clear_table(ctx); lzw__clear_table(ctx);
ctx->prev_code = ctx->clear_code; ctx->prev_code = ctx->clear_code;
*stack_base_out = ctx->stack_base;
return LZW_OK; return LZW_OK;
} }
@ -302,29 +300,44 @@ static inline void lzw__table_add_entry(
* Write values for this code to the output stack. * Write values for this code to the output stack.
* *
* \param[in] ctx LZW reading context, updated. * \param[in] ctx LZW reading context, updated.
* \param[in] output Array to write output values into.
* \param[in] code LZW code to output values for. * \param[in] code LZW code to output values for.
* \return Number of pixel values written. * \return Number of pixel values written.
*/ */
static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx, static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
void *restrict output,
uint32_t code) uint32_t code)
{ {
uint8_t *stack_pos = ctx->stack_base; uint8_t *restrict output_pos = (uint8_t *)output;
struct lzw_table_entry * const table = ctx->table; struct lzw_table_entry * const table = ctx->table;
uint32_t count = table[code].count; uint32_t count = table[code].count;
stack_pos += count; output_pos += count;
for (unsigned i = count; i != 0; i--) { for (unsigned i = count; i != 0; i--) {
struct lzw_table_entry *entry = table + code; struct lzw_table_entry *entry = table + code;
*--stack_pos = entry->value; *--output_pos = entry->value;
code = entry->extends; code = entry->extends;
} }
return count; return count;
} }
/* Exported function, documented in lzw.h */ /**
lzw_result lzw_decode(struct lzw_ctx *ctx, * Fill the LZW stack with decompressed data
uint32_t *written) *
* Ensure anything in output is used before calling this, as anything
* on the there before this call will be trampled.
*
* \param[in] ctx LZW reading context, updated.
* \param[in] output Array to write output values into.
* \param[out] used 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,
uint8_t *restrict output,
uint32_t *restrict used)
{ {
lzw_result res; lzw_result res;
uint32_t code; uint32_t code;
@ -362,7 +375,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
} }
} }
*written += lzw__write_pixels(ctx, code); *used += lzw__write_pixels(ctx, output, code);
} }
/* Store details of this code as "previous code" to the context. */ /* Store details of this code as "previous code" to the context. */
@ -372,3 +385,13 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
return LZW_OK; return LZW_OK;
} }
/* Exported function, documented in lzw.h */
lzw_result lzw_decode(struct lzw_ctx *ctx,
const uint8_t *restrict* const restrict data,
uint32_t *restrict used)
{
*used = 0;
*data = ctx->stack_base;
return lzw__decode(ctx, ctx->stack_base, used);
}

View File

@ -74,23 +74,21 @@ lzw_result lzw_decode_init(
const uint8_t *compressed_data, const uint8_t *compressed_data,
uint32_t compressed_data_len, uint32_t compressed_data_len,
uint32_t compressed_data_pos, uint32_t compressed_data_pos,
uint8_t minimum_code_size, uint8_t minimum_code_size);
const uint8_t ** const stack_base_out);
/** /**
* Fill the LZW stack with decompressed data * Read a single LZW code and write into lzw context owned output buffer.
* *
* Ensure anything on the stack is used before calling this, as anything * Ensure anything in output is used before calling this, as anything
* on the stack before this call will be trampled. * on the there before this call will be trampled.
* *
* \param[in] ctx LZW reading context, updated. * \param[in] ctx LZW reading context, updated.
* \param[out] written Returns the number of values written. * \param[out] data Returns pointer to array of output values.
* Use with `stack_base_out` value from previous * \param[out] used Returns the number of values written to data.
* lzw_decode_init() call.
* \return LZW_OK on success, or appropriate error code otherwise. * \return LZW_OK on success, or appropriate error code otherwise.
*/ */
lzw_result lzw_decode( lzw_result lzw_decode(struct lzw_ctx *ctx,
struct lzw_ctx *ctx, const uint8_t *restrict *const restrict data,
uint32_t *written); uint32_t *restrict used);
#endif #endif