Coverage Report

Created: 2026-09-14 07:34

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
46.0k
{
94
46.0k
    char buf[1024];
95
46.0k
    va_list ap;
96
46.0k
    int n;
97
98
46.0k
    va_start(ap, fmt);
99
46.0k
    n = vsnprintf(buf, sizeof(buf), fmt, ap);
100
46.0k
    va_end(ap);
101
46.0k
    if (n < 0 || n == sizeof(buf))
102
0
        ctx->error_callback(ctx->error_callback_data, "failed to generate error string", severity, segment_number);
103
46.0k
    else
104
46.0k
        ctx->error_callback(ctx->error_callback_data, buf, severity, segment_number);
105
46.0k
    return -1;
106
46.0k
}
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
796
{
111
796
    Jbig2Ctx *result;
112
113
796
    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
796
    if (allocator == NULL)
123
0
        allocator = &jbig2_default_allocator;
124
796
    if (error_callback == NULL)
125
0
        error_callback = &jbig2_default_error;
126
127
796
    result = (Jbig2Ctx *) jbig2_alloc(allocator, sizeof(Jbig2Ctx), 1);
128
796
    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
796
    result->allocator = allocator;
134
796
    result->options = options;
135
796
    result->global_ctx = (const Jbig2Ctx *)global_ctx;
136
796
    result->error_callback = error_callback;
137
796
    result->error_callback_data = error_callback_data;
138
139
796
    result->state = (options & JBIG2_OPTIONS_EMBEDDED) ? JBIG2_FILE_SEQUENTIAL_HEADER : JBIG2_FILE_HEADER;
140
796
    if ((options & JBIG2_OPTIONS_EMBEDDED_FORGIVING) == JBIG2_OPTIONS_EMBEDDED_FORGIVING)
141
792
        result->state = JBIG2_FILE_HEADER_MAYBE;
142
143
796
    result->buf = NULL;
144
145
796
    result->n_segments = 0;
146
796
    result->n_segments_max = 16;
147
796
    result->segments = jbig2_new(result, Jbig2Segment *, result->n_segments_max);
148
796
    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
796
    result->segment_index = 0;
154
155
796
    result->current_page = 0;
156
796
    result->max_page_index = 4;
157
796
    result->pages = jbig2_new(result, Jbig2Page, result->max_page_index);
158
796
    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
796
    {
165
796
        uint32_t index;
166
167
3.98k
        for (index = 0; index < result->max_page_index; index++) {
168
3.18k
            result->pages[index].state = JBIG2_PAGE_FREE;
169
3.18k
            result->pages[index].number = 0;
170
3.18k
            result->pages[index].width = 0;
171
3.18k
            result->pages[index].height = 0xffffffff;
172
3.18k
            result->pages[index].x_resolution = 0;
173
3.18k
            result->pages[index].y_resolution = 0;
174
3.18k
            result->pages[index].stripe_size = 0;
175
3.18k
            result->pages[index].striped = 0;
176
3.18k
            result->pages[index].end_row = 0;
177
3.18k
            result->pages[index].flags = 0;
178
3.18k
            result->pages[index].image = NULL;
179
3.18k
        }
180
796
    }
181
182
796
    return result;
183
796
}
184
185
#define get_uint16(bptr)\
186
25.1k
    (((bptr)[0] << 8) | (bptr)[1])
187
#define get_int16(bptr)\
188
1.00k
    (((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
509
{
195
509
    return get_int16(bptr);
196
509
}
197
198
/* coverity[ -tainted_data_return ] */
199
/* coverity[ -tainted_data_argument : arg-0 ] */
200
uint16_t
201
jbig2_get_uint16(const byte *bptr)
202
768
{
203
768
    return get_uint16(bptr);
204
768
}
205
206
/* coverity[ -tainted_data_return ] */
207
/* coverity[ -tainted_data_argument : arg-0 ] */
208
int32_t
209
jbig2_get_int32(const byte *bptr)
210
494
{
211
494
    return ((int32_t) get_int16(bptr) << 16) | get_uint16(bptr + 2);
212
494
}
213
214
/* coverity[ -tainted_data_return ] */
215
/* coverity[ -tainted_data_argument : arg-0 ] */
216
uint32_t
217
jbig2_get_uint32(const byte *bptr)
218
11.4k
{
219
11.4k
    return ((uint32_t) get_uint16(bptr) << 16) | get_uint16(bptr + 2);
220
11.4k
}
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.63k
    while (size < desired)
232
3.02k
        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
2.98k
{
253
2.98k
    if (ctx->buf == NULL) {
254
785
        size_t buf_size = jbig2_find_buffer_size(size);
255
785
        ctx->buf = jbig2_new(ctx, byte, buf_size);
256
785
        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
785
        ctx->buf_size = buf_size;
260
785
        ctx->buf_rd_ix = 0;
261
785
        ctx->buf_wr_ix = 0;
262
2.19k
    } else if (size > ctx->buf_size - ctx->buf_wr_ix) {
263
825
        size_t already = ctx->buf_wr_ix - ctx->buf_rd_ix;
264
265
825
        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
825
        } else {
268
825
            byte *buf;
269
825
            size_t buf_size;
270
271
825
            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
825
            buf_size = jbig2_find_buffer_size(size + already);
276
277
825
            buf = jbig2_new(ctx, byte, buf_size);
278
825
            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
825
            memcpy(buf, ctx->buf + ctx->buf_rd_ix, already);
282
825
            jbig2_free(ctx->allocator, ctx->buf);
283
825
            ctx->buf = buf;
284
825
            ctx->buf_size = buf_size;
285
825
        }
286
825
        ctx->buf_wr_ix -= ctx->buf_rd_ix;
287
825
        ctx->buf_rd_ix = 0;
288
825
    }
289
290
2.98k
    memcpy(ctx->buf + ctx->buf_wr_ix, data, size);
291
2.98k
    ctx->buf_wr_ix += size;
292
293
    /* data has now been added to buffer */
294
295
7.38k
    for (;;) {
296
7.38k
        const byte jbig2_id_string[8] = { 0x97, 0x4a, 0x42, 0x32, 0x0d, 0x0a, 0x1a, 0x0a };
297
7.38k
        Jbig2Segment *segment;
298
7.38k
        size_t header_size;
299
7.38k
        int code;
300
301
7.38k
        switch (ctx->state) {
302
781
        case JBIG2_FILE_HEADER_MAYBE:
303
            /* Accept either a file header, or an embedded file. */
304
781
            if (ctx->buf_wr_ix - ctx->buf_rd_ix < 9)
305
5
                return 0;
306
776
            if (memcmp(ctx->buf + ctx->buf_rd_ix, jbig2_id_string, 8) == 0)
307
2
            {
308
2
                ctx->state = JBIG2_FILE_HEADER;
309
2
                (void)jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "JBIG2 file header ignored in supposedly embedded stream");
310
2
            }
311
774
            else
312
774
                ctx->state = JBIG2_FILE_SEQUENTIAL_HEADER;
313
776
            break;
314
2
        case JBIG2_FILE_HEADER:
315
            /* D.4.1 */
316
2
            if (ctx->buf_wr_ix - ctx->buf_rd_ix < 9)
317
0
                return 0;
318
2
            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
2
            ctx->file_header_flags = ctx->buf[ctx->buf_rd_ix + 8];
322
            /* Check for T.88 amendment 2 */
323
2
            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
2
            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
2
            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
2
            if (!(ctx->file_header_flags & 2)) {        /* number of pages is known */
333
2
                if (ctx->buf_wr_ix - ctx->buf_rd_ix < 13)
334
0
                    return 0;
335
2
                ctx->n_pages = jbig2_get_uint32(ctx->buf + ctx->buf_rd_ix + 9);
336
2
                ctx->buf_rd_ix += 13;
337
2
                if (ctx->n_pages == 1)
338
2
                    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
2
            } 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
2
            if (ctx->file_header_flags & 1) {
347
2
                ctx->state = JBIG2_FILE_SEQUENTIAL_HEADER;
348
2
                jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "file header indicates sequential organization");
349
2
            } 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
2
            break;
354
2.35k
        case JBIG2_FILE_SEQUENTIAL_HEADER:
355
2.35k
        case JBIG2_FILE_RANDOM_HEADERS:
356
2.35k
            segment = jbig2_parse_segment_header(ctx, ctx->buf + ctx->buf_rd_ix, ctx->buf_wr_ix - ctx->buf_rd_ix, &header_size);
357
2.35k
            if (segment == NULL)
358
298
                return 0; /* need more data */
359
2.05k
            ctx->buf_rd_ix += header_size;
360
361
2.05k
            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
2.05k
            ctx->segments[ctx->n_segments++] = segment;
385
2.05k
            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
2.05k
                ctx->state = JBIG2_FILE_SEQUENTIAL_BODY;
390
2.05k
            break;
391
4.24k
        case JBIG2_FILE_SEQUENTIAL_BODY:
392
4.24k
        case JBIG2_FILE_RANDOM_BODIES:
393
4.24k
            segment = ctx->segments[ctx->segment_index];
394
395
            /* immediate generic regions may have unknown size */
396
4.24k
            if (segment->data_length == 0xffffffff && (segment->flags & 63) == 38) {
397
3
                byte *s, *e, *p;
398
3
                int mmr;
399
3
                byte mmr_marker[2] = { 0x00, 0x00 };
400
3
                byte arith_marker[2] = { 0xff, 0xac };
401
3
                byte *desired_marker;
402
403
3
                s = p = ctx->buf + ctx->buf_rd_ix;
404
3
                e = ctx->buf + ctx->buf_wr_ix;
405
406
3
                if (e - p < 18)
407
0
                        return 0; /* need more data */
408
409
3
                mmr = p[17] & 1;
410
3
                p += 18;
411
3
                desired_marker = mmr ? mmr_marker : arith_marker;
412
413
                /* look for two byte marker */
414
3
                if (e - p < 2)
415
0
                    return 0; /* need more data */
416
417
687
                while (p[0] != desired_marker[0] || p[1] != desired_marker[1]) {
418
684
                    p++;
419
684
                    if (e - p < 2)
420
0
                        return 0; /* need more data */
421
684
                }
422
3
                p += 2;
423
424
                /* the marker is followed by a four byte row count */
425
3
                if (e - p < 4)
426
0
                        return 0; /* need more data */
427
3
                segment->rows = jbig2_get_uint32(p);
428
3
                p += 4;
429
430
3
                segment->data_length = (size_t) (p - s);
431
3
                jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "unknown length determined to be %lu", (long) segment->data_length);
432
3
            }
433
4.24k
            else if (segment->data_length > ctx->buf_wr_ix - ctx->buf_rd_ix)
434
2.59k
                    return 0; /* need more data */
435
436
1.65k
            code = jbig2_parse_segment(ctx, segment, ctx->buf + ctx->buf_rd_ix);
437
1.65k
            ctx->buf_rd_ix += segment->data_length;
438
1.65k
            ctx->segment_index++;
439
1.65k
            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.65k
            } else {            /* JBIG2_FILE_SEQUENTIAL_BODY */
443
1.65k
                ctx->state = JBIG2_FILE_SEQUENTIAL_HEADER;
444
1.65k
            }
445
1.65k
            if (code < 0) {
446
88
                ctx->state = JBIG2_FILE_EOF;
447
88
                return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode; treating as end of file");
448
88
            }
449
1.56k
            break;
450
1.56k
        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
7.38k
        }
455
7.38k
    }
456
2.98k
}
457
458
Jbig2Allocator *
459
jbig2_ctx_free(Jbig2Ctx *ctx)
460
796
{
461
796
    Jbig2Allocator *ca;
462
796
    uint32_t i;
463
464
796
    if (ctx == NULL)
465
0
        return NULL;
466
467
796
    ca = ctx->allocator;
468
796
    jbig2_free(ca, ctx->buf);
469
796
    if (ctx->segments != NULL) {
470
2.85k
        for (i = 0; i < ctx->n_segments; i++)
471
2.05k
            jbig2_free_segment(ctx, ctx->segments[i]);
472
796
        jbig2_free(ca, ctx->segments);
473
796
    }
474
475
796
    if (ctx->pages != NULL) {
476
1.59k
        for (i = 0; i <= ctx->current_page; i++)
477
797
            if (ctx->pages[i].image != NULL)
478
509
                jbig2_image_release(ctx, ctx->pages[i].image);
479
796
        jbig2_free(ca, ctx->pages);
480
796
    }
481
482
796
    jbig2_free(ca, ctx);
483
484
796
    return ca;
485
796
}
486
487
Jbig2GlobalCtx *
488
jbig2_make_global_ctx(Jbig2Ctx *ctx)
489
4
{
490
4
    return (Jbig2GlobalCtx *) ctx;
491
4
}
492
493
Jbig2Allocator *
494
jbig2_global_ctx_free(Jbig2GlobalCtx *global_ctx)
495
4
{
496
4
    return jbig2_ctx_free((Jbig2Ctx *) global_ctx);
497
4
}
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.00M
{
513
1.00M
    Jbig2WordStreamBuf *z = (Jbig2WordStreamBuf *) self;
514
1.00M
    uint32_t val = 0;
515
1.00M
    int ret = 0;
516
517
1.00M
    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.00M
    if (offset >= z->size) {
521
648
        *word = 0;
522
648
        return 0;
523
648
    }
524
525
1.00M
    if (offset < z->size) {
526
1.00M
        val = (uint32_t) z->data[offset] << 24;
527
1.00M
        ret++;
528
1.00M
    }
529
1.00M
    if (offset + 1 < z->size) {
530
1.00M
        val |= (uint32_t) z->data[offset + 1] << 16;
531
1.00M
        ret++;
532
1.00M
    }
533
1.00M
    if (offset + 2 < z->size) {
534
1.00M
        val |= (uint32_t) z->data[offset + 2] << 8;
535
1.00M
        ret++;
536
1.00M
    }
537
1.00M
    if (offset + 3 < z->size) {
538
1.00M
        val |= z->data[offset + 3];
539
1.00M
        ret++;
540
1.00M
    }
541
1.00M
    *word = val;
542
1.00M
    return ret;
543
1.00M
}
544
545
Jbig2WordStream *
546
jbig2_word_stream_buf_new(Jbig2Ctx *ctx, const byte *data, size_t size)
547
1.00k
{
548
1.00k
    Jbig2WordStreamBuf *result = jbig2_new(ctx, Jbig2WordStreamBuf, 1);
549
550
1.00k
    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
1.00k
    result->super.get_next_word = jbig2_word_stream_buf_get_next_word;
556
1.00k
    result->data = data;
557
1.00k
    result->size = size;
558
559
1.00k
    return &result->super;
560
1.00k
}
561
562
void
563
jbig2_word_stream_buf_free(Jbig2Ctx *ctx, Jbig2WordStream *ws)
564
1.01k
{
565
1.01k
    jbig2_free(ctx->allocator, ws);
566
1.01k
}
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.92M
{
580
3.92M
    allocator->free(allocator, p);
581
3.92M
}
582
583
void *
584
jbig2_realloc(Jbig2Allocator *allocator, void *p, size_t size, size_t num)
585
50
{
586
    /* check for integer multiplication overflow */
587
50
    if (num > 0 && size >= SIZE_MAX / num)
588
0
        return NULL;
589
50
    return allocator->realloc(allocator, p, size * num);
590
50
}