comparison mupdf-source/thirdparty/jbig2dec/jbig2.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /* Copyright (C) 2001-2023 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
13 CA 94129, USA, for further information.
14 */
15
16 /*
17 jbig2dec
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 #include "os_types.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <string.h>
29 #include <limits.h>
30
31 #include "jbig2.h"
32 #include "jbig2_priv.h"
33 #include "jbig2_image.h"
34 #include "jbig2_page.h"
35 #include "jbig2_segment.h"
36
37 static void *
38 jbig2_default_alloc(Jbig2Allocator *allocator, size_t size)
39 {
40 return malloc(size);
41 }
42
43 static void
44 jbig2_default_free(Jbig2Allocator *allocator, void *p)
45 {
46 free(p);
47 }
48
49 static void *
50 jbig2_default_realloc(Jbig2Allocator *allocator, void *p, size_t size)
51 {
52 return realloc(p, size);
53 }
54
55 static Jbig2Allocator jbig2_default_allocator = {
56 jbig2_default_alloc,
57 jbig2_default_free,
58 jbig2_default_realloc
59 };
60
61 void *
62 jbig2_alloc(Jbig2Allocator *allocator, size_t size, size_t num)
63 {
64 /* Check for integer multiplication overflow when computing
65 the full size of the allocation. */
66 if (num > 0 && size > SIZE_MAX / num)
67 return NULL;
68 return allocator->alloc(allocator, size * num);
69 }
70
71 /* jbig2_free and jbig2_realloc moved to the bottom of this file */
72
73 static void
74 jbig2_default_error(void *data, const char *msg, Jbig2Severity severity, uint32_t seg_idx)
75 {
76 /* report only fatal errors by default */
77 if (severity == JBIG2_SEVERITY_FATAL) {
78 fprintf(stderr, "jbig2 decoder FATAL ERROR: %s", msg);
79 if (seg_idx != JBIG2_UNKNOWN_SEGMENT_NUMBER)
80 fprintf(stderr, " (segment 0x%02x)", seg_idx);
81 fprintf(stderr, "\n");
82 fflush(stderr);
83 }
84 }
85
86 int
87 jbig2_error(Jbig2Ctx *ctx, Jbig2Severity severity, uint32_t segment_number, const char *fmt, ...)
88 {
89 char buf[1024];
90 va_list ap;
91 int n;
92
93 va_start(ap, fmt);
94 n = vsnprintf(buf, sizeof(buf), fmt, ap);
95 va_end(ap);
96 if (n < 0 || n == sizeof(buf))
97 strncpy(buf, "failed to generate error string", sizeof(buf));
98 ctx->error_callback(ctx->error_callback_data, buf, severity, segment_number);
99 return -1;
100 }
101
102 Jbig2Ctx *
103 jbig2_ctx_new_imp(Jbig2Allocator *allocator, Jbig2Options options, Jbig2GlobalCtx *global_ctx, Jbig2ErrorCallback error_callback, void *error_callback_data, int jbig2_version_major, int jbig2_version_minor)
104 {
105 Jbig2Ctx *result;
106
107 if (jbig2_version_major != JBIG2_VERSION_MAJOR || jbig2_version_minor != JBIG2_VERSION_MINOR) {
108 Jbig2Ctx fakectx;
109 fakectx.error_callback = error_callback;
110 fakectx.error_callback_data = error_callback_data;
111 jbig2_error(&fakectx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "incompatible jbig2dec header (%d.%d) and library (%d.%d) versions",
112 jbig2_version_major, jbig2_version_minor, JBIG2_VERSION_MAJOR, JBIG2_VERSION_MINOR);
113 return NULL;
114 }
115
116 if (allocator == NULL)
117 allocator = &jbig2_default_allocator;
118 if (error_callback == NULL)
119 error_callback = &jbig2_default_error;
120
121 result = (Jbig2Ctx *) jbig2_alloc(allocator, sizeof(Jbig2Ctx), 1);
122 if (result == NULL) {
123 error_callback(error_callback_data, "failed to allocate initial context", JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER);
124 return NULL;
125 }
126
127 result->allocator = allocator;
128 result->options = options;
129 result->global_ctx = (const Jbig2Ctx *)global_ctx;
130 result->error_callback = error_callback;
131 result->error_callback_data = error_callback_data;
132
133 result->state = (options & JBIG2_OPTIONS_EMBEDDED) ? JBIG2_FILE_SEQUENTIAL_HEADER : JBIG2_FILE_HEADER;
134
135 result->buf = NULL;
136
137 result->n_segments = 0;
138 result->n_segments_max = 16;
139 result->segments = jbig2_new(result, Jbig2Segment *, result->n_segments_max);
140 if (result->segments == NULL) {
141 error_callback(error_callback_data, "failed to allocate initial segments", JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER);
142 jbig2_free(allocator, result);
143 return NULL;
144 }
145 result->segment_index = 0;
146
147 result->current_page = 0;
148 result->max_page_index = 4;
149 result->pages = jbig2_new(result, Jbig2Page, result->max_page_index);
150 if (result->pages == NULL) {
151 error_callback(error_callback_data, "failed to allocated initial pages", JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER);
152 jbig2_free(allocator, result->segments);
153 jbig2_free(allocator, result);
154 return NULL;
155 }
156 {
157 uint32_t index;
158
159 for (index = 0; index < result->max_page_index; index++) {
160 result->pages[index].state = JBIG2_PAGE_FREE;
161 result->pages[index].number = 0;
162 result->pages[index].width = 0;
163 result->pages[index].height = 0xffffffff;
164 result->pages[index].x_resolution = 0;
165 result->pages[index].y_resolution = 0;
166 result->pages[index].stripe_size = 0;
167 result->pages[index].striped = 0;
168 result->pages[index].end_row = 0;
169 result->pages[index].flags = 0;
170 result->pages[index].image = NULL;
171 }
172 }
173
174 return result;
175 }
176
177 #define get_uint16(bptr)\
178 (((bptr)[0] << 8) | (bptr)[1])
179 #define get_int16(bptr)\
180 (((int)get_uint16(bptr) ^ 0x8000) - 0x8000)
181
182 /* coverity[ -tainted_data_return ] */
183 /* coverity[ -tainted_data_argument : arg-0 ] */
184 int16_t
185 jbig2_get_int16(const byte *bptr)
186 {
187 return get_int16(bptr);
188 }
189
190 /* coverity[ -tainted_data_return ] */
191 /* coverity[ -tainted_data_argument : arg-0 ] */
192 uint16_t
193 jbig2_get_uint16(const byte *bptr)
194 {
195 return get_uint16(bptr);
196 }
197
198 /* coverity[ -tainted_data_return ] */
199 /* coverity[ -tainted_data_argument : arg-0 ] */
200 int32_t
201 jbig2_get_int32(const byte *bptr)
202 {
203 return ((int32_t) get_int16(bptr) << 16) | get_uint16(bptr + 2);
204 }
205
206 /* coverity[ -tainted_data_return ] */
207 /* coverity[ -tainted_data_argument : arg-0 ] */
208 uint32_t
209 jbig2_get_uint32(const byte *bptr)
210 {
211 return ((uint32_t) get_uint16(bptr) << 16) | get_uint16(bptr + 2);
212 }
213
214 static size_t
215 jbig2_find_buffer_size(size_t desired)
216 {
217 const size_t initial_buf_size = 1024;
218 size_t size = initial_buf_size;
219
220 if (desired == SIZE_MAX)
221 return SIZE_MAX;
222
223 while (size < desired)
224 size <<= 1;
225
226 return size;
227 }
228
229
230 /**
231 * jbig2_data_in: submit data for decoding
232 * @ctx: The jbig2dec decoder context
233 * @data: a pointer to the data buffer
234 * @size: the size of the data buffer in bytes
235 *
236 * Copies the specified data into internal storage and attempts
237 * to (continue to) parse it as part of a jbig2 data stream.
238 *
239 * Return code: 0 on success
240 * -1 if there is a parsing error
241 **/
242 int
243 jbig2_data_in(Jbig2Ctx *ctx, const unsigned char *data, size_t size)
244 {
245 if (ctx->buf == NULL) {
246 size_t buf_size = jbig2_find_buffer_size(size);
247 ctx->buf = jbig2_new(ctx, byte, buf_size);
248 if (ctx->buf == NULL) {
249 return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate buffer when reading data");
250 }
251 ctx->buf_size = buf_size;
252 ctx->buf_rd_ix = 0;
253 ctx->buf_wr_ix = 0;
254 } else if (size > ctx->buf_size - ctx->buf_wr_ix) {
255 size_t already = ctx->buf_wr_ix - ctx->buf_rd_ix;
256
257 if (ctx->buf_rd_ix <= (ctx->buf_size >> 1) && size <= ctx->buf_size - already) {
258 memmove(ctx->buf, ctx->buf + ctx->buf_rd_ix, already);
259 } else {
260 byte *buf;
261 size_t buf_size;
262
263 if (already > SIZE_MAX - size) {
264 return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "read data causes buffer to grow too large");
265 }
266
267 buf_size = jbig2_find_buffer_size(size + already);
268
269 buf = jbig2_new(ctx, byte, buf_size);
270 if (buf == NULL) {
271 return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate bigger buffer when reading data");
272 }
273 memcpy(buf, ctx->buf + ctx->buf_rd_ix, already);
274 jbig2_free(ctx->allocator, ctx->buf);
275 ctx->buf = buf;
276 ctx->buf_size = buf_size;
277 }
278 ctx->buf_wr_ix -= ctx->buf_rd_ix;
279 ctx->buf_rd_ix = 0;
280 }
281
282 memcpy(ctx->buf + ctx->buf_wr_ix, data, size);
283 ctx->buf_wr_ix += size;
284
285 /* data has now been added to buffer */
286
287 for (;;) {
288 const byte jbig2_id_string[8] = { 0x97, 0x4a, 0x42, 0x32, 0x0d, 0x0a, 0x1a, 0x0a };
289 Jbig2Segment *segment;
290 size_t header_size;
291 int code;
292
293 switch (ctx->state) {
294 case JBIG2_FILE_HEADER:
295 /* D.4.1 */
296 if (ctx->buf_wr_ix - ctx->buf_rd_ix < 9)
297 return 0;
298 if (memcmp(ctx->buf + ctx->buf_rd_ix, jbig2_id_string, 8))
299 return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "not a JBIG2 file header");
300 /* D.4.2 */
301 ctx->file_header_flags = ctx->buf[ctx->buf_rd_ix + 8];
302 /* Check for T.88 amendment 2 */
303 if (ctx->file_header_flags & 0x04)
304 return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "file header indicates use of 12 adaptive template pixels (NYI)");
305 /* Check for T.88 amendment 3 */
306 if (ctx->file_header_flags & 0x08)
307 return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "file header indicates use of colored region segments (NYI)");
308 if (ctx->file_header_flags & 0xFC) {
309 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);
310 }
311 /* D.4.3 */
312 if (!(ctx->file_header_flags & 2)) { /* number of pages is known */
313 if (ctx->buf_wr_ix - ctx->buf_rd_ix < 13)
314 return 0;
315 ctx->n_pages = jbig2_get_uint32(ctx->buf + ctx->buf_rd_ix + 9);
316 ctx->buf_rd_ix += 13;
317 if (ctx->n_pages == 1)
318 jbig2_error(ctx, JBIG2_SEVERITY_INFO, JBIG2_UNKNOWN_SEGMENT_NUMBER, "file header indicates a single page document");
319 else
320 jbig2_error(ctx, JBIG2_SEVERITY_INFO, JBIG2_UNKNOWN_SEGMENT_NUMBER, "file header indicates a %d page document", ctx->n_pages);
321 } else { /* number of pages not known */
322 ctx->n_pages = 0;
323 ctx->buf_rd_ix += 9;
324 }
325 /* determine the file organization based on the flags - D.4.2 again */
326 if (ctx->file_header_flags & 1) {
327 ctx->state = JBIG2_FILE_SEQUENTIAL_HEADER;
328 jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "file header indicates sequential organization");
329 } else {
330 ctx->state = JBIG2_FILE_RANDOM_HEADERS;
331 jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "file header indicates random-access organization");
332 }
333 break;
334 case JBIG2_FILE_SEQUENTIAL_HEADER:
335 case JBIG2_FILE_RANDOM_HEADERS:
336 segment = jbig2_parse_segment_header(ctx, ctx->buf + ctx->buf_rd_ix, ctx->buf_wr_ix - ctx->buf_rd_ix, &header_size);
337 if (segment == NULL)
338 return 0; /* need more data */
339 ctx->buf_rd_ix += header_size;
340
341 if (ctx->n_segments >= ctx->n_segments_max) {
342 Jbig2Segment **segments;
343
344 if (ctx->n_segments_max == UINT32_MAX) {
345 ctx->state = JBIG2_FILE_EOF;
346 return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "too many segments in jbig2 image");
347 }
348 else if (ctx->n_segments_max > (UINT32_MAX >> 2)) {
349 ctx->n_segments_max = UINT32_MAX;
350 }
351
352 segments = jbig2_renew(ctx, ctx->segments, Jbig2Segment *, (ctx->n_segments_max <<= 2));
353 if (segments == NULL) {
354 ctx->state = JBIG2_FILE_EOF;
355 return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate space for more segments");
356 }
357 ctx->segments = segments;
358 }
359
360 ctx->segments[ctx->n_segments++] = segment;
361 if (ctx->state == JBIG2_FILE_RANDOM_HEADERS) {
362 if ((segment->flags & 63) == 51) /* end of file */
363 ctx->state = JBIG2_FILE_RANDOM_BODIES;
364 } else /* JBIG2_FILE_SEQUENTIAL_HEADER */
365 ctx->state = JBIG2_FILE_SEQUENTIAL_BODY;
366 break;
367 case JBIG2_FILE_SEQUENTIAL_BODY:
368 case JBIG2_FILE_RANDOM_BODIES:
369 segment = ctx->segments[ctx->segment_index];
370
371 /* immediate generic regions may have unknown size */
372 if (segment->data_length == 0xffffffff && (segment->flags & 63) == 38) {
373 byte *s, *e, *p;
374 int mmr;
375 byte mmr_marker[2] = { 0x00, 0x00 };
376 byte arith_marker[2] = { 0xff, 0xac };
377 byte *desired_marker;
378
379 s = p = ctx->buf + ctx->buf_rd_ix;
380 e = ctx->buf + ctx->buf_wr_ix;
381
382 if (e - p < 18)
383 return 0; /* need more data */
384
385 mmr = p[17] & 1;
386 p += 18;
387 desired_marker = mmr ? mmr_marker : arith_marker;
388
389 /* look for two byte marker */
390 if (e - p < 2)
391 return 0; /* need more data */
392
393 while (p[0] != desired_marker[0] || p[1] != desired_marker[1]) {
394 p++;
395 if (e - p < 2)
396 return 0; /* need more data */
397 }
398 p += 2;
399
400 /* the marker is followed by a four byte row count */
401 if (e - p < 4)
402 return 0; /* need more data */
403 segment->rows = jbig2_get_uint32(p);
404 p += 4;
405
406 segment->data_length = (size_t) (p - s);
407 jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "unknown length determined to be %lu", (long) segment->data_length);
408 }
409 else if (segment->data_length > ctx->buf_wr_ix - ctx->buf_rd_ix)
410 return 0; /* need more data */
411
412 code = jbig2_parse_segment(ctx, segment, ctx->buf + ctx->buf_rd_ix);
413 ctx->buf_rd_ix += segment->data_length;
414 ctx->segment_index++;
415 if (ctx->state == JBIG2_FILE_RANDOM_BODIES) {
416 if (ctx->segment_index == ctx->n_segments)
417 ctx->state = JBIG2_FILE_EOF;
418 } else { /* JBIG2_FILE_SEQUENTIAL_BODY */
419 ctx->state = JBIG2_FILE_SEQUENTIAL_HEADER;
420 }
421 if (code < 0) {
422 ctx->state = JBIG2_FILE_EOF;
423 return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode; treating as end of file");
424 }
425 break;
426 case JBIG2_FILE_EOF:
427 if (ctx->buf_rd_ix == ctx->buf_wr_ix)
428 return 0;
429 return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "garbage beyond end of file");
430 }
431 }
432 }
433
434 Jbig2Allocator *
435 jbig2_ctx_free(Jbig2Ctx *ctx)
436 {
437 Jbig2Allocator *ca;
438 uint32_t i;
439
440 if (ctx == NULL)
441 return NULL;
442
443 ca = ctx->allocator;
444 jbig2_free(ca, ctx->buf);
445 if (ctx->segments != NULL) {
446 for (i = 0; i < ctx->n_segments; i++)
447 jbig2_free_segment(ctx, ctx->segments[i]);
448 jbig2_free(ca, ctx->segments);
449 }
450
451 if (ctx->pages != NULL) {
452 for (i = 0; i <= ctx->current_page; i++)
453 if (ctx->pages[i].image != NULL)
454 jbig2_image_release(ctx, ctx->pages[i].image);
455 jbig2_free(ca, ctx->pages);
456 }
457
458 jbig2_free(ca, ctx);
459
460 return ca;
461 }
462
463 Jbig2GlobalCtx *
464 jbig2_make_global_ctx(Jbig2Ctx *ctx)
465 {
466 return (Jbig2GlobalCtx *) ctx;
467 }
468
469 Jbig2Allocator *
470 jbig2_global_ctx_free(Jbig2GlobalCtx *global_ctx)
471 {
472 return jbig2_ctx_free((Jbig2Ctx *) global_ctx);
473 }
474
475 /* I'm not committed to keeping the word stream interface. It's handy
476 when you think you may be streaming your input, but if you're not
477 (as is currently the case), it just adds complexity.
478 */
479
480 typedef struct {
481 Jbig2WordStream super;
482 const byte *data;
483 size_t size;
484 } Jbig2WordStreamBuf;
485
486 static int
487 jbig2_word_stream_buf_get_next_word(Jbig2Ctx *ctx, Jbig2WordStream *self, size_t offset, uint32_t *word)
488 {
489 Jbig2WordStreamBuf *z = (Jbig2WordStreamBuf *) self;
490 uint32_t val = 0;
491 int ret = 0;
492
493 if (self == NULL || word == NULL) {
494 return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to read next word of stream because stream or output missing");
495 }
496 if (offset >= z->size) {
497 *word = 0;
498 return 0;
499 }
500
501 if (offset < z->size) {
502 val = (uint32_t) z->data[offset] << 24;
503 ret++;
504 }
505 if (offset + 1 < z->size) {
506 val |= (uint32_t) z->data[offset + 1] << 16;
507 ret++;
508 }
509 if (offset + 2 < z->size) {
510 val |= (uint32_t) z->data[offset + 2] << 8;
511 ret++;
512 }
513 if (offset + 3 < z->size) {
514 val |= z->data[offset + 3];
515 ret++;
516 }
517 *word = val;
518 return ret;
519 }
520
521 Jbig2WordStream *
522 jbig2_word_stream_buf_new(Jbig2Ctx *ctx, const byte *data, size_t size)
523 {
524 Jbig2WordStreamBuf *result = jbig2_new(ctx, Jbig2WordStreamBuf, 1);
525
526 if (result == NULL) {
527 jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate word stream");
528 return NULL;
529 }
530
531 result->super.get_next_word = jbig2_word_stream_buf_get_next_word;
532 result->data = data;
533 result->size = size;
534
535 return &result->super;
536 }
537
538 void
539 jbig2_word_stream_buf_free(Jbig2Ctx *ctx, Jbig2WordStream *ws)
540 {
541 jbig2_free(ctx->allocator, ws);
542 }
543
544 /* When Memento is in use, the ->free and ->realloc calls get
545 * turned into ->Memento_free and ->Memento_realloc, which is
546 * obviously problematic. Undefine free and realloc here to
547 * avoid this. */
548 #ifdef MEMENTO
549 #undef free
550 #undef realloc
551 #endif
552
553 void
554 jbig2_free(Jbig2Allocator *allocator, void *p)
555 {
556 allocator->free(allocator, p);
557 }
558
559 void *
560 jbig2_realloc(Jbig2Allocator *allocator, void *p, size_t size, size_t num)
561 {
562 /* check for integer multiplication overflow */
563 if (num > 0 && size >= SIZE_MAX / num)
564 return NULL;
565 return allocator->realloc(allocator, p, size * num);
566 }