Coverage Report

Created: 2026-08-14 07:34

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