Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/jbig2dec/jbig2_text.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
#ifdef HAVE_CONFIG_H
21
#include "config.h"
22
#endif
23
#include "os_types.h"
24
25
#include <stddef.h>
26
#include <string.h>             /* memset() */
27
28
#include "jbig2.h"
29
#include "jbig2_priv.h"
30
#include "jbig2_arith.h"
31
#include "jbig2_arith_int.h"
32
#include "jbig2_arith_iaid.h"
33
#include "jbig2_generic.h"
34
#include "jbig2_huffman.h"
35
#include "jbig2_image.h"
36
#include "jbig2_page.h"
37
#include "jbig2_refinement.h"
38
#include "jbig2_segment.h"
39
#include "jbig2_symbol_dict.h"
40
#include "jbig2_text.h"
41
42
/**
43
 * jbig2_decode_text_region: decode a text region segment
44
 *
45
 * @ctx: jbig2 decoder context
46
 * @segment: jbig2 segment (header) structure
47
 * @params: parameters from the text region header
48
 * @dicts: an array of referenced symbol dictionaries
49
 * @n_dicts: the number of referenced symbol dictionaries
50
 * @image: image structure in which to store the decoded region bitmap
51
 * @data: pointer to text region data to be decoded
52
 * @size: length of text region data
53
 *
54
 * Implements the text region decoding procedure
55
 * described in section 6.4 of the JBIG2 spec.
56
 *
57
 * returns: 0 on success
58
 **/
59
int
60
jbig2_decode_text_region(Jbig2Ctx *ctx, Jbig2Segment *segment,
61
                         const Jbig2TextRegionParams *params,
62
                         const Jbig2SymbolDict *const *dicts, const uint32_t n_dicts,
63
                         Jbig2Image *image, const byte *data, const size_t size, Jbig2ArithCx *GR_stats, Jbig2ArithState *as, Jbig2WordStream *ws)
64
9
{
65
    /* relevant bits of 6.4.4 */
66
9
    uint32_t NINSTANCES;
67
9
    uint32_t ID;
68
9
    int32_t STRIPT;
69
9
    int32_t FIRSTS;
70
9
    int32_t DT;
71
9
    int32_t DFS;
72
9
    int32_t IDS;
73
9
    int32_t CURS;
74
9
    int32_t CURT;
75
9
    int S, T;
76
9
    int x, y;
77
9
    bool first_symbol;
78
9
    uint32_t index, SBNUMSYMS;
79
9
    Jbig2Image *IB = NULL;
80
9
    Jbig2Image *IBO = NULL;
81
9
    Jbig2Image *refimage = NULL;
82
9
    Jbig2HuffmanState *hs = NULL;
83
9
    Jbig2HuffmanTable *SBSYMCODES = NULL;
84
9
    int code = 0;
85
9
    int RI;
86
87
9
    SBNUMSYMS = 0;
88
17
    for (index = 0; index < n_dicts; index++) {
89
8
        SBNUMSYMS += dicts[index]->n_symbols;
90
8
    }
91
9
    jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "symbol list contains %d glyphs in %d dictionaries", SBNUMSYMS, n_dicts);
92
93
9
    if (params->SBHUFF) {
94
0
        Jbig2HuffmanTable *runcodes = NULL;
95
0
        Jbig2HuffmanParams runcodeparams;
96
0
        Jbig2HuffmanLine runcodelengths[35];
97
0
        Jbig2HuffmanLine *symcodelengths = NULL;
98
0
        Jbig2HuffmanParams symcodeparams;
99
0
        int err, len, range, r;
100
101
0
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "huffman coded text region");
102
0
        hs = jbig2_huffman_new(ctx, ws);
103
0
        if (hs == NULL)
104
0
            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region");
105
106
        /* 7.4.3.1.7 - decode symbol ID Huffman table */
107
        /* this is actually part of the segment header, but it is more
108
           convenient to handle it here */
109
110
        /* parse and build the runlength code huffman table */
111
0
        for (index = 0; index < 35; index++) {
112
0
            runcodelengths[index].PREFLEN = jbig2_huffman_get_bits(hs, 4, &code);
113
0
            if (code < 0) {
114
0
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to read huffman runcode lengths");
115
0
                goto cleanup1;
116
0
            }
117
0
            if (code > 0) {
118
0
                jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB decoding huffman runcode lengths");
119
0
                goto cleanup1;
120
0
            }
121
0
            runcodelengths[index].RANGELEN = 0;
122
0
            runcodelengths[index].RANGELOW = index;
123
0
            jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "  read runcode%d length %d", index, runcodelengths[index].PREFLEN);
124
0
        }
125
0
        runcodeparams.HTOOB = 0;
126
0
        runcodeparams.lines = runcodelengths;
127
0
        runcodeparams.n_lines = 35;
128
0
        runcodes = jbig2_build_huffman_table(ctx, &runcodeparams);
129
0
        if (runcodes == NULL) {
130
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "error constructing symbol ID runcode table");
131
0
            goto cleanup1;
132
0
        }
133
134
        /* decode the symbol ID code lengths using the runlength table */
135
0
        symcodelengths = jbig2_new(ctx, Jbig2HuffmanLine, SBNUMSYMS);
136
0
        if (symcodelengths == NULL) {
137
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate memory when reading symbol ID huffman table");
138
0
            goto cleanup1;
139
0
        }
140
0
        index = 0;
141
0
        while (index < SBNUMSYMS) {
142
0
            code = jbig2_huffman_get(hs, runcodes, &err);
143
0
            if (err < 0) {
144
0
                code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "error reading symbol ID huffman table");
145
0
                goto cleanup1;
146
0
            }
147
0
            if (err > 0) {
148
0
                code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB decoding symbol ID huffman table");
149
0
                goto cleanup1;
150
0
            }
151
0
            if (code < 0 || code >= 35) {
152
0
                code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "symbol ID huffman table out of range");
153
0
                goto cleanup1;
154
0
            }
155
156
0
            if (code < 32) {
157
0
                len = code;
158
0
                range = 1;
159
0
            } else {
160
0
                if (code == 32) {
161
0
                    if (index < 1) {
162
0
                        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "error decoding symbol ID table: run length with no antecedent");
163
0
                        goto cleanup1;
164
0
                    }
165
0
                    len = symcodelengths[index - 1].PREFLEN;
166
0
                } else {
167
0
                    len = 0;    /* code == 33 or 34 */
168
0
                }
169
0
                err = 0;
170
0
                if (code == 32)
171
0
                    range = jbig2_huffman_get_bits(hs, 2, &err) + 3;
172
0
                else if (code == 33)
173
0
                    range = jbig2_huffman_get_bits(hs, 3, &err) + 3;
174
0
                else if (code == 34)
175
0
                    range = jbig2_huffman_get_bits(hs, 7, &err) + 11;
176
0
                if (err < 0) {
177
0
                    code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to read huffman code");
178
0
                    goto cleanup1;
179
0
                }
180
0
                if (err > 0) {
181
0
                    code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB decoding huffman code");
182
0
                    goto cleanup1;
183
0
                }
184
0
            }
185
0
            jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "  read runcode%d at index %d (length %d range %d)", code, index, len, range);
186
0
            if (index + range > SBNUMSYMS) {
187
0
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
188
0
                            "runlength extends %d entries beyond the end of symbol ID table", index + range - SBNUMSYMS);
189
0
                range = SBNUMSYMS - index;
190
0
            }
191
0
            for (r = 0; r < range; r++) {
192
0
                symcodelengths[index + r].PREFLEN = len;
193
0
                symcodelengths[index + r].RANGELEN = 0;
194
0
                symcodelengths[index + r].RANGELOW = index + r;
195
0
            }
196
0
            index += r;
197
0
        }
198
199
0
        if (index < SBNUMSYMS) {
200
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "runlength codes do not cover the available symbol set");
201
0
            goto cleanup1;
202
0
        }
203
204
0
        symcodeparams.HTOOB = 0;
205
0
        symcodeparams.lines = symcodelengths;
206
0
        symcodeparams.n_lines = SBNUMSYMS;
207
208
        /* skip to byte boundary */
209
0
        err = jbig2_huffman_skip(hs);
210
0
        if (err < 0)
211
0
        {
212
0
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to skip to next byte when building huffman table");
213
0
            goto cleanup1;
214
0
        }
215
216
        /* finally, construct the symbol ID huffman table itself */
217
0
        SBSYMCODES = jbig2_build_huffman_table(ctx, &symcodeparams);
218
219
0
cleanup1:
220
0
        jbig2_free(ctx->allocator, symcodelengths);
221
0
        jbig2_release_huffman_table(ctx, runcodes);
222
223
0
        if (SBSYMCODES == NULL) {
224
0
            jbig2_huffman_free(ctx, hs);
225
0
            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to construct symbol ID huffman table");
226
0
        }
227
0
    }
228
229
    /* 6.4.5 (1) */
230
9
    jbig2_image_clear(ctx, image, params->SBDEFPIXEL);
231
232
    /* 6.4.6 */
233
9
    if (params->SBHUFF) {
234
0
        STRIPT = jbig2_huffman_get(hs, params->SBHUFFDT, &code);
235
9
    } else {
236
9
        code = jbig2_arith_int_decode(ctx, params->IADT, as, &STRIPT);
237
9
    }
238
9
    if (code < 0) {
239
0
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode strip T");
240
0
        goto cleanup2;
241
0
    }
242
9
    if (code > 0) {
243
0
        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB obtained when decoding strip T");
244
0
        goto cleanup2;
245
0
    }
246
247
    /* 6.4.5 (2) */
248
9
    STRIPT *= -(params->SBSTRIPS);
249
9
    FIRSTS = 0;
250
9
    NINSTANCES = 0;
251
252
    /* 6.4.5 (3) */
253
18
    while (NINSTANCES < params->SBNUMINSTANCES) {
254
        /* (3b) */
255
9
        if (params->SBHUFF) {
256
0
            DT = jbig2_huffman_get(hs, params->SBHUFFDT, &code);
257
9
        } else {
258
9
            code = jbig2_arith_int_decode(ctx, params->IADT, as, &DT);
259
9
        }
260
9
        if (code < 0) {
261
0
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode delta T");
262
0
            goto cleanup2;
263
0
        }
264
9
        if (code > 0) {
265
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB obtained when decoding delta T");
266
0
            goto cleanup2;
267
0
        }
268
9
        DT *= params->SBSTRIPS;
269
9
        STRIPT += DT;
270
271
9
        first_symbol = TRUE;
272
        /* 6.4.5 (3c) - decode symbols in strip */
273
93
        for (;;) {
274
            /* (3c.i) */
275
93
            if (first_symbol) {
276
                /* 6.4.7 */
277
9
                if (params->SBHUFF) {
278
0
                    DFS = jbig2_huffman_get(hs, params->SBHUFFFS, &code);
279
9
                } else {
280
9
                    code = jbig2_arith_int_decode(ctx, params->IAFS, as, &DFS);
281
9
                }
282
9
                if (code < 0) {
283
0
                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode strip symbol S-difference");
284
0
                    goto cleanup2;
285
0
                }
286
9
                if (code > 0) {
287
0
                    code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB obtained when decoding strip symbol S-difference");
288
0
                    goto cleanup2;
289
0
                }
290
9
                FIRSTS += DFS;
291
9
                CURS = FIRSTS;
292
9
                first_symbol = FALSE;
293
84
            } else {
294
84
                if (NINSTANCES > params->SBNUMINSTANCES) {
295
3
                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "too many NINSTANCES (%d) decoded", NINSTANCES);
296
3
                    break;
297
3
                }
298
                /* (3c.ii) / 6.4.8 */
299
81
                if (params->SBHUFF) {
300
0
                    IDS = jbig2_huffman_get(hs, params->SBHUFFDS, &code);
301
81
                } else {
302
81
                    code = jbig2_arith_int_decode(ctx, params->IADS, as, &IDS);
303
81
                }
304
81
                if (code < 0) {
305
0
                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode symbol instance S coordinate");
306
0
                    goto cleanup2;
307
0
                }
308
81
                if (code > 0) {
309
6
                    jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "OOB obtained when decoding symbol instance S coordinate signals end of strip with T value %d", DT);
310
6
                    break;
311
6
                }
312
75
                CURS += IDS + params->SBDSOFFSET;
313
75
            }
314
315
            /* (3c.iii) / 6.4.9 */
316
84
            if (params->SBSTRIPS == 1) {
317
0
                CURT = 0;
318
84
            } else if (params->SBHUFF) {
319
0
                CURT = jbig2_huffman_get_bits(hs, params->LOGSBSTRIPS, &code);
320
84
            } else {
321
84
                code = jbig2_arith_int_decode(ctx, params->IAIT, as, &CURT);
322
84
            }
323
84
            if (code < 0) {
324
0
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode symbol instance T coordinate");
325
0
                goto cleanup2;
326
0
            }
327
84
            if (code > 0) {
328
0
                code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "OOB obtained when decoding symbol instance T coordinate");
329
0
                goto cleanup2;
330
0
            }
331
84
            T = STRIPT + CURT;
332
333
            /* (3b.iv) / 6.4.10 - decode the symbol ID */
334
84
            if (params->SBHUFF) {
335
0
                ID = jbig2_huffman_get(hs, SBSYMCODES, &code);
336
84
            } else {
337
84
                code = jbig2_arith_iaid_decode(ctx, params->IAID, as, (int *)&ID);
338
84
            }
339
84
            if (code < 0) {
340
0
                code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to obtain symbol instance symbol ID");
341
0
                goto cleanup2;
342
0
            }
343
84
            if (code > 0) {
344
0
                code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB obtained when decoding symbol instance symbol ID");
345
0
                goto cleanup2;
346
0
            }
347
84
            if (ID >= SBNUMSYMS) {
348
10
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "ignoring out of range symbol ID (%d/%d)", ID, SBNUMSYMS);
349
10
                IB = NULL;
350
74
            } else {
351
                /* (3c.v) / 6.4.11 - look up the symbol bitmap IB */
352
74
                uint32_t id = ID;
353
354
74
                index = 0;
355
74
                while (id >= dicts[index]->n_symbols)
356
0
                    id -= dicts[index++]->n_symbols;
357
74
                if (dicts[index]->glyphs[id] == NULL) {
358
0
                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "missing glyph (%d/%d), ignoring", index, id);
359
74
                } else {
360
74
                    IB = jbig2_image_reference(ctx, dicts[index]->glyphs[id]);
361
74
                }
362
74
            }
363
84
            if (params->SBREFINE) {
364
0
                if (params->SBHUFF) {
365
0
                    RI = jbig2_huffman_get_bits(hs, 1, &code);
366
0
                } else {
367
0
                    code = jbig2_arith_int_decode(ctx, params->IARI, as, &RI);
368
0
                }
369
0
                if (code < 0) {
370
0
                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode symbol bitmap refinement indicator");
371
0
                    goto cleanup2;
372
0
                }
373
0
                if (code > 0) {
374
0
                    code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB obtained when decoding symbol bitmap refinement indicator");
375
0
                    goto cleanup2;
376
0
                }
377
84
            } else {
378
84
                RI = 0;
379
84
            }
380
84
            if (RI) {
381
0
                Jbig2RefinementRegionParams rparams;
382
0
                int32_t RDW, RDH, RDX, RDY;
383
0
                size_t BMSIZE = 0;
384
0
                int code1 = 0;
385
0
                int code2 = 0;
386
0
                int code3 = 0;
387
0
                int code4 = 0;
388
0
                int code5 = 0;
389
0
                int code6 = 0;
390
391
                /* 6.4.11 (1, 2, 3, 4) */
392
0
                if (!params->SBHUFF) {
393
0
                    code1 = jbig2_arith_int_decode(ctx, params->IARDW, as, &RDW);
394
0
                    code2 = jbig2_arith_int_decode(ctx, params->IARDH, as, &RDH);
395
0
                    code3 = jbig2_arith_int_decode(ctx, params->IARDX, as, &RDX);
396
0
                    code4 = jbig2_arith_int_decode(ctx, params->IARDY, as, &RDY);
397
0
                } else {
398
0
                    RDW = jbig2_huffman_get(hs, params->SBHUFFRDW, &code1);
399
0
                    RDH = jbig2_huffman_get(hs, params->SBHUFFRDH, &code2);
400
0
                    RDX = jbig2_huffman_get(hs, params->SBHUFFRDX, &code3);
401
0
                    RDY = jbig2_huffman_get(hs, params->SBHUFFRDY, &code4);
402
0
                    BMSIZE = jbig2_huffman_get(hs, params->SBHUFFRSIZE, &code5);
403
0
                    code6 = jbig2_huffman_skip(hs);
404
0
                }
405
406
0
                if (code1 < 0 || code2 < 0 || code3 < 0 || code4 < 0 || code5 < 0 || code6 < 0) {
407
0
                    jbig2_image_release(ctx, IB);
408
0
                    code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode data");
409
0
                    goto cleanup2;
410
0
                }
411
0
                if (code1 > 0 || code2 > 0 || code3 > 0 || code4 > 0 || code5 > 0 || code6 > 0) {
412
0
                    code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB obtained when decoding symbol instance refinement data");
413
0
                    goto cleanup2;
414
0
                }
415
416
                /* 6.4.11 (6) */
417
0
                if (IB) {
418
0
                    IBO = IB;
419
0
                    IB = NULL;
420
0
                    if (((int32_t) IBO->width) + RDW < 0 || ((int32_t) IBO->height) + RDH < 0) {
421
0
                        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "reference image dimensions negative");
422
0
                        goto cleanup2;
423
0
                    }
424
0
                    refimage = jbig2_image_new(ctx, IBO->width + RDW, IBO->height + RDH);
425
0
                    if (refimage == NULL) {
426
0
                        code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate reference image");
427
0
                        goto cleanup2;
428
0
                    }
429
0
                    jbig2_image_clear(ctx, refimage, 0x00);
430
431
                    /* Table 12 */
432
0
                    rparams.GRTEMPLATE = params->SBRTEMPLATE;
433
0
                    rparams.GRREFERENCE = IBO;
434
0
                    rparams.GRREFERENCEDX = (RDW >> 1) + RDX;
435
0
                    rparams.GRREFERENCEDY = (RDH >> 1) + RDY;
436
0
                    rparams.TPGRON = 0;
437
0
                    memcpy(rparams.grat, params->sbrat, 4);
438
0
                    code = jbig2_decode_refinement_region(ctx, segment, &rparams, as, refimage, GR_stats);
439
0
                    if (code < 0) {
440
0
                        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode refinement region");
441
0
                        goto cleanup2;
442
0
                    }
443
444
0
                    jbig2_image_release(ctx, IBO);
445
0
                    IBO = NULL;
446
0
                    IB = refimage;
447
0
                    refimage = NULL;
448
0
                }
449
450
                /* 6.4.11 (7) */
451
0
                if (params->SBHUFF) {
452
0
                    code = jbig2_huffman_advance(hs, BMSIZE);
453
0
                    if (code < 0) {
454
0
                        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to advance after huffman decoding refinement region");
455
0
                        goto cleanup2;
456
0
                    }
457
0
                }
458
0
            }
459
460
            /* (3c.vi) */
461
84
            if ((!params->TRANSPOSED) && (params->REFCORNER > 1) && IB) {
462
0
                CURS += IB->width - 1;
463
84
            } else if ((params->TRANSPOSED) && !(params->REFCORNER & 1) && IB) {
464
0
                CURS += IB->height - 1;
465
0
            }
466
467
            /* (3c.vii) */
468
84
            S = CURS;
469
470
            /* (3c.viii) */
471
84
            if (!params->TRANSPOSED) {
472
84
                switch (params->REFCORNER) {
473
0
                case JBIG2_CORNER_TOPLEFT:
474
0
                    x = S;
475
0
                    y = T;
476
0
                    break;
477
0
                case JBIG2_CORNER_TOPRIGHT:
478
0
                    if (IB)
479
0
                        x = S - IB->width + 1;
480
0
                    else
481
0
                        x = S + 1;
482
0
                    y = T;
483
0
                    break;
484
84
                case JBIG2_CORNER_BOTTOMLEFT:
485
84
                    x = S;
486
84
                    if (IB)
487
74
                        y = T - IB->height + 1;
488
10
                    else
489
10
                        y = T + 1;
490
84
                    break;
491
0
                default:
492
0
                case JBIG2_CORNER_BOTTOMRIGHT:
493
0
                    if (IB ) {
494
0
                        x = S - IB->width + 1;
495
0
                        y = T - IB->height + 1;
496
0
                    } else {
497
0
                        x = S + 1;
498
0
                        y = T + 1;
499
0
                    }
500
0
                    break;
501
84
                }
502
84
            } else {            /* TRANSPOSED */
503
0
                switch (params->REFCORNER) {
504
0
                case JBIG2_CORNER_TOPLEFT:
505
0
                    x = T;
506
0
                    y = S;
507
0
                    break;
508
0
                case JBIG2_CORNER_TOPRIGHT:
509
0
                    if (IB)
510
0
                        x = T - IB->width + 1;
511
0
                    else
512
0
                        x = T + 1;
513
0
                    y = S;
514
0
                    break;
515
0
                case JBIG2_CORNER_BOTTOMLEFT:
516
0
                    x = T;
517
0
                    if (IB)
518
0
                        y = S - IB->height + 1;
519
0
                    else
520
0
                        y = S + 1;
521
0
                    break;
522
0
                default:
523
0
                case JBIG2_CORNER_BOTTOMRIGHT:
524
0
                    if (IB) {
525
0
                        x = T - IB->width + 1;
526
0
                        y = S - IB->height + 1;
527
0
                    } else {
528
0
                        x = T + 1;
529
0
                        y = S + 1;
530
0
                    }
531
0
                    break;
532
0
                }
533
0
            }
534
535
            /* (3c.ix) */
536
#ifdef JBIG2_DEBUG
537
            jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
538
                        "composing glyph ID %d: %dx%d @ (%d,%d) symbol %d/%d", ID, IB->width, IB->height, x, y, NINSTANCES + 1, params->SBNUMINSTANCES);
539
#endif
540
84
            code = jbig2_image_compose(ctx, image, IB, x, y, params->SBCOMBOP);
541
84
            if (code < 0) {
542
0
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to compose symbol instance symbol bitmap into picture");
543
0
                goto cleanup2;
544
0
            }
545
546
            /* (3c.x) */
547
84
            if (IB && (!params->TRANSPOSED) && (params->REFCORNER < 2)) {
548
74
                CURS += IB->width - 1;
549
74
            } else if (IB && (params->TRANSPOSED) && (params->REFCORNER & 1)) {
550
0
                CURS += IB->height - 1;
551
0
            }
552
553
            /* (3c.xi) */
554
84
            NINSTANCES++;
555
556
84
            jbig2_image_release(ctx, IB);
557
84
            IB = NULL;
558
84
        }
559
        /* end strip */
560
9
    }
561
    /* 6.4.5 (4) */
562
563
9
cleanup2:
564
9
    jbig2_image_release(ctx, refimage);
565
9
    jbig2_image_release(ctx, IBO);
566
9
    jbig2_image_release(ctx, IB);
567
9
    if (params->SBHUFF) {
568
0
        jbig2_release_huffman_table(ctx, SBSYMCODES);
569
0
    }
570
9
    jbig2_huffman_free(ctx, hs);
571
572
9
    return code;
573
9
}
574
575
/**
576
 * jbig2_text_region: read a text region segment header
577
 **/
578
int
579
jbig2_text_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data)
580
9
{
581
9
    uint32_t offset = 0;
582
9
    Jbig2RegionSegmentInfo region_info;
583
9
    Jbig2TextRegionParams params;
584
9
    Jbig2Image *image = NULL;
585
9
    Jbig2SymbolDict **dicts = NULL;
586
9
    uint32_t n_dicts = 0;
587
9
    uint16_t flags = 0;
588
9
    uint16_t huffman_flags = 0;
589
9
    Jbig2ArithCx *GR_stats = NULL;
590
9
    int code = 0;
591
9
    Jbig2WordStream *ws = NULL;
592
9
    Jbig2ArithState *as = NULL;
593
9
    uint32_t table_index = 0;
594
9
    const Jbig2HuffmanParams *huffman_params = NULL;
595
596
    /* zero params to ease cleanup later */
597
9
    memset(&params, 0, sizeof(Jbig2TextRegionParams));
598
599
    /* 7.4.1 */
600
9
    if (segment->data_length < 17) {
601
0
        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
602
0
        goto cleanup2;
603
0
    }
604
9
    jbig2_get_region_segment_info(&region_info, segment_data);
605
9
    offset += 17;
606
    /* Check for T.88 amendment 3 */
607
9
    if (region_info.flags & 8)
608
0
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "region segment flags indicate use of colored bitmap (NYI)");
609
610
    /* 7.4.3.1.1 */
611
9
    if (segment->data_length - offset < 2) {
612
0
        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
613
0
        goto cleanup2;
614
0
    }
615
9
    flags = jbig2_get_uint16(segment_data + offset);
616
9
    offset += 2;
617
618
9
    jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "text region header flags 0x%04x", flags);
619
620
9
    params.SBHUFF = flags & 0x0001;
621
9
    params.SBREFINE = flags & 0x0002;
622
9
    params.LOGSBSTRIPS = (flags & 0x000c) >> 2;
623
9
    params.SBSTRIPS = 1 << params.LOGSBSTRIPS;
624
9
    params.REFCORNER = (Jbig2RefCorner)((flags & 0x0030) >> 4);
625
9
    params.TRANSPOSED = flags & 0x0040;
626
9
    params.SBCOMBOP = (Jbig2ComposeOp)((flags & 0x0180) >> 7);
627
9
    params.SBDEFPIXEL = flags & 0x0200;
628
    /* SBDSOFFSET is a signed 5 bit integer */
629
9
    params.SBDSOFFSET = (flags & 0x7C00) >> 10;
630
9
    if (params.SBDSOFFSET > 0x0f)
631
0
        params.SBDSOFFSET -= 0x20;
632
9
    params.SBRTEMPLATE = flags & 0x8000;
633
634
9
    if (params.SBDSOFFSET) {
635
0
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "text region has SBDSOFFSET %d", params.SBDSOFFSET);
636
0
    }
637
638
9
    if (params.SBHUFF) {        /* Huffman coding */
639
        /* 7.4.3.1.2 */
640
0
        if (segment->data_length - offset < 2) {
641
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
642
0
            goto cleanup2;
643
0
        }
644
0
        huffman_flags = jbig2_get_uint16(segment_data + offset);
645
0
        offset += 2;
646
647
0
        if (huffman_flags & 0x8000)
648
0
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "reserved bit 15 of text region huffman flags is not zero");
649
9
    } else {                    /* arithmetic coding */
650
651
        /* 7.4.3.1.3 */
652
9
        if (segment->data_length - offset < 4) {
653
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
654
0
            goto cleanup2;
655
0
        }
656
9
        if ((params.SBREFINE) && !(params.SBRTEMPLATE)) {
657
0
            params.sbrat[0] = segment_data[offset];
658
0
            params.sbrat[1] = segment_data[offset + 1];
659
0
            params.sbrat[2] = segment_data[offset + 2];
660
0
            params.sbrat[3] = segment_data[offset + 3];
661
0
            offset += 4;
662
0
        }
663
9
    }
664
665
    /* 7.4.3.1.4 */
666
9
    if (segment->data_length - offset < 4) {
667
0
        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
668
0
        goto cleanup2;
669
0
    }
670
9
    params.SBNUMINSTANCES = jbig2_get_uint32(segment_data + offset);
671
9
    offset += 4;
672
673
9
    if (params.SBHUFF) {
674
        /* 7.4.3.1.5 - Symbol ID Huffman table */
675
        /* ...this is handled in the segment body decoder */
676
677
        /* 7.4.3.1.6 - Other Huffman table selection */
678
0
        switch (huffman_flags & 0x0003) {
679
0
        case 0:                /* Table B.6 */
680
0
            params.SBHUFFFS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_F);
681
0
            break;
682
0
        case 1:                /* Table B.7 */
683
0
            params.SBHUFFFS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_G);
684
0
            break;
685
0
        case 3:                /* Custom table from referred segment */
686
0
            huffman_params = jbig2_find_table(ctx, segment, table_index);
687
0
            if (huffman_params == NULL) {
688
0
                code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom FS huffman table not found (%d)", table_index);
689
0
                goto cleanup1;
690
0
            }
691
0
            params.SBHUFFFS = jbig2_build_huffman_table(ctx, huffman_params);
692
0
            ++table_index;
693
0
            break;
694
0
        case 2:                /* invalid */
695
0
        default:
696
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "text region specified invalid FS huffman table");
697
0
            goto cleanup1;
698
0
            break;
699
0
        }
700
0
        if (params.SBHUFFFS == NULL) {
701
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region specified FS huffman table");
702
0
            goto cleanup1;
703
0
        }
704
705
0
        switch ((huffman_flags & 0x000c) >> 2) {
706
0
        case 0:                /* Table B.8 */
707
0
            params.SBHUFFDS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_H);
708
0
            break;
709
0
        case 1:                /* Table B.9 */
710
0
            params.SBHUFFDS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_I);
711
0
            break;
712
0
        case 2:                /* Table B.10 */
713
0
            params.SBHUFFDS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_J);
714
0
            break;
715
0
        case 3:                /* Custom table from referred segment */
716
0
            huffman_params = jbig2_find_table(ctx, segment, table_index);
717
0
            if (huffman_params == NULL) {
718
0
                code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom DS huffman table not found (%d)", table_index);
719
0
                goto cleanup1;
720
0
            }
721
0
            params.SBHUFFDS = jbig2_build_huffman_table(ctx, huffman_params);
722
0
            ++table_index;
723
0
            break;
724
0
        }
725
0
        if (params.SBHUFFDS == NULL) {
726
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region specified DS huffman table");
727
0
            goto cleanup1;
728
0
        }
729
730
0
        switch ((huffman_flags & 0x0030) >> 4) {
731
0
        case 0:                /* Table B.11 */
732
0
            params.SBHUFFDT = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_K);
733
0
            break;
734
0
        case 1:                /* Table B.12 */
735
0
            params.SBHUFFDT = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_L);
736
0
            break;
737
0
        case 2:                /* Table B.13 */
738
0
            params.SBHUFFDT = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_M);
739
0
            break;
740
0
        case 3:                /* Custom table from referred segment */
741
0
            huffman_params = jbig2_find_table(ctx, segment, table_index);
742
0
            if (huffman_params == NULL) {
743
0
                code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom DT huffman table not found (%d)", table_index);
744
0
                goto cleanup1;
745
0
            }
746
0
            params.SBHUFFDT = jbig2_build_huffman_table(ctx, huffman_params);
747
0
            ++table_index;
748
0
            break;
749
0
        }
750
0
        if (params.SBHUFFDT == NULL) {
751
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region specified DT huffman table");
752
0
            goto cleanup1;
753
0
        }
754
755
0
        switch ((huffman_flags & 0x00c0) >> 6) {
756
0
        case 0:                /* Table B.14 */
757
0
            params.SBHUFFRDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_N);
758
0
            break;
759
0
        case 1:                /* Table B.15 */
760
0
            params.SBHUFFRDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);
761
0
            break;
762
0
        case 3:                /* Custom table from referred segment */
763
0
            huffman_params = jbig2_find_table(ctx, segment, table_index);
764
0
            if (huffman_params == NULL) {
765
0
                code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom RDW huffman table not found (%d)", table_index);
766
0
                goto cleanup1;
767
0
            }
768
0
            params.SBHUFFRDW = jbig2_build_huffman_table(ctx, huffman_params);
769
0
            ++table_index;
770
0
            break;
771
0
        case 2:                /* invalid */
772
0
        default:
773
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "text region specified invalid RDW huffman table");
774
0
            goto cleanup1;
775
0
            break;
776
0
        }
777
0
        if (params.SBHUFFRDW == NULL) {
778
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region specified RDW huffman table");
779
0
            goto cleanup1;
780
0
        }
781
782
0
        switch ((huffman_flags & 0x0300) >> 8) {
783
0
        case 0:                /* Table B.14 */
784
0
            params.SBHUFFRDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_N);
785
0
            break;
786
0
        case 1:                /* Table B.15 */
787
0
            params.SBHUFFRDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);
788
0
            break;
789
0
        case 3:                /* Custom table from referred segment */
790
0
            huffman_params = jbig2_find_table(ctx, segment, table_index);
791
0
            if (huffman_params == NULL) {
792
0
                code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom RDH huffman table not found (%d)", table_index);
793
0
                goto cleanup1;
794
0
            }
795
0
            params.SBHUFFRDH = jbig2_build_huffman_table(ctx, huffman_params);
796
0
            ++table_index;
797
0
            break;
798
0
        case 2:                /* invalid */
799
0
        default:
800
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "text region specified invalid RDH huffman table");
801
0
            goto cleanup1;
802
0
            break;
803
0
        }
804
0
        if (params.SBHUFFRDH == NULL) {
805
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region specified RDH huffman table");
806
0
            goto cleanup1;
807
0
        }
808
809
0
        switch ((huffman_flags & 0x0c00) >> 10) {
810
0
        case 0:                /* Table B.14 */
811
0
            params.SBHUFFRDX = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_N);
812
0
            break;
813
0
        case 1:                /* Table B.15 */
814
0
            params.SBHUFFRDX = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);
815
0
            break;
816
0
        case 3:                /* Custom table from referred segment */
817
0
            huffman_params = jbig2_find_table(ctx, segment, table_index);
818
0
            if (huffman_params == NULL) {
819
0
                code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom RDX huffman table not found (%d)", table_index);
820
0
                goto cleanup1;
821
0
            }
822
0
            params.SBHUFFRDX = jbig2_build_huffman_table(ctx, huffman_params);
823
0
            ++table_index;
824
0
            break;
825
0
        case 2:                /* invalid */
826
0
        default:
827
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "text region specified invalid RDX huffman table");
828
0
            goto cleanup1;
829
0
            break;
830
0
        }
831
0
        if (params.SBHUFFRDX == NULL) {
832
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region specified RDX huffman table");
833
0
            goto cleanup1;
834
0
        }
835
836
0
        switch ((huffman_flags & 0x3000) >> 12) {
837
0
        case 0:                /* Table B.14 */
838
0
            params.SBHUFFRDY = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_N);
839
0
            break;
840
0
        case 1:                /* Table B.15 */
841
0
            params.SBHUFFRDY = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);
842
0
            break;
843
0
        case 3:                /* Custom table from referred segment */
844
0
            huffman_params = jbig2_find_table(ctx, segment, table_index);
845
0
            if (huffman_params == NULL) {
846
0
                code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom RDY huffman table not found (%d)", table_index);
847
0
                goto cleanup1;
848
0
            }
849
0
            params.SBHUFFRDY = jbig2_build_huffman_table(ctx, huffman_params);
850
0
            ++table_index;
851
0
            break;
852
0
        case 2:                /* invalid */
853
0
        default:
854
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "text region specified invalid RDY huffman table");
855
0
            goto cleanup1;
856
0
            break;
857
0
        }
858
0
        if (params.SBHUFFRDY == NULL) {
859
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region specified RDY huffman table");
860
0
            goto cleanup1;
861
0
        }
862
863
0
        switch ((huffman_flags & 0x4000) >> 14) {
864
0
        case 0:                /* Table B.1 */
865
0
            params.SBHUFFRSIZE = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A);
866
0
            break;
867
0
        case 1:                /* Custom table from referred segment */
868
0
            huffman_params = jbig2_find_table(ctx, segment, table_index);
869
0
            if (huffman_params == NULL) {
870
0
                code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom RSIZE huffman table not found (%d)", table_index);
871
0
                goto cleanup1;
872
0
            }
873
0
            params.SBHUFFRSIZE = jbig2_build_huffman_table(ctx, huffman_params);
874
0
            ++table_index;
875
0
            break;
876
0
        }
877
0
        if (params.SBHUFFRSIZE == NULL) {
878
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region specified RSIZE huffman table");
879
0
            goto cleanup1;
880
0
        }
881
882
0
        if (huffman_flags & 0x8000) {
883
0
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "text region huffman flags bit 15 is set, contrary to spec");
884
0
        }
885
886
        /* 7.4.3.1.7 */
887
        /* For convenience this is done in the body decoder routine */
888
0
    }
889
890
9
    jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
891
9
                "text region: %d x %d @ (%d,%d) %d symbols", region_info.width, region_info.height, region_info.x, region_info.y, params.SBNUMINSTANCES);
892
893
    /* 7.4.3.2 (2) - compose the list of symbol dictionaries */
894
9
    n_dicts = jbig2_sd_count_referred(ctx, segment);
895
9
    if (n_dicts == 0) {
896
1
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "text region refers to no symbol dictionaries");
897
8
    } else {
898
8
        dicts = jbig2_sd_list_referred(ctx, segment);
899
8
        if (dicts == NULL) {
900
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unable to retrieve symbol dictionaries! previous parsing error?");
901
0
            goto cleanup1;
902
8
        } else {
903
8
            uint32_t index;
904
905
8
            if (dicts[0] == NULL) {
906
0
                code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to find first referenced symbol dictionary");
907
0
                goto cleanup1;
908
0
            }
909
8
            for (index = 1; index < n_dicts; index++)
910
0
                if (dicts[index] == NULL) {
911
0
                    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to find all referenced symbol dictionaries");
912
0
                    n_dicts = index;
913
0
                }
914
8
        }
915
8
    }
916
917
    /* 7.4.3.2 (3) */
918
9
    {
919
9
        int stats_size = params.SBRTEMPLATE ? 1 << 10 : 1 << 13;
920
921
9
        GR_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
922
9
        if (GR_stats == NULL) {
923
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "could not allocate arithmetic decoder state");
924
0
            goto cleanup1;
925
0
        }
926
9
        memset(GR_stats, 0, stats_size);
927
9
    }
928
929
0
    image = jbig2_image_new(ctx, region_info.width, region_info.height);
930
9
    if (image == NULL) {
931
0
        code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region image");
932
0
        goto cleanup2;
933
0
    }
934
935
9
    if (offset >= segment->data_length) {
936
0
        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
937
0
        goto cleanup2;
938
0
    }
939
9
    ws = jbig2_word_stream_buf_new(ctx, segment_data + offset, segment->data_length - offset);
940
9
    if (ws == NULL) {
941
0
        code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate word stream when handling text region image");
942
0
        goto cleanup2;
943
0
    }
944
945
9
    as = jbig2_arith_new(ctx, ws);
946
9
    if (as == NULL) {
947
0
        code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate arithmetic coding context when handling text region image");
948
0
        goto cleanup3;
949
0
    }
950
951
9
    if (!params.SBHUFF) {
952
9
        uint8_t SBSYMCODELEN;
953
9
        uint32_t index;
954
9
        uint32_t SBNUMSYMS = 0;
955
956
17
        for (index = 0; index < n_dicts; index++) {
957
8
            SBNUMSYMS += dicts[index]->n_symbols;
958
8
        }
959
960
9
        params.IADT = jbig2_arith_int_ctx_new(ctx);
961
9
        params.IAFS = jbig2_arith_int_ctx_new(ctx);
962
9
        params.IADS = jbig2_arith_int_ctx_new(ctx);
963
9
        params.IAIT = jbig2_arith_int_ctx_new(ctx);
964
9
        if (params.IADT == NULL || params.IAFS == NULL || params.IADS == NULL || params.IAIT == NULL) {
965
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region image data");
966
0
            goto cleanup4;
967
0
        }
968
969
        /* Table 31 */
970
33
        for (SBSYMCODELEN = 0; ((uint64_t) 1 << SBSYMCODELEN) < (uint64_t) SBNUMSYMS; SBSYMCODELEN++);
971
972
9
        params.IAID = jbig2_arith_iaid_ctx_new(ctx, SBSYMCODELEN);
973
9
        params.IARI = jbig2_arith_int_ctx_new(ctx);
974
9
        params.IARDW = jbig2_arith_int_ctx_new(ctx);
975
9
        params.IARDH = jbig2_arith_int_ctx_new(ctx);
976
9
        params.IARDX = jbig2_arith_int_ctx_new(ctx);
977
9
        params.IARDY = jbig2_arith_int_ctx_new(ctx);
978
9
        if (params.IAID == NULL || params.IARI == NULL ||
979
9
            params.IARDW == NULL || params.IARDH == NULL || params.IARDX == NULL || params.IARDY == NULL) {
980
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region image data");
981
0
            goto cleanup5;
982
0
        }
983
9
    }
984
985
9
    code = jbig2_decode_text_region(ctx, segment, &params,
986
9
                                    (const Jbig2SymbolDict * const *)dicts, n_dicts, image,
987
9
                                    segment_data + offset, segment->data_length - offset, GR_stats, as, ws);
988
9
    if (code < 0) {
989
0
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode text region image data");
990
0
        goto cleanup5;
991
0
    }
992
993
9
    if ((segment->flags & 63) == 4) {
994
        /* we have an intermediate region here. save it for later */
995
0
        segment->result = jbig2_image_reference(ctx, image);
996
9
    } else {
997
        /* otherwise composite onto the page */
998
9
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
999
9
                    "composing %dx%d decoded text region onto page at (%d, %d)", region_info.width, region_info.height, region_info.x, region_info.y);
1000
9
        code = jbig2_page_add_result(ctx, &ctx->pages[ctx->current_page], image, region_info.x, region_info.y, region_info.op);
1001
9
        if (code < 0)
1002
0
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to add text region to page");
1003
9
    }
1004
1005
9
cleanup5:
1006
9
    if (!params.SBHUFF) {
1007
9
        jbig2_arith_iaid_ctx_free(ctx, params.IAID);
1008
9
        jbig2_arith_int_ctx_free(ctx, params.IARI);
1009
9
        jbig2_arith_int_ctx_free(ctx, params.IARDW);
1010
9
        jbig2_arith_int_ctx_free(ctx, params.IARDH);
1011
9
        jbig2_arith_int_ctx_free(ctx, params.IARDX);
1012
9
        jbig2_arith_int_ctx_free(ctx, params.IARDY);
1013
9
    }
1014
1015
9
cleanup4:
1016
9
    if (!params.SBHUFF) {
1017
9
        jbig2_arith_int_ctx_free(ctx, params.IADT);
1018
9
        jbig2_arith_int_ctx_free(ctx, params.IAFS);
1019
9
        jbig2_arith_int_ctx_free(ctx, params.IADS);
1020
9
        jbig2_arith_int_ctx_free(ctx, params.IAIT);
1021
9
    }
1022
1023
9
cleanup3:
1024
9
    jbig2_free(ctx->allocator, as);
1025
9
    jbig2_word_stream_buf_free(ctx, ws);
1026
1027
9
cleanup2:
1028
9
    jbig2_free(ctx->allocator, GR_stats);
1029
9
    jbig2_image_release(ctx, image);
1030
1031
9
cleanup1:
1032
9
    if (params.SBHUFF) {
1033
0
        jbig2_release_huffman_table(ctx, params.SBHUFFFS);
1034
0
        jbig2_release_huffman_table(ctx, params.SBHUFFDS);
1035
0
        jbig2_release_huffman_table(ctx, params.SBHUFFDT);
1036
0
        jbig2_release_huffman_table(ctx, params.SBHUFFRDX);
1037
0
        jbig2_release_huffman_table(ctx, params.SBHUFFRDY);
1038
0
        jbig2_release_huffman_table(ctx, params.SBHUFFRDW);
1039
0
        jbig2_release_huffman_table(ctx, params.SBHUFFRDH);
1040
0
        jbig2_release_huffman_table(ctx, params.SBHUFFRSIZE);
1041
0
    }
1042
9
    jbig2_free(ctx->allocator, dicts);
1043
1044
9
    return code;
1045
9
}