Coverage Report

Created: 2025-02-03 06:29

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