Mercurial > hgrepos > Python2 > PyMuPDF
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(¶ms, 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(®ion_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, ¶ms, | |
| 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 } |
