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