Coverage Report

Created: 2026-10-28 08:05

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
3.91M
{
67
    /* Check for integer multiplication overflow when computing
68
    the full size of the allocation. */
69
3.91M
    if (num > 0 && size > SIZE_MAX / num)
70
0
        return NULL;
71
3.91M
    return allocator->alloc(allocator, size * num);
72
3.91M
}
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
10.9k
{
94
10.9k
    char buf[1024];
95
10.9k
    va_list ap;
96
10.9k
    int n;
97
98
10.9k
    va_start(ap, fmt);
99
10.9k
    n = vsnprintf(buf, sizeof(buf), fmt, ap);
100
10.9k
    va_end(ap);
101
10.9k
    if (n < 0 || n == sizeof(buf))
102
0
        ctx->error_callback(ctx->error_callback_data, "failed to generate error string", severity, segment_number);
103
10.9k
    else
104
10.9k
        ctx->error_callback(ctx->error_callback_data, buf, severity, segment_number);
105
10.9k
    return -1;
106
10.9k
}
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
627
{
111
627
    Jbig2Ctx *result;
112
113
627
    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
627
    if (allocator == NULL)
123
0
        allocator = &jbig2_default_allocator;
124
627
    if (error_callback == NULL)
125
0
        error_callback = &jbig2_default_error;
126
127
627
    result = (Jbig2Ctx *) jbig2_alloc(allocator, sizeof(Jbig2Ctx), 1);
128
627
    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
627
    result->allocator = allocator;
134
627
    result->options = options;
135
627
    result->global_ctx = (const Jbig2Ctx *)global_ctx;
136
627
    result->error_callback = error_callback;
137
627
    result->error_callback_data = error_callback_data;
138
139
627
    result->state = (options & JBIG2_OPTIONS_EMBEDDED) ? JBIG2_FILE_SEQUENTIAL_HEADER : JBIG2_FILE_HEADER;
140
627
    if ((options & JBIG2_OPTIONS_EMBEDDED_FORGIVING) == JBIG2_OPTIONS_EMBEDDED_FORGIVING)
141
626
        result->state = JBIG2_FILE_HEADER_MAYBE;
142
143
627
    result->buf = NULL;
144
145
627
    result->n_segments = 0;
146
627
    result->n_segments_max = 16;
147
627
    result->segments = jbig2_new(result, Jbig2Segment *, result->n_segments_max);
148
627
    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
627
    result->segment_index = 0;
154
155
627
    result->current_page = 0;
156
627
    result->max_page_index = 4;
157
627
    result->pages = jbig2_new(result, Jbig2Page, result->max_page_index);
158
627
    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
627
    {
165
627
        uint32_t index;
166
167
3.13k
        for (index = 0; index < result->max_page_index; index++) {
168
2.50k
            result->pages[index].state = JBIG2_PAGE_FREE;
169
2.50k
            result->pages[index].number = 0;
170
2.50k
            result->pages[index].width = 0;
171
2.50k
            result->pages[index].height = 0xffffffff;
172
2.50k
            result->pages[index].x_resolution = 0;
173
2.50k
            result->pages[index].y_resolution = 0;
174
2.50k
            result->pages[index].stripe_size = 0;
175
2.50k
            result->pages[index].striped = 0;
176
2.50k
            result->pages[index].end_row = 0;
177
2.50k
            result->pages[index].flags = 0;
178
2.50k
            result->pages[index].image = NULL;
179
2.50k
        }
180
627
    }
181
182
627
    return result;
183
627
}
184
185
#define get_uint16(bptr)\
186
13.3k
    (((bptr)[0] << 8) | (bptr)[1])
187
#define get_int16(bptr)\
188
341
    (((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
319
{
195
319
    return get_int16(bptr);
196
319
}
197
198
/* coverity[ -tainted_data_return ] */
199
/* coverity[ -tainted_data_argument : arg-0 ] */
200
uint16_t
201
jbig2_get_uint16(const byte *bptr)
202
140
{
203
140
    return get_uint16(bptr);
204
140
}
205
206
/* coverity[ -tainted_data_return ] */
207
/* coverity[ -tainted_data_argument : arg-0 ] */
208
int32_t
209
jbig2_get_int32(const byte *bptr)
210
22
{
211
22
    return ((int32_t) get_int16(bptr) << 16) | get_uint16(bptr + 2);
212
22
}
213
214
/* coverity[ -tainted_data_return ] */
215
/* coverity[ -tainted_data_argument : arg-0 ] */
216
uint32_t
217
jbig2_get_uint32(const byte *bptr)
218
6.44k
{
219
6.44k
    return ((uint32_t) get_uint16(bptr) << 16) | get_uint16(bptr + 2);
220
6.44k
}
221
222
static size_t
223
jbig2_find_buffer_size(size_t desired)
224
1.55k
{
225
1.55k
    const size_t initial_buf_size = 1024;
226
1.55k
    size_t size = initial_buf_size;
227
228
1.55k
    if (desired == SIZE_MAX)
229
0
        return SIZE_MAX;
230
231
5.02k
    while (size < desired)
232
3.47k
        size <<= 1;
233
234
1.55k
    return size;
235
1.55k
}
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.15k
{
253
3.15k
    if (ctx->buf == NULL) {
254
616
        size_t buf_size = jbig2_find_buffer_size(size);
255
616
        ctx->buf = jbig2_new(ctx, byte, buf_size);
256
616
        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
616
        ctx->buf_size = buf_size;
260
616
        ctx->buf_rd_ix = 0;
261
616
        ctx->buf_wr_ix = 0;
262
2.54k
    } else if (size > ctx->buf_size - ctx->buf_wr_ix) {
263
942
        size_t already = ctx->buf_wr_ix - ctx->buf_rd_ix;
264
265
942
        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
942
        } else {
268
942
            byte *buf;
269
942
            size_t buf_size;
270
271
942
            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
942
            buf_size = jbig2_find_buffer_size(size + already);
276
277
942
            buf = jbig2_new(ctx, byte, buf_size);
278
942
            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
942
            memcpy(buf, ctx->buf + ctx->buf_rd_ix, already);
282
942
            jbig2_free(ctx->allocator, ctx->buf);
283
942
            ctx->buf = buf;
284
942
            ctx->buf_size = buf_size;
285
942
        }
286
942
        ctx->buf_wr_ix -= ctx->buf_rd_ix;
287
942
        ctx->buf_rd_ix = 0;
288
942
    }
289
290
3.15k
    memcpy(ctx->buf + ctx->buf_wr_ix, data, size);
291
3.15k
    ctx->buf_wr_ix += size;
292
293
    /* data has now been added to buffer */
294
295
5.56k
    for (;;) {
296
5.56k
        const byte jbig2_id_string[8] = { 0x97, 0x4a, 0x42, 0x32, 0x0d, 0x0a, 0x1a, 0x0a };
297
5.56k
        Jbig2Segment *segment;
298
5.56k
        size_t header_size;
299
5.56k
        int code;
300
301
5.56k
        switch (ctx->state) {
302
615
        case JBIG2_FILE_HEADER_MAYBE:
303
            /* Accept either a file header, or an embedded file. */
304
615
            if (ctx->buf_wr_ix - ctx->buf_rd_ix < 9)
305
5
                return 0;
306
610
            if (memcmp(ctx->buf + ctx->buf_rd_ix, jbig2_id_string, 8) == 0)
307
1
            {
308
1
                ctx->state = JBIG2_FILE_HEADER;
309
1
                (void)jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "JBIG2 file header ignored in supposedly embedded stream");
310
1
            }
311
609
            else
312
609
                ctx->state = JBIG2_FILE_SEQUENTIAL_HEADER;
313
610
            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
1
                if (ctx->buf_wr_ix - ctx->buf_rd_ix < 13)
334
0
                    return 0;
335
1
                ctx->n_pages = jbig2_get_uint32(ctx->buf + ctx->buf_rd_ix + 9);
336
1
                ctx->buf_rd_ix += 13;
337
1
                if (ctx->n_pages == 1)
338
1
                    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
0
                ctx->n_pages = 0;
343
0
                ctx->buf_rd_ix += 9;
344
0
            }
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.30k
        case JBIG2_FILE_SEQUENTIAL_HEADER:
355
1.30k
        case JBIG2_FILE_RANDOM_HEADERS:
356
1.30k
            segment = jbig2_parse_segment_header(ctx, ctx->buf + ctx->buf_rd_ix, ctx->buf_wr_ix - ctx->buf_rd_ix, &header_size);
357
1.30k
            if (segment == NULL)
358
197
                return 0; /* need more data */
359
1.10k
            ctx->buf_rd_ix += header_size;
360
361
1.10k
            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.10k
            ctx->segments[ctx->n_segments++] = segment;
385
1.10k
            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.10k
                ctx->state = JBIG2_FILE_SEQUENTIAL_BODY;
390
1.10k
            break;
391
3.64k
        case JBIG2_FILE_SEQUENTIAL_BODY:
392
3.64k
        case JBIG2_FILE_RANDOM_BODIES:
393
3.64k
            segment = ctx->segments[ctx->segment_index];
394
395
            /* immediate generic regions may have unknown size */
396
3.64k
            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.64k
            else if (segment->data_length > ctx->buf_wr_ix - ctx->buf_rd_ix)
434
2.92k
                    return 0; /* need more data */
435
436
721
            code = jbig2_parse_segment(ctx, segment, ctx->buf + ctx->buf_rd_ix);
437
721
            ctx->buf_rd_ix += segment->data_length;
438
721
            ctx->segment_index++;
439
721
            if (ctx->state == JBIG2_FILE_RANDOM_BODIES) {
440
0
                if (ctx->segment_index == ctx->n_segments)
441
0
                    ctx->state = JBIG2_FILE_EOF;
442
721
            } else {            /* JBIG2_FILE_SEQUENTIAL_BODY */
443
721
                ctx->state = JBIG2_FILE_SEQUENTIAL_HEADER;
444
721
            }
445
721
            if (code < 0) {
446
29
                ctx->state = JBIG2_FILE_EOF;
447
29
                return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode; treating as end of file");
448
29
            }
449
692
            break;
450
692
        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
5.56k
        }
455
5.56k
    }
456
3.15k
}
457
458
Jbig2Allocator *
459
jbig2_ctx_free(Jbig2Ctx *ctx)
460
627
{
461
627
    Jbig2Allocator *ca;
462
627
    uint32_t i;
463
464
627
    if (ctx == NULL)
465
0
        return NULL;
466
467
627
    ca = ctx->allocator;
468
627
    jbig2_free(ca, ctx->buf);
469
627
    if (ctx->segments != NULL) {
470
1.73k
        for (i = 0; i < ctx->n_segments; i++)
471
1.10k
            jbig2_free_segment(ctx, ctx->segments[i]);
472
627
        jbig2_free(ca, ctx->segments);
473
627
    }
474
475
627
    if (ctx->pages != NULL) {
476
1.25k
        for (i = 0; i <= ctx->current_page; i++)
477
628
            if (ctx->pages[i].image != NULL)
478
319
                jbig2_image_release(ctx, ctx->pages[i].image);
479
627
        jbig2_free(ca, ctx->pages);
480
627
    }
481
482
627
    jbig2_free(ca, ctx);
483
484
627
    return ca;
485
627
}
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.16M
{
513
1.16M
    Jbig2WordStreamBuf *z = (Jbig2WordStreamBuf *) self;
514
1.16M
    uint32_t val = 0;
515
1.16M
    int ret = 0;
516
517
1.16M
    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.16M
    if (offset >= z->size) {
521
111
        *word = 0;
522
111
        return 0;
523
111
    }
524
525
1.16M
    if (offset < z->size) {
526
1.16M
        val = (uint32_t) z->data[offset] << 24;
527
1.16M
        ret++;
528
1.16M
    }
529
1.16M
    if (offset + 1 < z->size) {
530
1.16M
        val |= (uint32_t) z->data[offset + 1] << 16;
531
1.16M
        ret++;
532
1.16M
    }
533
1.16M
    if (offset + 2 < z->size) {
534
1.16M
        val |= (uint32_t) z->data[offset + 2] << 8;
535
1.16M
        ret++;
536
1.16M
    }
537
1.16M
    if (offset + 3 < z->size) {
538
1.16M
        val |= z->data[offset + 3];
539
1.16M
        ret++;
540
1.16M
    }
541
1.16M
    *word = val;
542
1.16M
    return ret;
543
1.16M
}
544
545
Jbig2WordStream *
546
jbig2_word_stream_buf_new(Jbig2Ctx *ctx, const byte *data, size_t size)
547
362
{
548
362
    Jbig2WordStreamBuf *result = jbig2_new(ctx, Jbig2WordStreamBuf, 1);
549
550
362
    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
362
    result->super.get_next_word = jbig2_word_stream_buf_get_next_word;
556
362
    result->data = data;
557
362
    result->size = size;
558
559
362
    return &result->super;
560
362
}
561
562
void
563
jbig2_word_stream_buf_free(Jbig2Ctx *ctx, Jbig2WordStream *ws)
564
364
{
565
364
    jbig2_free(ctx->allocator, ws);
566
364
}
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
3.91M
{
580
3.91M
    allocator->free(allocator, p);
581
3.91M
}
582
583
void *
584
jbig2_realloc(Jbig2Allocator *allocator, void *p, size_t size, size_t num)
585
5
{
586
    /* check for integer multiplication overflow */
587
5
    if (num > 0 && size >= SIZE_MAX / num)
588
0
        return NULL;
589
5
    return allocator->realloc(allocator, p, size * num);
590
5
}