Coverage Report

Created: 2026-08-08 08:00

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