lzw: Adapt main code handling to handle clear codes too.
This commit is contained in:
parent
367f64c5bc
commit
64ddf20599
@ -226,39 +226,13 @@ static inline lzw_result lzw__read_code(
|
|||||||
* \param[in] ctx LZW reading context, updated.
|
* \param[in] ctx LZW reading context, updated.
|
||||||
* \return LZW_OK or error code.
|
* \return LZW_OK or error code.
|
||||||
*/
|
*/
|
||||||
static lzw_result lzw__clear_codes(
|
static inline void lzw__clear_table(
|
||||||
struct lzw_ctx *ctx)
|
struct lzw_ctx *ctx)
|
||||||
{
|
{
|
||||||
uint32_t code;
|
|
||||||
|
|
||||||
/* Reset table building context */
|
/* Reset table building context */
|
||||||
ctx->code_size = ctx->initial_code_size;
|
ctx->code_size = ctx->initial_code_size;
|
||||||
ctx->code_max = (1 << ctx->initial_code_size) - 1;
|
ctx->code_max = (1 << ctx->initial_code_size) - 1;
|
||||||
ctx->table_size = ctx->eoi_code + 1;
|
ctx->table_size = ctx->eoi_code + 1;
|
||||||
|
|
||||||
/* There might be a sequence of clear codes, so process them all */
|
|
||||||
do {
|
|
||||||
lzw_result res = lzw__read_code(&ctx->input,
|
|
||||||
ctx->code_size, &code);
|
|
||||||
if (res != LZW_OK) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
} while (code == ctx->clear_code);
|
|
||||||
|
|
||||||
/* The initial code must be from the initial table. */
|
|
||||||
if (code > ctx->clear_code) {
|
|
||||||
return LZW_BAD_ICODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Record this initial code as "previous" code, needed during decode. */
|
|
||||||
ctx->prev_code = code;
|
|
||||||
ctx->prev_code_first = code;
|
|
||||||
ctx->prev_code_count = 1;
|
|
||||||
|
|
||||||
/* Reset the stack, and add first non-clear code added as first item. */
|
|
||||||
ctx->stack_base[ctx->written++] = code;
|
|
||||||
|
|
||||||
return LZW_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -298,10 +272,11 @@ lzw_result lzw_decode_init(
|
|||||||
table[i].count = 1;
|
table[i].count = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->written = 0;
|
lzw__clear_table(ctx);
|
||||||
|
ctx->prev_code = ctx->clear_code;
|
||||||
|
|
||||||
*stack_base_out = ctx->stack_base;
|
*stack_base_out = ctx->stack_base;
|
||||||
return lzw__clear_codes(ctx);
|
return LZW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -355,6 +330,8 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
|
|||||||
lzw_result res;
|
lzw_result res;
|
||||||
uint32_t code;
|
uint32_t code;
|
||||||
|
|
||||||
|
ctx->written = 0;
|
||||||
|
|
||||||
/* Get a new code from the input */
|
/* Get a new code from the input */
|
||||||
res = lzw__read_code(&ctx->input, ctx->code_size, &code);
|
res = lzw__read_code(&ctx->input, ctx->code_size, &code);
|
||||||
if (res != LZW_OK) {
|
if (res != LZW_OK) {
|
||||||
@ -362,46 +339,41 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Handle the new code */
|
/* Handle the new code */
|
||||||
if (code == ctx->clear_code) {
|
if (code == ctx->eoi_code) {
|
||||||
/* Got Clear code */
|
|
||||||
res = lzw__clear_codes(ctx);
|
|
||||||
if (res == LZW_OK) {
|
|
||||||
*written = ctx->written;
|
|
||||||
ctx->written = 0;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
|
|
||||||
} else if (code == ctx->eoi_code) {
|
|
||||||
/* Got End of Information code */
|
/* Got End of Information code */
|
||||||
return LZW_EOI_CODE;
|
return LZW_EOI_CODE;
|
||||||
|
|
||||||
} else if (code > ctx->table_size) {
|
} else if (code > ctx->table_size) {
|
||||||
/* Code is invalid */
|
/* Code is invalid */
|
||||||
return LZW_BAD_CODE;
|
return LZW_BAD_CODE;
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx->table_size < LZW_TABLE_ENTRY_MAX) {
|
} else if (code == ctx->clear_code) {
|
||||||
|
lzw__clear_table(ctx);
|
||||||
|
} else {
|
||||||
|
if (ctx->prev_code != ctx->clear_code &&
|
||||||
|
ctx->table_size < LZW_TABLE_ENTRY_MAX) {
|
||||||
uint32_t size = ctx->table_size;
|
uint32_t size = ctx->table_size;
|
||||||
lzw__table_add_entry(ctx, (code < size) ?
|
lzw__table_add_entry(ctx, (code < size) ?
|
||||||
ctx->table[code].first :
|
ctx->table[code].first :
|
||||||
ctx->prev_code_first);
|
ctx->prev_code_first);
|
||||||
|
|
||||||
/* Ensure code size is increased, if needed. */
|
/* Ensure code size is increased, if needed. */
|
||||||
if (size == ctx->code_max && ctx->code_size < LZW_CODE_MAX) {
|
if (size == ctx->code_max &&
|
||||||
|
ctx->code_size < LZW_CODE_MAX) {
|
||||||
ctx->code_size++;
|
ctx->code_size++;
|
||||||
ctx->code_max = (1 << ctx->code_size) - 1;
|
ctx->code_max = (1 << ctx->code_size) - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lzw__write_pixels(ctx, code);
|
||||||
|
}
|
||||||
|
|
||||||
/* Store details of this code as "previous code" to the context. */
|
/* Store details of this code as "previous code" to the context. */
|
||||||
ctx->prev_code_first = ctx->table[code].first;
|
ctx->prev_code_first = ctx->table[code].first;
|
||||||
ctx->prev_code_count = ctx->table[code].count;
|
ctx->prev_code_count = ctx->table[code].count;
|
||||||
ctx->prev_code = code;
|
ctx->prev_code = code;
|
||||||
|
|
||||||
lzw__write_pixels(ctx, code);
|
|
||||||
|
|
||||||
*written = ctx->written;
|
*written = ctx->written;
|
||||||
ctx->written = 0;
|
|
||||||
|
|
||||||
return LZW_OK;
|
return LZW_OK;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user