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

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