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