Coverage Report

Created: 2025-08-26 06:48

/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
122k
{
45
122k
    Jbig2Segment *result;
46
122k
    uint8_t rtscarf;
47
122k
    uint32_t rtscarf_long;
48
122k
    uint32_t *referred_to_segments;
49
122k
    uint32_t referred_to_segment_count;
50
122k
    uint32_t referred_to_segment_size;
51
122k
    uint32_t pa_size;
52
122k
    uint32_t offset;
53
54
    /* minimum possible size of a jbig2 segment header */
55
122k
    if (buf_size < 11)
56
570
        return NULL;
57
58
122k
    result = jbig2_new(ctx, Jbig2Segment, 1);
59
122k
    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
122k
    result->number = jbig2_get_uint32(buf);
66
122k
    if (result->number == JBIG2_UNKNOWN_SEGMENT_NUMBER) {
67
18
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "segment number too large");
68
18
        jbig2_free(ctx->allocator, result);
69
18
        return NULL;
70
18
    }
71
72
    /* 7.2.3 */
73
122k
    result->flags = buf[4];
74
75
    /* 7.2.4 referred-to segments */
76
122k
    rtscarf = buf[5];
77
122k
    if ((rtscarf & 0xe0) == 0xe0) {
78
838
        rtscarf_long = jbig2_get_uint32(buf + 5);
79
838
        referred_to_segment_count = rtscarf_long & 0x1fffffff;
80
838
        offset = 5 + 4 + (referred_to_segment_count + 1) / 8;
81
121k
    } else {
82
121k
        referred_to_segment_count = (rtscarf >> 5);
83
121k
        offset = 5 + 1;
84
121k
    }
85
122k
    result->referred_to_segment_count = referred_to_segment_count;
86
87
    /* we now have enough information to compute the full header length */
88
122k
    referred_to_segment_size = result->number <= 256 ? 1 : result->number <= 65536 ? 2 : 4;     /* 7.2.5 */
89
122k
    pa_size = result->flags & 0x40 ? 4 : 1;     /* 7.2.6 */
90
122k
    if (offset + referred_to_segment_count * referred_to_segment_size + pa_size + 4 > buf_size) {
91
772
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number, "attempted to parse segment header with insufficient data, asking for more data");
92
772
        jbig2_free(ctx->allocator, result);
93
772
        return NULL;
94
772
    }
95
96
    /* 7.2.5 */
97
121k
    if (referred_to_segment_count) {
98
49.0k
        uint32_t i;
99
100
49.0k
        referred_to_segments = jbig2_new(ctx, uint32_t, referred_to_segment_count * referred_to_segment_size);
101
49.0k
        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
283k
        for (i = 0; i < referred_to_segment_count; i++) {
108
234k
            referred_to_segments[i] =
109
234k
                (referred_to_segment_size == 1) ? buf[offset] :
110
234k
                (referred_to_segment_size == 2) ? jbig2_get_uint16(buf + offset) : jbig2_get_uint32(buf + offset);
111
234k
            offset += referred_to_segment_size;
112
234k
            jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number, "segment %d refers to segment %d", result->number, referred_to_segments[i]);
113
234k
        }
114
49.0k
        result->referred_to_segments = referred_to_segments;
115
72.1k
    } else {                    /* no referred-to segments */
116
117
72.1k
        result->referred_to_segments = NULL;
118
72.1k
    }
119
120
    /* 7.2.6 */
121
121k
    if (pa_size == 4) {
122
21.9k
        result->page_association = jbig2_get_uint32(buf + offset);
123
21.9k
        offset += 4;
124
99.2k
    } else {
125
99.2k
        result->page_association = buf[offset++];
126
99.2k
    }
127
121k
    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
121k
    result->rows = UINT32_MAX;
131
121k
    result->data_length = jbig2_get_uint32(buf + offset);
132
121k
    *p_header_size = offset + 4;
133
134
    /* no body parsing results yet */
135
121k
    result->result = NULL;
136
137
121k
    return result;
138
121k
}
139
140
void
141
jbig2_free_segment(Jbig2Ctx *ctx, Jbig2Segment *segment)
142
121k
{
143
121k
    if (segment == NULL)
144
0
        return;
145
146
121k
    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
121k
    switch (segment->flags & 63) {
151
43.4k
    case 0:                    /* symbol dictionary */
152
43.4k
        if (segment->result != NULL)
153
4.23k
            jbig2_sd_release(ctx, (Jbig2SymbolDict *) segment->result);
154
43.4k
        break;
155
678
    case 4:                    /* intermediate text region */
156
1.00k
    case 40:                   /* intermediate refinement region */
157
1.00k
        if (segment->result != NULL)
158
157
            jbig2_image_release(ctx, (Jbig2Image *) segment->result);
159
1.00k
        break;
160
24.9k
    case 16:                   /* pattern dictionary */
161
24.9k
        if (segment->result != NULL)
162
3.13k
            jbig2_hd_release(ctx, (Jbig2PatternDict *) segment->result);
163
24.9k
        break;
164
1.58k
    case 53:                   /* user-supplied huffman table */
165
1.58k
        if (segment->result != NULL)
166
1.24k
            jbig2_table_free(ctx, (Jbig2HuffmanParams *) segment->result);
167
1.58k
        break;
168
50.2k
    default:
169
        /* anything else is probably an undefined pointer */
170
50.2k
        break;
171
121k
    }
172
121k
    jbig2_free(ctx->allocator, segment);
173
121k
}
174
175
/* find a segment by number */
176
Jbig2Segment *
177
jbig2_find_segment(Jbig2Ctx *ctx, uint32_t number)
178
308k
{
179
308k
    int index, index_max = ctx->segment_index - 1;
180
308k
    const Jbig2Ctx *global_ctx = ctx->global_ctx;
181
182
    /* FIXME: binary search would be better */
183
2.22M
    for (index = index_max; index >= 0; index--)
184
2.05M
        if (ctx->segments[index]->number == number)
185
137k
            return (ctx->segments[index]);
186
187
171k
    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
171k
    return NULL;
194
171k
}
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.7k
{
200
    /* 7.4.1 */
201
19.7k
    info->width = jbig2_get_uint32(segment_data);
202
19.7k
    info->height = jbig2_get_uint32(segment_data + 4);
203
19.7k
    info->x = jbig2_get_uint32(segment_data + 8);
204
19.7k
    info->y = jbig2_get_uint32(segment_data + 12);
205
19.7k
    info->flags = segment_data[16];
206
19.7k
    info->op = (Jbig2ComposeOp)(info->flags & 0x7);
207
19.7k
}
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
690
{
213
690
    uint32_t type;
214
690
    bool reserved;
215
690
    bool necessary;
216
217
690
    if (segment->data_length < 4)
218
7
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
219
220
683
    type = jbig2_get_uint32(segment_data);
221
683
    reserved = type & 0x20000000;
222
    /* Not implemented since this bit
223
    is only needed by encoders.
224
    dependent = type & 0x40000000;
225
    */
226
683
    necessary = type & 0x80000000;
227
228
683
    if (necessary && !reserved) {
229
5
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "extension segment is marked 'necessary' but not 'reserved' contrary to spec");
230
5
    }
231
232
683
    switch (type) {
233
404
    case 0x20000000:
234
404
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "ignoring ASCII comment");
235
404
        break;
236
84
    case 0x20000002:
237
84
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "ignoring UCS-2 comment");
238
84
        break;
239
195
    default:
240
195
        if (necessary) {
241
29
            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unhandled necessary extension segment type 0x%08x", type);
242
166
        } else {
243
166
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unhandled non-necessary extension segment, skipping");
244
166
        }
245
683
    }
246
247
654
    return 0;
248
683
}
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
260
{
254
260
    uint32_t profiles;
255
260
    uint32_t i;
256
260
    uint32_t profile;
257
260
    int index;
258
260
    const char *requirements;
259
260
    const char *generic_region;
260
260
    const char *refinement_region;
261
260
    const char *halftone_region;
262
260
    const char *numerical_data;
263
264
260
    if (segment->data_length < 4)
265
7
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short");
266
253
    index = 0;
267
268
253
    profiles = jbig2_get_uint32(&segment_data[index]);
269
253
    index += 4;
270
271
23.2k
    for (i = 0; i < profiles; i++) {
272
23.1k
        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
23.0k
        profile = jbig2_get_uint32(&segment_data[index]);
276
23.0k
        index += 4;
277
278
23.0k
        switch (profile) {
279
404
        case 0x00000001:
280
404
            requirements = "All JBIG2 capabilities";
281
404
            generic_region = "No restriction";
282
404
            refinement_region = "No restriction";
283
404
            halftone_region = "No restriction";
284
404
            numerical_data = "No restriction";
285
404
            break;
286
127
        case 0x00000002:
287
127
            requirements = "Maximum compression";
288
127
            generic_region = "Arithmetic only; any template used";
289
127
            refinement_region = "No restriction";
290
127
            halftone_region = "No restriction";
291
127
            numerical_data = "Arithmetic only";
292
127
            break;
293
218
        case 0x00000003:
294
218
            requirements = "Medium complexity and medium compression";
295
218
            generic_region = "Arithmetic only; only 10-pixel and 13-pixel templates";
296
218
            refinement_region = "10-pixel template only";
297
218
            halftone_region = "No skip mask used";
298
218
            numerical_data = "Arithmetic only";
299
218
            break;
300
58
        case 0x00000004:
301
58
            requirements = "Low complexity with progressive lossless capability";
302
58
            generic_region = "MMR only";
303
58
            refinement_region = "10-pixel template only";
304
58
            halftone_region = "No skip mask used";
305
58
            numerical_data = "Huffman only";
306
58
            break;
307
110
        case 0x00000005:
308
110
            requirements = "Low complexity";
309
110
            generic_region = "MMR only";
310
110
            refinement_region = "Not available";
311
110
            halftone_region = "No skip mask used";
312
110
            numerical_data = "Huffman only";
313
110
            break;
314
22.0k
        default:
315
22.0k
            requirements = "Unknown";
316
22.0k
            generic_region = "Unknown";
317
22.0k
            refinement_region = "Unknown";
318
22.0k
            halftone_region = "Unknown";
319
22.0k
            numerical_data = "Unknown";
320
22.0k
            break;
321
23.0k
        }
322
323
23.0k
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "Supported profile: 0x%08x", profile);
324
23.0k
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "  Requirements: %s", requirements);
325
23.0k
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "  Generic region coding: %s", generic_region);
326
23.0k
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "  Refinement region coding: %s", refinement_region);
327
23.0k
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "  Halftone region coding: %s", halftone_region);
328
23.0k
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "  Numerical data: %s", numerical_data);
329
23.0k
    }
330
331
147
    return 0;
332
253
}
333
334
/* general segment parsing dispatch */
335
int
336
jbig2_parse_segment(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data)
337
40.3k
{
338
40.3k
    jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
339
40.3k
                "segment %d, flags=%x, type=%d, data_length=%ld", segment->number, segment->flags, segment->flags & 63, (long) segment->data_length);
340
40.3k
    switch (segment->flags & 63) {
341
5.77k
    case 0:
342
5.77k
        return jbig2_symbol_dictionary(ctx, segment, segment_data);
343
308
    case 4:                    /* intermediate text region */
344
550
    case 6:                    /* immediate text region */
345
2.11k
    case 7:                    /* immediate lossless text region */
346
2.11k
        return jbig2_text_region(ctx, segment, segment_data);
347
4.33k
    case 16:
348
4.33k
        return jbig2_pattern_dictionary(ctx, segment, segment_data);
349
53
    case 20:                   /* intermediate halftone region */
350
110
    case 22:                   /* immediate halftone region */
351
1.73k
    case 23:                   /* immediate lossless halftone region */
352
1.73k
        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
11.0k
    case 38:                   /* immediate generic region */
356
14.8k
    case 39:                   /* immediate lossless generic region */
357
14.8k
        return jbig2_immediate_generic_region(ctx, segment, segment_data);
358
91
    case 40:                   /* intermediate generic refinement region */
359
662
    case 42:                   /* immediate generic refinement region */
360
1.08k
    case 43:                   /* immediate lossless generic refinement region */
361
1.08k
        return jbig2_refinement_region(ctx, segment, segment_data);
362
4.80k
    case 48:
363
4.80k
        return jbig2_page_info(ctx, segment, segment_data);
364
1.42k
    case 49:
365
1.42k
        return jbig2_end_of_page(ctx, segment, segment_data);
366
506
    case 50:
367
506
        return jbig2_end_of_stripe(ctx, segment, segment_data);
368
395
    case 51:
369
395
        ctx->state = JBIG2_FILE_EOF;
370
395
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "end of file");
371
395
        break;
372
260
    case 52:
373
260
        return jbig2_parse_profile_segment(ctx, segment, segment_data);
374
1.37k
    case 53:                   /* user-supplied huffman table */
375
1.37k
        return jbig2_table(ctx, segment, segment_data);
376
1
    case 54:
377
1
        return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unhandled segment type 'color palette' (NYI)");
378
690
    case 62:
379
690
        return jbig2_parse_extension_segment(ctx, segment, segment_data);
380
969
    default:
381
969
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unknown segment type %d", segment->flags & 63);
382
40.3k
    }
383
1.36k
    return 0;
384
40.3k
}