Coverage Report

Created: 2026-09-14 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/sjbig2.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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
/* jbig2decode filter implementation -- hooks in libjbig2dec */
18
19
#include "stdint_.h"
20
#include "memory_.h"
21
#include "stdio_.h" /* sprintf() for debug output */
22
23
#include "gserrors.h"
24
#include "gdebug.h"
25
#include "strimpl.h"
26
#include "sjbig2.h"
27
#include <limits.h>                     /* UINT_MAX */
28
29
/* stream implementation */
30
31
/* The /JBIG2Decode filter is a fairly memory intensive one to begin with,
32
   particularly in the initial jbig2dec library implementation. Furthermore,
33
   as a PDF 1.4 feature, we can assume a fairly large (host-level) machine.
34
   We therefore dispense with the normal Ghostscript memory discipline and
35
   let the library allocate all its resources on the heap. The pointers to
36
   these are not enumerated and so will not be garbage collected. We rely
37
   on our release() proc being called to deallocate state.
38
 */
39
40
private_st_jbig2decode_state(); /* creates a gc object for our state, defined in sjbig2.h */
41
42
/* error callback for jbig2 decoder */
43
static void
44
s_jbig2decode_error(void *callback_data, const char *msg, Jbig2Severity severity,
45
               uint32_t seg_idx)
46
46.0k
{
47
46.0k
    s_jbig2_callback_data_t *error_data = (s_jbig2_callback_data_t *)callback_data;
48
46.0k
    const char *type;
49
46.0k
    char segment[22];
50
51
46.0k
    switch (severity) {
52
35.0k
        case JBIG2_SEVERITY_DEBUG:
53
35.0k
            type = "DEBUG"; break;;
54
4.46k
        case JBIG2_SEVERITY_INFO:
55
4.46k
            type = "info"; break;;
56
6.24k
        case JBIG2_SEVERITY_WARNING:
57
6.24k
            type = "WARNING"; break;;
58
341
        case JBIG2_SEVERITY_FATAL:
59
341
            type = "FATAL ERROR decoding image:";
60
            /* pass the fatal error upstream if possible */
61
341
            if (error_data != NULL) error_data->error = gs_error_ioerror;
62
341
            break;;
63
0
        default: type = "unknown message:"; break;;
64
46.0k
    }
65
46.0k
    if (seg_idx == JBIG2_UNKNOWN_SEGMENT_NUMBER) segment[0] = '\0';
66
18.7k
    else gs_snprintf(segment, sizeof(segment), "(segment 0x%02x)", seg_idx);
67
68
46.0k
    if (error_data)
69
46.0k
    {
70
46.0k
        char *message;
71
46.0k
        int len;
72
73
46.0k
        len = snprintf(NULL, 0, "jbig2dec %s %s %s", type, msg, segment);
74
46.0k
        if (len < 0)
75
0
            return;
76
77
46.0k
        message = (char *)gs_alloc_bytes(error_data->memory, len + 1, "sjbig2decode_error(message)");
78
46.0k
        if (message == NULL)
79
0
            return;
80
81
46.0k
        len = snprintf(message, len + 1, "jbig2dec %s %s %s", type, msg, segment);
82
46.0k
        if (len < 0)
83
0
        {
84
0
            gs_free_object(error_data->memory, message, "s_jbig2decode_error(message)");
85
0
            return;
86
0
        }
87
88
46.0k
        if (error_data->last_message != NULL && strcmp(message, error_data->last_message)) {
89
22.3k
            if (error_data->repeats > 1)
90
1.63k
            {
91
1.63k
                if (error_data->severity == JBIG2_SEVERITY_FATAL || error_data->severity == JBIG2_SEVERITY_WARNING) {
92
39
                    dmlprintf1(error_data->memory, "jbig2dec last message repeated %ld times\n", error_data->repeats);
93
1.59k
                } else {
94
1.59k
                    if_debug1m('w', error_data->memory, "[w] jbig2dec last message repeated %ld times\n", error_data->repeats);
95
1.59k
                }
96
1.63k
            }
97
22.3k
            gs_free_object(error_data->memory, error_data->last_message, "s_jbig2decode_error(last_message)");
98
22.3k
            if (severity == JBIG2_SEVERITY_FATAL || severity == JBIG2_SEVERITY_WARNING) {
99
5.80k
                dmlprintf1(error_data->memory, "%s\n", message);
100
16.5k
            } else {
101
16.5k
                if_debug1m('w', error_data->memory, "[w] %s\n", message);
102
16.5k
            }
103
22.3k
            error_data->last_message = message;
104
22.3k
            error_data->severity = severity;
105
22.3k
            error_data->type = type;
106
22.3k
            error_data->repeats = 0;
107
22.3k
        }
108
23.6k
        else if (error_data->last_message != NULL) {
109
22.9k
            error_data->repeats++;
110
22.9k
            if (error_data->repeats % 1000000 == 0)
111
0
            {
112
0
                if (error_data->severity == JBIG2_SEVERITY_FATAL || error_data->severity == JBIG2_SEVERITY_WARNING) {
113
0
                    dmlprintf1(error_data->memory, "jbig2dec last message repeated %ld times so far\n", error_data->repeats);
114
0
                } else {
115
0
                    if_debug1m('w', error_data->memory, "[w] jbig2dec last message repeated %ld times so far\n", error_data->repeats);
116
0
                }
117
0
            }
118
22.9k
            gs_free_object(error_data->memory, message, "s_jbig2decode_error(message)");
119
22.9k
        }
120
787
        else if (error_data->last_message == NULL) {
121
787
            if (severity == JBIG2_SEVERITY_FATAL || severity == JBIG2_SEVERITY_WARNING) {
122
13
                dmlprintf1(error_data->memory, "%s\n", message);
123
774
            } else {
124
774
                if_debug1m('w', error_data->memory, "[w] %s\n", message);
125
774
            }
126
787
            error_data->last_message = message;
127
787
            error_data->severity = severity;
128
787
            error_data->type = type;
129
787
            error_data->repeats = 0;
130
787
        }
131
46.0k
    }
132
10
    else
133
10
    {
134
/*
135
        FIXME s_jbig2_callback_data_t should be updated so that jbig2_ctx_new is not called
136
        with a NULL argument (see jbig2.h) and we never reach here with a NULL state
137
*/
138
10
        if (severity == JBIG2_SEVERITY_FATAL) {
139
0
            dlprintf3("jbig2dec %s %s %s\n", type, msg, segment);
140
10
        } else {
141
10
            if_debug3('w', "[w] jbig2dec %s %s %s\n", type, msg, segment);
142
10
        }
143
10
    }
144
46.0k
}
145
146
static void
147
s_jbig2decode_flush_errors(void *callback_data)
148
792
{
149
792
    s_jbig2_callback_data_t *error_data = (s_jbig2_callback_data_t *)callback_data;
150
151
792
    if (error_data == NULL)
152
0
        return;
153
154
792
    if (error_data->last_message != NULL) {
155
787
        if (error_data->repeats > 1)
156
0
        {
157
0
            if (error_data->severity == JBIG2_SEVERITY_FATAL || error_data->severity == JBIG2_SEVERITY_WARNING) {
158
0
                dmlprintf1(error_data->memory, "jbig2dec last message repeated %ld times\n", error_data->repeats);
159
0
            } else {
160
0
                if_debug1m('w', error_data->memory, "[w] jbig2dec last message repeated %ld times\n", error_data->repeats);
161
0
            }
162
0
        }
163
787
        gs_free_object(error_data->memory, error_data->last_message, "s_jbig2decode_error(last_message)");
164
787
        error_data->last_message = NULL;
165
787
        error_data->repeats = 0;
166
787
    }
167
792
}
168
169
/* invert the bits in a buffer */
170
/* jbig2 and postscript have different senses of what pixel
171
   value is black, so we must invert the image */
172
static void
173
s_jbig2decode_invert_buffer(unsigned char *buf, size_t length)
174
100k
{
175
100k
    size_t i;
176
177
205M
    for (i = 0; i < length; i++)
178
205M
        *buf++ ^= 0xFF;
179
100k
}
180
181
typedef struct {
182
        Jbig2Allocator allocator;
183
        gs_memory_t *mem;
184
} s_jbig2decode_allocator_t;
185
186
static void *s_jbig2decode_alloc(Jbig2Allocator *_allocator, size_t size)
187
3.91M
{
188
3.91M
        s_jbig2decode_allocator_t *allocator = (s_jbig2decode_allocator_t *) _allocator;
189
3.91M
        if (size > UINT_MAX)
190
2
            return NULL;
191
3.91M
        return gs_alloc_bytes(allocator->mem, size, "s_jbig2decode_alloc");
192
3.91M
}
193
194
static void s_jbig2decode_free(Jbig2Allocator *_allocator, void *p)
195
3.92M
{
196
3.92M
        s_jbig2decode_allocator_t *allocator = (s_jbig2decode_allocator_t *) _allocator;
197
3.92M
        gs_free_object(allocator->mem, p, "s_jbig2decode_free");
198
3.92M
}
199
200
static void *s_jbig2decode_realloc(Jbig2Allocator *_allocator, void *p, size_t size)
201
50
{
202
50
        s_jbig2decode_allocator_t *allocator = (s_jbig2decode_allocator_t *) _allocator;
203
50
        if (size > UINT_MAX)
204
0
            return NULL;
205
50
        return gs_resize_object(allocator->mem, p, size, "s_jbig2decode_realloc");
206
50
}
207
208
/* parse a globals stream packed into a gs_bytestring for us by the postscript
209
   layer and stuff the resulting context into a pointer for use in later decoding */
210
int
211
s_jbig2decode_make_global_data(gs_memory_t *mem, byte *data, uint length, void **result)
212
4
{
213
4
    Jbig2Ctx *ctx = NULL;
214
4
    int code;
215
4
    s_jbig2decode_allocator_t *allocator;
216
217
    /* the cvision encoder likes to include empty global streams */
218
4
    if (length == 0) {
219
0
        if_debug0('w', "[w] ignoring zero-length jbig2 global stream.\n");
220
0
        *result = NULL;
221
0
        return 0;
222
0
    }
223
224
4
    allocator = (s_jbig2decode_allocator_t *) gs_alloc_bytes(mem,
225
4
            sizeof (s_jbig2decode_allocator_t), "s_jbig2_make_global_data");
226
4
    if (allocator == NULL) {
227
0
        *result = NULL;
228
0
        return_error(gs_error_VMerror);
229
0
    }
230
231
4
    allocator->allocator.alloc = s_jbig2decode_alloc;
232
4
    allocator->allocator.free = s_jbig2decode_free;
233
4
    allocator->allocator.realloc = s_jbig2decode_realloc;
234
4
    allocator->mem = mem;
235
236
    /* allocate a context with which to parse our global segments */
237
4
    ctx = jbig2_ctx_new((Jbig2Allocator *) allocator, JBIG2_OPTIONS_EMBEDDED,
238
4
                            NULL, s_jbig2decode_error, NULL);
239
4
    if (ctx == NULL) {
240
0
        gs_free_object(mem, allocator, "s_jbig2_make_global_data");
241
0
        return_error(gs_error_VMerror);
242
0
    }
243
244
    /* parse the global bitstream */
245
4
    code = jbig2_data_in(ctx, data, length);
246
4
    if (code) {
247
        /* error parsing the global stream */
248
0
        allocator = (s_jbig2decode_allocator_t *) jbig2_ctx_free(ctx);
249
0
        gs_free_object(allocator->mem, allocator, "s_jbig2_make_global_data");
250
0
        *result = NULL;
251
0
        return_error(gs_error_ioerror);
252
0
    }
253
254
    /* canonize and store our global state */
255
4
    *result = jbig2_make_global_ctx(ctx);
256
257
4
    return 0; /* todo: check for allocation failure */
258
4
}
259
260
/* release a global ctx pointer */
261
void
262
s_jbig2decode_free_global_data(void *data)
263
4
{
264
4
    Jbig2GlobalCtx *global_ctx = (Jbig2GlobalCtx*)data;
265
4
    s_jbig2decode_allocator_t *allocator;
266
267
4
    allocator = (s_jbig2decode_allocator_t *) jbig2_global_ctx_free(global_ctx);
268
269
4
    gs_free_object(allocator->mem, allocator, "s_jbig2decode_free_global_data");
270
4
}
271
272
/* store a global ctx pointer in our state structure.
273
 * If "gd" is NULL, then this library must free the global context.
274
 * If not-NULL, then it will be memory managed by caller, for example,
275
 * garbage collected in the case of the PS interpreter.
276
 * Currently gpdf will use NULL, and the PDF implemented in the gs interpreter would use
277
 * the garbage collection.
278
 */
279
int
280
s_jbig2decode_set_global_data(stream_state *ss, s_jbig2_global_data_t *gd, void *global_ctx)
281
796
{
282
796
    stream_jbig2decode_state *state = (stream_jbig2decode_state*)ss;
283
796
    state->global_struct = gd;
284
796
    state->global_ctx = global_ctx;
285
796
    return 0;
286
796
}
287
288
/* initialize the steam.
289
   this involves allocating the context structures, and
290
   initializing the global context from the /JBIG2Globals object reference
291
 */
292
static int
293
s_jbig2decode_init(stream_state * ss)
294
792
{
295
792
    stream_jbig2decode_state *const state = (stream_jbig2decode_state *) ss;
296
792
    Jbig2GlobalCtx *global_ctx = state->global_ctx; /* may be NULL */
297
792
    int code = 0;
298
792
    s_jbig2decode_allocator_t *allocator = NULL;
299
300
792
    state->callback_data = (s_jbig2_callback_data_t *)gs_alloc_bytes(
301
792
                                                ss->memory->non_gc_memory,
302
792
                                                sizeof(s_jbig2_callback_data_t),
303
792
            "s_jbig2decode_init(callback_data)");
304
792
    if (state->callback_data) {
305
792
        state->callback_data->memory = ss->memory->non_gc_memory;
306
792
        state->callback_data->error = 0;
307
792
        state->callback_data->last_message = NULL;
308
792
        state->callback_data->repeats = 0;
309
310
792
        allocator = (s_jbig2decode_allocator_t *) gs_alloc_bytes(ss->memory->non_gc_memory, sizeof (s_jbig2decode_allocator_t), "s_jbig2decode_init(allocator)");
311
792
        if (allocator == NULL) {
312
0
                s_jbig2decode_error(state->callback_data, "failed to allocate custom jbig2dec allocator", JBIG2_SEVERITY_FATAL, -1);
313
0
        }
314
792
        else {
315
792
                Jbig2Options options;
316
317
792
                allocator->allocator.alloc = s_jbig2decode_alloc;
318
792
                allocator->allocator.free = s_jbig2decode_free;
319
792
                allocator->allocator.realloc = s_jbig2decode_realloc;
320
792
                allocator->mem = ss->memory->non_gc_memory;
321
322
                /* initialize the decoder with the parsed global context if any */
323
792
#ifdef JBIG2_SUPPORTS_FORGIVING
324
792
                options = JBIG2_OPTIONS_EMBEDDED_FORGIVING;
325
#else
326
                options = JBIG2_OPTIONS_EMBEDDED; /* Old version of JBIG2. Do the best we can. */
327
#endif
328
792
                state->decode_ctx = jbig2_ctx_new((Jbig2Allocator *) allocator, options,
329
792
                             global_ctx, s_jbig2decode_error, state->callback_data);
330
331
792
                if (state->decode_ctx == NULL) {
332
0
                        gs_free_object(allocator->mem, allocator, "s_jbig2decode_release");
333
0
                }
334
335
792
        }
336
337
792
        code = state->callback_data->error;
338
792
    }
339
0
    else {
340
0
        code = gs_error_VMerror;
341
0
    }
342
792
    state->image = 0;
343
344
345
792
    return_error (code);
346
792
}
347
348
/* process a section of the input and return any decoded data.
349
   see strimpl.h for return codes.
350
 */
351
static int
352
s_jbig2decode_process(stream_state * ss, stream_cursor_read * pr,
353
                  stream_cursor_write * pw, bool last)
354
103k
{
355
103k
    stream_jbig2decode_state *const state = (stream_jbig2decode_state *) ss;
356
103k
    Jbig2Image *image = state->image;
357
103k
    size_t in_size = pr->limit - pr->ptr;
358
103k
    size_t out_size = pw->limit - pw->ptr;
359
103k
    int status = 0;
360
361
    /* there will only be a single page image,
362
       so pass all data in before looking for any output.
363
       note that the gs stream library expects offset-by-one
364
       indexing of the buffers, while jbig2dec uses normal 0 indexes */
365
103k
    if (in_size > 0) {
366
        /* pass all available input to the decoder */
367
2.98k
        jbig2_data_in(state->decode_ctx, pr->ptr + 1, in_size);
368
2.98k
        pr->ptr += in_size;
369
        /* simulate end-of-page segment */
370
2.98k
        if (last == 1) {
371
779
            jbig2_complete_page(state->decode_ctx);
372
779
        }
373
        /* handle fatal decoding errors reported through our callback */
374
2.98k
        if (state->callback_data->error) return state->callback_data->error;
375
100k
    } else {
376
        /* Ran out of input, try and terminate cleanly */
377
100k
        if (last == 1) {
378
99.9k
            jbig2_complete_page(state->decode_ctx);
379
99.9k
        }
380
100k
    }
381
103k
    if (out_size > 0) {
382
103k
        if (image == NULL) {
383
            /* see if a page image in available */
384
3.16k
            image = jbig2_page_out(state->decode_ctx);
385
3.16k
            if (image != NULL) {
386
453
                state->image = image;
387
453
                state->offset = 0;
388
453
            }
389
3.16k
        }
390
103k
        if (image != NULL) {
391
            /* copy data out of the decoded image, if any */
392
100k
            size_t image_size = (size_t)image->height*image->stride;
393
100k
            size_t usable = min(image_size - state->offset, out_size);
394
100k
            memcpy(pw->ptr + 1, image->data + state->offset, usable);
395
100k
            s_jbig2decode_invert_buffer(pw->ptr + 1, usable);
396
100k
            state->offset += usable;
397
100k
            pw->ptr += usable;
398
100k
            status = (state->offset < image_size) ? 1 : 0;
399
100k
        }
400
103k
    }
401
402
103k
    return status;
403
103k
}
404
405
/* stream release.
406
   free all our decoder state.
407
 */
408
static void
409
s_jbig2decode_release(stream_state *ss)
410
1.58k
{
411
1.58k
    stream_jbig2decode_state *const state = (stream_jbig2decode_state *) ss;
412
413
1.58k
    if (state->decode_ctx) {
414
792
        s_jbig2decode_allocator_t *allocator = NULL;
415
416
792
        if (state->image) jbig2_release_page(state->decode_ctx, state->image);
417
792
  state->image = NULL;
418
792
        s_jbig2decode_flush_errors(state->callback_data);
419
792
        allocator = (s_jbig2decode_allocator_t *) jbig2_ctx_free(state->decode_ctx);
420
792
  state->decode_ctx = NULL;
421
422
792
        gs_free_object(allocator->mem, allocator, "s_jbig2decode_release");
423
792
    }
424
1.58k
    if (state->callback_data) {
425
792
        gs_memory_t *mem = state->callback_data->memory;
426
792
        gs_free_object(state->callback_data->memory, state->callback_data->last_message, "s_jbig2decode_release(message)");
427
792
        gs_free_object(mem, state->callback_data, "s_jbig2decode_release(callback_data)");
428
792
  state->callback_data = NULL;
429
792
    }
430
1.58k
    if (state->global_struct != NULL) {
431
        /* the interpreter calls jbig2decode_free_global_data() separately */
432
1.58k
    } else {
433
        /* We are responsible for freeing global context */
434
1.58k
        if (state->global_ctx) {
435
4
            s_jbig2decode_free_global_data(state->global_ctx);
436
4
            state->global_ctx = NULL;
437
4
        }
438
1.58k
    }
439
1.58k
}
440
441
void
442
s_jbig2decode_finalize(const gs_memory_t *cmem, void *vptr)
443
792
{
444
792
    (void)cmem;
445
446
792
    s_jbig2decode_release((stream_state *)vptr);
447
792
}
448
449
/* set stream defaults.
450
   this hook exists to avoid confusing the gc with bogus
451
   pointers. we use it similarly just to NULL all the pointers.
452
   (could just be done in _init?)
453
 */
454
static void
455
s_jbig2decode_set_defaults(stream_state *ss)
456
792
{
457
792
    stream_jbig2decode_state *const state = (stream_jbig2decode_state *) ss;
458
459
    /* state->global_ctx is not owned by us */
460
792
    state->global_struct = NULL;
461
792
    state->global_ctx = NULL;
462
792
    state->decode_ctx = NULL;
463
792
    state->image = NULL;
464
792
    state->offset = 0;
465
    state->callback_data = NULL;
466
792
}
467
468
/* stream template */
469
const stream_template s_jbig2decode_template = {
470
    &st_jbig2decode_state,
471
    s_jbig2decode_init,
472
    s_jbig2decode_process,
473
    1, 1, /* min in and out buffer sizes we can handle --should be ~32k,64k for efficiency? */
474
    s_jbig2decode_release,
475
    s_jbig2decode_set_defaults
476
};