diff options
Diffstat (limited to 'jbig2dec/jbig2.c')
-rw-r--r-- | jbig2dec/jbig2.c | 116 |
1 files changed, 70 insertions, 46 deletions
diff --git a/jbig2dec/jbig2.c b/jbig2dec/jbig2.c index 3fc6bf86..195a96e2 100644 --- a/jbig2dec/jbig2.c +++ b/jbig2dec/jbig2.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2019 Artifex Software, Inc. +/* Copyright (C) 2001-2020 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or @@ -71,12 +71,12 @@ jbig2_alloc(Jbig2Allocator *allocator, size_t size, size_t num) /* jbig2_free and jbig2_realloc moved to the bottom of this file */ static void -jbig2_default_error(void *data, const char *msg, Jbig2Severity severity, int32_t seg_idx) +jbig2_default_error(void *data, const char *msg, Jbig2Severity severity, uint32_t seg_idx) { /* report only fatal errors by default */ if (severity == JBIG2_SEVERITY_FATAL) { fprintf(stderr, "jbig2 decoder FATAL ERROR: %s", msg); - if (seg_idx != -1) + if (seg_idx != JBIG2_UNKNOWN_SEGMENT_NUMBER) fprintf(stderr, " (segment 0x%02x)", seg_idx); fprintf(stderr, "\n"); fflush(stderr); @@ -84,7 +84,7 @@ jbig2_default_error(void *data, const char *msg, Jbig2Severity severity, int32_t } int -jbig2_error(Jbig2Ctx *ctx, Jbig2Severity severity, int32_t segment_number, const char *fmt, ...) +jbig2_error(Jbig2Ctx *ctx, Jbig2Severity severity, uint32_t segment_number, const char *fmt, ...) { char buf[1024]; va_list ap; @@ -108,7 +108,7 @@ jbig2_ctx_new_imp(Jbig2Allocator *allocator, Jbig2Options options, Jbig2GlobalCt Jbig2Ctx fakectx; fakectx.error_callback = error_callback; fakectx.error_callback_data = error_callback_data; - jbig2_error(&fakectx, JBIG2_SEVERITY_FATAL, -1, "incompatible jbig2dec header (%d.%d) and library (%d.%d) versions", + jbig2_error(&fakectx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "incompatible jbig2dec header (%d.%d) and library (%d.%d) versions", jbig2_version_major, jbig2_version_minor, JBIG2_VERSION_MAJOR, JBIG2_VERSION_MINOR); return NULL; } @@ -120,7 +120,7 @@ jbig2_ctx_new_imp(Jbig2Allocator *allocator, Jbig2Options options, Jbig2GlobalCt result = (Jbig2Ctx *) jbig2_alloc(allocator, sizeof(Jbig2Ctx), 1); if (result == NULL) { - error_callback(error_callback_data, "failed to allocate initial context", JBIG2_SEVERITY_FATAL, -1); + error_callback(error_callback_data, "failed to allocate initial context", JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER); return NULL; } @@ -138,7 +138,7 @@ jbig2_ctx_new_imp(Jbig2Allocator *allocator, Jbig2Options options, Jbig2GlobalCt result->n_segments_max = 16; result->segments = jbig2_new(result, Jbig2Segment *, result->n_segments_max); if (result->segments == NULL) { - error_callback(error_callback_data, "failed to allocate initial segments", JBIG2_SEVERITY_FATAL, -1); + error_callback(error_callback_data, "failed to allocate initial segments", JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER); jbig2_free(allocator, result); return NULL; } @@ -148,13 +148,13 @@ jbig2_ctx_new_imp(Jbig2Allocator *allocator, Jbig2Options options, Jbig2GlobalCt result->max_page_index = 4; result->pages = jbig2_new(result, Jbig2Page, result->max_page_index); if (result->pages == NULL) { - error_callback(error_callback_data, "failed to allocated initial pages", JBIG2_SEVERITY_FATAL, -1); + error_callback(error_callback_data, "failed to allocated initial pages", JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER); jbig2_free(allocator, result->segments); jbig2_free(allocator, result); return NULL; } { - int index; + uint32_t index; for (index = 0; index < result->max_page_index; index++) { result->pages[index].state = JBIG2_PAGE_FREE; @@ -211,6 +211,22 @@ jbig2_get_uint32(const byte *bptr) return ((uint32_t) get_uint16(bptr) << 16) | get_uint16(bptr + 2); } +static size_t +jbig2_find_buffer_size(size_t desired) +{ + const size_t initial_buf_size = 1024; + size_t size = initial_buf_size; + + if (desired == SIZE_MAX) + return SIZE_MAX; + + while (size < desired) + size <<= 1; + + return size; +} + + /** * jbig2_data_in: submit data for decoding * @ctx: The jbig2dec decoder context @@ -226,36 +242,35 @@ jbig2_get_uint32(const byte *bptr) int jbig2_data_in(Jbig2Ctx *ctx, const unsigned char *data, size_t size) { - const size_t initial_buf_size = 1024; - if (ctx->buf == NULL) { - size_t buf_size = initial_buf_size; - - do - buf_size <<= 1; - while (buf_size < size); + size_t buf_size = jbig2_find_buffer_size(size); ctx->buf = jbig2_new(ctx, byte, buf_size); if (ctx->buf == NULL) { - return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate buffer when reading data"); + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate buffer when reading data"); } ctx->buf_size = buf_size; ctx->buf_rd_ix = 0; ctx->buf_wr_ix = 0; - } else if (ctx->buf_wr_ix + size > ctx->buf_size) { - if (ctx->buf_rd_ix <= (ctx->buf_size >> 1) && ctx->buf_wr_ix - ctx->buf_rd_ix + size <= ctx->buf_size) { - memmove(ctx->buf, ctx->buf + ctx->buf_rd_ix, ctx->buf_wr_ix - ctx->buf_rd_ix); + } else if (size > ctx->buf_size - ctx->buf_wr_ix) { + size_t already = ctx->buf_wr_ix - ctx->buf_rd_ix; + + if (ctx->buf_rd_ix <= (ctx->buf_size >> 1) && size <= ctx->buf_size - already) { + memmove(ctx->buf, ctx->buf + ctx->buf_rd_ix, already); } else { byte *buf; - size_t buf_size = initial_buf_size; + size_t buf_size; + + if (already > SIZE_MAX - size) { + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "read data causes buffer to grow too large"); + } + + buf_size = jbig2_find_buffer_size(size + already); - do - buf_size <<= 1; - while (buf_size < ctx->buf_wr_ix - ctx->buf_rd_ix + size); buf = jbig2_new(ctx, byte, buf_size); if (buf == NULL) { - return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate bigger buffer when reading data"); + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate bigger buffer when reading data"); } - memcpy(buf, ctx->buf + ctx->buf_rd_ix, ctx->buf_wr_ix - ctx->buf_rd_ix); + memcpy(buf, ctx->buf + ctx->buf_rd_ix, already); jbig2_free(ctx->allocator, ctx->buf); ctx->buf = buf; ctx->buf_size = buf_size; @@ -263,6 +278,7 @@ jbig2_data_in(Jbig2Ctx *ctx, const unsigned char *data, size_t size) ctx->buf_wr_ix -= ctx->buf_rd_ix; ctx->buf_rd_ix = 0; } + memcpy(ctx->buf + ctx->buf_wr_ix, data, size); ctx->buf_wr_ix += size; @@ -280,17 +296,17 @@ jbig2_data_in(Jbig2Ctx *ctx, const unsigned char *data, size_t size) if (ctx->buf_wr_ix - ctx->buf_rd_ix < 9) return 0; if (memcmp(ctx->buf + ctx->buf_rd_ix, jbig2_id_string, 8)) - return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "not a JBIG2 file header"); + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "not a JBIG2 file header"); /* D.4.2 */ ctx->file_header_flags = ctx->buf[ctx->buf_rd_ix + 8]; /* Check for T.88 amendment 2 */ if (ctx->file_header_flags & 0x04) - return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "file header indicates use of 12 adaptive template pixels (NYI)"); + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "file header indicates use of 12 adaptive template pixels (NYI)"); /* Check for T.88 amendment 3 */ if (ctx->file_header_flags & 0x08) - return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "file header indicates use of colored region segments (NYI)"); + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "file header indicates use of colored region segments (NYI)"); if (ctx->file_header_flags & 0xFC) { - jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "reserved bits (2-7) of file header flags are not zero (0x%02x)", ctx->file_header_flags); + jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "reserved bits (2-7) of file header flags are not zero (0x%02x)", ctx->file_header_flags); } /* D.4.3 */ if (!(ctx->file_header_flags & 2)) { /* number of pages is known */ @@ -299,9 +315,9 @@ jbig2_data_in(Jbig2Ctx *ctx, const unsigned char *data, size_t size) ctx->n_pages = jbig2_get_uint32(ctx->buf + ctx->buf_rd_ix + 9); ctx->buf_rd_ix += 13; if (ctx->n_pages == 1) - jbig2_error(ctx, JBIG2_SEVERITY_INFO, -1, "file header indicates a single page document"); + jbig2_error(ctx, JBIG2_SEVERITY_INFO, JBIG2_UNKNOWN_SEGMENT_NUMBER, "file header indicates a single page document"); else - jbig2_error(ctx, JBIG2_SEVERITY_INFO, -1, "file header indicates a %d page document", ctx->n_pages); + jbig2_error(ctx, JBIG2_SEVERITY_INFO, JBIG2_UNKNOWN_SEGMENT_NUMBER, "file header indicates a %d page document", ctx->n_pages); } else { /* number of pages not known */ ctx->n_pages = 0; ctx->buf_rd_ix += 9; @@ -309,10 +325,10 @@ jbig2_data_in(Jbig2Ctx *ctx, const unsigned char *data, size_t size) /* determine the file organization based on the flags - D.4.2 again */ if (ctx->file_header_flags & 1) { ctx->state = JBIG2_FILE_SEQUENTIAL_HEADER; - jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "file header indicates sequential organization"); + jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "file header indicates sequential organization"); } else { ctx->state = JBIG2_FILE_RANDOM_HEADERS; - jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "file header indicates random-access organization"); + jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "file header indicates random-access organization"); } break; case JBIG2_FILE_SEQUENTIAL_HEADER: @@ -322,9 +338,17 @@ jbig2_data_in(Jbig2Ctx *ctx, const unsigned char *data, size_t size) return 0; /* need more data */ ctx->buf_rd_ix += header_size; - if (ctx->n_segments == ctx->n_segments_max) { + if (ctx->n_segments >= ctx->n_segments_max) { Jbig2Segment **segments; + if (ctx->n_segments_max == UINT32_MAX) { + ctx->state = JBIG2_FILE_EOF; + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "too many segments in jbig2 image"); + } + else if (ctx->n_segments_max > (UINT32_MAX >> 2)) { + ctx->n_segments_max = UINT32_MAX; + } + segments = jbig2_renew(ctx, ctx->segments, Jbig2Segment *, (ctx->n_segments_max <<= 2)); if (segments == NULL) { ctx->state = JBIG2_FILE_EOF; @@ -333,7 +357,6 @@ jbig2_data_in(Jbig2Ctx *ctx, const unsigned char *data, size_t size) ctx->segments = segments; } - ctx->segments[ctx->n_segments++] = segment; if (ctx->state == JBIG2_FILE_RANDOM_HEADERS) { if ((segment->flags & 63) == 51) /* end of file */ @@ -380,7 +403,7 @@ jbig2_data_in(Jbig2Ctx *ctx, const unsigned char *data, size_t size) segment->rows = jbig2_get_uint32(p); p += 4; - segment->data_length = p - s; + segment->data_length = (size_t) (p - s); jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "unknown length determined to be %lu", (long) segment->data_length); } else if (segment->data_length > ctx->buf_wr_ix - ctx->buf_rd_ix) @@ -403,7 +426,7 @@ jbig2_data_in(Jbig2Ctx *ctx, const unsigned char *data, size_t size) case JBIG2_FILE_EOF: if (ctx->buf_rd_ix == ctx->buf_wr_ix) return 0; - return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "garbage beyond end of file"); + return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "garbage beyond end of file"); } } } @@ -412,7 +435,7 @@ Jbig2Allocator * jbig2_ctx_free(Jbig2Ctx *ctx) { Jbig2Allocator *ca; - int i; + uint32_t i; if (ctx == NULL) return NULL; @@ -461,29 +484,30 @@ typedef struct { } Jbig2WordStreamBuf; static int -jbig2_word_stream_buf_get_next_word(Jbig2WordStream *self, size_t offset, uint32_t *word) +jbig2_word_stream_buf_get_next_word(Jbig2Ctx *ctx, Jbig2WordStream *self, size_t offset, uint32_t *word) { Jbig2WordStreamBuf *z = (Jbig2WordStreamBuf *) self; uint32_t val = 0; int ret = 0; - if (self == NULL || word == NULL) - return -1; + if (self == NULL || word == NULL) { + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to read next word of stream because stream or output missing"); + } if (offset >= z->size) { *word = 0; return 0; } if (offset < z->size) { - val |= z->data[offset] << 24; + val = (uint32_t) z->data[offset] << 24; ret++; } if (offset + 1 < z->size) { - val |= z->data[offset + 1] << 16; + val |= (uint32_t) z->data[offset + 1] << 16; ret++; } if (offset + 2 < z->size) { - val |= z->data[offset + 2] << 8; + val |= (uint32_t) z->data[offset + 2] << 8; ret++; } if (offset + 3 < z->size) { @@ -500,7 +524,7 @@ jbig2_word_stream_buf_new(Jbig2Ctx *ctx, const byte *data, size_t size) Jbig2WordStreamBuf *result = jbig2_new(ctx, Jbig2WordStreamBuf, 1); if (result == NULL) { - jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate word stream"); + jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate word stream"); return NULL; } |