summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'jbig2dec/jbig2.c')
-rw-r--r--jbig2dec/jbig2.c116
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;
}