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