Coverage Report

Created: 2022-10-31 07:00

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