Coverage Report

Created: 2025-08-29 06:54

/src/jbig2dec/jbig2_segment.c
Line
Count
Source (jump to first uncovered line)
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 <stddef.h>             /* size_t */
26
27
#include "jbig2.h"
28
#include "jbig2_priv.h"
29
#include "jbig2_arith.h"
30
#include "jbig2_arith_int.h"
31
#include "jbig2_arith_iaid.h"
32
#include "jbig2_generic.h"
33
#include "jbig2_image.h"
34
#include "jbig2_halftone.h"
35
#include "jbig2_huffman.h"
36
#include "jbig2_page.h"
37
#include "jbig2_refinement.h"
38
#include "jbig2_segment.h"
39
#include "jbig2_symbol_dict.h"
40
#include "jbig2_text.h"
41
42
Jbig2Segment *
43
jbig2_parse_segment_header(Jbig2Ctx *ctx, uint8_t *buf, size_t buf_size, size_t *p_header_size)
44
116k
{
45
116k
    Jbig2Segment *result;
46
116k
    uint8_t rtscarf;
47
116k
    uint32_t rtscarf_long;
48
116k
    uint32_t *referred_to_segments;
49
116k
    uint32_t referred_to_segment_count;
50
116k
    uint32_t referred_to_segment_size;
51
116k
    uint32_t pa_size;
52
116k
    uint32_t offset;
53
54
    /* minimum possible size of a jbig2 segment header */
55
116k
    if (buf_size < 11)
56
517
        return NULL;
57
58
115k
    result = jbig2_new(ctx, Jbig2Segment, 1);
59
115k
    if (result == NULL) {
60
1
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate segment");
61
1
        return NULL;
62
1
    }
63
64
    /* 7.2.2 */
65
115k
    result->number = jbig2_get_uint32(buf);
66
115k
    if (result->number == JBIG2_UNKNOWN_SEGMENT_NUMBER) {
67
8
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "segment number too large");
68
8
        jbig2_free(ctx->allocator, result);
69
8
        return NULL;
70
8
    }
71
72
    /* 7.2.3 */
73
115k
    result->flags = buf[4];
74
75
    /* 7.2.4 referred-to segments */
76
115k
    rtscarf = buf[5];
77
115k
    if ((rtscarf & 0xe0) == 0xe0) {
78
638
        rtscarf_long = jbig2_get_uint32(buf + 5);
79
638
        referred_to_segment_count = rtscarf_long & 0x1fffffff;
80
638
        offset = 5 + 4 + (referred_to_segment_count + 1) / 8;
81
115k
    } else {
82
115k
        referred_to_segment_count = (rtscarf >> 5);
83
115k
        offset = 5 + 1;
84
115k
    }
85
115k
    result->referred_to_segment_count = referred_to_segment_count;
86
87
    /* we now have enough information to compute the full header length */
88
115k
    referred_to_segment_size = result->number <= 256 ? 1 : result->number <= 65536 ? 2 : 4;     /* 7.2.5 */
89
115k
    pa_size = result->flags & 0x40 ? 4 : 1;     /* 7.2.6 */
90
115k
    if (offset + referred_to_segment_count * referred_to_segment_size + pa_size + 4 > buf_size) {
91
567
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number, "attempted to parse segment header with insufficient data, asking for more data");
92
567
        jbig2_free(ctx->allocator, result);
93
567
        return NULL;
94
567
    }
95
96
    /* 7.2.5 */
97
115k
    if (referred_to_segment_count) {
98
10.1k
        uint32_t i;
99
100
10.1k
        referred_to_segments = jbig2_new(ctx, uint32_t, referred_to_segment_count * referred_to_segment_size);
101
10.1k
        if (referred_to_segments == NULL) {
102
1
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, result->number, "failed to allocate referred to segments");
103
1
            jbig2_free(ctx->allocator, result);
104
1
            return NULL;
105
1
        }
106
107
138k
        for (i = 0; i < referred_to_segment_count; i++) {
108
128k
            referred_to_segments[i] =
109
128k
                (referred_to_segment_size == 1) ? buf[offset] :
110
128k
                (referred_to_segment_size == 2) ? jbig2_get_uint16(buf + offset) : jbig2_get_uint32(buf + offset);
111
128k
            offset += referred_to_segment_size;
112
128k
            jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number, "segment %d refers to segment %d", result->number, referred_to_segments[i]);
113
128k
        }
114
10.1k
        result->referred_to_segments = referred_to_segments;
115
105k
    } else {                    /* no referred-to segments */
116
117
105k
        result->referred_to_segments = NULL;
118
105k
    }
119
120
    /* 7.2.6 */
121
115k
    if (pa_size == 4) {
122
1.25k
        result->page_association = jbig2_get_uint32(buf + offset);
123
1.25k
        offset += 4;
124
114k
    } else {
125
114k
        result->page_association = buf[offset++];
126
114k
    }
127
115k
    jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number, "segment %d is associated with page %d", result->number, result->page_association);
128
129
    /* 7.2.7 */
130
115k
    result->rows = UINT32_MAX;
131
115k
    result->data_length = jbig2_get_uint32(buf + offset);
132
115k
    *p_header_size = offset + 4;
133
134
    /* no body parsing results yet */
135
115k
    result->result = NULL;
136
137
115k
    return result;
138
115k
}
139
140
void
141
jbig2_free_segment(Jbig2Ctx *ctx, Jbig2Segment *segment)
142
115k
{
143
115k
    if (segment == NULL)
144
0
        return;
145
146
115k
    jbig2_free(ctx->allocator, segment->referred_to_segments);
147
    /* todo: we need either some separate fields or
148
       a more complex result object rather than this
149
       brittle special casing */
150
115k
    switch (segment->flags & 63) {
151
77.4k
    case 0:                    /* symbol dictionary */
152
77.4k
        if (segment->result != NULL)
153
5.14k
            jbig2_sd_release(ctx, (Jbig2SymbolDict *) segment->result);
154
77.4k
        break;
155
681
    case 4:                    /* intermediate text region */
156
1.01k
    case 40:                   /* intermediate refinement region */
157
1.01k
        if (segment->result != NULL)
158
155
            jbig2_image_release(ctx, (Jbig2Image *) segment->result);
159
1.01k
        break;
160
4.28k
    case 16:                   /* pattern dictionary */
161
4.28k
        if (segment->result != NULL)
162
2.96k
            jbig2_hd_release(ctx, (Jbig2PatternDict *) segment->result);
163
4.28k
        break;
164
1.33k
    case 53:                   /* user-supplied huffman table */
165
1.33k
        if (segment->result != NULL)
166
1.00k
            jbig2_table_free(ctx, (Jbig2HuffmanParams *) segment->result);
167
1.33k
        break;
168
31.1k
    default:
169
        /* anything else is probably an undefined pointer */
170
31.1k
        break;
171
115k
    }
172
115k
    jbig2_free(ctx->allocator, segment);
173
115k
}
174
175
/* find a segment by number */
176
Jbig2Segment *
177
jbig2_find_segment(Jbig2Ctx *ctx, uint32_t number)
178
274k
{
179
274k
    int index, index_max = ctx->segment_index - 1;
180
274k
    const Jbig2Ctx *global_ctx = ctx->global_ctx;
181
182
    /* FIXME: binary search would be better */
183
2.30M
    for (index = index_max; index >= 0; index--)
184
2.14M
        if (ctx->segments[index]->number == number)
185
119k
            return (ctx->segments[index]);
186
187
154k
    if (global_ctx)
188
0
        for (index = global_ctx->segment_index - 1; index >= 0; index--)
189
0
            if (global_ctx->segments[index]->number == number)
190
0
                return (global_ctx->segments[index]);
191
192
    /* didn't find a match */
193
154k
    return NULL;
194
154k
}
195
196
/* parse the generic portion of a region segment data header */
197
void
198
jbig2_get_region_segment_info(Jbig2RegionSegmentInfo *info, const uint8_t *segment_data)
199
19.1k
{
200
    /* 7.4.1 */
201
19.1k
    info->width = jbig2_get_uint32(segment_data);
202
19.1k
    info->height = jbig2_get_uint32(segment_data + 4);
203
19.1k
    info->x = jbig2_get_uint32(segment_data + 8);
204
19.1k
    info->y = jbig2_get_uint32(segment_data + 12);
205
19.1k
    info->flags = segment_data[16];
206
19.1k
    info->op = (Jbig2ComposeOp)(info->flags & 0x7);
207
19.1k
}
208
209
/* dispatch code for extension segment parsing */
210
static int
211
jbig2_parse_extension_segment(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data)
212
433
{
213
433
    uint32_t type;
214
433
    bool reserved;
215
433
    bool necessary;
216
217
433
    if (segment->data_length < 4)
218
4
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
219
220
429
    type = jbig2_get_uint32(segment_data);
221
429
    reserved = type & 0x20000000;
222
    /* Not implemented since this bit
223
    is only needed by encoders.
224
    dependent = type & 0x40000000;
225
    */
226
429
    necessary = type & 0x80000000;
227
228
429
    if (necessary && !reserved) {
229
3
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "extension segment is marked 'necessary' but not 'reserved' contrary to spec");
230
3
    }
231
232
429
    switch (type) {
233
173
    case 0x20000000:
234
173
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "ignoring ASCII comment");
235
173
        break;
236
49
    case 0x20000002:
237
49
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "ignoring UCS-2 comment");
238
49
        break;
239
207
    default:
240
207
        if (necessary) {
241
30
            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unhandled necessary extension segment type 0x%08x", type);
242
177
        } else {
243
177
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unhandled non-necessary extension segment, skipping");
244
177
        }
245
429
    }
246
247
399
    return 0;
248
429
}
249
250
/* dispatch code for profile segment parsing */
251
static int
252
jbig2_parse_profile_segment(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data)
253
316
{
254
316
    uint32_t profiles;
255
316
    uint32_t i;
256
316
    uint32_t profile;
257
316
    int index;
258
316
    const char *requirements;
259
316
    const char *generic_region;
260
316
    const char *refinement_region;
261
316
    const char *halftone_region;
262
316
    const char *numerical_data;
263
264
316
    if (segment->data_length < 4)
265
6
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short");
266
310
    index = 0;
267
268
310
    profiles = jbig2_get_uint32(&segment_data[index]);
269
310
    index += 4;
270
271
78.0k
    for (i = 0; i < profiles; i++) {
272
77.8k
        if (segment->data_length - index < 4)
273
106
            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short to store profile");
274
275
77.7k
        profile = jbig2_get_uint32(&segment_data[index]);
276
77.7k
        index += 4;
277
278
77.7k
        switch (profile) {
279
370
        case 0x00000001:
280
370
            requirements = "All JBIG2 capabilities";
281
370
            generic_region = "No restriction";
282
370
            refinement_region = "No restriction";
283
370
            halftone_region = "No restriction";
284
370
            numerical_data = "No restriction";
285
370
            break;
286
174
        case 0x00000002:
287
174
            requirements = "Maximum compression";
288
174
            generic_region = "Arithmetic only; any template used";
289
174
            refinement_region = "No restriction";
290
174
            halftone_region = "No restriction";
291
174
            numerical_data = "Arithmetic only";
292
174
            break;
293
131
        case 0x00000003:
294
131
            requirements = "Medium complexity and medium compression";
295
131
            generic_region = "Arithmetic only; only 10-pixel and 13-pixel templates";
296
131
            refinement_region = "10-pixel template only";
297
131
            halftone_region = "No skip mask used";
298
131
            numerical_data = "Arithmetic only";
299
131
            break;
300
175
        case 0x00000004:
301
175
            requirements = "Low complexity with progressive lossless capability";
302
175
            generic_region = "MMR only";
303
175
            refinement_region = "10-pixel template only";
304
175
            halftone_region = "No skip mask used";
305
175
            numerical_data = "Huffman only";
306
175
            break;
307
154
        case 0x00000005:
308
154
            requirements = "Low complexity";
309
154
            generic_region = "MMR only";
310
154
            refinement_region = "Not available";
311
154
            halftone_region = "No skip mask used";
312
154
            numerical_data = "Huffman only";
313
154
            break;
314
76.7k
        default:
315
76.7k
            requirements = "Unknown";
316
76.7k
            generic_region = "Unknown";
317
76.7k
            refinement_region = "Unknown";
318
76.7k
            halftone_region = "Unknown";
319
76.7k
            numerical_data = "Unknown";
320
76.7k
            break;
321
77.7k
        }
322
323
77.7k
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "Supported profile: 0x%08x", profile);
324
77.7k
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "  Requirements: %s", requirements);
325
77.7k
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "  Generic region coding: %s", generic_region);
326
77.7k
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "  Refinement region coding: %s", refinement_region);
327
77.7k
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "  Halftone region coding: %s", halftone_region);
328
77.7k
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "  Numerical data: %s", numerical_data);
329
77.7k
    }
330
331
204
    return 0;
332
310
}
333
334
/* general segment parsing dispatch */
335
int
336
jbig2_parse_segment(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data)
337
39.6k
{
338
39.6k
    jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
339
39.6k
                "segment %d, flags=%x, type=%d, data_length=%ld", segment->number, segment->flags, segment->flags & 63, (long) segment->data_length);
340
39.6k
    switch (segment->flags & 63) {
341
6.54k
    case 0:
342
6.54k
        return jbig2_symbol_dictionary(ctx, segment, segment_data);
343
314
    case 4:                    /* intermediate text region */
344
529
    case 6:                    /* immediate text region */
345
2.37k
    case 7:                    /* immediate lossless text region */
346
2.37k
        return jbig2_text_region(ctx, segment, segment_data);
347
3.96k
    case 16:
348
3.96k
        return jbig2_pattern_dictionary(ctx, segment, segment_data);
349
42
    case 20:                   /* intermediate halftone region */
350
98
    case 22:                   /* immediate halftone region */
351
1.62k
    case 23:                   /* immediate lossless halftone region */
352
1.62k
        return jbig2_halftone_region(ctx, segment, segment_data);
353
4
    case 36:
354
4
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unhandled segment type 'intermediate generic region' (NYI)");
355
10.8k
    case 38:                   /* immediate generic region */
356
14.3k
    case 39:                   /* immediate lossless generic region */
357
14.3k
        return jbig2_immediate_generic_region(ctx, segment, segment_data);
358
97
    case 40:                   /* intermediate generic refinement region */
359
575
    case 42:                   /* immediate generic refinement region */
360
855
    case 43:                   /* immediate lossless generic refinement region */
361
855
        return jbig2_refinement_region(ctx, segment, segment_data);
362
4.69k
    case 48:
363
4.69k
        return jbig2_page_info(ctx, segment, segment_data);
364
1.39k
    case 49:
365
1.39k
        return jbig2_end_of_page(ctx, segment, segment_data);
366
521
    case 50:
367
521
        return jbig2_end_of_stripe(ctx, segment, segment_data);
368
439
    case 51:
369
439
        ctx->state = JBIG2_FILE_EOF;
370
439
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "end of file");
371
439
        break;
372
316
    case 52:
373
316
        return jbig2_parse_profile_segment(ctx, segment, segment_data);
374
1.11k
    case 53:                   /* user-supplied huffman table */
375
1.11k
        return jbig2_table(ctx, segment, segment_data);
376
3
    case 54:
377
3
        return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unhandled segment type 'color palette' (NYI)");
378
433
    case 62:
379
433
        return jbig2_parse_extension_segment(ctx, segment, segment_data);
380
1.02k
    default:
381
1.02k
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unknown segment type %d", segment->flags & 63);
382
39.6k
    }
383
1.46k
    return 0;
384
39.6k
}