Coverage Report

Created: 2026-07-24 07:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/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
351
{
101
351
    Jbig2SymbolDict *new_dict = NULL;
102
103
351
    new_dict = jbig2_new(ctx, Jbig2SymbolDict, 1);
104
351
    if (new_dict != NULL) {
105
351
        new_dict->glyphs = jbig2_new(ctx, Jbig2Image *, n_symbols);
106
351
        new_dict->n_symbols = n_symbols;
107
351
    } else {
108
0
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate new empty symbol dictionary");
109
0
        return NULL;
110
0
    }
111
112
351
    if (new_dict->glyphs != NULL) {
113
351
        memset(new_dict->glyphs, 0, n_symbols * sizeof(Jbig2Image *));
114
351
    } else if (new_dict->n_symbols > 0) {
115
0
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate glyphs for new empty symbol dictionary");
116
0
        jbig2_free(ctx->allocator, new_dict);
117
0
        return NULL;
118
0
    }
119
120
351
    return new_dict;
121
351
}
122
123
/* release the memory associated with a symbol dict */
124
void
125
jbig2_sd_release(Jbig2Ctx *ctx, Jbig2SymbolDict *dict)
126
466
{
127
466
    uint32_t i;
128
129
466
    if (dict == NULL)
130
115
        return;
131
351
    if (dict->glyphs != NULL)
132
1.68k
        for (i = 0; i < dict->n_symbols; i++)
133
1.33k
            jbig2_image_release(ctx, dict->glyphs[i]);
134
351
    jbig2_free(ctx->allocator, dict->glyphs);
135
351
    jbig2_free(ctx->allocator, dict);
136
351
}
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
304
{
151
304
    int index;
152
304
    Jbig2Segment *rsegment;
153
304
    uint32_t n_dicts = 0;
154
155
554
    for (index = 0; index < segment->referred_to_segment_count; index++) {
156
250
        rsegment = jbig2_find_segment(ctx, segment->referred_to_segments[index]);
157
250
        if (rsegment && ((rsegment->flags & 63) == 0) &&
158
179
            rsegment->result && (((Jbig2SymbolDict *) rsegment->result)->n_symbols > 0) && ((*((Jbig2SymbolDict *) rsegment->result)->glyphs) != NULL))
159
178
            n_dicts++;
160
250
    }
161
162
304
    return (n_dicts);
163
304
}
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
89
{
169
89
    int index;
170
89
    Jbig2Segment *rsegment;
171
89
    Jbig2SymbolDict **dicts;
172
89
    uint32_t n_dicts = jbig2_sd_count_referred(ctx, segment);
173
89
    uint32_t dindex = 0;
174
175
89
    dicts = jbig2_new(ctx, Jbig2SymbolDict *, n_dicts);
176
89
    if (dicts == NULL) {
177
0
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate referred list of symbol dictionaries");
178
0
        return NULL;
179
0
    }
180
181
206
    for (index = 0; index < segment->referred_to_segment_count; index++) {
182
117
        rsegment = jbig2_find_segment(ctx, segment->referred_to_segments[index]);
183
117
        if (rsegment && ((rsegment->flags & 63) == 0) && rsegment->result &&
184
89
                (((Jbig2SymbolDict *) rsegment->result)->n_symbols > 0) && ((*((Jbig2SymbolDict *) rsegment->result)->glyphs) != NULL)) {
185
            /* add this referred to symbol dictionary */
186
89
            dicts[dindex++] = (Jbig2SymbolDict *) rsegment->result;
187
89
        }
188
117
    }
189
190
89
    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
89
    return (dicts);
198
89
}
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
6
{
205
6
    uint32_t i, j, k, symbols;
206
6
    Jbig2SymbolDict *new_dict = NULL;
207
208
    /* count the imported symbols and allocate a new array */
209
6
    symbols = 0;
210
12
    for (i = 0; i < n_dicts; i++)
211
6
    {
212
6
        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
6
        symbols += dicts[i]->n_symbols;
218
6
    }
219
220
    /* fill a new array with new references to glyph pointers */
221
6
    new_dict = jbig2_sd_new(ctx, symbols);
222
6
    if (new_dict != NULL) {
223
6
        k = 0;
224
12
        for (i = 0; i < n_dicts; i++)
225
35
            for (j = 0; j < dicts[i]->n_symbols; j++)
226
29
                new_dict->glyphs[k++] = jbig2_image_reference(ctx, dicts[i]->glyphs[j]);
227
6
    } else {
228
0
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate new symbol dictionary");
229
0
    }
230
231
6
    return new_dict;
232
6
}
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
119
{
242
119
    Jbig2SymbolDict *SDNEWSYMS = NULL;
243
119
    Jbig2SymbolDict *SDEXSYMS = NULL;
244
119
    uint32_t HCHEIGHT;
245
119
    uint32_t NSYMSDECODED;
246
119
    uint32_t SYMWIDTH, TOTWIDTH;
247
119
    uint32_t HCFIRSTSYM;
248
119
    uint32_t *SDNEWSYMWIDTHS = NULL;
249
119
    uint8_t SBSYMCODELEN = 0;
250
119
    Jbig2WordStream *ws = NULL;
251
119
    Jbig2HuffmanState *hs = NULL;
252
119
    Jbig2ArithState *as = NULL;
253
119
    Jbig2ArithIntCtx *IADH = NULL;
254
119
    Jbig2ArithIntCtx *IADW = NULL;
255
119
    Jbig2ArithIntCtx *IAEX = NULL;
256
119
    Jbig2ArithIntCtx *IAAI = NULL;
257
119
    int code = 0;
258
119
    Jbig2SymbolDict **refagg_dicts = NULL;
259
119
    uint32_t i;
260
119
    Jbig2TextRegionParams tparams;
261
119
    Jbig2Image *image = NULL;
262
119
    Jbig2Image *glyph = NULL;
263
119
    uint32_t emptyruns = 0;
264
265
119
    memset(&tparams, 0, sizeof(tparams));
266
267
    /* 6.5.5 (3) */
268
119
    HCHEIGHT = 0;
269
119
    NSYMSDECODED = 0;
270
271
119
    ws = jbig2_word_stream_buf_new(ctx, data, size);
272
119
    if (ws == NULL) {
273
0
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate word stream when decoding symbol dictionary");
274
0
        return NULL;
275
0
    }
276
277
119
    as = jbig2_arith_new(ctx, ws);
278
119
    if (as == NULL) {
279
0
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate arithmetic coding state when decoding symbol dictionary");
280
0
        jbig2_word_stream_buf_free(ctx, ws);
281
0
        return NULL;
282
0
    }
283
284
408
    for (SBSYMCODELEN = 0; ((uint64_t) 1 << SBSYMCODELEN) < ((uint64_t) params->SDNUMINSYMS + params->SDNUMNEWSYMS); SBSYMCODELEN++);
285
286
119
    if (params->SDHUFF) {
287
35
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "huffman coded symbol dictionary");
288
35
        hs = jbig2_huffman_new(ctx, ws);
289
35
        tparams.SBHUFFRDX = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);   /* Table B.15 */
290
35
        tparams.SBHUFFRDY = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);   /* Table B.15 */
291
35
        tparams.SBHUFFRSIZE = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A); /* Table B.1 */
292
35
        if (hs == NULL || tparams.SBHUFFRDX == NULL ||
293
35
                tparams.SBHUFFRDY == NULL || tparams.SBHUFFRSIZE == NULL) {
294
0
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate for symbol bitmap");
295
0
            goto cleanup;
296
0
        }
297
        /* 6.5.5 (2) */
298
35
        if (!params->SDREFAGG) {
299
33
            SDNEWSYMWIDTHS = jbig2_new(ctx, uint32_t, params->SDNUMNEWSYMS);
300
33
            if (SDNEWSYMWIDTHS == NULL) {
301
0
                jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate symbol widths (%u)", params->SDNUMNEWSYMS);
302
0
                goto cleanup;
303
0
            }
304
33
        } else {
305
2
            tparams.SBHUFFFS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_F);    /* Table B.6 */
306
2
            tparams.SBHUFFDS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_H);    /* Table B.8 */
307
2
            tparams.SBHUFFDT = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_K);    /* Table B.11 */
308
2
            tparams.SBHUFFRDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);   /* Table B.15 */
309
2
            tparams.SBHUFFRDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);   /* Table B.15 */
310
2
            if (tparams.SBHUFFFS == NULL || tparams.SBHUFFDS == NULL ||
311
2
                    tparams.SBHUFFDT == NULL || tparams.SBHUFFRDW == NULL ||
312
2
                    tparams.SBHUFFRDH == NULL) {
313
0
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "out of memory creating text region huffman decoder entries");
314
0
                goto cleanup;
315
0
            }
316
2
        }
317
84
    } else {
318
84
        IADH = jbig2_arith_int_ctx_new(ctx);
319
84
        IADW = jbig2_arith_int_ctx_new(ctx);
320
84
        IAEX = jbig2_arith_int_ctx_new(ctx);
321
84
        IAAI = jbig2_arith_int_ctx_new(ctx);
322
84
        if (IADH == NULL || IADW == NULL || IAEX == NULL || IAAI == NULL) {
323
0
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate symbol bitmap");
324
0
            goto cleanup;
325
0
        }
326
84
        tparams.IAID = jbig2_arith_iaid_ctx_new(ctx, SBSYMCODELEN);
327
84
        tparams.IARDX = jbig2_arith_int_ctx_new(ctx);
328
84
        tparams.IARDY = jbig2_arith_int_ctx_new(ctx);
329
84
        if (tparams.IAID == NULL || tparams.IARDX == NULL ||
330
84
                tparams.IARDY == NULL) {
331
0
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region arithmetic decoder contexts");
332
0
            goto cleanup;
333
0
        }
334
84
        if (params->SDREFAGG) {
335
            /* Values from Table 17, section 6.5.8.2 (2) */
336
3
            tparams.IADT = jbig2_arith_int_ctx_new(ctx);
337
3
            tparams.IAFS = jbig2_arith_int_ctx_new(ctx);
338
3
            tparams.IADS = jbig2_arith_int_ctx_new(ctx);
339
3
            tparams.IAIT = jbig2_arith_int_ctx_new(ctx);
340
            /* Table 31 */
341
3
            tparams.IARI = jbig2_arith_int_ctx_new(ctx);
342
3
            tparams.IARDW = jbig2_arith_int_ctx_new(ctx);
343
3
            tparams.IARDH = jbig2_arith_int_ctx_new(ctx);
344
3
            if (tparams.IADT == NULL || tparams.IAFS == NULL ||
345
3
                    tparams.IADS == NULL || tparams.IAIT == NULL ||
346
3
                    tparams.IARI == NULL || tparams.IARDW == NULL ||
347
3
                    tparams.IARDH == NULL) {
348
0
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region arith decoder contexts");
349
0
                goto cleanup;
350
0
            }
351
3
        }
352
84
    }
353
119
    tparams.SBHUFF = params->SDHUFF;
354
119
    tparams.SBREFINE = 1;
355
119
    tparams.SBSTRIPS = 1;
356
119
    tparams.SBDEFPIXEL = 0;
357
119
    tparams.SBCOMBOP = JBIG2_COMPOSE_OR;
358
119
    tparams.TRANSPOSED = 0;
359
119
    tparams.REFCORNER = JBIG2_CORNER_TOPLEFT;
360
119
    tparams.SBDSOFFSET = 0;
361
119
    tparams.SBRTEMPLATE = params->SDRTEMPLATE;
362
363
    /* 6.5.5 (1) */
364
119
    SDNEWSYMS = jbig2_sd_new(ctx, params->SDNUMNEWSYMS);
365
119
    if (SDNEWSYMS == NULL) {
366
0
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate new symbols (%u)", params->SDNUMNEWSYMS);
367
0
        goto cleanup;
368
0
    }
369
370
119
    refagg_dicts = jbig2_new(ctx, Jbig2SymbolDict *, 2);
371
119
    if (refagg_dicts == NULL) {
372
0
        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Out of memory allocating dictionary array");
373
0
        goto cleanup;
374
0
    }
375
119
    refagg_dicts[0] = jbig2_sd_new(ctx, params->SDNUMINSYMS);
376
119
    if (refagg_dicts[0] == NULL) {
377
0
        code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "out of memory allocating symbol dictionary");
378
0
        goto cleanup;
379
0
    }
380
147
    for (i = 0; i < params->SDNUMINSYMS; i++) {
381
28
        refagg_dicts[0]->glyphs[i] = jbig2_image_reference(ctx, params->SDINSYMS->glyphs[i]);
382
28
    }
383
119
    refagg_dicts[1] = SDNEWSYMS;
384
385
    /* 6.5.5 (4a) */
386
365
    while (NSYMSDECODED < params->SDNUMNEWSYMS) {
387
258
        int32_t HCDH, DW;
388
389
        /* 6.5.6 */
390
258
        if (params->SDHUFF) {
391
125
            HCDH = jbig2_huffman_get(hs, params->SDHUFFDH, &code);
392
133
        } else {
393
133
            code = jbig2_arith_int_decode(ctx, IADH, as, &HCDH);
394
133
        }
395
258
        if (code < 0) {
396
0
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode height class delta");
397
0
            goto cleanup;
398
0
        }
399
258
        if (code > 0) {
400
0
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "OOB decoding height class delta");
401
0
            goto cleanup;
402
0
        }
403
404
        /* 6.5.5 (4b) */
405
258
        HCHEIGHT = HCHEIGHT + HCDH;
406
258
        SYMWIDTH = 0;
407
258
        TOTWIDTH = 0;
408
258
        HCFIRSTSYM = NSYMSDECODED;
409
410
258
        if ((int32_t) HCHEIGHT < 0) {
411
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "invalid HCHEIGHT value");
412
0
            goto cleanup;
413
0
        }
414
#ifdef JBIG2_DEBUG
415
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "HCHEIGHT = %d", HCHEIGHT);
416
#endif
417
258
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "decoding height class %d with %d syms decoded", HCHEIGHT, NSYMSDECODED);
418
419
892
        for (;;) {
420
            /* 6.5.7 */
421
892
            if (params->SDHUFF) {
422
264
                DW = jbig2_huffman_get(hs, params->SDHUFFDW, &code);
423
628
            } else {
424
628
                code = jbig2_arith_int_decode(ctx, IADW, as, &DW);
425
628
            }
426
892
            if (code < 0)
427
0
            {
428
0
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode DW");
429
0
                goto cleanup;
430
0
            }
431
            /* 6.5.5 (4c.i) */
432
892
            if (code > 0) {
433
240
                jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "OOB when decoding DW signals end of height class %d", HCHEIGHT);
434
240
                break;
435
240
            }
436
437
            /* check for broken symbol table */
438
652
            if (NSYMSDECODED >= params->SDNUMNEWSYMS) {
439
12
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "no OOB signaling end of height class %d, continuing", HCHEIGHT);
440
12
                break;
441
12
            }
442
443
640
            if (DW < 0 && SYMWIDTH < (uint32_t) -DW) {
444
3
                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
3
                goto cleanup;
446
3
            }
447
637
            if (DW > 0 && (uint32_t) DW > UINT32_MAX - SYMWIDTH) {
448
0
                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
0
                goto cleanup;
450
0
            }
451
452
637
            SYMWIDTH = SYMWIDTH + DW;
453
637
            if (SYMWIDTH > UINT32_MAX - TOTWIDTH) {
454
0
                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
0
                goto cleanup;
456
0
            }
457
458
637
            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
637
            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
499
                if (!params->SDREFAGG) {
469
490
                    Jbig2GenericRegionParams region_params;
470
490
                    int sdat_bytes;
471
472
                    /* Table 16 */
473
490
                    region_params.MMR = 0;
474
490
                    region_params.GBTEMPLATE = params->SDTEMPLATE;
475
490
                    region_params.TPGDON = 0;
476
490
                    region_params.USESKIP = 0;
477
490
                    sdat_bytes = params->SDTEMPLATE == 0 ? 8 : 2;
478
490
                    memcpy(region_params.gbat, params->sdat, sdat_bytes);
479
480
490
                    image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT);
481
490
                    if (image == NULL) {
482
0
                        code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate image");
483
0
                        goto cleanup;
484
0
                    }
485
486
490
                    code = jbig2_decode_generic_region(ctx, segment, &region_params, as, image, GB_stats);
487
490
                    if (code < 0) {
488
1
                        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode generic region");
489
1
                        goto cleanup;
490
1
                    }
491
492
489
                    SDNEWSYMS->glyphs[NSYMSDECODED] = image;
493
489
                    image = NULL;
494
489
                } else {
495
                    /* 6.5.8.2 refinement/aggregate symbol */
496
9
                    uint32_t REFAGGNINST;
497
498
9
                    if (params->SDHUFF) {
499
3
                        REFAGGNINST = jbig2_huffman_get(hs, params->SDHUFFAGGINST, &code);
500
6
                    } else {
501
6
                        code = jbig2_arith_int_decode(ctx, IAAI, as, (int32_t *) &REFAGGNINST);
502
6
                    }
503
9
                    if (code < 0) {
504
0
                        code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode number of symbols in aggregate glyph");
505
0
                        goto cleanup;
506
0
                    }
507
9
                    if (code > 0) {
508
0
                        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB in number of symbols in aggregate glyph");
509
0
                        goto cleanup;
510
0
                    }
511
9
                    if ((int32_t) REFAGGNINST <= 0) {
512
0
                        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "invalid number of symbols in aggregate glyph");
513
0
                        goto cleanup;
514
0
                    }
515
516
9
                    jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "aggregate symbol coding (%d instances)", REFAGGNINST);
517
518
9
                    if (REFAGGNINST > 1) {
519
5
                        tparams.SBNUMINSTANCES = REFAGGNINST;
520
521
5
                        image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT);
522
5
                        if (image == NULL) {
523
0
                            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate symbol image");
524
0
                            goto cleanup;
525
0
                        }
526
527
                        /* multiple symbols are handled as a text region */
528
5
                        code = jbig2_decode_text_region(ctx, segment, &tparams, (const Jbig2SymbolDict * const *)refagg_dicts,
529
5
                                                        2, image, GR_stats, as, ws);
530
5
                        if (code < 0) {
531
2
                            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode text region");
532
2
                            goto cleanup;
533
2
                        }
534
535
3
                        SDNEWSYMS->glyphs[NSYMSDECODED] = image;
536
3
                        image = NULL;
537
4
                    } else {
538
                        /* 6.5.8.2.2 */
539
                        /* bool SBHUFF = params->SDHUFF; */
540
4
                        Jbig2RefinementRegionParams rparams;
541
4
                        uint32_t ID;
542
4
                        int32_t RDX, RDY;
543
4
                        size_t BMSIZE = 0;
544
4
                        uint32_t ninsyms = params->SDNUMINSYMS;
545
4
                        int code1 = 0;
546
4
                        int code2 = 0;
547
4
                        int code3 = 0;
548
4
                        int code4 = 0;
549
4
                        int code5 = 0;
550
551
                        /* 6.5.8.2.2 (2, 3, 4, 5) */
552
4
                        if (params->SDHUFF) {
553
1
                            ID = jbig2_huffman_get_bits(hs, SBSYMCODELEN, &code1);
554
1
                            RDX = jbig2_huffman_get(hs, tparams.SBHUFFRDX, &code2);
555
1
                            RDY = jbig2_huffman_get(hs, tparams.SBHUFFRDY, &code3);
556
1
                            BMSIZE = jbig2_huffman_get(hs, tparams.SBHUFFRSIZE, &code4);
557
1
                            code5 = jbig2_huffman_skip(hs);
558
3
                        } else {
559
3
                            code1 = jbig2_arith_iaid_decode(ctx, tparams.IAID, as, (int32_t *) &ID);
560
3
                            code2 = jbig2_arith_int_decode(ctx, tparams.IARDX, as, &RDX);
561
3
                            code3 = jbig2_arith_int_decode(ctx, tparams.IARDY, as, &RDY);
562
3
                        }
563
564
4
                        if (code1 < 0 || code2 < 0 || code3 < 0 || code4 < 0 || code5 < 0) {
565
0
                            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode data");
566
0
                            goto cleanup;
567
0
                        }
568
4
                        if (code1 > 0 || code2 > 0 || code3 > 0 || code4 > 0 || code5 > 0) {
569
0
                            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB in single refinement/aggregate coded symbol data");
570
0
                            goto cleanup;
571
0
                        }
572
573
4
                        if (ID >= ninsyms + NSYMSDECODED) {
574
0
                            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "refinement references unknown symbol %d", ID);
575
0
                            goto cleanup;
576
0
                        }
577
578
4
                        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
579
4
                                    "symbol is a refinement of ID %d with the refinement applied at (%d,%d)", ID, RDX, RDY);
580
581
4
                        image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT);
582
4
                        if (image == NULL) {
583
0
                            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate symbol image");
584
0
                            goto cleanup;
585
0
                        }
586
587
                        /* Table 18 */
588
4
                        rparams.GRTEMPLATE = params->SDRTEMPLATE;
589
4
                        rparams.GRREFERENCE = (ID < ninsyms) ? params->SDINSYMS->glyphs[ID] : SDNEWSYMS->glyphs[ID - ninsyms];
590
                        /* SumatraPDF: fail on missing glyphs */
591
4
                        if (rparams.GRREFERENCE == NULL) {
592
0
                            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "missing glyph %d/%d", ID, ninsyms);
593
0
                            goto cleanup;
594
0
                        }
595
4
                        rparams.GRREFERENCEDX = RDX;
596
4
                        rparams.GRREFERENCEDY = RDY;
597
4
                        rparams.TPGRON = 0;
598
4
                        memcpy(rparams.grat, params->sdrat, 4);
599
4
                        code = jbig2_decode_refinement_region(ctx, segment, &rparams, as, image, GR_stats);
600
4
                        if (code < 0) {
601
0
                            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode refinement region");
602
0
                            goto cleanup;
603
0
                        }
604
605
4
                        SDNEWSYMS->glyphs[NSYMSDECODED] = image;
606
4
                        image = NULL;
607
608
                        /* 6.5.8.2.2 (7) */
609
4
                        if (params->SDHUFF) {
610
1
                            if (BMSIZE == 0)
611
0
                                BMSIZE = (size_t) SDNEWSYMS->glyphs[NSYMSDECODED]->height *
612
0
                                    SDNEWSYMS->glyphs[NSYMSDECODED]->stride;
613
1
                            code = jbig2_huffman_advance(hs, BMSIZE);
614
1
                            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
1
                        }
619
4
                    }
620
9
                }
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
499
            }
641
642
            /* 6.5.5 (4c.iii) */
643
634
            if (params->SDHUFF && !params->SDREFAGG) {
644
138
                SDNEWSYMWIDTHS[NSYMSDECODED] = SYMWIDTH;
645
138
            }
646
647
            /* 6.5.5 (4c.iv) */
648
634
            NSYMSDECODED = NSYMSDECODED + 1;
649
650
634
            jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "decoded symbol %u of %u (%ux%u)", NSYMSDECODED, params->SDNUMNEWSYMS, SYMWIDTH, HCHEIGHT);
651
652
634
        }                       /* end height class decode loop */
653
654
        /* 6.5.5 (4d) */
655
252
        if (params->SDHUFF && !params->SDREFAGG) {
656
            /* 6.5.9 */
657
123
            size_t BMSIZE;
658
123
            uint32_t j;
659
123
            int x;
660
661
123
            BMSIZE = jbig2_huffman_get(hs, params->SDHUFFBMSIZE, &code);
662
123
            if (code < 0) {
663
0
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "error decoding size of collective bitmap");
664
0
                goto cleanup;
665
0
            }
666
123
            if (code > 0) {
667
0
                jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB obtained when decoding size of collective bitmap");
668
0
                goto cleanup;
669
0
            }
670
671
            /* skip any bits before the next byte boundary */
672
123
            code = jbig2_huffman_skip(hs);
673
123
            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
123
            image = jbig2_image_new(ctx, TOTWIDTH, HCHEIGHT);
678
123
            if (image == NULL) {
679
2
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate collective bitmap image");
680
2
                goto cleanup;
681
2
            }
682
683
121
            if (BMSIZE == 0) {
684
                /* if BMSIZE == 0 bitmap is uncompressed */
685
4
                const byte *src = data + jbig2_huffman_offset(hs);
686
4
                const int stride = (image->width >> 3) + ((image->width & 7) ? 1 : 0);
687
4
                byte *dst = image->data;
688
689
                /* SumatraPDF: prevent read access violation */
690
4
                if (size < jbig2_huffman_offset(hs) || (size - jbig2_huffman_offset(hs) < (size_t) image->height * stride) || (size < jbig2_huffman_offset(hs))) {
691
0
                    jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "not enough data for decoding uncompressed (%d/%li)", image->height * stride,
692
0
                                (long) (size - jbig2_huffman_offset(hs)));
693
0
                    goto cleanup;
694
0
                }
695
696
4
                BMSIZE = (size_t) image->height * stride;
697
4
                jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
698
4
                            "reading %dx%d uncompressed bitmap for %d symbols (%li bytes)", image->width, image->height, NSYMSDECODED - HCFIRSTSYM, (long) BMSIZE);
699
700
414
                for (j = 0; j < image->height; j++) {
701
410
                    memcpy(dst, src, stride);
702
410
                    dst += image->stride;
703
410
                    src += stride;
704
410
                }
705
117
            } else {
706
117
                Jbig2GenericRegionParams rparams;
707
708
                /* SumatraPDF: prevent read access violation */
709
117
                if (size < jbig2_huffman_offset(hs) || size < BMSIZE || size - jbig2_huffman_offset(hs) < BMSIZE) {
710
1
                    jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "not enough data for decoding (%li/%li)", (long) BMSIZE, (long) (size - jbig2_huffman_offset(hs)));
711
1
                    goto cleanup;
712
1
                }
713
714
116
                jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
715
116
                            "reading %dx%d collective bitmap for %d symbols (%li bytes)", image->width, image->height, NSYMSDECODED - HCFIRSTSYM, (long) BMSIZE);
716
717
116
                rparams.MMR = 1;
718
116
                code = jbig2_decode_generic_mmr(ctx, segment, &rparams, data + jbig2_huffman_offset(hs), BMSIZE, image);
719
116
                if (code) {
720
3
                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode MMR-coded generic region");
721
3
                    goto cleanup;
722
3
                }
723
116
            }
724
725
            /* advance past the data we've just read */
726
117
            code = jbig2_huffman_advance(hs, BMSIZE);
727
117
            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
117
            x = 0;
734
248
            for (j = HCFIRSTSYM; j < NSYMSDECODED; j++) {
735
131
                glyph = jbig2_image_new(ctx, SDNEWSYMWIDTHS[j], HCHEIGHT);
736
131
                if (glyph == NULL) {
737
0
                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to copy the collective bitmap into symbol dictionary");
738
0
                    goto cleanup;
739
0
                }
740
131
                code = jbig2_image_compose(ctx, glyph, image, -x, 0, JBIG2_COMPOSE_REPLACE);
741
131
                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
131
                x += SDNEWSYMWIDTHS[j];
746
131
                SDNEWSYMS->glyphs[j] = glyph;
747
131
                glyph = NULL;
748
131
            }
749
117
            jbig2_image_release(ctx, image);
750
117
            image = NULL;
751
117
        }
752
753
252
    }                           /* end of symbol decode loop */
754
755
    /* 6.5.10 */
756
107
    SDEXSYMS = jbig2_sd_new(ctx, params->SDNUMEXSYMS);
757
107
    if (SDEXSYMS == NULL) {
758
0
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate symbols exported from symbols dictionary");
759
0
        goto cleanup;
760
107
    } else {
761
107
        uint32_t i = 0;
762
107
        uint32_t j = 0;
763
107
        uint32_t k;
764
107
        int exflag = 0;
765
107
        uint32_t limit = params->SDNUMINSYMS + params->SDNUMNEWSYMS;
766
107
        uint32_t EXRUNLENGTH;
767
768
1.32k
        while (i < limit) {
769
1.21k
            if (params->SDHUFF)
770
1.05k
                EXRUNLENGTH = jbig2_huffman_get(hs, tparams.SBHUFFRSIZE, &code);
771
162
            else
772
162
                code = jbig2_arith_int_decode(ctx, IAEX, as, (int32_t *) &EXRUNLENGTH);
773
1.21k
            if (code < 0) {
774
0
                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
0
                jbig2_sd_release(ctx, SDEXSYMS);
777
0
                SDEXSYMS = NULL;
778
0
                break;
779
0
            }
780
1.21k
            if (code > 0) {
781
0
                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
0
                jbig2_sd_release(ctx, SDEXSYMS);
784
0
                SDEXSYMS = NULL;
785
0
                break;
786
0
            }
787
788
            /* prevent infinite list of empty runs, 1000 is just an arbitrary number */
789
1.21k
            if (EXRUNLENGTH <= 0 && ++emptyruns == 1000) {
790
1
                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
1
                jbig2_sd_release(ctx, SDEXSYMS);
793
1
                SDEXSYMS = NULL;
794
1
                break;
795
1.21k
            } else if (EXRUNLENGTH > 0) {
796
119
                emptyruns = 0;
797
119
            }
798
799
1.21k
            if (EXRUNLENGTH > limit - i) {
800
12
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "exporting more symbols than available (%u > %u), capping", i + EXRUNLENGTH, limit);
801
12
                EXRUNLENGTH = limit - i;
802
12
            }
803
1.21k
            if (exflag && j + EXRUNLENGTH > params->SDNUMEXSYMS) {
804
0
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "exporting more symbols than may be exported (%u > %u), capping", j + EXRUNLENGTH, params->SDNUMEXSYMS);
805
0
                EXRUNLENGTH = params->SDNUMEXSYMS - j;
806
0
            }
807
808
1.82k
            for (k = 0; k < EXRUNLENGTH; k++) {
809
616
                if (exflag) {
810
559
                    Jbig2Image *img;
811
559
                    if (i < params->SDNUMINSYMS) {
812
16
                        img = params->SDINSYMS->glyphs[i];
813
543
                    } else {
814
543
                        img = SDNEWSYMS->glyphs[i - params->SDNUMINSYMS];
815
543
                    }
816
559
                    SDEXSYMS->glyphs[j++] = jbig2_image_reference(ctx, img);
817
559
                }
818
616
                i++;
819
616
            }
820
1.21k
            exflag = !exflag;
821
1.21k
        }
822
107
    }
823
824
119
cleanup:
825
119
    jbig2_image_release(ctx, glyph);
826
119
    jbig2_image_release(ctx, image);
827
119
    if (refagg_dicts != NULL) {
828
119
        if (refagg_dicts[0] != NULL)
829
119
            jbig2_sd_release(ctx, refagg_dicts[0]);
830
        /* skip releasing refagg_dicts[1] as that is the same as SDNEWSYMS */
831
119
        jbig2_free(ctx->allocator, refagg_dicts);
832
119
    }
833
119
    jbig2_sd_release(ctx, SDNEWSYMS);
834
119
    if (params->SDHUFF) {
835
35
        jbig2_release_huffman_table(ctx, tparams.SBHUFFRSIZE);
836
35
        jbig2_release_huffman_table(ctx, tparams.SBHUFFRDY);
837
35
        jbig2_release_huffman_table(ctx, tparams.SBHUFFRDX);
838
35
        jbig2_release_huffman_table(ctx, tparams.SBHUFFRDH);
839
35
        jbig2_release_huffman_table(ctx, tparams.SBHUFFRDW);
840
35
        jbig2_release_huffman_table(ctx, tparams.SBHUFFDT);
841
35
        jbig2_release_huffman_table(ctx, tparams.SBHUFFDS);
842
35
        jbig2_release_huffman_table(ctx, tparams.SBHUFFFS);
843
35
        if (!params->SDREFAGG) {
844
33
            jbig2_free(ctx->allocator, SDNEWSYMWIDTHS);
845
33
        }
846
35
        jbig2_huffman_free(ctx, hs);
847
84
    } else {
848
84
        jbig2_arith_int_ctx_free(ctx, tparams.IARDY);
849
84
        jbig2_arith_int_ctx_free(ctx, tparams.IARDX);
850
84
        jbig2_arith_int_ctx_free(ctx, tparams.IARDH);
851
84
        jbig2_arith_int_ctx_free(ctx, tparams.IARDW);
852
84
        jbig2_arith_int_ctx_free(ctx, tparams.IARI);
853
84
        jbig2_arith_iaid_ctx_free(ctx, tparams.IAID);
854
84
        jbig2_arith_int_ctx_free(ctx, tparams.IAIT);
855
84
        jbig2_arith_int_ctx_free(ctx, tparams.IADS);
856
84
        jbig2_arith_int_ctx_free(ctx, tparams.IAFS);
857
84
        jbig2_arith_int_ctx_free(ctx, tparams.IADT);
858
84
        jbig2_arith_int_ctx_free(ctx, IAAI);
859
84
        jbig2_arith_int_ctx_free(ctx, IAEX);
860
84
        jbig2_arith_int_ctx_free(ctx, IADW);
861
84
        jbig2_arith_int_ctx_free(ctx, IADH);
862
84
    }
863
119
    jbig2_free(ctx->allocator, as);
864
119
    jbig2_word_stream_buf_free(ctx, ws);
865
866
119
    return SDEXSYMS;
867
107
}
868
869
/* 7.4.2 */
870
int
871
jbig2_symbol_dictionary(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data)
872
130
{
873
130
    Jbig2SymbolDictParams params;
874
130
    uint16_t flags;
875
130
    uint32_t sdat_bytes;
876
130
    uint32_t offset;
877
130
    Jbig2ArithCx *GB_stats = NULL;
878
130
    Jbig2ArithCx *GR_stats = NULL;
879
130
    int table_index = 0;
880
130
    const Jbig2HuffmanParams *huffman_params;
881
882
130
    params.SDHUFF = 0;
883
884
130
    if (segment->data_length < 10)
885
9
        goto too_short;
886
887
    /* 7.4.2.1.1 */
888
121
    flags = jbig2_get_uint16(segment_data);
889
890
    /* zero params to ease cleanup later */
891
121
    memset(&params, 0, sizeof(Jbig2SymbolDictParams));
892
893
121
    params.SDHUFF = flags & 1;
894
121
    params.SDREFAGG = (flags >> 1) & 1;
895
121
    params.SDTEMPLATE = (flags >> 10) & 3;
896
121
    params.SDRTEMPLATE = (flags >> 12) & 1;
897
898
121
    if (params.SDHUFF) {
899
35
        switch ((flags & 0x000c) >> 2) {
900
33
        case 0:                /* Table B.4 */
901
33
            params.SDHUFFDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_D);
902
33
            break;
903
1
        case 1:                /* Table B.5 */
904
1
            params.SDHUFFDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_E);
905
1
            break;
906
1
        case 3:                /* Custom table from referred segment */
907
1
            huffman_params = jbig2_find_table(ctx, segment, table_index);
908
1
            if (huffman_params == NULL) {
909
0
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom DH huffman table not found (%d)", table_index);
910
0
                goto cleanup;
911
0
            }
912
1
            params.SDHUFFDH = jbig2_build_huffman_table(ctx, huffman_params);
913
1
            ++table_index;
914
1
            break;
915
0
        case 2:
916
0
        default:
917
0
            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "symbol dictionary specified invalid huffman table");
918
35
        }
919
35
        if (params.SDHUFFDH == NULL) {
920
0
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate DH huffman table");
921
0
            goto cleanup;
922
0
        }
923
924
35
        switch ((flags & 0x0030) >> 4) {
925
33
        case 0:                /* Table B.2 */
926
33
            params.SDHUFFDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_B);
927
33
            break;
928
1
        case 1:                /* Table B.3 */
929
1
            params.SDHUFFDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_C);
930
1
            break;
931
1
        case 3:                /* Custom table from referred segment */
932
1
            huffman_params = jbig2_find_table(ctx, segment, table_index);
933
1
            if (huffman_params == NULL) {
934
0
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom DW huffman table not found (%d)", table_index);
935
0
                goto cleanup;
936
0
            }
937
1
            params.SDHUFFDW = jbig2_build_huffman_table(ctx, huffman_params);
938
1
            ++table_index;
939
1
            break;
940
0
        case 2:
941
0
        default:
942
0
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "symbol dictionary specified invalid huffman table");
943
0
            goto cleanup;       /* Jump direct to cleanup to avoid 2 errors being given */
944
35
        }
945
35
        if (params.SDHUFFDW == NULL) {
946
0
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate DW huffman table");
947
0
            goto cleanup;
948
0
        }
949
950
35
        if (flags & 0x0040) {
951
            /* Custom table from referred segment */
952
1
            huffman_params = jbig2_find_table(ctx, segment, table_index);
953
1
            if (huffman_params == NULL) {
954
0
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom BMSIZE huffman table not found (%d)", table_index);
955
0
                goto cleanup;
956
0
            }
957
1
            params.SDHUFFBMSIZE = jbig2_build_huffman_table(ctx, huffman_params);
958
1
            ++table_index;
959
34
        } else {
960
            /* Table B.1 */
961
34
            params.SDHUFFBMSIZE = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A);
962
34
        }
963
35
        if (params.SDHUFFBMSIZE == NULL) {
964
0
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate BMSIZE huffman table");
965
0
            goto cleanup;
966
0
        }
967
968
35
        if (flags & 0x0080) {
969
            /* Custom table from referred segment */
970
1
            huffman_params = jbig2_find_table(ctx, segment, table_index);
971
1
            if (huffman_params == NULL) {
972
0
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom REFAGG huffman table not found (%d)", table_index);
973
0
                goto cleanup;
974
0
            }
975
1
            params.SDHUFFAGGINST = jbig2_build_huffman_table(ctx, huffman_params);
976
1
            ++table_index;
977
34
        } else {
978
            /* Table B.1 */
979
34
            params.SDHUFFAGGINST = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A);
980
34
        }
981
35
        if (params.SDHUFFAGGINST == NULL) {
982
0
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate REFAGG huffman table");
983
0
            goto cleanup;
984
0
        }
985
35
    }
986
987
    /* FIXME: there are quite a few of these conditions to check */
988
    /* maybe #ifdef CONFORMANCE and a separate routine */
989
121
    if (!params.SDHUFF) {
990
86
        if (flags & 0x000c) {
991
1
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "SDHUFF is zero, but contrary to spec SDHUFFDH is not.");
992
1
            goto cleanup;
993
1
        }
994
85
        if (flags & 0x0030) {
995
0
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "SDHUFF is zero, but contrary to spec SDHUFFDW is not.");
996
0
            goto cleanup;
997
0
        }
998
85
    }
999
1000
    /* 7.4.2.1.2 */
1001
120
    sdat_bytes = params.SDHUFF ? 0 : params.SDTEMPLATE == 0 ? 8 : 2;
1002
120
    memcpy(params.sdat, segment_data + 2, sdat_bytes);
1003
120
    offset = 2 + sdat_bytes;
1004
1005
    /* 7.4.2.1.3 */
1006
120
    if (params.SDREFAGG && !params.SDRTEMPLATE) {
1007
4
        if (offset + 4 > segment->data_length)
1008
0
            goto too_short;
1009
4
        memcpy(params.sdrat, segment_data + offset, 4);
1010
4
        offset += 4;
1011
4
    }
1012
1013
120
    if (offset + 8 > segment->data_length)
1014
0
        goto too_short;
1015
1016
    /* 7.4.2.1.4 */
1017
120
    params.SDNUMEXSYMS = jbig2_get_uint32(segment_data + offset);
1018
    /* 7.4.2.1.5 */
1019
120
    params.SDNUMNEWSYMS = jbig2_get_uint32(segment_data + offset + 4);
1020
120
    offset += 8;
1021
1022
120
    jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
1023
120
                "symbol dictionary, flags=%04x, %u exported syms, %u new syms", flags, params.SDNUMEXSYMS, params.SDNUMNEWSYMS);
1024
1025
    /* 7.4.2.2 (2) */
1026
120
    {
1027
120
        uint32_t n_dicts = jbig2_sd_count_referred(ctx, segment);
1028
120
        Jbig2SymbolDict **dicts = NULL;
1029
1030
120
        if (n_dicts > 0) {
1031
6
            dicts = jbig2_sd_list_referred(ctx, segment);
1032
6
            if (dicts == NULL) {
1033
0
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate dicts in symbol dictionary");
1034
0
                goto cleanup;
1035
0
            }
1036
6
            params.SDINSYMS = jbig2_sd_cat(ctx, n_dicts, dicts);
1037
6
            if (params.SDINSYMS == NULL) {
1038
0
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate symbol array in symbol dictionary");
1039
0
                jbig2_free(ctx->allocator, dicts);
1040
0
                goto cleanup;
1041
0
            }
1042
6
            jbig2_free(ctx->allocator, dicts);
1043
6
        }
1044
120
        if (params.SDINSYMS != NULL) {
1045
6
            params.SDNUMINSYMS = params.SDINSYMS->n_symbols;
1046
6
        }
1047
120
    }
1048
1049
    /* 7.4.2.2 (3, 4) */
1050
120
    if (flags & 0x0100) {
1051
1
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "segment marks bitmap coding context as used (NYI)");
1052
1
        goto cleanup;
1053
119
    } else {
1054
119
        int stats_size = params.SDTEMPLATE == 0 ? 65536 : params.SDTEMPLATE == 1 ? 8192 : 1024;
1055
1056
119
        GB_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
1057
119
        if (GB_stats == NULL) {
1058
0
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate arithmetic decoder states for generic regions");
1059
0
            goto cleanup;
1060
0
        }
1061
119
        memset(GB_stats, 0, sizeof (Jbig2ArithCx) * stats_size);
1062
1063
119
        stats_size = params.SDRTEMPLATE ? 1 << 10 : 1 << 13;
1064
119
        GR_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
1065
119
        if (GR_stats == NULL) {
1066
0
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate arithmetic decoder states for generic refinement regions");
1067
0
            jbig2_free(ctx->allocator, GB_stats);
1068
0
            goto cleanup;
1069
0
        }
1070
119
        memset(GR_stats, 0, sizeof (Jbig2ArithCx) * stats_size);
1071
119
    }
1072
1073
119
    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
119
    if (flags & 0x0200) {
1081
        /* todo: retain GB_stats, GR_stats */
1082
1
        jbig2_free(ctx->allocator, GR_stats);
1083
1
        jbig2_free(ctx->allocator, GB_stats);
1084
1
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "segment marks bitmap coding context as retained (NYI)");
1085
1
        goto cleanup;
1086
118
    } else {
1087
118
        jbig2_free(ctx->allocator, GR_stats);
1088
118
        jbig2_free(ctx->allocator, GB_stats);
1089
118
    }
1090
1091
121
cleanup:
1092
121
    if (params.SDHUFF) {
1093
35
        jbig2_release_huffman_table(ctx, params.SDHUFFDH);
1094
35
        jbig2_release_huffman_table(ctx, params.SDHUFFDW);
1095
35
        jbig2_release_huffman_table(ctx, params.SDHUFFBMSIZE);
1096
35
        jbig2_release_huffman_table(ctx, params.SDHUFFAGGINST);
1097
35
    }
1098
121
    jbig2_sd_release(ctx, params.SDINSYMS);
1099
1100
121
    return (segment->result != NULL) ? 0 : -1;
1101
1102
9
too_short:
1103
9
    if (params.SDHUFF) {
1104
0
        jbig2_release_huffman_table(ctx, params.SDHUFFDH);
1105
0
        jbig2_release_huffman_table(ctx, params.SDHUFFDW);
1106
0
        jbig2_release_huffman_table(ctx, params.SDHUFFBMSIZE);
1107
0
        jbig2_release_huffman_table(ctx, params.SDHUFFAGGINST);
1108
0
    }
1109
9
    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
1110
119
}