Mercurial > hgrepos > Python2 > PyMuPDF
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 } |
