/src/libspectre/ghostscript/jbig2dec/jbig2_segment.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2020 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, |
13 | | CA 94945, U.S.A., +1(415)492-9861, for further information. |
14 | | */ |
15 | | |
16 | | /* |
17 | | jbig2dec |
18 | | */ |
19 | | |
20 | | #ifdef HAVE_CONFIG_H |
21 | | #include "config.h" |
22 | | #endif |
23 | | #include "os_types.h" |
24 | | |
25 | | #include <stddef.h> /* size_t */ |
26 | | |
27 | | #include "jbig2.h" |
28 | | #include "jbig2_priv.h" |
29 | | #include "jbig2_arith.h" |
30 | | #include "jbig2_arith_int.h" |
31 | | #include "jbig2_arith_iaid.h" |
32 | | #include "jbig2_generic.h" |
33 | | #include "jbig2_image.h" |
34 | | #include "jbig2_halftone.h" |
35 | | #include "jbig2_huffman.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 | | Jbig2Segment * |
43 | | jbig2_parse_segment_header(Jbig2Ctx *ctx, uint8_t *buf, size_t buf_size, size_t *p_header_size) |
44 | 0 | { |
45 | 0 | Jbig2Segment *result; |
46 | 0 | uint8_t rtscarf; |
47 | 0 | uint32_t rtscarf_long; |
48 | 0 | uint32_t *referred_to_segments; |
49 | 0 | uint32_t referred_to_segment_count; |
50 | 0 | uint32_t referred_to_segment_size; |
51 | 0 | uint32_t pa_size; |
52 | 0 | uint32_t offset; |
53 | | |
54 | | /* minimum possible size of a jbig2 segment header */ |
55 | 0 | if (buf_size < 11) |
56 | 0 | return NULL; |
57 | | |
58 | 0 | result = jbig2_new(ctx, Jbig2Segment, 1); |
59 | 0 | if (result == NULL) { |
60 | 0 | jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate segment"); |
61 | 0 | return NULL; |
62 | 0 | } |
63 | | |
64 | | /* 7.2.2 */ |
65 | 0 | result->number = jbig2_get_uint32(buf); |
66 | 0 | if (result->number == JBIG2_UNKNOWN_SEGMENT_NUMBER) { |
67 | 0 | jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "segment number too large"); |
68 | 0 | jbig2_free(ctx->allocator, result); |
69 | 0 | return NULL; |
70 | 0 | } |
71 | | |
72 | | /* 7.2.3 */ |
73 | 0 | result->flags = buf[4]; |
74 | | |
75 | | /* 7.2.4 referred-to segments */ |
76 | 0 | rtscarf = buf[5]; |
77 | 0 | if ((rtscarf & 0xe0) == 0xe0) { |
78 | 0 | rtscarf_long = jbig2_get_uint32(buf + 5); |
79 | 0 | referred_to_segment_count = rtscarf_long & 0x1fffffff; |
80 | 0 | offset = 5 + 4 + (referred_to_segment_count + 1) / 8; |
81 | 0 | } else { |
82 | 0 | referred_to_segment_count = (rtscarf >> 5); |
83 | 0 | offset = 5 + 1; |
84 | 0 | } |
85 | 0 | result->referred_to_segment_count = referred_to_segment_count; |
86 | | |
87 | | /* we now have enough information to compute the full header length */ |
88 | 0 | referred_to_segment_size = result->number <= 256 ? 1 : result->number <= 65536 ? 2 : 4; /* 7.2.5 */ |
89 | 0 | pa_size = result->flags & 0x40 ? 4 : 1; /* 7.2.6 */ |
90 | 0 | if (offset + referred_to_segment_count * referred_to_segment_size + pa_size + 4 > buf_size) { |
91 | 0 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number, "attempted to parse segment header with insufficient data, asking for more data"); |
92 | 0 | jbig2_free(ctx->allocator, result); |
93 | 0 | return NULL; |
94 | 0 | } |
95 | | |
96 | | /* 7.2.5 */ |
97 | 0 | if (referred_to_segment_count) { |
98 | 0 | uint32_t i; |
99 | |
|
100 | 0 | referred_to_segments = jbig2_new(ctx, uint32_t, referred_to_segment_count * referred_to_segment_size); |
101 | 0 | if (referred_to_segments == NULL) { |
102 | 0 | jbig2_error(ctx, JBIG2_SEVERITY_FATAL, result->number, "failed to allocate referred to segments"); |
103 | 0 | jbig2_free(ctx->allocator, result); |
104 | 0 | return NULL; |
105 | 0 | } |
106 | | |
107 | 0 | for (i = 0; i < referred_to_segment_count; i++) { |
108 | 0 | referred_to_segments[i] = |
109 | 0 | (referred_to_segment_size == 1) ? buf[offset] : |
110 | 0 | (referred_to_segment_size == 2) ? jbig2_get_uint16(buf + offset) : jbig2_get_uint32(buf + offset); |
111 | 0 | offset += referred_to_segment_size; |
112 | 0 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number, "segment %d refers to segment %d", result->number, referred_to_segments[i]); |
113 | 0 | } |
114 | 0 | result->referred_to_segments = referred_to_segments; |
115 | 0 | } else { /* no referred-to segments */ |
116 | |
|
117 | 0 | result->referred_to_segments = NULL; |
118 | 0 | } |
119 | | |
120 | | /* 7.2.6 */ |
121 | 0 | if (pa_size == 4) { |
122 | 0 | result->page_association = jbig2_get_uint32(buf + offset); |
123 | 0 | offset += 4; |
124 | 0 | } else { |
125 | 0 | result->page_association = buf[offset++]; |
126 | 0 | } |
127 | 0 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number, "segment %d is associated with page %d", result->number, result->page_association); |
128 | | |
129 | | /* 7.2.7 */ |
130 | 0 | result->rows = UINT32_MAX; |
131 | 0 | result->data_length = jbig2_get_uint32(buf + offset); |
132 | 0 | *p_header_size = offset + 4; |
133 | | |
134 | | /* no body parsing results yet */ |
135 | 0 | result->result = NULL; |
136 | |
|
137 | 0 | return result; |
138 | 0 | } |
139 | | |
140 | | void |
141 | | jbig2_free_segment(Jbig2Ctx *ctx, Jbig2Segment *segment) |
142 | 0 | { |
143 | 0 | if (segment == NULL) |
144 | 0 | return; |
145 | | |
146 | 0 | jbig2_free(ctx->allocator, segment->referred_to_segments); |
147 | | /* todo: we need either some separate fields or |
148 | | a more complex result object rather than this |
149 | | brittle special casing */ |
150 | 0 | switch (segment->flags & 63) { |
151 | 0 | case 0: /* symbol dictionary */ |
152 | 0 | if (segment->result != NULL) |
153 | 0 | jbig2_sd_release(ctx, (Jbig2SymbolDict *) segment->result); |
154 | 0 | break; |
155 | 0 | case 4: /* intermediate text region */ |
156 | 0 | case 40: /* intermediate refinement region */ |
157 | 0 | if (segment->result != NULL) |
158 | 0 | jbig2_image_release(ctx, (Jbig2Image *) segment->result); |
159 | 0 | break; |
160 | 0 | case 16: /* pattern dictionary */ |
161 | 0 | if (segment->result != NULL) |
162 | 0 | jbig2_hd_release(ctx, (Jbig2PatternDict *) segment->result); |
163 | 0 | break; |
164 | 0 | case 53: /* user-supplied huffman table */ |
165 | 0 | if (segment->result != NULL) |
166 | 0 | jbig2_table_free(ctx, (Jbig2HuffmanParams *) segment->result); |
167 | 0 | break; |
168 | 0 | default: |
169 | | /* anything else is probably an undefined pointer */ |
170 | 0 | break; |
171 | 0 | } |
172 | 0 | jbig2_free(ctx->allocator, segment); |
173 | 0 | } |
174 | | |
175 | | /* find a segment by number */ |
176 | | Jbig2Segment * |
177 | | jbig2_find_segment(Jbig2Ctx *ctx, uint32_t number) |
178 | 0 | { |
179 | 0 | int index, index_max = ctx->segment_index - 1; |
180 | 0 | const Jbig2Ctx *global_ctx = ctx->global_ctx; |
181 | | |
182 | | /* FIXME: binary search would be better */ |
183 | 0 | for (index = index_max; index >= 0; index--) |
184 | 0 | if (ctx->segments[index]->number == number) |
185 | 0 | return (ctx->segments[index]); |
186 | | |
187 | 0 | if (global_ctx) |
188 | 0 | for (index = global_ctx->segment_index - 1; index >= 0; index--) |
189 | 0 | if (global_ctx->segments[index]->number == number) |
190 | 0 | return (global_ctx->segments[index]); |
191 | | |
192 | | /* didn't find a match */ |
193 | 0 | return NULL; |
194 | 0 | } |
195 | | |
196 | | /* parse the generic portion of a region segment data header */ |
197 | | void |
198 | | jbig2_get_region_segment_info(Jbig2RegionSegmentInfo *info, const uint8_t *segment_data) |
199 | 0 | { |
200 | | /* 7.4.1 */ |
201 | 0 | info->width = jbig2_get_uint32(segment_data); |
202 | 0 | info->height = jbig2_get_uint32(segment_data + 4); |
203 | 0 | info->x = jbig2_get_uint32(segment_data + 8); |
204 | 0 | info->y = jbig2_get_uint32(segment_data + 12); |
205 | 0 | info->flags = segment_data[16]; |
206 | 0 | info->op = (Jbig2ComposeOp)(info->flags & 0x7); |
207 | 0 | } |
208 | | |
209 | | /* dispatch code for extension segment parsing */ |
210 | | static int |
211 | | jbig2_parse_extension_segment(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) |
212 | 0 | { |
213 | 0 | uint32_t type; |
214 | 0 | bool reserved; |
215 | 0 | bool necessary; |
216 | |
|
217 | 0 | if (segment->data_length < 4) |
218 | 0 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short"); |
219 | | |
220 | 0 | type = jbig2_get_uint32(segment_data); |
221 | 0 | reserved = type & 0x20000000; |
222 | | /* Not implemented since this bit |
223 | | is only needed by encoders. |
224 | | dependent = type & 0x40000000; |
225 | | */ |
226 | 0 | necessary = type & 0x80000000; |
227 | |
|
228 | 0 | if (necessary && !reserved) { |
229 | 0 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "extension segment is marked 'necessary' but not 'reserved' contrary to spec"); |
230 | 0 | } |
231 | |
|
232 | 0 | switch (type) { |
233 | 0 | case 0x20000000: |
234 | 0 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "ignoring ASCII comment"); |
235 | 0 | break; |
236 | 0 | case 0x20000002: |
237 | 0 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "ignoring UCS-2 comment"); |
238 | 0 | break; |
239 | 0 | default: |
240 | 0 | if (necessary) { |
241 | 0 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unhandled necessary extension segment type 0x%08x", type); |
242 | 0 | } else { |
243 | 0 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unhandled non-necessary extension segment, skipping"); |
244 | 0 | } |
245 | 0 | } |
246 | | |
247 | 0 | return 0; |
248 | 0 | } |
249 | | |
250 | | /* dispatch code for profile segment parsing */ |
251 | | static int |
252 | | jbig2_parse_profile_segment(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) |
253 | 0 | { |
254 | 0 | uint32_t profiles; |
255 | 0 | uint32_t i; |
256 | 0 | uint32_t profile; |
257 | 0 | int index; |
258 | 0 | const char *requirements; |
259 | 0 | const char *generic_region; |
260 | 0 | const char *refinement_region; |
261 | 0 | const char *halftone_region; |
262 | 0 | const char *numerical_data; |
263 | |
|
264 | 0 | if (segment->data_length < 4) |
265 | 0 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short"); |
266 | 0 | index = 0; |
267 | |
|
268 | 0 | profiles = jbig2_get_uint32(&segment_data[index]); |
269 | 0 | index += 4; |
270 | |
|
271 | 0 | for (i = 0; i < profiles; i++) { |
272 | 0 | if (segment->data_length - index < 4) |
273 | 0 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short to store profile"); |
274 | | |
275 | 0 | profile = jbig2_get_uint32(&segment_data[index]); |
276 | 0 | index += 4; |
277 | |
|
278 | 0 | switch (profile) { |
279 | 0 | case 0x00000001: |
280 | 0 | requirements = "All JBIG2 capabilities"; |
281 | 0 | generic_region = "No restriction"; |
282 | 0 | refinement_region = "No restriction"; |
283 | 0 | halftone_region = "No restriction"; |
284 | 0 | numerical_data = "No restriction"; |
285 | 0 | break; |
286 | 0 | case 0x00000002: |
287 | 0 | requirements = "Maximum compression"; |
288 | 0 | generic_region = "Arithmetic only; any template used"; |
289 | 0 | refinement_region = "No restriction"; |
290 | 0 | halftone_region = "No restriction"; |
291 | 0 | numerical_data = "Arithmetic only"; |
292 | 0 | break; |
293 | 0 | case 0x00000003: |
294 | 0 | requirements = "Medium complexity and medium compression"; |
295 | 0 | generic_region = "Arithmetic only; only 10-pixel and 13-pixel templates"; |
296 | 0 | refinement_region = "10-pixel template only"; |
297 | 0 | halftone_region = "No skip mask used"; |
298 | 0 | numerical_data = "Arithmetic only"; |
299 | 0 | break; |
300 | 0 | case 0x00000004: |
301 | 0 | requirements = "Low complexity with progressive lossless capability"; |
302 | 0 | generic_region = "MMR only"; |
303 | 0 | refinement_region = "10-pixel template only"; |
304 | 0 | halftone_region = "No skip mask used"; |
305 | 0 | numerical_data = "Huffman only"; |
306 | 0 | break; |
307 | 0 | case 0x00000005: |
308 | 0 | requirements = "Low complexity"; |
309 | 0 | generic_region = "MMR only"; |
310 | 0 | refinement_region = "Not available"; |
311 | 0 | halftone_region = "No skip mask used"; |
312 | 0 | numerical_data = "Huffman only"; |
313 | 0 | break; |
314 | 0 | default: |
315 | 0 | requirements = "Unknown"; |
316 | 0 | generic_region = "Unknown"; |
317 | 0 | refinement_region = "Unknown"; |
318 | 0 | halftone_region = "Unknown"; |
319 | 0 | numerical_data = "Unknown"; |
320 | 0 | break; |
321 | 0 | } |
322 | | |
323 | 0 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "Supported profile: 0x%08x", profile); |
324 | 0 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, " Requirements: %s", requirements); |
325 | 0 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, " Generic region coding: %s", generic_region); |
326 | 0 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, " Refinement region coding: %s", refinement_region); |
327 | 0 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, " Halftone region coding: %s", halftone_region); |
328 | 0 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, " Numerical data: %s", numerical_data); |
329 | 0 | } |
330 | | |
331 | 0 | return 0; |
332 | 0 | } |
333 | | |
334 | | /* general segment parsing dispatch */ |
335 | | int |
336 | | jbig2_parse_segment(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) |
337 | 0 | { |
338 | 0 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, |
339 | 0 | "segment %d, flags=%x, type=%d, data_length=%ld", segment->number, segment->flags, segment->flags & 63, (long) segment->data_length); |
340 | 0 | switch (segment->flags & 63) { |
341 | 0 | case 0: |
342 | 0 | return jbig2_symbol_dictionary(ctx, segment, segment_data); |
343 | 0 | case 4: /* intermediate text region */ |
344 | 0 | case 6: /* immediate text region */ |
345 | 0 | case 7: /* immediate lossless text region */ |
346 | 0 | return jbig2_text_region(ctx, segment, segment_data); |
347 | 0 | case 16: |
348 | 0 | return jbig2_pattern_dictionary(ctx, segment, segment_data); |
349 | 0 | case 20: /* intermediate halftone region */ |
350 | 0 | case 22: /* immediate halftone region */ |
351 | 0 | case 23: /* immediate lossless halftone region */ |
352 | 0 | return jbig2_halftone_region(ctx, segment, segment_data); |
353 | 0 | case 36: |
354 | 0 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unhandled segment type 'intermediate generic region' (NYI)"); |
355 | 0 | case 38: /* immediate generic region */ |
356 | 0 | case 39: /* immediate lossless generic region */ |
357 | 0 | return jbig2_immediate_generic_region(ctx, segment, segment_data); |
358 | 0 | case 40: /* intermediate generic refinement region */ |
359 | 0 | case 42: /* immediate generic refinement region */ |
360 | 0 | case 43: /* immediate lossless generic refinement region */ |
361 | 0 | return jbig2_refinement_region(ctx, segment, segment_data); |
362 | 0 | case 48: |
363 | 0 | return jbig2_page_info(ctx, segment, segment_data); |
364 | 0 | case 49: |
365 | 0 | return jbig2_end_of_page(ctx, segment, segment_data); |
366 | 0 | case 50: |
367 | 0 | return jbig2_end_of_stripe(ctx, segment, segment_data); |
368 | 0 | case 51: |
369 | 0 | ctx->state = JBIG2_FILE_EOF; |
370 | 0 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "end of file"); |
371 | 0 | break; |
372 | 0 | case 52: |
373 | 0 | return jbig2_parse_profile_segment(ctx, segment, segment_data); |
374 | 0 | case 53: /* user-supplied huffman table */ |
375 | 0 | return jbig2_table(ctx, segment, segment_data); |
376 | 0 | case 54: |
377 | 0 | return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unhandled segment type 'color palette' (NYI)"); |
378 | 0 | case 62: |
379 | 0 | return jbig2_parse_extension_segment(ctx, segment, segment_data); |
380 | 0 | default: |
381 | 0 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unknown segment type %d", segment->flags & 63); |
382 | 0 | } |
383 | 0 | return 0; |
384 | 0 | } |