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