shithub: jbig2

Download patch

ref: 1a5457ace287a9c755995e5ec7bc626318966600
parent: 3effe5c33cb3f2013216e960b4f4d8d2822b15fc
author: Sebastian Rasmussen <[email protected]>
date: Wed Mar 11 12:35:53 EDT 2020

jbig2dec: Pass segment numbers as unsigned values to error callback.

According to the JBIG2 specification segments numbers are 32 bit unsigned
integer. Previously any segment numbers larger than INT32_MAX would be passed
as negative numbers.

Some parts of the decoder do not yet know, or do not have access to the
currently decoded segment number, and this needs to be specially indicated.
Therefore jbig2dec appropriates the unlikely segment number 0xffffffff to
indicate an unknown segment number.

This is a change of the public API.

--- a/jbig2.c
+++ b/jbig2.c
@@ -71,12 +71,12 @@
 /* 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 @@
 }
 
 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 @@
         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 @@
 
     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 @@
     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,7 +148,7 @@
     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;
@@ -236,7 +236,7 @@
         while (buf_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;
@@ -253,7 +253,7 @@
             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);
             jbig2_free(ctx->allocator, ctx->buf);
@@ -280,17 +280,17 @@
             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 +299,9 @@
                 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 +309,10 @@
             /* 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:
@@ -403,7 +403,7 @@
         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");
         }
     }
 }
@@ -468,7 +468,7 @@
     int ret = 0;
 
     if (self == NULL || word == NULL) {
-        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to read next word of stream because stream or output missing");
+        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;
@@ -501,7 +501,7 @@
     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;
     }
 
--- a/jbig2.h
+++ b/jbig2.h
@@ -65,7 +65,8 @@
    handler is used which prints fatal errors to the stderr stream. */
 
 /* error callback */
-typedef void (*Jbig2ErrorCallback)(void *data, const char *msg, Jbig2Severity severity, int32_t seg_idx);
+#define JBIG2_UNKNOWN_SEGMENT_NUMBER ~0U
+typedef void (*Jbig2ErrorCallback)(void *data, const char *msg, Jbig2Severity severity, uint32_t seg_idx);
 
 /* memory allocation is likewise done via a set of callbacks so that
    clients can better control memory usage. If a NULL is passed for
--- a/jbig2_arith.c
+++ b/jbig2_arith.c
@@ -60,11 +60,11 @@
 
     /* Treat both errors and reading beyond end of stream as an error. */
     if (as->next_word_bytes < 0) {
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to read from underlying stream during arithmetic decoding");
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to read from underlying stream during arithmetic decoding");
         return -1;
     }
     if (as->next_word_bytes == 0) {
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to read beyond end of underlying stream during arithmetic decoding");
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to read beyond end of underlying stream during arithmetic decoding");
         return -1;
     }
 
@@ -96,10 +96,10 @@
         if (as->next_word_bytes <= 1) {
             as->next_word_bytes = as->ws->get_next_word(ctx, as->ws, as->offset, &as->next_word);
             if (as->next_word_bytes < 0) {
-                return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to check for marker code due to failure in underlying stream during arithmetic decoding");
+                return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to check for marker code due to failure in underlying stream during arithmetic decoding");
             }
             if (as->next_word_bytes == 0) {
-                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to read end of possible terminating marker code, assuming terminating marker code");
+                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to read end of possible terminating marker code, assuming terminating marker code");
                 as->next_word = 0xFF900000;
                 as->next_word_bytes = 2;
                 as->C += 0xFF00;
@@ -153,10 +153,10 @@
         if (as->next_word_bytes == 0) {
             as->next_word_bytes = as->ws->get_next_word(ctx, as->ws, as->offset, &as->next_word);
             if (as->next_word_bytes < 0) {
-                return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to read from underlying stream during arithmetic decoding");
+                return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to read from underlying stream during arithmetic decoding");
             }
             if (as->next_word_bytes == 0) {
-                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to find terminating marker code before end of underlying stream, assuming terminating marker code");
+                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to find terminating marker code before end of underlying stream, assuming terminating marker code");
                 as->next_word = 0xFF900000;
                 as->next_word_bytes = 2;
                 as->C += 0xFF00;
@@ -186,7 +186,7 @@
 
     result = jbig2_new(ctx, Jbig2ArithState, 1);
     if (result == NULL) {
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate arithmetic coding state");
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate arithmetic coding state");
         return NULL;
     }
 
@@ -196,12 +196,12 @@
     result->next_word_bytes = result->ws->get_next_word(ctx, result->ws, result->offset, &result->next_word);
     if (result->next_word_bytes < 0) {
         jbig2_free(ctx->allocator, result);
-        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to initialize underlying stream of arithmetic decoder");
+        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to initialize underlying stream of arithmetic decoder");
         return NULL;
     }
     if (result->next_word_bytes == 0) {
         jbig2_free(ctx->allocator, result);
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to read first byte from underlying stream when initializing arithmetic decoder");
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to read first byte from underlying stream when initializing arithmetic decoder");
         return NULL;
     }
     result->offset += result->next_word_bytes;
@@ -212,7 +212,7 @@
     /* Figure E.20 (2) */
     if (jbig2_arith_bytein(ctx, result) < 0) {
         jbig2_free(ctx->allocator, result);
-        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to read second byte from underlying stream when initializing arithmetic decoder");
+        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to read second byte from underlying stream when initializing arithmetic decoder");
         return NULL;
     }
 
@@ -289,7 +289,7 @@
     /* Figure E.18 */
     do {
         if (as->CT == 0 && jbig2_arith_bytein(ctx, as) < 0) {
-            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to read byte from compressed data stream");
+            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to read byte from compressed data stream");
         }
         as->A <<= 1;
         as->C <<= 1;
@@ -308,7 +308,7 @@
     bool D;
 
     if (index >= MAX_QE_ARRAY_SIZE) {
-        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to determine probability estimate because index out of range");
+        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to determine probability estimate because index out of range");
     }
 
     pqe = &jbig2_arith_Qe[index];
@@ -326,7 +326,7 @@
                 *pcx ^= pqe->mps_xor;
             }
             if (jbig2_arith_renormd(ctx, as) < 0) {
-                return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to renormalize decoder");
+                return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to renormalize decoder");
             }
 
             return D;
@@ -346,7 +346,7 @@
             *pcx ^= pqe->lps_xor;
         }
         if (jbig2_arith_renormd(ctx, as) < 0) {
-            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to renormalize decoder");
+            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to renormalize decoder");
         }
 
         return D;
--- a/jbig2_arith_iaid.c
+++ b/jbig2_arith_iaid.c
@@ -49,7 +49,7 @@
 
     if (sizeof(ctx_size) * 8 <= SBSYMCODELEN)
     {
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "requested IAID arithmetic coding state size too large");
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "requested IAID arithmetic coding state size too large");
         return NULL;
     }
 
@@ -57,7 +57,7 @@
 
     result = jbig2_new(ctx, Jbig2ArithIaidCtx, 1);
     if (result == NULL) {
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate IAID arithmetic coding state");
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate IAID arithmetic coding state");
         return NULL;
     }
 
@@ -66,7 +66,7 @@
     if (result->IAIDx == NULL)
     {
         jbig2_free(ctx->allocator, result);
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate symbol ID in IAID arithmetic coding state");
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate symbol ID in IAID arithmetic coding state");
         return NULL;
     }
 
@@ -90,7 +90,7 @@
     for (i = 0; i < SBSYMCODELEN; i++) {
         D = jbig2_arith_decode(ctx, as, &IAIDx[PREV]);
         if (D < 0)
-            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to decode IAIDx code");
+            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to decode IAIDx code");
 #ifdef VERBOSE
         fprintf(stderr, "IAID%x: D = %d\n", PREV, D);
 #endif
--- a/jbig2_arith_int.c
+++ b/jbig2_arith_int.c
@@ -42,7 +42,7 @@
     Jbig2ArithIntCtx *result = jbig2_new(ctx, Jbig2ArithIntCtx, 1);
 
     if (result == NULL) {
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate arithmetic integer coding state");
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate arithmetic integer coding state");
         return NULL;
     } else {
         memset(result->IAx, 0, sizeof(result->IAx));
@@ -66,35 +66,35 @@
 
     S = jbig2_arith_decode(ctx, as, &IAx[PREV]);
     if (S < 0)
-        return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to decode IAx S");
+        return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to decode IAx S");
     PREV = (PREV << 1) | S;
 
     bit = jbig2_arith_decode(ctx, as, &IAx[PREV]);
     if (bit < 0)
-        return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to decode IAx decision bit 0");
+        return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to decode IAx decision bit 0");
     PREV = (PREV << 1) | bit;
     if (bit) {
         bit = jbig2_arith_decode(ctx, as, &IAx[PREV]);
         if (bit < 0)
-            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to decode IAx decision bit 1");
+            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to decode IAx decision bit 1");
         PREV = (PREV << 1) | bit;
 
         if (bit) {
             bit = jbig2_arith_decode(ctx, as, &IAx[PREV]);
             if (bit < 0)
-                return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to decode IAx decision bit 2");
+                return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to decode IAx decision bit 2");
             PREV = (PREV << 1) | bit;
 
             if (bit) {
                 bit = jbig2_arith_decode(ctx, as, &IAx[PREV]);
                 if (bit < 0)
-                    return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to decode IAx decision bit 3");
+                    return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to decode IAx decision bit 3");
                 PREV = (PREV << 1) | bit;
 
                 if (bit) {
                     bit = jbig2_arith_decode(ctx, as, &IAx[PREV]);
                     if (bit < 0)
-                        return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to decode IAx decision bit 4");
+                        return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to decode IAx decision bit 4");
                     PREV = (PREV << 1) | bit;
 
                     if (bit) {
@@ -125,7 +125,7 @@
     for (i = 0; i < n_tail; i++) {
         bit = jbig2_arith_decode(ctx, as, &IAx[PREV]);
         if (bit < 0)
-            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to decode IAx V bit %d", i);
+            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to decode IAx V bit %d", i);
         PREV = ((PREV << 1) & 511) | (PREV & 256) | bit;
         V = (V << 1) | bit;
     }
--- a/jbig2_halftone.c
+++ b/jbig2_halftone.c
@@ -51,7 +51,7 @@
 
     if (N == 0) {
         /* We've wrapped. */
-        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "params->GRAYMAX out of range");
+        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "params->GRAYMAX out of range");
         return NULL;
     }
 
@@ -60,7 +60,7 @@
     if (new != NULL) {
         new->patterns = jbig2_new(ctx, Jbig2Image *, N);
         if (new->patterns == NULL) {
-            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate pattern in collective bitmap dictionary");
+            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate pattern in collective bitmap dictionary");
             jbig2_free(ctx->allocator, new);
             return NULL;
         }
@@ -72,7 +72,7 @@
         for (i = 0; i < N; i++) {
             new->patterns[i] = jbig2_image_new(ctx, HPW, HPH);
             if (new->patterns[i] == NULL) {
-                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to allocate pattern element image");
+                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate pattern element image");
                 for (j = 0; j < i; j++)
                     jbig2_free(ctx->allocator, new->patterns[j]);
                 jbig2_free(ctx->allocator, new);
@@ -83,7 +83,7 @@
                proper sub image */
             code = jbig2_image_compose(ctx, new->patterns[i], image, -i * (int32_t) HPW, 0, JBIG2_COMPOSE_REPLACE);
             if (code < 0) {
-                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to compose image into collective bitmap dictionary");
+                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to compose image into collective bitmap dictionary");
                 for (j = 0; j < i; j++)
                     jbig2_free(ctx->allocator, new->patterns[j]);
                 jbig2_free(ctx->allocator, new);
@@ -91,7 +91,7 @@
             }
         }
     } else {
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate collective bitmap dictionary");
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate collective bitmap dictionary");
     }
 
     return new;
--- a/jbig2_huffman.c
+++ b/jbig2_huffman.c
@@ -80,18 +80,18 @@
         result->ctx = ctx;
         code = huff_get_next_word(result, 0, &result->this_word);
         if (code < 0) {
-            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to read first huffman word");
+            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to read first huffman word");
             jbig2_huffman_free(ctx, result);
             return NULL;
         }
         code = huff_get_next_word(result, 4, &result->next_word);
         if (code < 0) {
-            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to read second huffman word");
+            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to read second huffman word");
             jbig2_huffman_free(ctx, result);
             return NULL;
         }
     } else {
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate new huffman coding state");
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate new huffman coding state");
         return NULL;
     }
 
@@ -192,7 +192,7 @@
         hs->offset += 4;
         code = huff_get_next_word(hs, hs->offset + 4, &hs->next_word);
         if (code < 0) {
-            return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, -1, "failed to read next huffman word when skipping");
+            return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to read next huffman word when skipping");
         }
         hs->offset_bits -= 32;
         if (hs->offset_bits) {
@@ -216,11 +216,11 @@
     }
     code = huff_get_next_word(hs, hs->offset, &hs->this_word);
     if (code < 0) {
-        return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, -1, "failed to get first huffman word after advancing");
+        return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to get first huffman word after advancing");
     }
     code = huff_get_next_word(hs, hs->offset + 4, &hs->next_word);
     if (code < 0) {
-        return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, -1, "failed to get second huffman word after advancing");
+        return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to get second huffman word after advancing");
     }
     if (hs->offset_bits > 0)
         hs->this_word = (hs->this_word << hs->offset_bits) | (hs->next_word >> (32 - hs->offset_bits));
@@ -248,7 +248,7 @@
 
     if (hs->offset_limit && hs->offset >= hs->offset_limit) {
         *err = -1;
-        return jbig2_error(hs->ctx, JBIG2_SEVERITY_FATAL, -1, "end of jbig2 buffer reached at offset %d", hs->offset);
+        return jbig2_error(hs->ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "end of jbig2 buffer reached at offset %d", hs->offset);
     }
 
     result = this_word >> (32 - bits);
@@ -259,7 +259,7 @@
         hs->this_word = hs->next_word;
         code = huff_get_next_word(hs, hs->offset + 4, &hs->next_word);
         if (code < 0) {
-            return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, -1, "failed to get next huffman word");
+            return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to get next huffman word");
         }
         if (hs->offset_bits) {
             hs->this_word = (hs->this_word << hs->offset_bits) | (hs->next_word >> (32 - hs->offset_bits));
@@ -287,7 +287,7 @@
     if (hs->offset_limit && hs->offset >= hs->offset_limit) {
         if (oob)
             *oob = -1;
-        return jbig2_error(hs->ctx, JBIG2_SEVERITY_FATAL, -1, "end of Jbig2WordStream reached at offset %d", hs->offset);
+        return jbig2_error(hs->ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "end of Jbig2WordStream reached at offset %d", hs->offset);
     }
 
     for (;;) {
@@ -302,7 +302,7 @@
         if (flags == (byte) -1 || PREFLEN == (byte) -1) {
             if (oob)
                 *oob = -1;
-            return jbig2_error(hs->ctx, JBIG2_SEVERITY_FATAL, -1, "encountered unpopulated huffman table entry");
+            return jbig2_error(hs->ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "encountered unpopulated huffman table entry");
         }
 
         next_word = hs->next_word;
@@ -312,7 +312,7 @@
             hs->offset += 4;
             code = huff_get_next_word(hs, hs->offset + 4, &next_word);
             if (code < 0) {
-                return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, -1, "failed to get next huffman word");
+                return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to get next huffman word");
             }
             offset_bits -= 32;
             hs->next_word = next_word;
@@ -343,7 +343,7 @@
             hs->offset += 4;
             code = huff_get_next_word(hs, hs->offset + 4, &next_word);
             if (code < 0) {
-                return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, -1, "failed to get next huffman word");
+                return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to get next huffman word");
             }
             offset_bits -= 32;
             hs->next_word = next_word;
@@ -391,7 +391,7 @@
     LENCOUNT = jbig2_new(ctx, int, lencountcount);
 
     if (LENCOUNT == NULL) {
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate huffman histogram");
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate huffman histogram");
         return NULL;
     }
     memset(LENCOUNT, 0, sizeof(int) * lencountcount);
@@ -414,12 +414,12 @@
         if (lts <= LOG_TABLE_SIZE_MAX && log_table_size < lts)
             log_table_size = lts;
     }
-    jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "constructing huffman table log size %d", log_table_size);
+    jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "constructing huffman table log size %d", log_table_size);
     max_j = 1 << log_table_size;
 
     result = jbig2_new(ctx, Jbig2HuffmanTable, 1);
     if (result == NULL) {
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate result");
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate result");
         jbig2_free(ctx->allocator, LENCOUNT);
         return NULL;
     }
@@ -426,7 +426,7 @@
     result->log_table_size = log_table_size;
     entries = jbig2_new(ctx, Jbig2HuffmanEntry, max_j);
     if (entries == NULL) {
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate result entries");
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate result entries");
         jbig2_free(ctx->allocator, result);
         jbig2_free(ctx->allocator, LENCOUNT);
         return NULL;
@@ -455,7 +455,7 @@
                 byte eflags = 0;
 
                 if (end_j > max_j) {
-                    jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "ran off the end of the entries table! (%d >= %d)", end_j, max_j);
+                    jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "ran off the end of the entries table! (%d >= %d)", end_j, max_j);
                     jbig2_free(ctx->allocator, result->entries);
                     jbig2_free(ctx->allocator, result);
                     jbig2_free(ctx->allocator, LENCOUNT);
--- a/jbig2_image.c
+++ b/jbig2_image.c
@@ -38,13 +38,13 @@
     uint32_t stride;
 
     if (width == 0 || height == 0) {
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to create zero sized image");
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to create zero sized image");
         return NULL;
     }
 
     image = jbig2_new(ctx, Jbig2Image, 1);
     if (image == NULL) {
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate image");
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate image");
         return NULL;
     }
 
@@ -52,13 +52,13 @@
 
     /* check for integer multiplication overflow */
     if (height > (INT32_MAX / stride)) {
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "integer multiplication overflow (stride=%u, height=%u)", stride, height);
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "integer multiplication overflow (stride=%u, height=%u)", stride, height);
         jbig2_free(ctx->allocator, image);
         return NULL;
     }
     image->data = jbig2_new(ctx, uint8_t, (size_t) height * stride);
     if (image->data == NULL) {
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate image data buffer (stride=%u, height=%u)", stride, height);
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate image data buffer (stride=%u, height=%u)", stride, height);
         jbig2_free(ctx->allocator, image);
         return NULL;
     }
@@ -110,13 +110,13 @@
 
         /* check for integer multiplication overflow */
         if (image->height > (INT32_MAX / image->stride)) {
-            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "integer multiplication overflow during resize (stride=%u, height=%u)", image->stride, height);
+            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "integer multiplication overflow during resize (stride=%u, height=%u)", image->stride, height);
             return NULL;
         }
         /* use the same stride, just change the length */
         data = jbig2_renew(ctx, image->data, uint8_t, (size_t) height * image->stride);
         if (data == NULL) {
-            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to reallocate image");
+            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to reallocate image");
             return NULL;
         }
         image->data = data;
@@ -134,7 +134,7 @@
 
         newimage = jbig2_image_new(ctx, width, height);
         if (newimage == NULL) {
-            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to allocate resized image");
+            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate resized image");
             return NULL;
         }
         jbig2_image_clear(ctx, newimage, value);
@@ -141,7 +141,7 @@
 
         code = jbig2_image_compose(ctx, newimage, image, 0, 0, JBIG2_COMPOSE_REPLACE);
         if (code < 0) {
-            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to compose image buffers when resizing");
+            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to compose image buffers when resizing");
             jbig2_image_release(ctx, newimage);
             return NULL;
         }
@@ -351,7 +351,7 @@
         (UINT32_MAX - src->height < (y > 0 ? y : -y)))
     {
 #ifdef JBIG2_DEBUG
-        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "overflow in compose_image");
+        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "overflow in compose_image");
 #endif
         return 0;
     }
@@ -411,13 +411,13 @@
             h = dst->height - y;
     }
 #ifdef JBIG2_DEBUG
-    jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "compositing %dx%d at (%d, %d) after clipping", w, h, x, y);
+    jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "compositing %dx%d at (%d, %d) after clipping", w, h, x, y);
 #endif
 
     /* check for zero clipping region */
     if ((w <= 0) || (h <= 0)) {
 #ifdef JBIG2_DEBUG
-        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "zero clipping region");
+        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "zero clipping region");
 #endif
         return 0;
     }
--- a/jbig2_mmr.c
+++ b/jbig2_mmr.c
@@ -951,11 +951,11 @@
     do {
         val = jbig2_decode_get_code(mmr, table, initial_bits);
         if (val == ERROR)
-            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "invalid code detected in MMR-coded data");
+            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "invalid code detected in MMR-coded data");
         else if (val == UNCOMPRESSED)
-            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "uncompressed code in MMR-coded data");
+            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "uncompressed code in MMR-coded data");
         else if (val == ZEROES)
-            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "zeroes code in MMR-coded data");
+            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "zeroes code in MMR-coded data");
         result += val;
     } while (val >= 64);
 
@@ -988,10 +988,10 @@
             if (c == 0) {
                 white_run = jbig2_decode_get_run(ctx, mmr, jbig2_mmr_white_decode, 8);
                 if (white_run < 0)
-                    return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to decode white H run");
+                    return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to decode white H run");
                 black_run = jbig2_decode_get_run(ctx, mmr, jbig2_mmr_black_decode, 7);
                 if (black_run < 0)
-                    return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to decode black H run");
+                    return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to decode black H run");
                 /* printf ("H %d %d\n", white_run, black_run); */
                 a1 = a0 + white_run;
                 a2 = a1 + black_run;
@@ -1000,7 +1000,7 @@
                 if (a2 > mmr->width)
                     a2 = mmr->width;
                 if (a2 < a1) {
-                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "ignoring negative black H run");
+                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "ignoring negative black H run");
                     a2 = a1;
                 }
                 if (a1 < mmr->width)
@@ -1009,10 +1009,10 @@
             } else {
                 black_run = jbig2_decode_get_run(ctx, mmr, jbig2_mmr_black_decode, 7);
                 if (black_run < 0)
-                    return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to decode black H run");
+                    return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to decode black H run");
                 white_run = jbig2_decode_get_run(ctx, mmr, jbig2_mmr_white_decode, 8);
                 if (white_run < 0)
-                    return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to decode white H run");
+                    return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to decode white H run");
                 /* printf ("H %d %d\n", black_run, white_run); */
                 a1 = a0 + black_run;
                 a2 = a1 + white_run;
@@ -1021,7 +1021,7 @@
                 if (a2 > mmr->width)
                     a2 = mmr->width;
                 if (a1 < a0) {
-                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "ignoring negative white H run");
+                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "ignoring negative white H run");
                     a1 = a0;
                 }
                 if (a0 < mmr->width)
@@ -1037,7 +1037,7 @@
             b2 = jbig2_find_changing_element(ref, b1, mmr->width);
             if (c) {
                 if (b2 < a0) {
-                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "ignoring negative P run");
+                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "ignoring negative P run");
                     b2 = a0;
                 }
                 if (a0 < mmr->width)
@@ -1052,7 +1052,7 @@
             b1 = jbig2_find_changing_element_of_color(ref, a0, mmr->width, !c);
             if (c) {
                 if (b1 < a0) {
-                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "ignoring negative V(0) run");
+                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "ignoring negative V(0) run");
                     b1 = a0;
                 }
                 if (a0 < mmr->width)
@@ -1070,7 +1070,7 @@
                 b1 += 1;
             if (c) {
                 if (b1 < a0) {
-                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "ignoring negative VR(1) run");
+                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "ignoring negative VR(1) run");
                     b1 = a0;
                 }
                 if (a0 < mmr->width)
@@ -1088,7 +1088,7 @@
                 b1 += 2;
             if (c) {
                 if (b1 < a0) {
-                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "ignoring negative VR(2) run");
+                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "ignoring negative VR(2) run");
                     b1 = a0;
                 }
                 if (a0 < mmr->width)
@@ -1106,7 +1106,7 @@
                 b1 += 3;
             if (c) {
                 if (b1 < a0) {
-                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "ignoring negative VR(3) run");
+                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "ignoring negative VR(3) run");
                     b1 = a0;
                 }
                 if (a0 < mmr->width)
@@ -1124,7 +1124,7 @@
                 b1 -= 1;
             if (c) {
                 if (b1 < a0) {
-                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "ignoring negative VL(1) run");
+                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "ignoring negative VL(1) run");
                     b1 = a0;
                 }
                 if (a0 < mmr->width)
@@ -1142,7 +1142,7 @@
                 b1 -= 2;
             if (c) {
                 if (b1 < a0) {
-                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "ignoring negative VL(2) run");
+                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "ignoring negative VL(2) run");
                     b1 = a0;
                 }
                 if (a0 < mmr->width)
@@ -1160,7 +1160,7 @@
                 b1 -= 3;
             if (c) {
                 if (b1 < a0) {
-                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "ignoring negative VL(3) run");
+                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "ignoring negative VL(3) run");
                     b1 = a0;
                 }
                 if (a0 < mmr->width)
@@ -1245,7 +1245,7 @@
         memset(dst, 0, rowstride);
         code = jbig2_decode_mmr_line(ctx, &mmr, ref, dst, &eofb);
         if (code < 0)
-            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to decode halftone mmr line");
+            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to decode halftone mmr line");
         ref = dst;
         dst += rowstride;
     }
--- a/jbig2_page.c
+++ b/jbig2_page.c
@@ -215,7 +215,7 @@
 
     /* ensure image exists before marking page as complete */
     if (ctx->pages[ctx->current_page].image == NULL) {
-        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "page has no image, cannot be completed");
+        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "page has no image, cannot be completed");
     }
 
     ctx->pages[ctx->current_page].state = JBIG2_PAGE_COMPLETE;
@@ -263,11 +263,11 @@
     int code;
 
     if (x > INT32_MAX || y > INT32_MAX)
-        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "unsupported image coordinates");
+        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "unsupported image coordinates");
 
     /* ensure image exists first */
     if (page->image == NULL)
-        return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "page info possibly missing, no image defined");
+        return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "page info possibly missing, no image defined");
 
     /* grow the page to accommodate a new stripe if necessary */
     if (page->striped && page->height == 0xFFFFFFFF) {
@@ -274,16 +274,16 @@
         uint32_t new_height;
 
         if (y > UINT32_MAX - image->height)
-                return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "adding image at coordinate would grow page out of bounds");
+                return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "adding image at coordinate would grow page out of bounds");
         new_height = y + image->height;
 
         if (page->image->height < new_height) {
             Jbig2Image *resized_image = NULL;
 
-            jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "growing page buffer to %u rows to accommodate new stripe", new_height);
+            jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "growing page buffer to %u rows to accommodate new stripe", new_height);
             resized_image = jbig2_image_resize(ctx, page->image, page->image->width, new_height, page->flags & 4);
             if (resized_image == NULL) {
-                return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "unable to resize image to accommodate new stripe");
+                return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "unable to resize image to accommodate new stripe");
             }
             page->image = resized_image;
         }
@@ -291,7 +291,7 @@
 
     code = jbig2_image_compose(ctx, page->image, image, x, y, op);
     if (code < 0)
-        return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to compose image with page");
+        return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to compose image with page");
 
     return 0;
 }
@@ -320,12 +320,12 @@
             uint32_t page_number = ctx->pages[index].number;
 
             if (img == NULL) {
-                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "page %d returned with no associated image", page_number);
+                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "page %d returned with no associated image", page_number);
                 continue;
             }
 
             ctx->pages[index].state = JBIG2_PAGE_RETURNED;
-            jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "page %d returned to the client", page_number);
+            jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "page %d returned to the client", page_number);
             return jbig2_image_reference(ctx, img);
         }
     }
@@ -350,11 +350,11 @@
         if (ctx->pages[index].image == image) {
             jbig2_image_release(ctx, image);
             ctx->pages[index].state = JBIG2_PAGE_RELEASED;
-            jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "page %d released by the client", ctx->pages[index].number);
+            jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "page %d released by the client", ctx->pages[index].number);
             return;
         }
     }
 
     /* no matching pages */
-    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to release unknown page");
+    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to release unknown page");
 }
--- a/jbig2_priv.h
+++ b/jbig2_priv.h
@@ -125,7 +125,7 @@
 
 #define jbig2_renew(ctx, p, t, size) ((t *)jbig2_realloc(ctx->allocator, (p), size, sizeof(t)))
 
-int jbig2_error(Jbig2Ctx *ctx, Jbig2Severity severity, int32_t seg_idx, const char *fmt, ...)
+int jbig2_error(Jbig2Ctx *ctx, Jbig2Severity severity, uint32_t seg_idx, const char *fmt, ...)
 #ifdef __GNUC__
     __attribute__ ((format (__printf__, 4, 5)))
 #endif
--- a/jbig2_refinement.c
+++ b/jbig2_refinement.c
@@ -312,19 +312,19 @@
     if (params->GRTEMPLATE == 0 &&
         (pixel_outside_field(params->grat[0], params->grat[1]) ||
         refpixel_outside_field(params->grat[2], params->grat[3])))
-        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER,
                            "adaptive template pixel is out of field");
 
     for (y = 0; y < GRH; y++) {
         int bit = jbig2_arith_decode(ctx, as, &GR_stats[start_context]);
         if (bit < 0)
-            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to decode arithmetic code when handling refinement TPGRON1");
+            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to decode arithmetic code when handling refinement TPGRON1");
         LTP ^= bit;
         if (!LTP) {
             for (x = 0; x < GRW; x++) {
                 bit = jbig2_arith_decode(ctx, as, &GR_stats[mkctx(params, image, x, y)]);
                 if (bit < 0)
-                    return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to decode arithmetic code when handling refinement TPGRON1");
+                    return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to decode arithmetic code when handling refinement TPGRON1");
                 jbig2_image_set_pixel(image, x, y, bit);
             }
         } else {
@@ -333,7 +333,7 @@
                 if (iv < 0) {
                     int bit = jbig2_arith_decode(ctx, as, &GR_stats[mkctx(params, image, x, y)]);
                     if (bit < 0)
-                        return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to decode arithmetic code when handling refinement TPGRON1");
+                        return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to decode arithmetic code when handling refinement TPGRON1");
                     jbig2_image_set_pixel(image, x, y, bit);
                 } else
                     jbig2_image_set_pixel(image, x, y, iv);
--- a/jbig2_segment.c
+++ b/jbig2_segment.c
@@ -57,12 +57,17 @@
 
     result = jbig2_new(ctx, Jbig2Segment, 1);
     if (result == NULL) {
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate segment");
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate segment");
         return NULL;
     }
 
     /* 7.2.2 */
     result->number = jbig2_get_uint32(buf);
+    if (result->number == JBIG2_UNKNOWN_SEGMENT_NUMBER) {
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "segment number too large");
+        jbig2_free(ctx->allocator, result);
+        return NULL;
+    }
 
     /* 7.2.3 */
     result->flags = buf[4];
--- a/jbig2_symbol_dict.c
+++ b/jbig2_symbol_dict.c
@@ -102,7 +102,7 @@
         new_dict->glyphs = jbig2_new(ctx, Jbig2Image *, n_symbols);
         new_dict->n_symbols = n_symbols;
     } else {
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate new empty symbol dictionary");
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate new empty symbol dictionary");
         return NULL;
     }
 
@@ -109,7 +109,7 @@
     if (new_dict->glyphs != NULL) {
         memset(new_dict->glyphs, 0, n_symbols * sizeof(Jbig2Image *));
     } else if (new_dict->n_symbols > 0) {
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate glyphs for new empty symbol dictionary");
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate glyphs for new empty symbol dictionary");
         jbig2_free(ctx->allocator, new_dict);
         return NULL;
     }
@@ -215,7 +215,7 @@
             for (j = 0; j < dicts[i]->n_symbols; j++)
                 new_dict->glyphs[k++] = jbig2_image_reference(ctx, dicts[i]->glyphs[j]);
     } else {
-        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to allocate new symbol dictionary");
+        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate new symbol dictionary");
     }
 
     return new_dict;
--- a/jbig2dec.c
+++ b/jbig2dec.c
@@ -113,7 +113,7 @@
         if (allocator->ctx) {
             size_t limit_mb = allocator->memory_limit / MBYTE;
             size_t peak_mb = allocator->memory_peak / MBYTE;
-            jbig2_error(allocator->ctx, JBIG2_SEVERITY_DEBUG, -1, "memory: limit: %lu Mbyte peak usage: %lu Mbyte", limit_mb, peak_mb);
+            jbig2_error(allocator->ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "memory: limit: %lu Mbyte peak usage: %lu Mbyte", limit_mb, peak_mb);
         }
     }
 
@@ -181,7 +181,7 @@
         if (allocator->ctx) {
             size_t limit_mb = allocator->memory_limit / MBYTE;
             size_t peak_mb = allocator->memory_peak / MBYTE;
-            jbig2_error(allocator->ctx, JBIG2_SEVERITY_DEBUG, -1, "memory: limit: %lu Mbyte peak usage: %lu Mbyte", limit_mb, peak_mb);
+            jbig2_error(allocator->ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "memory: limit: %lu Mbyte peak usage: %lu Mbyte", limit_mb, peak_mb);
         }
     }
 
@@ -372,7 +372,7 @@
 }
 
 static void
-error_callback(void *error_callback_data, const char *buf, Jbig2Severity severity, int32_t seg_idx)
+error_callback(void *error_callback_data, const char *buf, Jbig2Severity severity, uint32_t seg_idx)
 {
     jbig2dec_error_callback_state_t *state = (jbig2dec_error_callback_state_t *) error_callback_data;
     char *type;
@@ -407,7 +407,7 @@
     strlen("jbig2dec ") +
     strlen(type) + strlen(" ") +
     strlen(buf) + strlen(" ") +
-    strlen("(segment 0x") + strlen("2147483648") + strlen(")") +
+    strlen("(segment 0x") + strlen("4294967296") + strlen(")") +
     1 for trailing NUL. The constant parts amount to 45 bytes. */
     len = 45;
     len += strlen(type);
@@ -417,7 +417,7 @@
     if (message == NULL) {
         return;
     }
-    if (seg_idx == -1)
+    if (seg_idx == JBIG2_UNKNOWN_SEGMENT_NUMBER)
         snprintf(message, len + 1, "jbig2dec %s %s", type, buf);
     else
         snprintf(message, len + 1, "jbig2dec %s %s (segment 0x%02x)", type, buf, seg_idx);
@@ -683,7 +683,7 @@
             with parse errors. */
             code = jbig2_complete_page(ctx);
             if (code < 0) {
-                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "unable to complete page");
+                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "unable to complete page");
                 goto cleanup;
             }
 
@@ -739,7 +739,7 @@
     if (allocator != NULL && allocator->ctx != NULL) {
         size_t limit_mb = allocator->memory_limit / MBYTE;
         size_t peak_mb = allocator->memory_peak / MBYTE;
-        jbig2_error(allocator->ctx, JBIG2_SEVERITY_DEBUG, -1, "memory: limit: %lu Mbyte peak usage: %lu Mbyte", limit_mb, peak_mb);
+        jbig2_error(allocator->ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "memory: limit: %lu Mbyte peak usage: %lu Mbyte", limit_mb, peak_mb);
     }
 
     /* fin */