Coverage Report

Created: 2025-06-24 07:01

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