Mercurial > hgrepos > Python2 > PyMuPDF
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/thirdparty/jbig2dec/jbig2_segment.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,384 @@ +/* Copyright (C) 2001-2023 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, + modified or distributed except as expressly authorized under the terms + of the license contained in the file LICENSE in this distribution. + + Refer to licensing information at http://www.artifex.com or contact + Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, + CA 94129, USA, for further information. +*/ + +/* + jbig2dec +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "os_types.h" + +#include <stddef.h> /* size_t */ + +#include "jbig2.h" +#include "jbig2_priv.h" +#include "jbig2_arith.h" +#include "jbig2_arith_int.h" +#include "jbig2_arith_iaid.h" +#include "jbig2_generic.h" +#include "jbig2_image.h" +#include "jbig2_halftone.h" +#include "jbig2_huffman.h" +#include "jbig2_page.h" +#include "jbig2_refinement.h" +#include "jbig2_segment.h" +#include "jbig2_symbol_dict.h" +#include "jbig2_text.h" + +Jbig2Segment * +jbig2_parse_segment_header(Jbig2Ctx *ctx, uint8_t *buf, size_t buf_size, size_t *p_header_size) +{ + Jbig2Segment *result; + uint8_t rtscarf; + uint32_t rtscarf_long; + uint32_t *referred_to_segments; + uint32_t referred_to_segment_count; + uint32_t referred_to_segment_size; + uint32_t pa_size; + uint32_t offset; + + /* minimum possible size of a jbig2 segment header */ + if (buf_size < 11) + return NULL; + + result = jbig2_new(ctx, Jbig2Segment, 1); + if (result == NULL) { + jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate segment"); + return NULL; + } + + /* 7.2.2 */ + result->number = jbig2_get_uint32(buf); + if (result->number == JBIG2_UNKNOWN_SEGMENT_NUMBER) { + jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "segment number too large"); + jbig2_free(ctx->allocator, result); + return NULL; + } + + /* 7.2.3 */ + result->flags = buf[4]; + + /* 7.2.4 referred-to segments */ + rtscarf = buf[5]; + if ((rtscarf & 0xe0) == 0xe0) { + rtscarf_long = jbig2_get_uint32(buf + 5); + referred_to_segment_count = rtscarf_long & 0x1fffffff; + offset = 5 + 4 + (referred_to_segment_count + 1) / 8; + } else { + referred_to_segment_count = (rtscarf >> 5); + offset = 5 + 1; + } + result->referred_to_segment_count = referred_to_segment_count; + + /* we now have enough information to compute the full header length */ + referred_to_segment_size = result->number <= 256 ? 1 : result->number <= 65536 ? 2 : 4; /* 7.2.5 */ + pa_size = result->flags & 0x40 ? 4 : 1; /* 7.2.6 */ + if (offset + referred_to_segment_count * referred_to_segment_size + pa_size + 4 > buf_size) { + jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number, "attempted to parse segment header with insufficient data, asking for more data"); + jbig2_free(ctx->allocator, result); + return NULL; + } + + /* 7.2.5 */ + if (referred_to_segment_count) { + uint32_t i; + + referred_to_segments = jbig2_new(ctx, uint32_t, referred_to_segment_count * referred_to_segment_size); + if (referred_to_segments == NULL) { + jbig2_error(ctx, JBIG2_SEVERITY_FATAL, result->number, "failed to allocate referred to segments"); + jbig2_free(ctx->allocator, result); + return NULL; + } + + for (i = 0; i < referred_to_segment_count; i++) { + referred_to_segments[i] = + (referred_to_segment_size == 1) ? buf[offset] : + (referred_to_segment_size == 2) ? jbig2_get_uint16(buf + offset) : jbig2_get_uint32(buf + offset); + offset += referred_to_segment_size; + jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number, "segment %d refers to segment %d", result->number, referred_to_segments[i]); + } + result->referred_to_segments = referred_to_segments; + } else { /* no referred-to segments */ + + result->referred_to_segments = NULL; + } + + /* 7.2.6 */ + if (pa_size == 4) { + result->page_association = jbig2_get_uint32(buf + offset); + offset += 4; + } else { + result->page_association = buf[offset++]; + } + jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number, "segment %d is associated with page %d", result->number, result->page_association); + + /* 7.2.7 */ + result->rows = UINT32_MAX; + result->data_length = jbig2_get_uint32(buf + offset); + *p_header_size = offset + 4; + + /* no body parsing results yet */ + result->result = NULL; + + return result; +} + +void +jbig2_free_segment(Jbig2Ctx *ctx, Jbig2Segment *segment) +{ + if (segment == NULL) + return; + + jbig2_free(ctx->allocator, segment->referred_to_segments); + /* todo: we need either some separate fields or + a more complex result object rather than this + brittle special casing */ + switch (segment->flags & 63) { + case 0: /* symbol dictionary */ + if (segment->result != NULL) + jbig2_sd_release(ctx, (Jbig2SymbolDict *) segment->result); + break; + case 4: /* intermediate text region */ + case 40: /* intermediate refinement region */ + if (segment->result != NULL) + jbig2_image_release(ctx, (Jbig2Image *) segment->result); + break; + case 16: /* pattern dictionary */ + if (segment->result != NULL) + jbig2_hd_release(ctx, (Jbig2PatternDict *) segment->result); + break; + case 53: /* user-supplied huffman table */ + if (segment->result != NULL) + jbig2_table_free(ctx, (Jbig2HuffmanParams *) segment->result); + break; + default: + /* anything else is probably an undefined pointer */ + break; + } + jbig2_free(ctx->allocator, segment); +} + +/* find a segment by number */ +Jbig2Segment * +jbig2_find_segment(Jbig2Ctx *ctx, uint32_t number) +{ + int index, index_max = ctx->segment_index - 1; + const Jbig2Ctx *global_ctx = ctx->global_ctx; + + /* FIXME: binary search would be better */ + for (index = index_max; index >= 0; index--) + if (ctx->segments[index]->number == number) + return (ctx->segments[index]); + + if (global_ctx) + for (index = global_ctx->segment_index - 1; index >= 0; index--) + if (global_ctx->segments[index]->number == number) + return (global_ctx->segments[index]); + + /* didn't find a match */ + return NULL; +} + +/* parse the generic portion of a region segment data header */ +void +jbig2_get_region_segment_info(Jbig2RegionSegmentInfo *info, const uint8_t *segment_data) +{ + /* 7.4.1 */ + info->width = jbig2_get_uint32(segment_data); + info->height = jbig2_get_uint32(segment_data + 4); + info->x = jbig2_get_uint32(segment_data + 8); + info->y = jbig2_get_uint32(segment_data + 12); + info->flags = segment_data[16]; + info->op = (Jbig2ComposeOp)(info->flags & 0x7); +} + +/* dispatch code for extension segment parsing */ +static int +jbig2_parse_extension_segment(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) +{ + uint32_t type; + bool reserved; + bool necessary; + + if (segment->data_length < 4) + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short"); + + type = jbig2_get_uint32(segment_data); + reserved = type & 0x20000000; + /* Not implemented since this bit + is only needed by encoders. + dependent = type & 0x40000000; + */ + necessary = type & 0x80000000; + + if (necessary && !reserved) { + jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "extension segment is marked 'necessary' but not 'reserved' contrary to spec"); + } + + switch (type) { + case 0x20000000: + jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "ignoring ASCII comment"); + break; + case 0x20000002: + jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "ignoring UCS-2 comment"); + break; + default: + if (necessary) { + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unhandled necessary extension segment type 0x%08x", type); + } else { + jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unhandled non-necessary extension segment, skipping"); + } + } + + return 0; +} + +/* dispatch code for profile segment parsing */ +static int +jbig2_parse_profile_segment(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) +{ + uint32_t profiles; + uint32_t i; + uint32_t profile; + int index; + const char *requirements; + const char *generic_region; + const char *refinement_region; + const char *halftone_region; + const char *numerical_data; + + if (segment->data_length < 4) + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short"); + index = 0; + + profiles = jbig2_get_uint32(&segment_data[index]); + index += 4; + + for (i = 0; i < profiles; i++) { + if (segment->data_length - index < 4) + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short to store profile"); + + profile = jbig2_get_uint32(&segment_data[index]); + index += 4; + + switch (profile) { + case 0x00000001: + requirements = "All JBIG2 capabilities"; + generic_region = "No restriction"; + refinement_region = "No restriction"; + halftone_region = "No restriction"; + numerical_data = "No restriction"; + break; + case 0x00000002: + requirements = "Maximum compression"; + generic_region = "Arithmetic only; any template used"; + refinement_region = "No restriction"; + halftone_region = "No restriction"; + numerical_data = "Arithmetic only"; + break; + case 0x00000003: + requirements = "Medium complexity and medium compression"; + generic_region = "Arithmetic only; only 10-pixel and 13-pixel templates"; + refinement_region = "10-pixel template only"; + halftone_region = "No skip mask used"; + numerical_data = "Arithmetic only"; + break; + case 0x00000004: + requirements = "Low complexity with progressive lossless capability"; + generic_region = "MMR only"; + refinement_region = "10-pixel template only"; + halftone_region = "No skip mask used"; + numerical_data = "Huffman only"; + break; + case 0x00000005: + requirements = "Low complexity"; + generic_region = "MMR only"; + refinement_region = "Not available"; + halftone_region = "No skip mask used"; + numerical_data = "Huffman only"; + break; + default: + requirements = "Unknown"; + generic_region = "Unknown"; + refinement_region = "Unknown"; + halftone_region = "Unknown"; + numerical_data = "Unknown"; + break; + } + + jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "Supported profile: 0x%08x", profile); + jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, " Requirements: %s", requirements); + jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, " Generic region coding: %s", generic_region); + jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, " Refinement region coding: %s", refinement_region); + jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, " Halftone region coding: %s", halftone_region); + jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, " Numerical data: %s", numerical_data); + } + + return 0; +} + +/* general segment parsing dispatch */ +int +jbig2_parse_segment(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) +{ + jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, + "segment %d, flags=%x, type=%d, data_length=%ld", segment->number, segment->flags, segment->flags & 63, (long) segment->data_length); + switch (segment->flags & 63) { + case 0: + return jbig2_symbol_dictionary(ctx, segment, segment_data); + case 4: /* intermediate text region */ + case 6: /* immediate text region */ + case 7: /* immediate lossless text region */ + return jbig2_text_region(ctx, segment, segment_data); + case 16: + return jbig2_pattern_dictionary(ctx, segment, segment_data); + case 20: /* intermediate halftone region */ + case 22: /* immediate halftone region */ + case 23: /* immediate lossless halftone region */ + return jbig2_halftone_region(ctx, segment, segment_data); + case 36: + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unhandled segment type 'intermediate generic region' (NYI)"); + case 38: /* immediate generic region */ + case 39: /* immediate lossless generic region */ + return jbig2_immediate_generic_region(ctx, segment, segment_data); + case 40: /* intermediate generic refinement region */ + case 42: /* immediate generic refinement region */ + case 43: /* immediate lossless generic refinement region */ + return jbig2_refinement_region(ctx, segment, segment_data); + case 48: + return jbig2_page_info(ctx, segment, segment_data); + case 49: + return jbig2_end_of_page(ctx, segment, segment_data); + case 50: + return jbig2_end_of_stripe(ctx, segment, segment_data); + case 51: + ctx->state = JBIG2_FILE_EOF; + jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "end of file"); + break; + case 52: + return jbig2_parse_profile_segment(ctx, segment, segment_data); + case 53: /* user-supplied huffman table */ + return jbig2_table(ctx, segment, segment_data); + case 54: + return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unhandled segment type 'color palette' (NYI)"); + case 62: + return jbig2_parse_extension_segment(ctx, segment, segment_data); + default: + jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unknown segment type %d", segment->flags & 63); + } + return 0; +}
