| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- /* 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;
- }
|