comparison mupdf-source/thirdparty/jbig2dec/jbig2_text.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
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 #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 {
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
219 cleanup1:
220 jbig2_free(ctx->allocator, symcodelengths);
221 jbig2_release_huffman_table(ctx, runcodes);
222
223 if (SBSYMCODES == NULL) {
224 jbig2_huffman_free(ctx, hs);
225 return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to construct symbol ID huffman table");
226 }
227 }
228
229 /* 6.4.5 (1) */
230 jbig2_image_clear(ctx, image, params->SBDEFPIXEL);
231
232 /* 6.4.6 */
233 if (params->SBHUFF) {
234 STRIPT = jbig2_huffman_get(hs, params->SBHUFFDT, &code);
235 } else {
236 code = jbig2_arith_int_decode(ctx, params->IADT, as, &STRIPT);
237 }
238 if (code < 0) {
239 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode strip T");
240 goto cleanup2;
241 }
242 if (code > 0) {
243 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB obtained when decoding strip T");
244 goto cleanup2;
245 }
246
247 /* 6.4.5 (2) */
248 STRIPT *= -(params->SBSTRIPS);
249 FIRSTS = 0;
250 NINSTANCES = 0;
251
252 /* 6.4.5 (3) */
253 while (NINSTANCES < params->SBNUMINSTANCES) {
254 /* (3b) */
255 if (params->SBHUFF) {
256 DT = jbig2_huffman_get(hs, params->SBHUFFDT, &code);
257 } else {
258 code = jbig2_arith_int_decode(ctx, params->IADT, as, &DT);
259 }
260 if (code < 0) {
261 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode delta T");
262 goto cleanup2;
263 }
264 if (code > 0) {
265 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB obtained when decoding delta T");
266 goto cleanup2;
267 }
268 DT *= params->SBSTRIPS;
269 STRIPT += DT;
270
271 first_symbol = TRUE;
272 /* 6.4.5 (3c) - decode symbols in strip */
273 for (;;) {
274 /* (3c.i) */
275 if (first_symbol) {
276 /* 6.4.7 */
277 if (params->SBHUFF) {
278 DFS = jbig2_huffman_get(hs, params->SBHUFFFS, &code);
279 } else {
280 code = jbig2_arith_int_decode(ctx, params->IAFS, as, &DFS);
281 }
282 if (code < 0) {
283 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode strip symbol S-difference");
284 goto cleanup2;
285 }
286 if (code > 0) {
287 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB obtained when decoding strip symbol S-difference");
288 goto cleanup2;
289 }
290 FIRSTS += DFS;
291 CURS = FIRSTS;
292 first_symbol = FALSE;
293 } else {
294 if (NINSTANCES > params->SBNUMINSTANCES) {
295 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "too many NINSTANCES (%d) decoded", NINSTANCES);
296 break;
297 }
298 /* (3c.ii) / 6.4.8 */
299 if (params->SBHUFF) {
300 IDS = jbig2_huffman_get(hs, params->SBHUFFDS, &code);
301 } else {
302 code = jbig2_arith_int_decode(ctx, params->IADS, as, &IDS);
303 }
304 if (code < 0) {
305 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode symbol instance S coordinate");
306 goto cleanup2;
307 }
308 if (code > 0) {
309 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 break;
311 }
312 CURS += IDS + params->SBDSOFFSET;
313 }
314
315 /* (3c.iii) / 6.4.9 */
316 if (params->SBSTRIPS == 1) {
317 CURT = 0;
318 } else if (params->SBHUFF) {
319 CURT = jbig2_huffman_get_bits(hs, params->LOGSBSTRIPS, &code);
320 } else {
321 code = jbig2_arith_int_decode(ctx, params->IAIT, as, &CURT);
322 }
323 if (code < 0) {
324 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode symbol instance T coordinate");
325 goto cleanup2;
326 }
327 if (code > 0) {
328 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "OOB obtained when decoding symbol instance T coordinate");
329 goto cleanup2;
330 }
331 T = STRIPT + CURT;
332
333 /* (3b.iv) / 6.4.10 - decode the symbol ID */
334 if (params->SBHUFF) {
335 ID = jbig2_huffman_get(hs, SBSYMCODES, &code);
336 } else {
337 code = jbig2_arith_iaid_decode(ctx, params->IAID, as, (int *)&ID);
338 }
339 if (code < 0) {
340 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to obtain symbol instance symbol ID");
341 goto cleanup2;
342 }
343 if (code > 0) {
344 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB obtained when decoding symbol instance symbol ID");
345 goto cleanup2;
346 }
347 if (ID >= SBNUMSYMS) {
348 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "ignoring out of range symbol ID (%d/%d)", ID, SBNUMSYMS);
349 IB = NULL;
350 } else {
351 /* (3c.v) / 6.4.11 - look up the symbol bitmap IB */
352 uint32_t id = ID;
353
354 index = 0;
355 while (id >= dicts[index]->n_symbols)
356 id -= dicts[index++]->n_symbols;
357 if (dicts[index]->glyphs[id] == NULL) {
358 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "missing glyph (%d/%d), ignoring", index, id);
359 } else {
360 IB = jbig2_image_reference(ctx, dicts[index]->glyphs[id]);
361 }
362 }
363 if (params->SBREFINE) {
364 if (params->SBHUFF) {
365 RI = jbig2_huffman_get_bits(hs, 1, &code);
366 } else {
367 code = jbig2_arith_int_decode(ctx, params->IARI, as, &RI);
368 }
369 if (code < 0) {
370 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode symbol bitmap refinement indicator");
371 goto cleanup2;
372 }
373 if (code > 0) {
374 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB obtained when decoding symbol bitmap refinement indicator");
375 goto cleanup2;
376 }
377 } else {
378 RI = 0;
379 }
380 if (RI) {
381 Jbig2RefinementRegionParams rparams;
382 int32_t RDW, RDH, RDX, RDY;
383 size_t BMSIZE = 0;
384 int code1 = 0;
385 int code2 = 0;
386 int code3 = 0;
387 int code4 = 0;
388 int code5 = 0;
389 int code6 = 0;
390
391 /* 6.4.11 (1, 2, 3, 4) */
392 if (!params->SBHUFF) {
393 code1 = jbig2_arith_int_decode(ctx, params->IARDW, as, &RDW);
394 code2 = jbig2_arith_int_decode(ctx, params->IARDH, as, &RDH);
395 code3 = jbig2_arith_int_decode(ctx, params->IARDX, as, &RDX);
396 code4 = jbig2_arith_int_decode(ctx, params->IARDY, as, &RDY);
397 } else {
398 RDW = jbig2_huffman_get(hs, params->SBHUFFRDW, &code1);
399 RDH = jbig2_huffman_get(hs, params->SBHUFFRDH, &code2);
400 RDX = jbig2_huffman_get(hs, params->SBHUFFRDX, &code3);
401 RDY = jbig2_huffman_get(hs, params->SBHUFFRDY, &code4);
402 BMSIZE = jbig2_huffman_get(hs, params->SBHUFFRSIZE, &code5);
403 code6 = jbig2_huffman_skip(hs);
404 }
405
406 if (code1 < 0 || code2 < 0 || code3 < 0 || code4 < 0 || code5 < 0 || code6 < 0) {
407 jbig2_image_release(ctx, IB);
408 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode data");
409 goto cleanup2;
410 }
411 if (code1 > 0 || code2 > 0 || code3 > 0 || code4 > 0 || code5 > 0 || code6 > 0) {
412 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB obtained when decoding symbol instance refinement data");
413 goto cleanup2;
414 }
415
416 /* 6.4.11 (6) */
417 if (IB) {
418 IBO = IB;
419 IB = NULL;
420 if (((int32_t) IBO->width) + RDW < 0 || ((int32_t) IBO->height) + RDH < 0) {
421 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "reference image dimensions negative");
422 goto cleanup2;
423 }
424 refimage = jbig2_image_new(ctx, IBO->width + RDW, IBO->height + RDH);
425 if (refimage == NULL) {
426 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate reference image");
427 goto cleanup2;
428 }
429 jbig2_image_clear(ctx, refimage, 0x00);
430
431 /* Table 12 */
432 rparams.GRTEMPLATE = params->SBRTEMPLATE;
433 rparams.GRREFERENCE = IBO;
434 rparams.GRREFERENCEDX = (RDW >> 1) + RDX;
435 rparams.GRREFERENCEDY = (RDH >> 1) + RDY;
436 rparams.TPGRON = 0;
437 memcpy(rparams.grat, params->sbrat, 4);
438 code = jbig2_decode_refinement_region(ctx, segment, &rparams, as, refimage, GR_stats);
439 if (code < 0) {
440 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode refinement region");
441 goto cleanup2;
442 }
443
444 jbig2_image_release(ctx, IBO);
445 IBO = NULL;
446 IB = refimage;
447 refimage = NULL;
448 }
449
450 /* 6.4.11 (7) */
451 if (params->SBHUFF) {
452 code = jbig2_huffman_advance(hs, BMSIZE);
453 if (code < 0) {
454 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to advance after huffman decoding refinement region");
455 goto cleanup2;
456 }
457 }
458 }
459
460 /* (3c.vi) */
461 if ((!params->TRANSPOSED) && (params->REFCORNER > 1) && IB) {
462 CURS += IB->width - 1;
463 } else if ((params->TRANSPOSED) && !(params->REFCORNER & 1) && IB) {
464 CURS += IB->height - 1;
465 }
466
467 /* (3c.vii) */
468 S = CURS;
469
470 /* (3c.viii) */
471 if (!params->TRANSPOSED) {
472 switch (params->REFCORNER) {
473 case JBIG2_CORNER_TOPLEFT:
474 x = S;
475 y = T;
476 break;
477 case JBIG2_CORNER_TOPRIGHT:
478 if (IB)
479 x = S - IB->width + 1;
480 else
481 x = S + 1;
482 y = T;
483 break;
484 case JBIG2_CORNER_BOTTOMLEFT:
485 x = S;
486 if (IB)
487 y = T - IB->height + 1;
488 else
489 y = T + 1;
490 break;
491 default:
492 case JBIG2_CORNER_BOTTOMRIGHT:
493 if (IB ) {
494 x = S - IB->width + 1;
495 y = T - IB->height + 1;
496 } else {
497 x = S + 1;
498 y = T + 1;
499 }
500 break;
501 }
502 } else { /* TRANSPOSED */
503 switch (params->REFCORNER) {
504 case JBIG2_CORNER_TOPLEFT:
505 x = T;
506 y = S;
507 break;
508 case JBIG2_CORNER_TOPRIGHT:
509 if (IB)
510 x = T - IB->width + 1;
511 else
512 x = T + 1;
513 y = S;
514 break;
515 case JBIG2_CORNER_BOTTOMLEFT:
516 x = T;
517 if (IB)
518 y = S - IB->height + 1;
519 else
520 y = S + 1;
521 break;
522 default:
523 case JBIG2_CORNER_BOTTOMRIGHT:
524 if (IB) {
525 x = T - IB->width + 1;
526 y = S - IB->height + 1;
527 } else {
528 x = T + 1;
529 y = S + 1;
530 }
531 break;
532 }
533 }
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 code = jbig2_image_compose(ctx, image, IB, x, y, params->SBCOMBOP);
541 if (code < 0) {
542 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to compose symbol instance symbol bitmap into picture");
543 goto cleanup2;
544 }
545
546 /* (3c.x) */
547 if (IB && (!params->TRANSPOSED) && (params->REFCORNER < 2)) {
548 CURS += IB->width - 1;
549 } else if (IB && (params->TRANSPOSED) && (params->REFCORNER & 1)) {
550 CURS += IB->height - 1;
551 }
552
553 /* (3c.xi) */
554 NINSTANCES++;
555
556 jbig2_image_release(ctx, IB);
557 IB = NULL;
558 }
559 /* end strip */
560 }
561 /* 6.4.5 (4) */
562
563 cleanup2:
564 jbig2_image_release(ctx, refimage);
565 jbig2_image_release(ctx, IBO);
566 jbig2_image_release(ctx, IB);
567 if (params->SBHUFF) {
568 jbig2_release_huffman_table(ctx, SBSYMCODES);
569 }
570 jbig2_huffman_free(ctx, hs);
571
572 return code;
573 }
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 {
581 uint32_t offset = 0;
582 Jbig2RegionSegmentInfo region_info;
583 Jbig2TextRegionParams params;
584 Jbig2Image *image = NULL;
585 Jbig2SymbolDict **dicts = NULL;
586 uint32_t n_dicts = 0;
587 uint16_t flags = 0;
588 uint16_t huffman_flags = 0;
589 Jbig2ArithCx *GR_stats = NULL;
590 int code = 0;
591 Jbig2WordStream *ws = NULL;
592 Jbig2ArithState *as = NULL;
593 uint32_t table_index = 0;
594 const Jbig2HuffmanParams *huffman_params = NULL;
595
596 /* zero params to ease cleanup later */
597 memset(&params, 0, sizeof(Jbig2TextRegionParams));
598
599 /* 7.4.1 */
600 if (segment->data_length < 17) {
601 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
602 goto cleanup2;
603 }
604 jbig2_get_region_segment_info(&region_info, segment_data);
605 offset += 17;
606 /* Check for T.88 amendment 3 */
607 if (region_info.flags & 8)
608 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 if (segment->data_length - offset < 2) {
612 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
613 goto cleanup2;
614 }
615 flags = jbig2_get_uint16(segment_data + offset);
616 offset += 2;
617
618 jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "text region header flags 0x%04x", flags);
619
620 params.SBHUFF = flags & 0x0001;
621 params.SBREFINE = flags & 0x0002;
622 params.LOGSBSTRIPS = (flags & 0x000c) >> 2;
623 params.SBSTRIPS = 1 << params.LOGSBSTRIPS;
624 params.REFCORNER = (Jbig2RefCorner)((flags & 0x0030) >> 4);
625 params.TRANSPOSED = flags & 0x0040;
626 params.SBCOMBOP = (Jbig2ComposeOp)((flags & 0x0180) >> 7);
627 params.SBDEFPIXEL = flags & 0x0200;
628 /* SBDSOFFSET is a signed 5 bit integer */
629 params.SBDSOFFSET = (flags & 0x7C00) >> 10;
630 if (params.SBDSOFFSET > 0x0f)
631 params.SBDSOFFSET -= 0x20;
632 params.SBRTEMPLATE = flags & 0x8000;
633
634 if (params.SBDSOFFSET) {
635 jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "text region has SBDSOFFSET %d", params.SBDSOFFSET);
636 }
637
638 if (params.SBHUFF) { /* Huffman coding */
639 /* 7.4.3.1.2 */
640 if (segment->data_length - offset < 2) {
641 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
642 goto cleanup2;
643 }
644 huffman_flags = jbig2_get_uint16(segment_data + offset);
645 offset += 2;
646
647 if (huffman_flags & 0x8000)
648 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "reserved bit 15 of text region huffman flags is not zero");
649 } else { /* arithmetic coding */
650
651 /* 7.4.3.1.3 */
652 if (segment->data_length - offset < 4) {
653 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
654 goto cleanup2;
655 }
656 if ((params.SBREFINE) && !(params.SBRTEMPLATE)) {
657 params.sbrat[0] = segment_data[offset];
658 params.sbrat[1] = segment_data[offset + 1];
659 params.sbrat[2] = segment_data[offset + 2];
660 params.sbrat[3] = segment_data[offset + 3];
661 offset += 4;
662 }
663 }
664
665 /* 7.4.3.1.4 */
666 if (segment->data_length - offset < 4) {
667 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
668 goto cleanup2;
669 }
670 params.SBNUMINSTANCES = jbig2_get_uint32(segment_data + offset);
671 offset += 4;
672
673 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 switch (huffman_flags & 0x0003) {
679 case 0: /* Table B.6 */
680 params.SBHUFFFS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_F);
681 break;
682 case 1: /* Table B.7 */
683 params.SBHUFFFS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_G);
684 break;
685 case 3: /* Custom table from referred segment */
686 huffman_params = jbig2_find_table(ctx, segment, table_index);
687 if (huffman_params == NULL) {
688 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom FS huffman table not found (%d)", table_index);
689 goto cleanup1;
690 }
691 params.SBHUFFFS = jbig2_build_huffman_table(ctx, huffman_params);
692 ++table_index;
693 break;
694 case 2: /* invalid */
695 default:
696 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "text region specified invalid FS huffman table");
697 goto cleanup1;
698 break;
699 }
700 if (params.SBHUFFFS == NULL) {
701 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region specified FS huffman table");
702 goto cleanup1;
703 }
704
705 switch ((huffman_flags & 0x000c) >> 2) {
706 case 0: /* Table B.8 */
707 params.SBHUFFDS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_H);
708 break;
709 case 1: /* Table B.9 */
710 params.SBHUFFDS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_I);
711 break;
712 case 2: /* Table B.10 */
713 params.SBHUFFDS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_J);
714 break;
715 case 3: /* Custom table from referred segment */
716 huffman_params = jbig2_find_table(ctx, segment, table_index);
717 if (huffman_params == NULL) {
718 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom DS huffman table not found (%d)", table_index);
719 goto cleanup1;
720 }
721 params.SBHUFFDS = jbig2_build_huffman_table(ctx, huffman_params);
722 ++table_index;
723 break;
724 }
725 if (params.SBHUFFDS == NULL) {
726 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region specified DS huffman table");
727 goto cleanup1;
728 }
729
730 switch ((huffman_flags & 0x0030) >> 4) {
731 case 0: /* Table B.11 */
732 params.SBHUFFDT = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_K);
733 break;
734 case 1: /* Table B.12 */
735 params.SBHUFFDT = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_L);
736 break;
737 case 2: /* Table B.13 */
738 params.SBHUFFDT = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_M);
739 break;
740 case 3: /* Custom table from referred segment */
741 huffman_params = jbig2_find_table(ctx, segment, table_index);
742 if (huffman_params == NULL) {
743 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom DT huffman table not found (%d)", table_index);
744 goto cleanup1;
745 }
746 params.SBHUFFDT = jbig2_build_huffman_table(ctx, huffman_params);
747 ++table_index;
748 break;
749 }
750 if (params.SBHUFFDT == NULL) {
751 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region specified DT huffman table");
752 goto cleanup1;
753 }
754
755 switch ((huffman_flags & 0x00c0) >> 6) {
756 case 0: /* Table B.14 */
757 params.SBHUFFRDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_N);
758 break;
759 case 1: /* Table B.15 */
760 params.SBHUFFRDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);
761 break;
762 case 3: /* Custom table from referred segment */
763 huffman_params = jbig2_find_table(ctx, segment, table_index);
764 if (huffman_params == NULL) {
765 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom RDW huffman table not found (%d)", table_index);
766 goto cleanup1;
767 }
768 params.SBHUFFRDW = jbig2_build_huffman_table(ctx, huffman_params);
769 ++table_index;
770 break;
771 case 2: /* invalid */
772 default:
773 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "text region specified invalid RDW huffman table");
774 goto cleanup1;
775 break;
776 }
777 if (params.SBHUFFRDW == NULL) {
778 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region specified RDW huffman table");
779 goto cleanup1;
780 }
781
782 switch ((huffman_flags & 0x0300) >> 8) {
783 case 0: /* Table B.14 */
784 params.SBHUFFRDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_N);
785 break;
786 case 1: /* Table B.15 */
787 params.SBHUFFRDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);
788 break;
789 case 3: /* Custom table from referred segment */
790 huffman_params = jbig2_find_table(ctx, segment, table_index);
791 if (huffman_params == NULL) {
792 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom RDH huffman table not found (%d)", table_index);
793 goto cleanup1;
794 }
795 params.SBHUFFRDH = jbig2_build_huffman_table(ctx, huffman_params);
796 ++table_index;
797 break;
798 case 2: /* invalid */
799 default:
800 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "text region specified invalid RDH huffman table");
801 goto cleanup1;
802 break;
803 }
804 if (params.SBHUFFRDH == NULL) {
805 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region specified RDH huffman table");
806 goto cleanup1;
807 }
808
809 switch ((huffman_flags & 0x0c00) >> 10) {
810 case 0: /* Table B.14 */
811 params.SBHUFFRDX = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_N);
812 break;
813 case 1: /* Table B.15 */
814 params.SBHUFFRDX = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);
815 break;
816 case 3: /* Custom table from referred segment */
817 huffman_params = jbig2_find_table(ctx, segment, table_index);
818 if (huffman_params == NULL) {
819 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom RDX huffman table not found (%d)", table_index);
820 goto cleanup1;
821 }
822 params.SBHUFFRDX = jbig2_build_huffman_table(ctx, huffman_params);
823 ++table_index;
824 break;
825 case 2: /* invalid */
826 default:
827 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "text region specified invalid RDX huffman table");
828 goto cleanup1;
829 break;
830 }
831 if (params.SBHUFFRDX == NULL) {
832 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region specified RDX huffman table");
833 goto cleanup1;
834 }
835
836 switch ((huffman_flags & 0x3000) >> 12) {
837 case 0: /* Table B.14 */
838 params.SBHUFFRDY = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_N);
839 break;
840 case 1: /* Table B.15 */
841 params.SBHUFFRDY = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);
842 break;
843 case 3: /* Custom table from referred segment */
844 huffman_params = jbig2_find_table(ctx, segment, table_index);
845 if (huffman_params == NULL) {
846 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom RDY huffman table not found (%d)", table_index);
847 goto cleanup1;
848 }
849 params.SBHUFFRDY = jbig2_build_huffman_table(ctx, huffman_params);
850 ++table_index;
851 break;
852 case 2: /* invalid */
853 default:
854 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "text region specified invalid RDY huffman table");
855 goto cleanup1;
856 break;
857 }
858 if (params.SBHUFFRDY == NULL) {
859 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region specified RDY huffman table");
860 goto cleanup1;
861 }
862
863 switch ((huffman_flags & 0x4000) >> 14) {
864 case 0: /* Table B.1 */
865 params.SBHUFFRSIZE = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A);
866 break;
867 case 1: /* Custom table from referred segment */
868 huffman_params = jbig2_find_table(ctx, segment, table_index);
869 if (huffman_params == NULL) {
870 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "custom RSIZE huffman table not found (%d)", table_index);
871 goto cleanup1;
872 }
873 params.SBHUFFRSIZE = jbig2_build_huffman_table(ctx, huffman_params);
874 ++table_index;
875 break;
876 }
877 if (params.SBHUFFRSIZE == NULL) {
878 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region specified RSIZE huffman table");
879 goto cleanup1;
880 }
881
882 if (huffman_flags & 0x8000) {
883 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "text region huffman flags bit 15 is set, contrary to spec");
884 }
885
886 /* 7.4.3.1.7 */
887 /* For convenience this is done in the body decoder routine */
888 }
889
890 jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
891 "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 n_dicts = jbig2_sd_count_referred(ctx, segment);
895 if (n_dicts == 0) {
896 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "text region refers to no symbol dictionaries");
897 } else {
898 dicts = jbig2_sd_list_referred(ctx, segment);
899 if (dicts == NULL) {
900 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unable to retrieve symbol dictionaries! previous parsing error?");
901 goto cleanup1;
902 } else {
903 uint32_t index;
904
905 if (dicts[0] == NULL) {
906 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to find first referenced symbol dictionary");
907 goto cleanup1;
908 }
909 for (index = 1; index < n_dicts; index++)
910 if (dicts[index] == NULL) {
911 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to find all referenced symbol dictionaries");
912 n_dicts = index;
913 }
914 }
915 }
916
917 /* 7.4.3.2 (3) */
918 {
919 int stats_size = params.SBRTEMPLATE ? 1 << 10 : 1 << 13;
920
921 GR_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
922 if (GR_stats == NULL) {
923 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "could not allocate arithmetic decoder state");
924 goto cleanup1;
925 }
926 memset(GR_stats, 0, stats_size);
927 }
928
929 image = jbig2_image_new(ctx, region_info.width, region_info.height);
930 if (image == NULL) {
931 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region image");
932 goto cleanup2;
933 }
934
935 if (offset >= segment->data_length) {
936 code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
937 goto cleanup2;
938 }
939 ws = jbig2_word_stream_buf_new(ctx, segment_data + offset, segment->data_length - offset);
940 if (ws == NULL) {
941 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate word stream when handling text region image");
942 goto cleanup2;
943 }
944
945 as = jbig2_arith_new(ctx, ws);
946 if (as == NULL) {
947 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate arithmetic coding context when handling text region image");
948 goto cleanup3;
949 }
950
951 if (!params.SBHUFF) {
952 uint8_t SBSYMCODELEN;
953 uint32_t index;
954 uint32_t SBNUMSYMS = 0;
955
956 for (index = 0; index < n_dicts; index++) {
957 SBNUMSYMS += dicts[index]->n_symbols;
958 }
959
960 params.IADT = jbig2_arith_int_ctx_new(ctx);
961 params.IAFS = jbig2_arith_int_ctx_new(ctx);
962 params.IADS = jbig2_arith_int_ctx_new(ctx);
963 params.IAIT = jbig2_arith_int_ctx_new(ctx);
964 if (params.IADT == NULL || params.IAFS == NULL || params.IADS == NULL || params.IAIT == NULL) {
965 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region image data");
966 goto cleanup4;
967 }
968
969 /* Table 31 */
970 for (SBSYMCODELEN = 0; ((uint64_t) 1 << SBSYMCODELEN) < (uint64_t) SBNUMSYMS; SBSYMCODELEN++);
971
972 params.IAID = jbig2_arith_iaid_ctx_new(ctx, SBSYMCODELEN);
973 params.IARI = jbig2_arith_int_ctx_new(ctx);
974 params.IARDW = jbig2_arith_int_ctx_new(ctx);
975 params.IARDH = jbig2_arith_int_ctx_new(ctx);
976 params.IARDX = jbig2_arith_int_ctx_new(ctx);
977 params.IARDY = jbig2_arith_int_ctx_new(ctx);
978 if (params.IAID == NULL || params.IARI == NULL ||
979 params.IARDW == NULL || params.IARDH == NULL || params.IARDX == NULL || params.IARDY == NULL) {
980 code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate text region image data");
981 goto cleanup5;
982 }
983 }
984
985 code = jbig2_decode_text_region(ctx, segment, &params,
986 (const Jbig2SymbolDict * const *)dicts, n_dicts, image,
987 segment_data + offset, segment->data_length - offset, GR_stats, as, ws);
988 if (code < 0) {
989 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode text region image data");
990 goto cleanup5;
991 }
992
993 if ((segment->flags & 63) == 4) {
994 /* we have an intermediate region here. save it for later */
995 segment->result = jbig2_image_reference(ctx, image);
996 } else {
997 /* otherwise composite onto the page */
998 jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
999 "composing %dx%d decoded text region onto page at (%d, %d)", region_info.width, region_info.height, region_info.x, region_info.y);
1000 code = jbig2_page_add_result(ctx, &ctx->pages[ctx->current_page], image, region_info.x, region_info.y, region_info.op);
1001 if (code < 0)
1002 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to add text region to page");
1003 }
1004
1005 cleanup5:
1006 if (!params.SBHUFF) {
1007 jbig2_arith_iaid_ctx_free(ctx, params.IAID);
1008 jbig2_arith_int_ctx_free(ctx, params.IARI);
1009 jbig2_arith_int_ctx_free(ctx, params.IARDW);
1010 jbig2_arith_int_ctx_free(ctx, params.IARDH);
1011 jbig2_arith_int_ctx_free(ctx, params.IARDX);
1012 jbig2_arith_int_ctx_free(ctx, params.IARDY);
1013 }
1014
1015 cleanup4:
1016 if (!params.SBHUFF) {
1017 jbig2_arith_int_ctx_free(ctx, params.IADT);
1018 jbig2_arith_int_ctx_free(ctx, params.IAFS);
1019 jbig2_arith_int_ctx_free(ctx, params.IADS);
1020 jbig2_arith_int_ctx_free(ctx, params.IAIT);
1021 }
1022
1023 cleanup3:
1024 jbig2_free(ctx->allocator, as);
1025 jbig2_word_stream_buf_free(ctx, ws);
1026
1027 cleanup2:
1028 jbig2_free(ctx->allocator, GR_stats);
1029 jbig2_image_release(ctx, image);
1030
1031 cleanup1:
1032 if (params.SBHUFF) {
1033 jbig2_release_huffman_table(ctx, params.SBHUFFFS);
1034 jbig2_release_huffman_table(ctx, params.SBHUFFDS);
1035 jbig2_release_huffman_table(ctx, params.SBHUFFDT);
1036 jbig2_release_huffman_table(ctx, params.SBHUFFRDX);
1037 jbig2_release_huffman_table(ctx, params.SBHUFFRDY);
1038 jbig2_release_huffman_table(ctx, params.SBHUFFRDW);
1039 jbig2_release_huffman_table(ctx, params.SBHUFFRDH);
1040 jbig2_release_huffman_table(ctx, params.SBHUFFRSIZE);
1041 }
1042 jbig2_free(ctx->allocator, dicts);
1043
1044 return code;
1045 }