summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Drake <michael.drake@codethink.co.uk>2017-04-04 12:53:51 (GMT)
committer Michael Drake <michael.drake@codethink.co.uk>2017-04-05 10:06:23 (GMT)
commitf9797e4ae82090808036b1e1ec4318d0f1bdc456 (patch)
tree5a8d0c86954d5bc46deff890cf7551ab1f4a5989
parent34f3a9a81824dcda5a3e1944d14b0273298ec0c3 (diff)
downloadlibnsgif-f9797e4ae82090808036b1e1ec4318d0f1bdc456.tar.gz
libnsgif-f9797e4ae82090808036b1e1ec4318d0f1bdc456.tar.bz2
New LZW decoder: Real-world fix; continue after dictionary is full.
-rw-r--r--src/libnsgif.c1
-rw-r--r--src/lzw.c27
-rw-r--r--src/lzw.h1
3 files changed, 13 insertions, 16 deletions
diff --git a/src/libnsgif.c b/src/libnsgif.c
index fffbd94..6bf9956 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -566,7 +566,6 @@ static gif_result gif_error_from_lzw(lzw_result l_res)
[LZW_EOI_CODE] = GIF_FRAME_DATA_ERROR,
[LZW_BAD_ICODE] = GIF_FRAME_DATA_ERROR,
[LZW_BAD_CODE] = GIF_FRAME_DATA_ERROR,
- [LZW_BAD_DATA] = GIF_FRAME_DATA_ERROR,
};
return g_res[l_res];
}
diff --git a/src/lzw.c b/src/lzw.c
index b161799..6b7156e 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -301,7 +301,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
lzw_result res;
uint32_t code_new;
uint32_t code_out;
- struct lzw_dictionary_entry *entry;
+ uint8_t last_value;
uint8_t *stack_pos = ctx->stack_base;
uint32_t clear_code = ctx->clear_code;
uint32_t current_entry = ctx->current_entry;
@@ -322,28 +322,28 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
return LZW_EOI_CODE;
}
- if (current_entry >= (1 << LZW_CODE_MAX)) {
- /* No space in table for new entries, only Clear and
- * End of Information codes were allowed. */
- return LZW_BAD_DATA;
- }
-
- entry = table + current_entry;
if (code_new > current_entry) {
/* Code is invalid */
return LZW_BAD_CODE;
} else if (code_new < current_entry) {
/* Code is in table */
code_out = code_new;
- entry->last_value = table[code_new].first_value;
+ last_value = table[code_new].first_value;
} else {
/* Code not in table */
*stack_pos++ = ctx->previous_code_first;
code_out = ctx->previous_code;
- entry->last_value = ctx->previous_code_first;
+ last_value = ctx->previous_code_first;
+ }
+
+ /* Add to the dictionary, only if there's space */
+ if (current_entry < (1 << LZW_CODE_MAX)) {
+ struct lzw_dictionary_entry *entry = table + current_entry;
+ entry->last_value = last_value;
+ entry->first_value = ctx->previous_code_first;
+ entry->previous_entry = ctx->previous_code;
+ ctx->current_entry++;
}
- entry->first_value = ctx->previous_code_first;
- entry->previous_entry = ctx->previous_code;
/* Ensure code size is increased, if needed. */
if (current_entry == ctx->current_code_size_max) {
@@ -353,7 +353,6 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
(1 << ctx->current_code_size) - 1;
}
}
- ctx->current_entry++;
ctx->previous_code_first = table[code_new].first_value;
ctx->previous_code = code_new;
@@ -362,7 +361,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
* Note, in the case of "code not in table", the last entry of the
* current code has already been placed on the stack above. */
while (code_out > clear_code) {
- entry = table + code_out;
+ struct lzw_dictionary_entry *entry = table + code_out;
*stack_pos++ = entry->last_value;
code_out = entry->previous_entry;
}
diff --git a/src/lzw.h b/src/lzw.h
index 5812c0d..385b425 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -34,7 +34,6 @@ typedef enum lzw_result {
LZW_EOI_CODE, /**< Error: End of Information code */
LZW_BAD_ICODE, /**< Error: Bad initial LZW code */
LZW_BAD_CODE, /**< Error: Bad LZW code */
- LZW_BAD_DATA, /**< Error: Bad data */
} lzw_result;