ref: 04004561cba7f208162e121f472f1fdc756423b7
parent: 466be6852e589edac29f9c3dc063df2200daecd4
author: Sebastian Rasmussen <[email protected]>
date: Sun Jun 24 12:00:30 EDT 2018
jbig2dec: Handle immediate generic regions with unknown height.
--- a/jbig2.c
+++ b/jbig2.c
@@ -292,7 +292,7 @@
case JBIG2_FILE_RANDOM_HEADERS:
segment = jbig2_parse_segment_header(ctx, ctx->buf + ctx->buf_rd_ix, ctx->buf_wr_ix - ctx->buf_rd_ix, &header_size);
if (segment == NULL)
- return 0; /* need more data */
+ return 0; /* need more data */
ctx->buf_rd_ix += header_size;
if (ctx->n_segments == ctx->n_segments_max) {
@@ -317,8 +317,48 @@
case JBIG2_FILE_SEQUENTIAL_BODY:
case JBIG2_FILE_RANDOM_BODIES:
segment = ctx->segments[ctx->segment_index];
- if (segment->data_length > ctx->buf_wr_ix - ctx->buf_rd_ix)
- return 0; /* need more data */
+
+ /* immediate generic regions may have unknown size */
+ if (segment->data_length == 0xffffffff && (segment->flags & 63) == 38) {
+ byte *s, *e, *p;
+ int mmr;
+ byte mmr_marker[2] = { 0x00, 0x00 };
+ byte arith_marker[2] = { 0xff, 0xac };
+ byte *desired_marker;
+
+ s = p = ctx->buf + ctx->buf_rd_ix;
+ e = ctx->buf + ctx->buf_wr_ix;
+
+ if (e - p < 18)
+ return 0; /* need more data */
+
+ mmr = p[17] & 1;
+ p += 18;
+ desired_marker = mmr ? mmr_marker : arith_marker;
+
+ /* look for two byte marker */
+ if (e - p < 2)
+ return 0; /* need more data */
+
+ while (p[0] != desired_marker[0] || p[1] != desired_marker[1]) {
+ p++;
+ if (e - p < 2)
+ return 0; /* need more data */
+ }
+ p += 2;
+
+ /* the marker is followed by a four byte row count */
+ if (e - p < 4)
+ return 0; /* need more data */
+ segment->rows = jbig2_get_uint32(p);
+ p += 4;
+
+ segment->data_length = p - s;
+ jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "unknown length determined to be %u", segment->data_length);
+ }
+ else if (segment->data_length > ctx->buf_wr_ix - ctx->buf_rd_ix)
+ return 0; /* need more data */
+
code = jbig2_parse_segment(ctx, segment, ctx->buf + ctx->buf_rd_ix);
ctx->buf_rd_ix += segment->data_length;
ctx->segment_index++;
--- a/jbig2_generic.c
+++ b/jbig2_generic.c
@@ -795,6 +795,7 @@
Jbig2WordStream *ws = NULL;
Jbig2ArithState *as = NULL;
Jbig2ArithCx *GB_stats = NULL;
+ uint32_t height;
/* 7.4.6 */
if (segment->data_length < 18)
@@ -803,6 +804,14 @@
jbig2_get_region_segment_info(&rsi, segment_data);
jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "generic region: %d x %d @ (%d, %d), flags = %02x", rsi.width, rsi.height, rsi.x, rsi.y, rsi.flags);
+ /* 7.4.6.4 */
+ height = rsi.height;
+ if (segment->rows != UINT32_MAX) {
+ if (segment->rows > rsi.height)
+ return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment contains more rows than stated in header");
+ height = segment->rows;
+ }
+
/* 7.4.6.2 */
seg_flags = segment_data[17];
jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "segment flags = %02x", seg_flags);
@@ -831,10 +840,10 @@
params.USESKIP = 0;
memcpy(params.gbat, gbat, gbat_bytes);
- image = jbig2_image_new(ctx, rsi.width, rsi.height);
+ image = jbig2_image_new(ctx, rsi.width, height);
if (image == NULL)
return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to allocate generic image");
- jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "allocated %d x %d image buffer for region decode results", rsi.width, rsi.height);
+ jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "allocated %d x %d image buffer for region decode results", rsi.width, height);
if (params.MMR) {
code = jbig2_decode_generic_mmr(ctx, segment, ¶ms, segment_data + offset, segment->data_length - offset, image);
--- a/jbig2_segment.c
+++ b/jbig2_segment.c
@@ -121,6 +121,7 @@
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number, "segment %d is associated with page %d", result->number, result->page_association);
/* 7.2.7 */
+ result->rows = UINT32_MAX;
result->data_length = jbig2_get_uint32(buf + offset);
*p_header_size = offset + 4;
--- a/jbig2_segment.h
+++ b/jbig2_segment.h
@@ -29,6 +29,7 @@
size_t data_length;
int referred_to_segment_count;
uint32_t *referred_to_segments;
+ uint32_t rows;
void *result;
};