Coverage Report

Created: 2026-07-16 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/jbig2dec/jbig2_symbol_dict.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
/* symbol dictionary segment decode and support */
21
22
#ifdef HAVE_CONFIG_H
23
#include "config.h"
24
#endif
25
#include "os_types.h"
26
27
#include <stddef.h>
28
#include <string.h>             /* memset() */
29
30
#if defined(OUTPUT_PBM) || defined(DUMP_SYMDICT)
31
#include <stdio.h>
32
#endif
33
34
#include "jbig2.h"
35
#include "jbig2_priv.h"
36
#include "jbig2_arith.h"
37
#include "jbig2_arith_int.h"
38
#include "jbig2_arith_iaid.h"
39
#include "jbig2_generic.h"
40
#include "jbig2_huffman.h"
41
#include "jbig2_image.h"
42
#include "jbig2_mmr.h"
43
#include "jbig2_refinement.h"
44
#include "jbig2_segment.h"
45
#include "jbig2_symbol_dict.h"
46
#include "jbig2_text.h"
47
#ifdef OUTPUT_PBM
48
#include "jbig2_image_rw.h"
49
#endif
50
51
/* Table 13 */
52
typedef struct {
53
    bool SDHUFF;
54
    bool SDREFAGG;
55
    uint32_t SDNUMINSYMS;
56
    Jbig2SymbolDict *SDINSYMS;
57
    uint32_t SDNUMNEWSYMS;
58
    uint32_t SDNUMEXSYMS;
59
    Jbig2HuffmanTable *SDHUFFDH;
60
    Jbig2HuffmanTable *SDHUFFDW;
61
    Jbig2HuffmanTable *SDHUFFBMSIZE;
62
    Jbig2HuffmanTable *SDHUFFAGGINST;
63
    int SDTEMPLATE;
64
    int8_t sdat[8];
65
    bool SDRTEMPLATE;
66
    int8_t sdrat[4];
67
} Jbig2SymbolDictParams;
68
69
/* Utility routines */
70
71
#ifdef DUMP_SYMDICT
72
void
73
jbig2_dump_symbol_dict(Jbig2Ctx *ctx, Jbig2Segment *segment)
74
{
75
    Jbig2SymbolDict *dict = (Jbig2SymbolDict *) segment->result;
76
    uint32_t index;
77
    char filename[24];
78
    int code;
79
80
    if (dict == NULL)
81
        return;
82
    jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "dumping symbol dictionary as %d individual png files", dict->n_symbols);
83
    for (index = 0; index < dict->n_symbols; index++) {
84
        snprintf(filename, sizeof(filename), "symbol_%02d-%04d.png", segment->number, index);
85
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "dumping symbol %d/%d as '%s'", index, dict->n_symbols, filename);
86
#ifdef HAVE_LIBPNG
87
        code = jbig2_image_write_png_file(dict->glyphs[index], filename);
88
#else
89
        code = jbig2_image_write_pbm_file(dict->glyphs[index], filename);
90
#endif
91
        if (code < 0)
92
            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to dump symbol %d/%d as '%s'", index, dict->n_symbols, filename);
93
    }
94
}
95
#endif /* DUMP_SYMDICT */
96
97
/* return a new empty symbol dict */
98
Jbig2SymbolDict *
99
jbig2_sd_new(Jbig2Ctx *ctx, uint32_t n_symbols)
100
17.5k
{
101
17.5k
    Jbig2SymbolDict *new_dict = NULL;
102
103
17.5k
    new_dict = jbig2_new(ctx, Jbig2SymbolDict, 1);
104
17.5k
    if (new_dict != NULL) {
105
17.5k
        new_dict->glyphs = jbig2_new(ctx, Jbig2Image *, n_symbols);
106
17.5k
        new_dict->n_symbols = n_symbols;
107
17.5k
    } else {
108
1
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate new empty symbol dictionary");
109
1
        return NULL;
110
1
    }
111
112
17.5k
    if (new_dict->glyphs != NULL) {
113
11.9k
        memset(new_dict->glyphs, 0, n_symbols * sizeof(Jbig2Image *));
114
11.9k
    } else if (new_dict->n_symbols > 0) {
115
146
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate glyphs for new empty symbol dictionary");
116
146
        jbig2_free(ctx->allocator, new_dict);
117
146
        return NULL;
118
146
    }
119
120
17.3k
    return new_dict;
121
17.5k
}
122
123
/* release the memory associated with a symbol dict */
124
void
125
jbig2_sd_release(Jbig2Ctx *ctx, Jbig2SymbolDict *dict)
126
22.3k
{
127
22.3k
    uint32_t i;
128
129
22.3k
    if (dict == NULL)
130
5.01k
        return;
131
17.3k
    if (dict->glyphs != NULL)
132
404M
        for (i = 0; i < dict->n_symbols; i++)
133
403M
            jbig2_image_release(ctx, dict->glyphs[i]);
134
17.3k
    jbig2_free(ctx->allocator, dict->glyphs);
135
17.3k
    jbig2_free(ctx->allocator, dict);
136
17.3k
}
137
138
/* get a particular glyph by index */
139
Jbig2Image *
140
jbig2_sd_glyph(Jbig2SymbolDict *dict, unsigned int id)
141
0
{
142
0
    if (dict == NULL)
143
0
        return NULL;
144
0
    return dict->glyphs[id];
145
0
}
146
147
/* count the number of dictionary segments referred to by the given segment */
148
uint32_t
149
jbig2_sd_count_referred(Jbig2Ctx *ctx, Jbig2Segment *segment)
150
13.4k
{
151
13.4k
    int index;
152
13.4k
    Jbig2Segment *rsegment;
153
13.4k
    uint32_t n_dicts = 0;
154
155
243k
    for (index = 0; index < segment->referred_to_segment_count; index++) {
156
230k
        rsegment = jbig2_find_segment(ctx, segment->referred_to_segments[index]);
157
230k
        if (rsegment && ((rsegment->flags & 63) == 0) &&
158
78.4k
            rsegment->result && (((Jbig2SymbolDict *) rsegment->result)->n_symbols > 0) && ((*((Jbig2SymbolDict *) rsegment->result)->glyphs) != NULL))
159
69.9k
            n_dicts++;
160
230k
    }
161
162
13.4k
    return (n_dicts);
163
13.4k
}
164
165
/* return an array of pointers to symbol dictionaries referred to by the given segment */
166
Jbig2SymbolDict **
167
jbig2_sd_list_referred(Jbig2Ctx *ctx, Jbig2Segment *segment)
168
3.92k
{
169
3.92k
    int index;
170
3.92k
    Jbig2Segment *rsegment;
171
3.92k
    Jbig2SymbolDict **dicts;
172
3.92k
    uint32_t n_dicts = jbig2_sd_count_referred(ctx, segment);
173
3.92k
    uint32_t dindex = 0;
174
175
3.92k
    dicts = jbig2_new(ctx, Jbig2SymbolDict *, n_dicts);
176
3.92k
    if (dicts == NULL) {
177
2
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate referred list of symbol dictionaries");
178
2
        return NULL;
179
2
    }
180
181
104k
    for (index = 0; index < segment->referred_to_segment_count; index++) {
182
100k
        rsegment = jbig2_find_segment(ctx, segment->referred_to_segments[index]);
183
100k
        if (rsegment && ((rsegment->flags & 63) == 0) && rsegment->result &&
184
35.1k
                (((Jbig2SymbolDict *) rsegment->result)->n_symbols > 0) && ((*((Jbig2SymbolDict *) rsegment->result)->glyphs) != NULL)) {
185
            /* add this referred to symbol dictionary */
186
31.6k
            dicts[dindex++] = (Jbig2SymbolDict *) rsegment->result;
187
31.6k
        }
188
100k
    }
189
190
3.92k
    if (dindex != n_dicts) {
191
        /* should never happen */
192
0
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "counted %d symbol dictionaries but built a list with %d.", n_dicts, dindex);
193
0
        jbig2_free(ctx->allocator, dicts);
194
0
        return NULL;
195
0
    }
196
197
3.92k
    return (dicts);
198
3.92k
}
199
200
/* generate a new symbol dictionary by concatenating a list of
201
   existing dictionaries */
202
Jbig2SymbolDict *
203
jbig2_sd_cat(Jbig2Ctx *ctx, uint32_t n_dicts, Jbig2SymbolDict **dicts)
204
1.05k
{
205
1.05k
    uint32_t i, j, k, symbols;
206
1.05k
    Jbig2SymbolDict *new_dict = NULL;
207
208
    /* count the imported symbols and allocate a new array */
209
1.05k
    symbols = 0;
210
22.3k
    for (i = 0; i < n_dicts; i++)
211
21.2k
    {
212
21.2k
        if (dicts[i]->n_symbols > UINT32_MAX - symbols)
213
0
        {
214
0
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "too many symbols in dicts to concat");
215
0
            return NULL;
216
0
        }
217
21.2k
        symbols += dicts[i]->n_symbols;
218
21.2k
    }
219
220
    /* fill a new array with new references to glyph pointers */
221
1.05k
    new_dict = jbig2_sd_new(ctx, symbols);
222
1.05k
    if (new_dict != NULL) {
223
1.05k
        k = 0;
224
22.3k
        for (i = 0; i < n_dicts; i++)
225
16.5M
            for (j = 0; j < dicts[i]->n_symbols; j++)
226
16.5M
                new_dict->glyphs[k++] = jbig2_image_reference(ctx, dicts[i]->glyphs[j]);
227
1.05k
    } else {
228
4
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate new symbol dictionary");
229
4
    }
230
231
1.05k
    return new_dict;
232
1.05k
}
233
234
/* Decoding routines */
235
236
/* 6.5 */
237
static Jbig2SymbolDict *
238
jbig2_decode_symbol_dict(Jbig2Ctx *ctx,
239
                         Jbig2Segment *segment,
240
                         const Jbig2SymbolDictParams *params, const byte *data, size_t size, Jbig2ArithCx *GB_stats, Jbig2ArithCx *GR_stats)
241
5.91k
{
242
5.91k
    Jbig2SymbolDict *SDNEWSYMS = NULL;
243
5.91k
    Jbig2SymbolDict *SDEXSYMS = NULL;
244
5.91k
    uint32_t HCHEIGHT;
245
5.91k
    uint32_t NSYMSDECODED;
246
5.91k
    uint32_t SYMWIDTH, TOTWIDTH;
247
5.91k
    uint32_t HCFIRSTSYM;
248
5.91k
    uint32_t *SDNEWSYMWIDTHS = NULL;
249
5.91k
    uint8_t SBSYMCODELEN = 0;
250
5.91k
    Jbig2WordStream *ws = NULL;
251
5.91k
    Jbig2HuffmanState *hs = NULL;
252
5.91k
    Jbig2ArithState *as = NULL;
253
5.91k
    Jbig2ArithIntCtx *IADH = NULL;
254
5.91k
    Jbig2ArithIntCtx *IADW = NULL;
255
5.91k
    Jbig2ArithIntCtx *IAEX = NULL;
256
5.91k
    Jbig2ArithIntCtx *IAAI = NULL;
257
5.91k
    int code = 0;
258
5.91k
    Jbig2SymbolDict **refagg_dicts = NULL;
259
5.91k
    uint32_t i;
260
5.91k
    Jbig2TextRegionParams tparams;
261
5.91k
    Jbig2Image *image = NULL;
262
5.91k
    Jbig2Image *glyph = NULL;
263
5.91k
    uint32_t emptyruns = 0;
264
265
5.91k
    memset(&tparams, 0, sizeof(tparams));
266
267
    /* 6.5.5 (3) */
268
5.91k
    HCHEIGHT = 0;
269
5.91k
    NSYMSDECODED = 0;
270
271
5.91k
    ws = jbig2_word_stream_buf_new(ctx, data, size);
272
5.91k
    if (ws == NULL) {
273
1
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate word stream when decoding symbol dictionary");
274
1
        return NULL;
275
1
    }
276
277
5.91k
    as = jbig2_arith_new(ctx, ws);
278
5.91k
    if (as == NULL) {
279
9
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate arithmetic coding state when decoding symbol dictionary");
280
9
        jbig2_word_stream_buf_free(ctx, ws);
281
9
        return NULL;
282
9
    }
283
284
30.1k
    for (SBSYMCODELEN = 0; ((uint64_t) 1 << SBSYMCODELEN) < ((uint64_t) params->SDNUMINSYMS + params->SDNUMNEWSYMS); SBSYMCODELEN++);
285
286
5.90k
    if (params->SDHUFF) {
287
3.25k
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "huffman coded symbol dictionary");
288
3.25k
        hs = jbig2_huffman_new(ctx, ws);
289
3.25k
        tparams.SBHUFFRDX = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);   /* Table B.15 */
290
3.25k
        tparams.SBHUFFRDY = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);   /* Table B.15 */
291
3.25k
        tparams.SBHUFFRSIZE = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A); /* Table B.1 */
292
3.25k
        if (hs == NULL || tparams.SBHUFFRDX == NULL ||
293
3.25k
                tparams.SBHUFFRDY == NULL || tparams.SBHUFFRSIZE == NULL) {
294
7
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate for symbol bitmap");
295
7
            goto cleanup;
296
7
        }
297
        /* 6.5.5 (2) */
298
3.24k
        if (!params->SDREFAGG) {
299
2.63k
            SDNEWSYMWIDTHS = jbig2_new(ctx, uint32_t, params->SDNUMNEWSYMS);
300
2.63k
            if (SDNEWSYMWIDTHS == NULL) {
301
7
                jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate symbol widths (%u)", params->SDNUMNEWSYMS);
302
7
                goto cleanup;
303
7
            }
304
2.63k
        } else {
305
611
            tparams.SBHUFFFS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_F);    /* Table B.6 */
306
611
            tparams.SBHUFFDS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_H);    /* Table B.8 */
307
611
            tparams.SBHUFFDT = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_K);    /* Table B.11 */
308
611
            tparams.SBHUFFRDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);   /* Table B.15 */
309
611
            tparams.SBHUFFRDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);   /* Table B.15 */
310
611
            if (tparams.SBHUFFFS == NULL || tparams.SBHUFFDS == NULL ||
311
608
                    tparams.SBHUFFDT == NULL || tparams.SBHUFFRDW == NULL ||
312
606
                    tparams.SBHUFFRDH == NULL) {
313
6
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "out of memory creating text region huffman decoder entries");
314
6
                goto cleanup;
315
6
            }
316
611
        }
317
3.24k
    } else {
318
2.64k
        IADH = jbig2_arith_int_ctx_new(ctx);
319
2.64k
        IADW = jbig2_arith_int_ctx_new(ctx);
320
2.64k
        IAEX = jbig2_arith_int_ctx_new(ctx);
321
2.64k
        IAAI = jbig2_arith_int_ctx_new(ctx);
322
2.64k
        if (IADH == NULL || IADW == NULL || IAEX == NULL || IAAI == NULL) {
323
4
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate symbol bitmap");
324
4
            goto cleanup;
325
4
        }
326
2.64k
        tparams.IAID = jbig2_arith_iaid_ctx_new(ctx, SBSYMCODELEN);
327
2.64k
        tparams.IARDX = jbig2_arith_int_ctx_new(ctx);
328
2.64k
        tparams.IARDY = jbig2_arith_int_ctx_new(ctx);
329
2.64k
        if (tparams.IAID == NULL || tparams.IARDX == NULL ||
330
2.62k
                tparams.IARDY == NULL) {
331
18
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region arithmetic decoder contexts");
332
18
            goto cleanup;
333
18
        }
334
2.62k
        if (params->SDREFAGG) {
335
            /* Values from Table 17, section 6.5.8.2 (2) */
336
427
            tparams.IADT = jbig2_arith_int_ctx_new(ctx);
337
427
            tparams.IAFS = jbig2_arith_int_ctx_new(ctx);
338
427
            tparams.IADS = jbig2_arith_int_ctx_new(ctx);
339
427
            tparams.IAIT = jbig2_arith_int_ctx_new(ctx);
340
            /* Table 31 */
341
427
            tparams.IARI = jbig2_arith_int_ctx_new(ctx);
342
427
            tparams.IARDW = jbig2_arith_int_ctx_new(ctx);
343
427
            tparams.IARDH = jbig2_arith_int_ctx_new(ctx);
344
427
            if (tparams.IADT == NULL || tparams.IAFS == NULL ||
345
425
                    tparams.IADS == NULL || tparams.IAIT == NULL ||
346
422
                    tparams.IARI == NULL || tparams.IARDW == NULL ||
347
419
                    tparams.IARDH == NULL) {
348
9
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region arith decoder contexts");
349
9
                goto cleanup;
350
9
            }
351
427
        }
352
2.62k
    }
353
5.85k
    tparams.SBHUFF = params->SDHUFF;
354
5.85k
    tparams.SBREFINE = 1;
355
5.85k
    tparams.SBSTRIPS = 1;
356
5.85k
    tparams.SBDEFPIXEL = 0;
357
5.85k
    tparams.SBCOMBOP = JBIG2_COMPOSE_OR;
358
5.85k
    tparams.TRANSPOSED = 0;
359
5.85k
    tparams.REFCORNER = JBIG2_CORNER_TOPLEFT;
360
5.85k
    tparams.SBDSOFFSET = 0;
361
5.85k
    tparams.SBRTEMPLATE = params->SDRTEMPLATE;
362
363
    /* 6.5.5 (1) */
364
5.85k
    SDNEWSYMS = jbig2_sd_new(ctx, params->SDNUMNEWSYMS);
365
5.85k
    if (SDNEWSYMS == NULL) {
366
38
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate new symbols (%u)", params->SDNUMNEWSYMS);
367
38
        goto cleanup;
368
38
    }
369
370
5.81k
    refagg_dicts = jbig2_new(ctx, Jbig2SymbolDict *, 2);
371
5.81k
    if (refagg_dicts == NULL) {
372
1
        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Out of memory allocating dictionary array");
373
1
        goto cleanup;
374
1
    }
375
5.81k
    refagg_dicts[0] = jbig2_sd_new(ctx, params->SDNUMINSYMS);
376
5.81k
    if (refagg_dicts[0] == NULL) {
377
3
        code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "out of memory allocating symbol dictionary");
378
3
        goto cleanup;
379
3
    }
380
14.3M
    for (i = 0; i < params->SDNUMINSYMS; i++) {
381
14.3M
        refagg_dicts[0]->glyphs[i] = jbig2_image_reference(ctx, params->SDINSYMS->glyphs[i]);
382
14.3M
    }
383
5.80k
    refagg_dicts[1] = SDNEWSYMS;
384
385
    /* 6.5.5 (4a) */
386
1.51M
    while (NSYMSDECODED < params->SDNUMNEWSYMS) {
387
1.51M
        int32_t HCDH, DW;
388
389
        /* 6.5.6 */
390
1.51M
        if (params->SDHUFF) {
391
10.2k
            HCDH = jbig2_huffman_get(hs, params->SDHUFFDH, &code);
392
1.50M
        } else {
393
1.50M
            code = jbig2_arith_int_decode(ctx, IADH, as, &HCDH);
394
1.50M
        }
395
1.51M
        if (code < 0) {
396
4
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode height class delta");
397
4
            goto cleanup;
398
4
        }
399
1.51M
        if (code > 0) {
400
9
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "OOB decoding height class delta");
401
9
            goto cleanup;
402
9
        }
403
404
        /* 6.5.5 (4b) */
405
1.51M
        HCHEIGHT = HCHEIGHT + HCDH;
406
1.51M
        SYMWIDTH = 0;
407
1.51M
        TOTWIDTH = 0;
408
1.51M
        HCFIRSTSYM = NSYMSDECODED;
409
410
1.51M
        if ((int32_t) HCHEIGHT < 0) {
411
42
            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "invalid HCHEIGHT value");
412
42
            goto cleanup;
413
42
        }
414
#ifdef JBIG2_DEBUG
415
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "HCHEIGHT = %d", HCHEIGHT);
416
#endif
417
1.51M
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "decoding height class %d with %d syms decoded", HCHEIGHT, NSYMSDECODED);
418
419
24.6M
        for (;;) {
420
            /* 6.5.7 */
421
24.6M
            if (params->SDHUFF) {
422
23.0M
                DW = jbig2_huffman_get(hs, params->SDHUFFDW, &code);
423
23.0M
            } else {
424
1.59M
                code = jbig2_arith_int_decode(ctx, IADW, as, &DW);
425
1.59M
            }
426
24.6M
            if (code < 0)
427
1
            {
428
1
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode DW");
429
1
                goto cleanup;
430
1
            }
431
            /* 6.5.5 (4c.i) */
432
24.6M
            if (code > 0) {
433
1.51M
                jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "OOB when decoding DW signals end of height class %d", HCHEIGHT);
434
1.51M
                break;
435
1.51M
            }
436
437
            /* check for broken symbol table */
438
23.1M
            if (NSYMSDECODED >= params->SDNUMNEWSYMS) {
439
2.56k
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "no OOB signaling end of height class %d, continuing", HCHEIGHT);
440
2.56k
                break;
441
2.56k
            }
442
443
23.1M
            if (DW < 0 && SYMWIDTH < (uint32_t) -DW) {
444
172
                code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "DW value (%d) would make SYMWIDTH (%u) negative at symbol %u", DW, SYMWIDTH, NSYMSDECODED + 1);
445
172
                goto cleanup;
446
172
            }
447
23.1M
            if (DW > 0 && (uint32_t) DW > UINT32_MAX - SYMWIDTH) {
448
1
                code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "DW value (%d) would make SYMWIDTH (%u) too large at symbol %u", DW, SYMWIDTH, NSYMSDECODED + 1);
449
1
                goto cleanup;
450
1
            }
451
452
23.1M
            SYMWIDTH = SYMWIDTH + DW;
453
23.1M
            if (SYMWIDTH > UINT32_MAX - TOTWIDTH) {
454
26
                code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "SYMWIDTH value (%u) would make TOTWIDTH (%u) too large at symbol %u", SYMWIDTH, TOTWIDTH, NSYMSDECODED + 1);
455
26
                goto cleanup;
456
26
            }
457
458
23.1M
            TOTWIDTH = TOTWIDTH + SYMWIDTH;
459
#ifdef JBIG2_DEBUG
460
            jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "SYMWIDTH = %u TOTWIDTH = %u", SYMWIDTH, TOTWIDTH);
461
#endif
462
            /* 6.5.5 (4c.ii) */
463
23.1M
            if (!params->SDHUFF || params->SDREFAGG) {
464
#ifdef JBIG2_DEBUG
465
                jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "SDHUFF = %d; SDREFAGG = %d", params->SDHUFF, params->SDREFAGG);
466
#endif
467
                /* 6.5.8 */
468
97.5k
                if (!params->SDREFAGG) {
469
88.4k
                    Jbig2GenericRegionParams region_params;
470
88.4k
                    int sdat_bytes;
471
472
                    /* Table 16 */
473
88.4k
                    region_params.MMR = 0;
474
88.4k
                    region_params.GBTEMPLATE = params->SDTEMPLATE;
475
88.4k
                    region_params.TPGDON = 0;
476
88.4k
                    region_params.USESKIP = 0;
477
88.4k
                    sdat_bytes = params->SDTEMPLATE == 0 ? 8 : 2;
478
88.4k
                    memcpy(region_params.gbat, params->sdat, sdat_bytes);
479
480
88.4k
                    image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT);
481
88.4k
                    if (image == NULL) {
482
71
                        code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate image");
483
71
                        goto cleanup;
484
71
                    }
485
486
88.4k
                    code = jbig2_decode_generic_region(ctx, segment, &region_params, as, image, GB_stats);
487
88.4k
                    if (code < 0) {
488
24
                        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode generic region");
489
24
                        goto cleanup;
490
24
                    }
491
492
88.3k
                    SDNEWSYMS->glyphs[NSYMSDECODED] = image;
493
88.3k
                    image = NULL;
494
88.3k
                } else {
495
                    /* 6.5.8.2 refinement/aggregate symbol */
496
9.09k
                    uint32_t REFAGGNINST;
497
498
9.09k
                    if (params->SDHUFF) {
499
3.11k
                        REFAGGNINST = jbig2_huffman_get(hs, params->SDHUFFAGGINST, &code);
500
5.97k
                    } else {
501
5.97k
                        code = jbig2_arith_int_decode(ctx, IAAI, as, (int32_t *) &REFAGGNINST);
502
5.97k
                    }
503
9.09k
                    if (code < 0) {
504
1
                        code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode number of symbols in aggregate glyph");
505
1
                        goto cleanup;
506
1
                    }
507
9.09k
                    if (code > 0) {
508
2
                        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB in number of symbols in aggregate glyph");
509
2
                        goto cleanup;
510
2
                    }
511
9.08k
                    if ((int32_t) REFAGGNINST <= 0) {
512
74
                        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "invalid number of symbols in aggregate glyph");
513
74
                        goto cleanup;
514
74
                    }
515
516
9.01k
                    jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "aggregate symbol coding (%d instances)", REFAGGNINST);
517
518
9.01k
                    if (REFAGGNINST > 1) {
519
7.60k
                        tparams.SBNUMINSTANCES = REFAGGNINST;
520
521
7.60k
                        image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT);
522
7.60k
                        if (image == NULL) {
523
14
                            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate symbol image");
524
14
                            goto cleanup;
525
14
                        }
526
527
                        /* multiple symbols are handled as a text region */
528
7.58k
                        code = jbig2_decode_text_region(ctx, segment, &tparams, (const Jbig2SymbolDict * const *)refagg_dicts,
529
7.58k
                                                        2, image, GR_stats, as, ws);
530
7.58k
                        if (code < 0) {
531
280
                            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode text region");
532
280
                            goto cleanup;
533
280
                        }
534
535
7.30k
                        SDNEWSYMS->glyphs[NSYMSDECODED] = image;
536
7.30k
                        image = NULL;
537
7.30k
                    } else {
538
                        /* 6.5.8.2.2 */
539
                        /* bool SBHUFF = params->SDHUFF; */
540
1.41k
                        Jbig2RefinementRegionParams rparams;
541
1.41k
                        uint32_t ID;
542
1.41k
                        int32_t RDX, RDY;
543
1.41k
                        size_t BMSIZE = 0;
544
1.41k
                        uint32_t ninsyms = params->SDNUMINSYMS;
545
1.41k
                        int code1 = 0;
546
1.41k
                        int code2 = 0;
547
1.41k
                        int code3 = 0;
548
1.41k
                        int code4 = 0;
549
1.41k
                        int code5 = 0;
550
551
                        /* 6.5.8.2.2 (2, 3, 4, 5) */
552
1.41k
                        if (params->SDHUFF) {
553
912
                            ID = jbig2_huffman_get_bits(hs, SBSYMCODELEN, &code1);
554
912
                            RDX = jbig2_huffman_get(hs, tparams.SBHUFFRDX, &code2);
555
912
                            RDY = jbig2_huffman_get(hs, tparams.SBHUFFRDY, &code3);
556
912
                            BMSIZE = jbig2_huffman_get(hs, tparams.SBHUFFRSIZE, &code4);
557
912
                            code5 = jbig2_huffman_skip(hs);
558
912
                        } else {
559
501
                            code1 = jbig2_arith_iaid_decode(ctx, tparams.IAID, as, (int32_t *) &ID);
560
501
                            code2 = jbig2_arith_int_decode(ctx, tparams.IARDX, as, &RDX);
561
501
                            code3 = jbig2_arith_int_decode(ctx, tparams.IARDY, as, &RDY);
562
501
                        }
563
564
1.41k
                        if (code1 < 0 || code2 < 0 || code3 < 0 || code4 < 0 || code5 < 0) {
565
1
                            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode data");
566
1
                            goto cleanup;
567
1
                        }
568
1.41k
                        if (code1 > 0 || code2 > 0 || code3 > 0 || code4 > 0 || code5 > 0) {
569
4
                            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB in single refinement/aggregate coded symbol data");
570
4
                            goto cleanup;
571
4
                        }
572
573
1.40k
                        if (ID >= ninsyms + NSYMSDECODED) {
574
26
                            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "refinement references unknown symbol %d", ID);
575
26
                            goto cleanup;
576
26
                        }
577
578
1.38k
                        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
579
1.38k
                                    "symbol is a refinement of ID %d with the refinement applied at (%d,%d)", ID, RDX, RDY);
580
581
1.38k
                        image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT);
582
1.38k
                        if (image == NULL) {
583
1
                            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate symbol image");
584
1
                            goto cleanup;
585
1
                        }
586
587
                        /* Table 18 */
588
1.38k
                        rparams.GRTEMPLATE = params->SDRTEMPLATE;
589
1.38k
                        rparams.GRREFERENCE = (ID < ninsyms) ? params->SDINSYMS->glyphs[ID] : SDNEWSYMS->glyphs[ID - ninsyms];
590
                        /* SumatraPDF: fail on missing glyphs */
591
1.38k
                        if (rparams.GRREFERENCE == NULL) {
592
3
                            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "missing glyph %d/%d", ID, ninsyms);
593
3
                            goto cleanup;
594
3
                        }
595
1.37k
                        rparams.GRREFERENCEDX = RDX;
596
1.37k
                        rparams.GRREFERENCEDY = RDY;
597
1.37k
                        rparams.TPGRON = 0;
598
1.37k
                        memcpy(rparams.grat, params->sdrat, 4);
599
1.37k
                        code = jbig2_decode_refinement_region(ctx, segment, &rparams, as, image, GR_stats);
600
1.37k
                        if (code < 0) {
601
2
                            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode refinement region");
602
2
                            goto cleanup;
603
2
                        }
604
605
1.37k
                        SDNEWSYMS->glyphs[NSYMSDECODED] = image;
606
1.37k
                        image = NULL;
607
608
                        /* 6.5.8.2.2 (7) */
609
1.37k
                        if (params->SDHUFF) {
610
888
                            if (BMSIZE == 0)
611
439
                                BMSIZE = (size_t) SDNEWSYMS->glyphs[NSYMSDECODED]->height *
612
439
                                    SDNEWSYMS->glyphs[NSYMSDECODED]->stride;
613
888
                            code = jbig2_huffman_advance(hs, BMSIZE);
614
888
                            if (code < 0) {
615
0
                                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to advance after huffman decoding in refinement region");
616
0
                                goto cleanup;
617
0
                            }
618
888
                        }
619
1.37k
                    }
620
9.01k
                }
621
622
#ifdef OUTPUT_PBM
623
                {
624
                    char name[64];
625
                    FILE *out;
626
                    int code;
627
628
                    snprintf(name, 64, "sd.%04d.%04d.pbm", segment->number, NSYMSDECODED);
629
                    out = fopen(name, "wb");
630
                    code = jbig2_image_write_pbm(SDNEWSYMS->glyphs[NSYMSDECODED], out);
631
                    fclose(out);
632
                    if (code < 0) {
633
                        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to write glyph");
634
                        goto cleanup;
635
                    }
636
                    jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "writing out glyph as '%s' ...", name);
637
                }
638
#endif
639
640
97.5k
            }
641
642
            /* 6.5.5 (4c.iii) */
643
23.1M
            if (params->SDHUFF && !params->SDREFAGG) {
644
23.0M
                SDNEWSYMWIDTHS[NSYMSDECODED] = SYMWIDTH;
645
23.0M
            }
646
647
            /* 6.5.5 (4c.iv) */
648
23.1M
            NSYMSDECODED = NSYMSDECODED + 1;
649
650
23.1M
            jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "decoded symbol %u of %u (%ux%u)", NSYMSDECODED, params->SDNUMNEWSYMS, SYMWIDTH, HCHEIGHT);
651
652
23.1M
        }                       /* end height class decode loop */
653
654
        /* 6.5.5 (4d) */
655
1.51M
        if (params->SDHUFF && !params->SDREFAGG) {
656
            /* 6.5.9 */
657
9.52k
            size_t BMSIZE;
658
9.52k
            uint32_t j;
659
9.52k
            int x;
660
661
9.52k
            BMSIZE = jbig2_huffman_get(hs, params->SDHUFFBMSIZE, &code);
662
9.52k
            if (code < 0) {
663
1
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "error decoding size of collective bitmap");
664
1
                goto cleanup;
665
1
            }
666
9.52k
            if (code > 0) {
667
1
                jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB obtained when decoding size of collective bitmap");
668
1
                goto cleanup;
669
1
            }
670
671
            /* skip any bits before the next byte boundary */
672
9.52k
            code = jbig2_huffman_skip(hs);
673
9.52k
            if (code < 0) {
674
0
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to skip to next byte when decoding collective bitmap");
675
0
            }
676
677
9.52k
            image = jbig2_image_new(ctx, TOTWIDTH, HCHEIGHT);
678
9.52k
            if (image == NULL) {
679
48
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate collective bitmap image");
680
48
                goto cleanup;
681
48
            }
682
683
9.47k
            if (BMSIZE == 0) {
684
                /* if BMSIZE == 0 bitmap is uncompressed */
685
968
                const byte *src = data + jbig2_huffman_offset(hs);
686
968
                const int stride = (image->width >> 3) + ((image->width & 7) ? 1 : 0);
687
968
                byte *dst = image->data;
688
689
                /* SumatraPDF: prevent read access violation */
690
968
                if (size < jbig2_huffman_offset(hs) || (size - jbig2_huffman_offset(hs) < (size_t) image->height * stride) || (size < jbig2_huffman_offset(hs))) {
691
77
                    jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "not enough data for decoding uncompressed (%d/%li)", image->height * stride,
692
77
                                (long) (size - jbig2_huffman_offset(hs)));
693
77
                    goto cleanup;
694
77
                }
695
696
891
                BMSIZE = (size_t) image->height * stride;
697
891
                jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
698
891
                            "reading %dx%d uncompressed bitmap for %d symbols (%li bytes)", image->width, image->height, NSYMSDECODED - HCFIRSTSYM, (long) BMSIZE);
699
700
10.2k
                for (j = 0; j < image->height; j++) {
701
9.32k
                    memcpy(dst, src, stride);
702
9.32k
                    dst += image->stride;
703
9.32k
                    src += stride;
704
9.32k
                }
705
8.50k
            } else {
706
8.50k
                Jbig2GenericRegionParams rparams;
707
708
                /* SumatraPDF: prevent read access violation */
709
8.50k
                if (size < jbig2_huffman_offset(hs) || size < BMSIZE || size - jbig2_huffman_offset(hs) < BMSIZE) {
710
105
                    jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "not enough data for decoding (%li/%li)", (long) BMSIZE, (long) (size - jbig2_huffman_offset(hs)));
711
105
                    goto cleanup;
712
105
                }
713
714
8.40k
                jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
715
8.40k
                            "reading %dx%d collective bitmap for %d symbols (%li bytes)", image->width, image->height, NSYMSDECODED - HCFIRSTSYM, (long) BMSIZE);
716
717
8.40k
                rparams.MMR = 1;
718
8.40k
                code = jbig2_decode_generic_mmr(ctx, segment, &rparams, data + jbig2_huffman_offset(hs), BMSIZE, image);
719
8.40k
                if (code) {
720
12
                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode MMR-coded generic region");
721
12
                    goto cleanup;
722
12
                }
723
8.40k
            }
724
725
            /* advance past the data we've just read */
726
9.28k
            code = jbig2_huffman_advance(hs, BMSIZE);
727
9.28k
            if (code < 0) {
728
0
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to advance after huffman decoding MMR bitmap image");
729
0
                goto cleanup;
730
0
            }
731
732
            /* copy the collective bitmap into the symbol dictionary */
733
9.28k
            x = 0;
734
286k
            for (j = HCFIRSTSYM; j < NSYMSDECODED; j++) {
735
277k
                glyph = jbig2_image_new(ctx, SDNEWSYMWIDTHS[j], HCHEIGHT);
736
277k
                if (glyph == NULL) {
737
20
                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to copy the collective bitmap into symbol dictionary");
738
20
                    goto cleanup;
739
20
                }
740
277k
                code = jbig2_image_compose(ctx, glyph, image, -x, 0, JBIG2_COMPOSE_REPLACE);
741
277k
                if (code) {
742
0
                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to compose image into glyph");
743
0
                    goto cleanup;
744
0
                }
745
277k
                x += SDNEWSYMWIDTHS[j];
746
277k
                SDNEWSYMS->glyphs[j] = glyph;
747
277k
                glyph = NULL;
748
277k
            }
749
9.26k
            jbig2_image_release(ctx, image);
750
9.26k
            image = NULL;
751
9.26k
        }
752
753
1.51M
    }                           /* end of symbol decode loop */
754
755
    /* 6.5.10 */
756
4.78k
    SDEXSYMS = jbig2_sd_new(ctx, params->SDNUMEXSYMS);
757
4.78k
    if (SDEXSYMS == NULL) {
758
102
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate symbols exported from symbols dictionary");
759
102
        goto cleanup;
760
4.68k
    } else {
761
4.68k
        uint32_t i = 0;
762
4.68k
        uint32_t j = 0;
763
4.68k
        uint32_t k;
764
4.68k
        int exflag = 0;
765
4.68k
        uint32_t limit = params->SDNUMINSYMS + params->SDNUMNEWSYMS;
766
4.68k
        uint32_t EXRUNLENGTH;
767
768
33.3k
        while (i < limit) {
769
28.6k
            if (params->SDHUFF)
770
14.6k
                EXRUNLENGTH = jbig2_huffman_get(hs, tparams.SBHUFFRSIZE, &code);
771
14.0k
            else
772
14.0k
                code = jbig2_arith_int_decode(ctx, IAEX, as, (int32_t *) &EXRUNLENGTH);
773
28.6k
            if (code < 0) {
774
1
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode runlength for exported symbols");
775
                /* skip to the cleanup code and return SDEXSYMS = NULL */
776
1
                jbig2_sd_release(ctx, SDEXSYMS);
777
1
                SDEXSYMS = NULL;
778
1
                break;
779
1
            }
780
28.6k
            if (code > 0) {
781
12
                jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB when decoding runlength for exported symbols");
782
                /* skip to the cleanup code and return SDEXSYMS = NULL */
783
12
                jbig2_sd_release(ctx, SDEXSYMS);
784
12
                SDEXSYMS = NULL;
785
12
                break;
786
12
            }
787
788
            /* prevent infinite list of empty runs, 1000 is just an arbitrary number */
789
28.6k
            if (EXRUNLENGTH <= 0 && ++emptyruns == 1000) {
790
12
                jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "runlength too small in export symbol table (%u == 0 i = %u limit = %u)", EXRUNLENGTH, i, limit);
791
                /* skip to the cleanup code and return SDEXSYMS = NULL */
792
12
                jbig2_sd_release(ctx, SDEXSYMS);
793
12
                SDEXSYMS = NULL;
794
12
                break;
795
28.6k
            } else if (EXRUNLENGTH > 0) {
796
13.5k
                emptyruns = 0;
797
13.5k
            }
798
799
28.6k
            if (EXRUNLENGTH > limit - i) {
800
3.63k
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "exporting more symbols than available (%u > %u), capping", i + EXRUNLENGTH, limit);
801
3.63k
                EXRUNLENGTH = limit - i;
802
3.63k
            }
803
28.6k
            if (exflag && j + EXRUNLENGTH > params->SDNUMEXSYMS) {
804
2.35k
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "exporting more symbols than may be exported (%u > %u), capping", j + EXRUNLENGTH, params->SDNUMEXSYMS);
805
2.35k
                EXRUNLENGTH = params->SDNUMEXSYMS - j;
806
2.35k
            }
807
808
12.8M
            for (k = 0; k < EXRUNLENGTH; k++) {
809
12.8M
                if (exflag) {
810
635k
                    Jbig2Image *img;
811
635k
                    if (i < params->SDNUMINSYMS) {
812
614k
                        img = params->SDINSYMS->glyphs[i];
813
614k
                    } else {
814
21.1k
                        img = SDNEWSYMS->glyphs[i - params->SDNUMINSYMS];
815
21.1k
                    }
816
635k
                    SDEXSYMS->glyphs[j++] = jbig2_image_reference(ctx, img);
817
635k
                }
818
12.8M
                i++;
819
12.8M
            }
820
28.6k
            exflag = !exflag;
821
28.6k
        }
822
4.68k
    }
823
824
5.90k
cleanup:
825
5.90k
    jbig2_image_release(ctx, glyph);
826
5.90k
    jbig2_image_release(ctx, image);
827
5.90k
    if (refagg_dicts != NULL) {
828
5.81k
        if (refagg_dicts[0] != NULL)
829
5.80k
            jbig2_sd_release(ctx, refagg_dicts[0]);
830
        /* skip releasing refagg_dicts[1] as that is the same as SDNEWSYMS */
831
5.81k
        jbig2_free(ctx->allocator, refagg_dicts);
832
5.81k
    }
833
5.90k
    jbig2_sd_release(ctx, SDNEWSYMS);
834
5.90k
    if (params->SDHUFF) {
835
3.25k
        jbig2_release_huffman_table(ctx, tparams.SBHUFFRSIZE);
836
3.25k
        jbig2_release_huffman_table(ctx, tparams.SBHUFFRDY);
837
3.25k
        jbig2_release_huffman_table(ctx, tparams.SBHUFFRDX);
838
3.25k
        jbig2_release_huffman_table(ctx, tparams.SBHUFFRDH);
839
3.25k
        jbig2_release_huffman_table(ctx, tparams.SBHUFFRDW);
840
3.25k
        jbig2_release_huffman_table(ctx, tparams.SBHUFFDT);
841
3.25k
        jbig2_release_huffman_table(ctx, tparams.SBHUFFDS);
842
3.25k
        jbig2_release_huffman_table(ctx, tparams.SBHUFFFS);
843
3.25k
        if (!params->SDREFAGG) {
844
2.63k
            jbig2_free(ctx->allocator, SDNEWSYMWIDTHS);
845
2.63k
        }
846
3.25k
        jbig2_huffman_free(ctx, hs);
847
3.25k
    } else {
848
2.64k
        jbig2_arith_int_ctx_free(ctx, tparams.IARDY);
849
2.64k
        jbig2_arith_int_ctx_free(ctx, tparams.IARDX);
850
2.64k
        jbig2_arith_int_ctx_free(ctx, tparams.IARDH);
851
2.64k
        jbig2_arith_int_ctx_free(ctx, tparams.IARDW);
852
2.64k
        jbig2_arith_int_ctx_free(ctx, tparams.IARI);
853
2.64k
        jbig2_arith_iaid_ctx_free(ctx, tparams.IAID);
854
2.64k
        jbig2_arith_int_ctx_free(ctx, tparams.IAIT);
855
2.64k
        jbig2_arith_int_ctx_free(ctx, tparams.IADS);
856
2.64k
        jbig2_arith_int_ctx_free(ctx, tparams.IAFS);
857
2.64k
        jbig2_arith_int_ctx_free(ctx, tparams.IADT);
858
2.64k
        jbig2_arith_int_ctx_free(ctx, IAAI);
859
2.64k
        jbig2_arith_int_ctx_free(ctx, IAEX);
860
2.64k
        jbig2_arith_int_ctx_free(ctx, IADW);
861
2.64k
        jbig2_arith_int_ctx_free(ctx, IADH);
862
2.64k
    }
863
5.90k
    jbig2_free(ctx->allocator, as);
864
5.90k
    jbig2_word_stream_buf_free(ctx, ws);
865
866
5.90k
    return SDEXSYMS;
867
4.78k
}
868
869
/* 7.4.2 */
870
int
871
jbig2_symbol_dictionary(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data)
872
6.02k
{
873
6.02k
    Jbig2SymbolDictParams params;
874
6.02k
    uint16_t flags;
875
6.02k
    uint32_t sdat_bytes;
876
6.02k
    uint32_t offset;
877
6.02k
    Jbig2ArithCx *GB_stats = NULL;
878
6.02k
    Jbig2ArithCx *GR_stats = NULL;
879
6.02k
    int table_index = 0;
880
6.02k
    const Jbig2HuffmanParams *huffman_params;
881
882
6.02k
    params.SDHUFF = 0;
883
884
6.02k
    if (segment->data_length < 10)
885
32
        goto too_short;
886
887
    /* 7.4.2.1.1 */
888
5.99k
    flags = jbig2_get_uint16(segment_data);
889
890
    /* zero params to ease cleanup later */
891
5.99k
    memset(&params, 0, sizeof(Jbig2SymbolDictParams));
892
893
5.99k
    params.SDHUFF = flags & 1;
894
5.99k
    params.SDREFAGG = (flags >> 1) & 1;
895
5.99k
    params.SDTEMPLATE = (flags >> 10) & 3;
896
5.99k
    params.SDRTEMPLATE = (flags >> 12) & 1;
897
898
5.99k
    if (params.SDHUFF) {
899
3.32k
        switch ((flags & 0x000c) >> 2) {
900
2.96k
        case 0:                /* Table B.4 */
901
2.96k
            params.SDHUFFDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_D);
902
2.96k
            break;
903
238
        case 1:                /* Table B.5 */
904
238
            params.SDHUFFDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_E);
905
238
            break;
906
122
        case 3:                /* Custom table from referred segment */
907
122
            huffman_params = jbig2_find_table(ctx, segment, table_index);
908
122
            if (huffman_params == NULL) {
909
10
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom DH huffman table not found (%d)", table_index);
910
10
                goto cleanup;
911
10
            }
912
112
            params.SDHUFFDH = jbig2_build_huffman_table(ctx, huffman_params);
913
112
            ++table_index;
914
112
            break;
915
1
        case 2:
916
1
        default:
917
1
            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "symbol dictionary specified invalid huffman table");
918
3.32k
        }
919
3.31k
        if (params.SDHUFFDH == NULL) {
920
4
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate DH huffman table");
921
4
            goto cleanup;
922
4
        }
923
924
3.30k
        switch ((flags & 0x0030) >> 4) {
925
2.87k
        case 0:                /* Table B.2 */
926
2.87k
            params.SDHUFFDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_B);
927
2.87k
            break;
928
336
        case 1:                /* Table B.3 */
929
336
            params.SDHUFFDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_C);
930
336
            break;
931
98
        case 3:                /* Custom table from referred segment */
932
98
            huffman_params = jbig2_find_table(ctx, segment, table_index);
933
98
            if (huffman_params == NULL) {
934
10
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom DW huffman table not found (%d)", table_index);
935
10
                goto cleanup;
936
10
            }
937
88
            params.SDHUFFDW = jbig2_build_huffman_table(ctx, huffman_params);
938
88
            ++table_index;
939
88
            break;
940
4
        case 2:
941
4
        default:
942
4
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "symbol dictionary specified invalid huffman table");
943
4
            goto cleanup;       /* Jump direct to cleanup to avoid 2 errors being given */
944
3.30k
        }
945
3.29k
        if (params.SDHUFFDW == NULL) {
946
7
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate DW huffman table");
947
7
            goto cleanup;
948
7
        }
949
950
3.28k
        if (flags & 0x0040) {
951
            /* Custom table from referred segment */
952
102
            huffman_params = jbig2_find_table(ctx, segment, table_index);
953
102
            if (huffman_params == NULL) {
954
7
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom BMSIZE huffman table not found (%d)", table_index);
955
7
                goto cleanup;
956
7
            }
957
95
            params.SDHUFFBMSIZE = jbig2_build_huffman_table(ctx, huffman_params);
958
95
            ++table_index;
959
3.18k
        } else {
960
            /* Table B.1 */
961
3.18k
            params.SDHUFFBMSIZE = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A);
962
3.18k
        }
963
3.28k
        if (params.SDHUFFBMSIZE == NULL) {
964
1
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate BMSIZE huffman table");
965
1
            goto cleanup;
966
1
        }
967
968
3.27k
        if (flags & 0x0080) {
969
            /* Custom table from referred segment */
970
49
            huffman_params = jbig2_find_table(ctx, segment, table_index);
971
49
            if (huffman_params == NULL) {
972
4
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom REFAGG huffman table not found (%d)", table_index);
973
4
                goto cleanup;
974
4
            }
975
45
            params.SDHUFFAGGINST = jbig2_build_huffman_table(ctx, huffman_params);
976
45
            ++table_index;
977
3.23k
        } else {
978
            /* Table B.1 */
979
3.23k
            params.SDHUFFAGGINST = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A);
980
3.23k
        }
981
3.27k
        if (params.SDHUFFAGGINST == NULL) {
982
1
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate REFAGG huffman table");
983
1
            goto cleanup;
984
1
        }
985
3.27k
    }
986
987
    /* FIXME: there are quite a few of these conditions to check */
988
    /* maybe #ifdef CONFORMANCE and a separate routine */
989
5.94k
    if (!params.SDHUFF) {
990
2.67k
        if (flags & 0x000c) {
991
5
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "SDHUFF is zero, but contrary to spec SDHUFFDH is not.");
992
5
            goto cleanup;
993
5
        }
994
2.66k
        if (flags & 0x0030) {
995
2
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "SDHUFF is zero, but contrary to spec SDHUFFDW is not.");
996
2
            goto cleanup;
997
2
        }
998
2.66k
    }
999
1000
    /* 7.4.2.1.2 */
1001
5.93k
    sdat_bytes = params.SDHUFF ? 0 : params.SDTEMPLATE == 0 ? 8 : 2;
1002
5.93k
    memcpy(params.sdat, segment_data + 2, sdat_bytes);
1003
5.93k
    offset = 2 + sdat_bytes;
1004
1005
    /* 7.4.2.1.3 */
1006
5.93k
    if (params.SDREFAGG && !params.SDRTEMPLATE) {
1007
790
        if (offset + 4 > segment->data_length)
1008
1
            goto too_short;
1009
789
        memcpy(params.sdrat, segment_data + offset, 4);
1010
789
        offset += 4;
1011
789
    }
1012
1013
5.93k
    if (offset + 8 > segment->data_length)
1014
8
        goto too_short;
1015
1016
    /* 7.4.2.1.4 */
1017
5.92k
    params.SDNUMEXSYMS = jbig2_get_uint32(segment_data + offset);
1018
    /* 7.4.2.1.5 */
1019
5.92k
    params.SDNUMNEWSYMS = jbig2_get_uint32(segment_data + offset + 4);
1020
5.92k
    offset += 8;
1021
1022
5.92k
    jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
1023
5.92k
                "symbol dictionary, flags=%04x, %u exported syms, %u new syms", flags, params.SDNUMEXSYMS, params.SDNUMNEWSYMS);
1024
1025
    /* 7.4.2.2 (2) */
1026
5.92k
    {
1027
5.92k
        uint32_t n_dicts = jbig2_sd_count_referred(ctx, segment);
1028
5.92k
        Jbig2SymbolDict **dicts = NULL;
1029
1030
5.92k
        if (n_dicts > 0) {
1031
1.05k
            dicts = jbig2_sd_list_referred(ctx, segment);
1032
1.05k
            if (dicts == NULL) {
1033
1
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate dicts in symbol dictionary");
1034
1
                goto cleanup;
1035
1
            }
1036
1.05k
            params.SDINSYMS = jbig2_sd_cat(ctx, n_dicts, dicts);
1037
1.05k
            if (params.SDINSYMS == NULL) {
1038
4
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate symbol array in symbol dictionary");
1039
4
                jbig2_free(ctx->allocator, dicts);
1040
4
                goto cleanup;
1041
4
            }
1042
1.05k
            jbig2_free(ctx->allocator, dicts);
1043
1.05k
        }
1044
5.92k
        if (params.SDINSYMS != NULL) {
1045
1.05k
            params.SDNUMINSYMS = params.SDINSYMS->n_symbols;
1046
1.05k
        }
1047
5.92k
    }
1048
1049
    /* 7.4.2.2 (3, 4) */
1050
5.92k
    if (flags & 0x0100) {
1051
10
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "segment marks bitmap coding context as used (NYI)");
1052
10
        goto cleanup;
1053
5.91k
    } else {
1054
5.91k
        int stats_size = params.SDTEMPLATE == 0 ? 65536 : params.SDTEMPLATE == 1 ? 8192 : 1024;
1055
1056
5.91k
        GB_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
1057
5.91k
        if (GB_stats == NULL) {
1058
1
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate arithmetic decoder states for generic regions");
1059
1
            goto cleanup;
1060
1
        }
1061
5.91k
        memset(GB_stats, 0, sizeof (Jbig2ArithCx) * stats_size);
1062
1063
5.91k
        stats_size = params.SDRTEMPLATE ? 1 << 10 : 1 << 13;
1064
5.91k
        GR_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
1065
5.91k
        if (GR_stats == NULL) {
1066
1
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate arithmetic decoder states for generic refinement regions");
1067
1
            jbig2_free(ctx->allocator, GB_stats);
1068
1
            goto cleanup;
1069
1
        }
1070
5.91k
        memset(GR_stats, 0, sizeof (Jbig2ArithCx) * stats_size);
1071
5.91k
    }
1072
1073
5.91k
    segment->result = (void *)jbig2_decode_symbol_dict(ctx, segment, &params, segment_data + offset, segment->data_length - offset, GB_stats, GR_stats);
1074
#ifdef DUMP_SYMDICT
1075
    if (segment->result)
1076
        jbig2_dump_symbol_dict(ctx, segment);
1077
#endif
1078
1079
    /* 7.4.2.2 (7) */
1080
5.91k
    if (flags & 0x0200) {
1081
        /* todo: retain GB_stats, GR_stats */
1082
310
        jbig2_free(ctx->allocator, GR_stats);
1083
310
        jbig2_free(ctx->allocator, GB_stats);
1084
310
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "segment marks bitmap coding context as retained (NYI)");
1085
310
        goto cleanup;
1086
5.60k
    } else {
1087
5.60k
        jbig2_free(ctx->allocator, GR_stats);
1088
5.60k
        jbig2_free(ctx->allocator, GB_stats);
1089
5.60k
    }
1090
1091
5.98k
cleanup:
1092
5.98k
    if (params.SDHUFF) {
1093
3.32k
        jbig2_release_huffman_table(ctx, params.SDHUFFDH);
1094
3.32k
        jbig2_release_huffman_table(ctx, params.SDHUFFDW);
1095
3.32k
        jbig2_release_huffman_table(ctx, params.SDHUFFBMSIZE);
1096
3.32k
        jbig2_release_huffman_table(ctx, params.SDHUFFAGGINST);
1097
3.32k
    }
1098
5.98k
    jbig2_sd_release(ctx, params.SDINSYMS);
1099
1100
5.98k
    return (segment->result != NULL) ? 0 : -1;
1101
1102
41
too_short:
1103
41
    if (params.SDHUFF) {
1104
2
        jbig2_release_huffman_table(ctx, params.SDHUFFDH);
1105
2
        jbig2_release_huffman_table(ctx, params.SDHUFFDW);
1106
2
        jbig2_release_huffman_table(ctx, params.SDHUFFBMSIZE);
1107
2
        jbig2_release_huffman_table(ctx, params.SDHUFFAGGINST);
1108
2
    }
1109
41
    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
1110
5.91k
}