update libnsgif
for improved lzw decode
This commit is contained in:
parent
83c4e56cfb
commit
cc1020ae55
File diff suppressed because it is too large
Load Diff
@ -224,18 +224,39 @@ static inline lzw_result lzw__read_code(
|
||||
|
||||
|
||||
/**
|
||||
* Clear LZW code table.
|
||||
* Handle clear code.
|
||||
*
|
||||
* \param[in] ctx LZW reading context, updated.
|
||||
* \param[in] ctx LZW reading context, updated.
|
||||
* \param[out] code_out Returns next code after a clear code.
|
||||
* \return LZW_OK or error code.
|
||||
*/
|
||||
static inline void lzw__clear_table(
|
||||
struct lzw_ctx *ctx)
|
||||
static inline lzw_result lzw__handle_clear(
|
||||
struct lzw_ctx *ctx,
|
||||
uint32_t *code_out)
|
||||
{
|
||||
uint32_t code;
|
||||
|
||||
/* Reset table building context */
|
||||
ctx->code_size = ctx->initial_code_size;
|
||||
ctx->code_max = (1 << ctx->initial_code_size) - 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;
|
||||
}
|
||||
|
||||
*code_out = code;
|
||||
return LZW_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -248,6 +269,8 @@ lzw_result lzw_decode_init(
|
||||
uint8_t minimum_code_size)
|
||||
{
|
||||
struct lzw_table_entry *table = ctx->table;
|
||||
lzw_result res;
|
||||
uint32_t code;
|
||||
|
||||
if (minimum_code_size >= LZW_CODE_MAX) {
|
||||
return LZW_BAD_ICODE;
|
||||
@ -276,8 +299,19 @@ lzw_result lzw_decode_init(
|
||||
table[i].count = 1;
|
||||
}
|
||||
|
||||
lzw__clear_table(ctx);
|
||||
ctx->prev_code = ctx->clear_code;
|
||||
res = lzw__handle_clear(ctx, &code);
|
||||
if (res != LZW_OK) {
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Store details of this code as "previous code" to the context. */
|
||||
ctx->prev_code_first = ctx->table[code].first;
|
||||
ctx->prev_code_count = ctx->table[code].count;
|
||||
ctx->prev_code = code;
|
||||
|
||||
/* Add code to context for immediate output. */
|
||||
ctx->output_code = code;
|
||||
ctx->output_left = 1;
|
||||
|
||||
return LZW_OK;
|
||||
}
|
||||
@ -345,31 +379,27 @@ static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
|
||||
return LZW_BAD_CODE;
|
||||
|
||||
} else if (code == ctx->clear_code) {
|
||||
lzw__clear_table(ctx);
|
||||
} else {
|
||||
if (ctx->prev_code == ctx->clear_code) {
|
||||
if (code > ctx->clear_code) {
|
||||
return LZW_BAD_ICODE;
|
||||
}
|
||||
|
||||
} else if (ctx->table_size < LZW_TABLE_ENTRY_MAX) {
|
||||
uint32_t size = ctx->table_size;
|
||||
lzw__table_add_entry(ctx, (code < size) ?
|
||||
ctx->table[code].first :
|
||||
ctx->prev_code_first);
|
||||
|
||||
/* Ensure code size is increased, if needed. */
|
||||
if (size == ctx->code_max &&
|
||||
ctx->code_size < LZW_CODE_MAX) {
|
||||
ctx->code_size++;
|
||||
ctx->code_max = (1 << ctx->code_size) - 1;
|
||||
}
|
||||
res = lzw__handle_clear(ctx, &code);
|
||||
if (res != LZW_OK) {
|
||||
return res;
|
||||
}
|
||||
|
||||
*used += write_pixels(ctx, output, length, *used, code,
|
||||
ctx->table[code].count);
|
||||
} else if (ctx->table_size < LZW_TABLE_ENTRY_MAX) {
|
||||
uint32_t size = ctx->table_size;
|
||||
lzw__table_add_entry(ctx, (code < size) ?
|
||||
ctx->table[code].first :
|
||||
ctx->prev_code_first);
|
||||
|
||||
/* Ensure code size is increased, if needed. */
|
||||
if (size == ctx->code_max && ctx->code_size < LZW_CODE_MAX) {
|
||||
ctx->code_size++;
|
||||
ctx->code_max = (1 << ctx->code_size) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
*used += write_pixels(ctx, output, length, *used, code,
|
||||
ctx->table[code].count);
|
||||
|
||||
/* Store details of this code as "previous code" to the context. */
|
||||
ctx->prev_code_first = ctx->table[code].first;
|
||||
ctx->prev_code_count = ctx->table[code].count;
|
||||
@ -432,20 +462,9 @@ 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,
|
||||
const uint8_t *restrict* const restrict data,
|
||||
uint32_t *restrict used)
|
||||
{
|
||||
*used = 0;
|
||||
*data = ctx->stack_base;
|
||||
return lzw__decode(ctx, ctx->stack_base, sizeof(ctx->stack_base),
|
||||
lzw__write_pixels, used);
|
||||
}
|
||||
|
||||
/* Exported function, documented in lzw.h */
|
||||
lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
|
||||
const uint8_t ** const data,
|
||||
const uint8_t *restrict *const restrict data,
|
||||
uint32_t *restrict used)
|
||||
{
|
||||
*used = 0;
|
||||
|
@ -76,21 +76,6 @@ lzw_result lzw_decode_init(
|
||||
uint32_t compressed_data_pos,
|
||||
uint8_t minimum_code_size);
|
||||
|
||||
/**
|
||||
* Read a single LZW code and write into 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.
|
||||
*
|
||||
* \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.
|
||||
* \return LZW_OK on success, or appropriate error code otherwise.
|
||||
*/
|
||||
lzw_result lzw_decode(struct lzw_ctx *ctx,
|
||||
const uint8_t *restrict *const restrict data,
|
||||
uint32_t *restrict used);
|
||||
|
||||
/**
|
||||
* Read input codes until end of lzw context owned output buffer.
|
||||
*
|
||||
@ -103,7 +88,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
|
||||
* \return LZW_OK on success, or appropriate error code otherwise.
|
||||
*/
|
||||
lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
|
||||
const uint8_t ** const data,
|
||||
const uint8_t *restrict *const restrict data,
|
||||
uint32_t *restrict used);
|
||||
|
||||
/**
|
||||
|
@ -1,23 +1,13 @@
|
||||
--- libnsgif-orig.c 2021-02-28 14:10:41.818557190 +0000
|
||||
+++ libnsgif.c 2021-02-28 14:11:55.942285930 +0000
|
||||
@@ -435,20 +435,15 @@
|
||||
block_size = gif_data[0] + 1;
|
||||
/* Check if the frame data runs off the end of the file */
|
||||
if ((int)(gif_bytes - block_size) < 0) {
|
||||
- /* Try to recover by signaling the end of the gif.
|
||||
- * Once we get garbage data, there is no logical way to
|
||||
- * determine where the next frame is. It's probably
|
||||
- * better to partially load the gif than not at all.
|
||||
- */
|
||||
- if (gif_bytes >= 2) {
|
||||
- gif_data[0] = 0;
|
||||
- gif_data[1] = GIF_TRAILER;
|
||||
- gif_bytes = 1;
|
||||
- ++gif_data;
|
||||
- break;
|
||||
- } else {
|
||||
- return GIF_INSUFFICIENT_FRAME_DATA;
|
||||
- }
|
||||
--- libnsgif.c.orig 2021-04-24 18:33:02.757323861 +0100
|
||||
+++ libnsgif.c 2021-04-24 18:35:14.659860190 +0100
|
||||
@@ -424,20 +424,15 @@
|
||||
block_size = gif_data[0] + 1;
|
||||
/* Check if the frame data runs off the end of the file */
|
||||
if ((int)(gif_bytes - block_size) < 0) {
|
||||
- /* Try to recover by signaling the end of the gif.
|
||||
- * Once we get garbage data, there is no logical way to
|
||||
- * determine where the next frame is. It's probably
|
||||
- * better to partially load the gif than not at all.
|
||||
+ /* jcupitt 15/9/19
|
||||
+ *
|
||||
+ * There was code here to set a TRAILER tag. But this
|
||||
@ -25,8 +15,17 @@
|
||||
+ * libvips, where buffers can be mmaped read only files.
|
||||
+ *
|
||||
+ * Instead, just signal insufficient frame data.
|
||||
+ */
|
||||
*/
|
||||
- if (gif_bytes >= 2) {
|
||||
- gif_data[0] = 0;
|
||||
- gif_data[1] = GIF_TRAILER;
|
||||
- gif_bytes = 1;
|
||||
- ++gif_data;
|
||||
- break;
|
||||
- } else {
|
||||
- return GIF_INSUFFICIENT_FRAME_DATA;
|
||||
- }
|
||||
+ return GIF_INSUFFICIENT_FRAME_DATA;
|
||||
} else {
|
||||
gif_bytes -= block_size;
|
||||
gif_data += block_size;
|
||||
} else {
|
||||
gif_bytes -= block_size;
|
||||
gif_data += block_size;
|
||||
|
Loading…
Reference in New Issue
Block a user