cidload.c (25095B)
1 /**************************************************************************** 2 * 3 * cidload.c 4 * 5 * CID-keyed Type1 font loader (body). 6 * 7 * Copyright (C) 1996-2025 by 8 * David Turner, Robert Wilhelm, and Werner Lemberg. 9 * 10 * This file is part of the FreeType project, and may only be used, 11 * modified, and distributed under the terms of the FreeType project 12 * license, LICENSE.TXT. By continuing to use, modify, or distribute 13 * this file you indicate that you have read the license and 14 * understand and accept it fully. 15 * 16 */ 17 18 19 #include <ft2build.h> 20 #include <freetype/internal/ftdebug.h> 21 #include FT_CONFIG_CONFIG_H 22 #include <freetype/ftmm.h> 23 #include <freetype/internal/t1types.h> 24 #include <freetype/internal/psaux.h> 25 26 #include "cidload.h" 27 28 #include "ciderrs.h" 29 30 31 /************************************************************************** 32 * 33 * The macro FT_COMPONENT is used in trace mode. It is an implicit 34 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log 35 * messages during execution. 36 */ 37 #undef FT_COMPONENT 38 #define FT_COMPONENT cidload 39 40 41 /* read a single offset */ 42 FT_LOCAL_DEF( FT_ULong ) 43 cid_get_offset( FT_Byte* *start, 44 FT_UInt offsize ) 45 { 46 FT_ULong result; 47 FT_Byte* p = *start; 48 49 50 for ( result = 0; offsize > 0; offsize-- ) 51 { 52 result <<= 8; 53 result |= *p++; 54 } 55 56 *start = p; 57 return result; 58 } 59 60 61 /*************************************************************************/ 62 /*************************************************************************/ 63 /***** *****/ 64 /***** TYPE 1 SYMBOL PARSING *****/ 65 /***** *****/ 66 /*************************************************************************/ 67 /*************************************************************************/ 68 69 70 static FT_Error 71 cid_load_keyword( CID_Face face, 72 CID_Loader* loader, 73 const T1_Field keyword ) 74 { 75 FT_Error error; 76 CID_Parser* parser = &loader->parser; 77 FT_Byte* object; 78 void* dummy_object; 79 CID_FaceInfo cid = &face->cid; 80 81 82 /* if the keyword has a dedicated callback, call it */ 83 if ( keyword->type == T1_FIELD_TYPE_CALLBACK ) 84 { 85 FT_TRACE4(( " %s", keyword->ident )); 86 87 keyword->reader( (FT_Face)face, parser ); 88 error = parser->root.error; 89 goto Exit; 90 } 91 92 /* we must now compute the address of our target object */ 93 switch ( keyword->location ) 94 { 95 case T1_FIELD_LOCATION_CID_INFO: 96 object = (FT_Byte*)cid; 97 break; 98 99 case T1_FIELD_LOCATION_FONT_INFO: 100 object = (FT_Byte*)&cid->font_info; 101 break; 102 103 case T1_FIELD_LOCATION_FONT_EXTRA: 104 object = (FT_Byte*)&face->font_extra; 105 break; 106 107 case T1_FIELD_LOCATION_BBOX: 108 object = (FT_Byte*)&cid->font_bbox; 109 break; 110 111 default: 112 { 113 CID_FaceDict dict; 114 115 116 if ( parser->num_dict >= cid->num_dicts ) 117 { 118 FT_ERROR(( "cid_load_keyword: invalid use of `%s'\n", 119 keyword->ident )); 120 error = FT_THROW( Syntax_Error ); 121 goto Exit; 122 } 123 124 dict = cid->font_dicts + parser->num_dict; 125 switch ( keyword->location ) 126 { 127 case T1_FIELD_LOCATION_PRIVATE: 128 object = (FT_Byte*)&dict->private_dict; 129 break; 130 131 default: 132 object = (FT_Byte*)dict; 133 } 134 } 135 } 136 137 FT_TRACE4(( " %s", keyword->ident )); 138 139 dummy_object = object; 140 141 /* now, load the keyword data in the object's field(s) */ 142 if ( keyword->type == T1_FIELD_TYPE_INTEGER_ARRAY || 143 keyword->type == T1_FIELD_TYPE_FIXED_ARRAY ) 144 error = cid_parser_load_field_table( &loader->parser, keyword, 145 &dummy_object ); 146 else 147 error = cid_parser_load_field( &loader->parser, 148 keyword, &dummy_object ); 149 150 FT_TRACE4(( "\n" )); 151 152 Exit: 153 return error; 154 } 155 156 157 FT_CALLBACK_DEF( void ) 158 cid_parse_font_matrix( FT_Face face, /* CID_Face */ 159 void* parser_ ) 160 { 161 CID_Face cidface = (CID_Face)face; 162 CID_Parser* parser = (CID_Parser*)parser_; 163 CID_FaceDict dict; 164 FT_Fixed temp[6]; 165 FT_Fixed temp_scale; 166 167 168 if ( parser->num_dict < cidface->cid.num_dicts ) 169 { 170 FT_Matrix* matrix; 171 FT_Vector* offset; 172 FT_Int result; 173 174 175 dict = cidface->cid.font_dicts + parser->num_dict; 176 matrix = &dict->font_matrix; 177 offset = &dict->font_offset; 178 179 /* input is scaled by 1000 to accommodate default FontMatrix */ 180 result = cid_parser_to_fixed_array( parser, 6, temp, 3 ); 181 182 if ( result < 6 ) 183 { 184 FT_ERROR(( "cid_parse_font_matrix: not enough matrix elements\n" )); 185 goto Exit; 186 } 187 188 FT_TRACE4(( " [%f %f %f %f %f %f]\n", 189 (double)temp[0] / 65536 / 1000, 190 (double)temp[1] / 65536 / 1000, 191 (double)temp[2] / 65536 / 1000, 192 (double)temp[3] / 65536 / 1000, 193 (double)temp[4] / 65536 / 1000, 194 (double)temp[5] / 65536 / 1000 )); 195 196 temp_scale = FT_ABS( temp[3] ); 197 198 if ( temp_scale == 0 ) 199 { 200 FT_ERROR(( "cid_parse_font_matrix: invalid font matrix\n" )); 201 goto Exit; 202 } 203 204 /* atypical case */ 205 if ( temp_scale != 0x10000L ) 206 { 207 /* set units per EM based on FontMatrix values */ 208 face->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale ); 209 210 temp[0] = FT_DivFix( temp[0], temp_scale ); 211 temp[1] = FT_DivFix( temp[1], temp_scale ); 212 temp[2] = FT_DivFix( temp[2], temp_scale ); 213 temp[4] = FT_DivFix( temp[4], temp_scale ); 214 temp[5] = FT_DivFix( temp[5], temp_scale ); 215 temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L; 216 } 217 218 matrix->xx = temp[0]; 219 matrix->yx = temp[1]; 220 matrix->xy = temp[2]; 221 matrix->yy = temp[3]; 222 223 if ( !FT_Matrix_Check( matrix ) ) 224 { 225 FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" )); 226 parser->root.error = FT_THROW( Invalid_File_Format ); 227 goto Exit; 228 } 229 230 /* note that the font offsets are expressed in integer font units */ 231 offset->x = temp[4] >> 16; 232 offset->y = temp[5] >> 16; 233 } 234 235 Exit: 236 return; 237 } 238 239 240 FT_CALLBACK_DEF( void ) 241 parse_fd_array( FT_Face face, /* CID_Face */ 242 void* parser_ ) 243 { 244 CID_Face cidface = (CID_Face)face; 245 CID_Parser* parser = (CID_Parser*)parser_; 246 CID_FaceInfo cid = &cidface->cid; 247 FT_Memory memory = FT_FACE_MEMORY( face ); 248 FT_Stream stream = parser->stream; 249 FT_Error error = FT_Err_Ok; 250 FT_Long num_dicts, max_dicts; 251 252 253 num_dicts = cid_parser_to_int( parser ); 254 if ( num_dicts < 0 || num_dicts > FT_INT_MAX ) 255 { 256 FT_ERROR(( "parse_fd_array: invalid number of dictionaries\n" )); 257 goto Exit; 258 } 259 260 FT_TRACE4(( " %ld\n", num_dicts )); 261 262 /* 263 * A single entry in the FDArray must (at least) contain the following 264 * structure elements. 265 * 266 * %ADOBeginFontDict 18 267 * X dict begin 13 268 * /FontMatrix [X X X X] 22 269 * /Private X dict begin 22 270 * end 4 271 * end 4 272 * %ADOEndFontDict 16 273 * 274 * This needs 18+13+22+22+4+4+16=99 bytes or more. Normally, you also 275 * need a `dup X' at the very beginning and a `put' at the end, so a 276 * rough guess using 100 bytes as the minimum is justified. 277 */ 278 max_dicts = (FT_Long)( stream->size / 100 ); 279 if ( num_dicts > max_dicts ) 280 { 281 FT_TRACE0(( "parse_fd_array: adjusting FDArray size" 282 " (from %ld to %ld)\n", 283 num_dicts, max_dicts )); 284 num_dicts = max_dicts; 285 } 286 287 if ( !cid->font_dicts ) 288 { 289 FT_UInt n; 290 291 292 if ( FT_NEW_ARRAY( cid->font_dicts, num_dicts ) ) 293 goto Exit; 294 295 cid->num_dicts = num_dicts; 296 297 /* set some default values (the same as for Type 1 fonts) */ 298 for ( n = 0; n < cid->num_dicts; n++ ) 299 { 300 CID_FaceDict dict = cid->font_dicts + n; 301 302 303 dict->private_dict.blue_shift = 7; 304 dict->private_dict.blue_fuzz = 1; 305 dict->private_dict.lenIV = 4; 306 dict->private_dict.expansion_factor = (FT_Fixed)( 0.06 * 0x10000L ); 307 dict->private_dict.blue_scale = (FT_Fixed)( 308 0.039625 * 0x10000L * 1000 ); 309 } 310 } 311 312 Exit: 313 return; 314 } 315 316 317 /* By mistake, `expansion_factor' appears both in PS_PrivateRec */ 318 /* and CID_FaceDictRec (both are public header files and can't */ 319 /* be thus changed). We simply copy the value. */ 320 321 FT_CALLBACK_DEF( void ) 322 parse_expansion_factor( FT_Face face, /* CID_Face */ 323 void* parser_ ) 324 { 325 CID_Face cidface = (CID_Face)face; 326 CID_Parser* parser = (CID_Parser*)parser_; 327 CID_FaceDict dict; 328 329 330 if ( parser->num_dict < cidface->cid.num_dicts ) 331 { 332 dict = cidface->cid.font_dicts + parser->num_dict; 333 334 dict->expansion_factor = cid_parser_to_fixed( parser, 0 ); 335 dict->private_dict.expansion_factor = dict->expansion_factor; 336 337 FT_TRACE4(( "%ld\n", dict->expansion_factor )); 338 } 339 340 return; 341 } 342 343 344 /* By mistake, `CID_FaceDictRec' doesn't contain a field for the */ 345 /* `FontName' keyword. FreeType doesn't need it, but it is nice */ 346 /* to catch it for producing better trace output. */ 347 348 FT_CALLBACK_DEF( void ) 349 parse_font_name( FT_Face face, /* CID_Face */ 350 void* parser_ ) 351 { 352 #ifdef FT_DEBUG_LEVEL_TRACE 353 CID_Face cidface = (CID_Face)face; 354 CID_Parser* parser = (CID_Parser*)parser_; 355 356 357 if ( parser->num_dict < cidface->cid.num_dicts ) 358 { 359 T1_TokenRec token; 360 FT_UInt len; 361 362 363 cid_parser_to_token( parser, &token ); 364 365 len = (FT_UInt)( token.limit - token.start ); 366 if ( len ) 367 FT_TRACE4(( " %.*s\n", len, token.start )); 368 else 369 FT_TRACE4(( " <no value>\n" )); 370 } 371 #else 372 FT_UNUSED( face ); 373 FT_UNUSED( parser_ ); 374 #endif 375 376 return; 377 } 378 379 380 static 381 const T1_FieldRec cid_field_records[] = 382 { 383 384 #include "cidtoken.h" 385 386 T1_FIELD_CALLBACK( "FDArray", parse_fd_array, 0 ) 387 T1_FIELD_CALLBACK( "FontMatrix", cid_parse_font_matrix, 0 ) 388 T1_FIELD_CALLBACK( "ExpansionFactor", parse_expansion_factor, 0 ) 389 T1_FIELD_CALLBACK( "FontName", parse_font_name, 0 ) 390 391 T1_FIELD_ZERO 392 }; 393 394 395 static FT_Error 396 cid_parse_dict( CID_Face face, 397 CID_Loader* loader, 398 FT_Byte* base, 399 FT_ULong size ) 400 { 401 CID_Parser* parser = &loader->parser; 402 403 404 parser->root.cursor = base; 405 parser->root.limit = base + size; 406 parser->root.error = FT_Err_Ok; 407 408 { 409 FT_Byte* cur = base; 410 FT_Byte* limit = cur + size; 411 412 413 for (;;) 414 { 415 FT_Byte* newlimit; 416 417 418 parser->root.cursor = cur; 419 cid_parser_skip_spaces( parser ); 420 421 if ( parser->root.cursor >= limit ) 422 newlimit = limit - 1 - 17; 423 else 424 newlimit = parser->root.cursor - 17; 425 426 /* look for `%ADOBeginFontDict' */ 427 for ( ; cur < newlimit; cur++ ) 428 { 429 if ( *cur == '%' && 430 ft_strncmp( (char*)cur, "%ADOBeginFontDict", 17 ) == 0 ) 431 { 432 /* if /FDArray was found, then cid->num_dicts is > 0, and */ 433 /* we can start increasing parser->num_dict */ 434 if ( face->cid.num_dicts > 0 ) 435 { 436 parser->num_dict++; 437 438 #ifdef FT_DEBUG_LEVEL_TRACE 439 FT_TRACE4(( " FontDict %u", parser->num_dict )); 440 if ( parser->num_dict > face->cid.num_dicts ) 441 FT_TRACE4(( " (ignored)" )); 442 FT_TRACE4(( "\n" )); 443 #endif 444 } 445 } 446 } 447 448 cur = parser->root.cursor; 449 /* no error can occur in cid_parser_skip_spaces */ 450 if ( cur >= limit ) 451 break; 452 453 cid_parser_skip_PS_token( parser ); 454 if ( parser->root.cursor >= limit || parser->root.error ) 455 break; 456 457 /* look for immediates */ 458 if ( *cur == '/' && cur + 2 < limit ) 459 { 460 FT_UInt len; 461 462 463 cur++; 464 len = (FT_UInt)( parser->root.cursor - cur ); 465 466 if ( len > 0 && len < 22 ) 467 { 468 /* now compare the immediate name to the keyword table */ 469 T1_Field keyword = (T1_Field)cid_field_records; 470 471 472 while ( keyword->len ) 473 { 474 FT_Byte* name = (FT_Byte*)keyword->ident; 475 476 477 if ( keyword->len == len && 478 ft_memcmp( cur, name, len ) == 0 ) 479 { 480 /* we found it - run the parsing callback */ 481 parser->root.error = cid_load_keyword( face, 482 loader, 483 keyword ); 484 if ( parser->root.error ) 485 return parser->root.error; 486 break; 487 } 488 489 keyword++; 490 } 491 } 492 } 493 494 cur = parser->root.cursor; 495 } 496 497 if ( !face->cid.num_dicts ) 498 { 499 FT_ERROR(( "cid_parse_dict: No font dictionary found\n" )); 500 return FT_THROW( Invalid_File_Format ); 501 } 502 } 503 504 return parser->root.error; 505 } 506 507 508 /* read the subrmap and the subrs of each font dict */ 509 static FT_Error 510 cid_read_subrs( CID_Face face ) 511 { 512 CID_FaceInfo cid = &face->cid; 513 FT_Memory memory = face->root.memory; 514 FT_Stream stream = face->cid_stream; 515 FT_Error error; 516 FT_UInt n; 517 CID_Subrs subr; 518 FT_UInt max_offsets = 0; 519 FT_ULong* offsets = NULL; 520 PSAux_Service psaux = (PSAux_Service)face->psaux; 521 522 523 if ( FT_NEW_ARRAY( face->subrs, cid->num_dicts ) ) 524 goto Exit; 525 526 subr = face->subrs; 527 for ( n = 0; n < cid->num_dicts; n++, subr++ ) 528 { 529 CID_FaceDict dict = cid->font_dicts + n; 530 FT_Int lenIV = dict->private_dict.lenIV; 531 FT_UInt count, num_subrs = dict->num_subrs; 532 FT_ULong data_len; 533 FT_Byte* p; 534 535 536 if ( !num_subrs ) 537 continue; 538 539 /* reallocate offsets array if needed */ 540 if ( num_subrs + 1 > max_offsets ) 541 { 542 FT_UInt new_max = FT_PAD_CEIL( num_subrs + 1, 4 ); 543 544 545 if ( new_max <= max_offsets ) 546 { 547 error = FT_THROW( Syntax_Error ); 548 goto Fail; 549 } 550 551 if ( FT_QRENEW_ARRAY( offsets, max_offsets, new_max ) ) 552 goto Fail; 553 554 max_offsets = new_max; 555 } 556 557 /* read the subrmap's offsets */ 558 if ( FT_STREAM_SEEK( cid->data_offset + dict->subrmap_offset ) || 559 FT_FRAME_ENTER( ( num_subrs + 1 ) * dict->sd_bytes ) ) 560 goto Fail; 561 562 p = (FT_Byte*)stream->cursor; 563 for ( count = 0; count <= num_subrs; count++ ) 564 offsets[count] = cid_get_offset( &p, dict->sd_bytes ); 565 566 FT_FRAME_EXIT(); 567 568 /* offsets must be ordered */ 569 for ( count = 1; count <= num_subrs; count++ ) 570 if ( offsets[count - 1] > offsets[count] ) 571 { 572 FT_ERROR(( "cid_read_subrs: offsets are not ordered\n" )); 573 error = FT_THROW( Invalid_File_Format ); 574 goto Fail; 575 } 576 577 if ( offsets[num_subrs] > stream->size - cid->data_offset ) 578 { 579 FT_ERROR(( "cid_read_subrs: too large `subrs' offsets\n" )); 580 error = FT_THROW( Invalid_File_Format ); 581 goto Fail; 582 } 583 584 /* now, compute the size of subrs charstrings, */ 585 /* allocate, and read them */ 586 data_len = offsets[num_subrs] - offsets[0]; 587 588 if ( FT_QNEW_ARRAY( subr->code, num_subrs + 1 ) || 589 FT_QALLOC( subr->code[0], data_len ) ) 590 goto Fail; 591 592 if ( FT_STREAM_SEEK( cid->data_offset + offsets[0] ) || 593 FT_STREAM_READ( subr->code[0], data_len ) ) 594 goto Fail; 595 596 /* set up pointers */ 597 for ( count = 1; count <= num_subrs; count++ ) 598 { 599 FT_ULong len; 600 601 602 len = offsets[count] - offsets[count - 1]; 603 subr->code[count] = subr->code[count - 1] + len; 604 } 605 606 /* decrypt subroutines, but only if lenIV >= 0 */ 607 if ( lenIV >= 0 ) 608 { 609 for ( count = 0; count < num_subrs; count++ ) 610 { 611 FT_ULong len; 612 613 614 len = offsets[count + 1] - offsets[count]; 615 psaux->t1_decrypt( subr->code[count], len, 4330 ); 616 } 617 } 618 619 subr->num_subrs = (FT_Int)num_subrs; 620 } 621 622 Exit: 623 FT_FREE( offsets ); 624 return error; 625 626 Fail: 627 if ( face->subrs ) 628 { 629 for ( n = 0; n < cid->num_dicts; n++ ) 630 { 631 if ( face->subrs[n].code ) 632 FT_FREE( face->subrs[n].code[0] ); 633 634 FT_FREE( face->subrs[n].code ); 635 } 636 FT_FREE( face->subrs ); 637 } 638 goto Exit; 639 } 640 641 642 static void 643 cid_init_loader( CID_Loader* loader, 644 CID_Face face ) 645 { 646 FT_UNUSED( face ); 647 648 FT_ZERO( loader ); 649 } 650 651 652 static void 653 cid_done_loader( CID_Loader* loader ) 654 { 655 CID_Parser* parser = &loader->parser; 656 657 658 /* finalize parser */ 659 cid_parser_done( parser ); 660 } 661 662 663 static FT_Error 664 cid_hex_to_binary( FT_Byte* data, 665 FT_ULong data_len, 666 FT_ULong offset, 667 CID_Face face, 668 FT_ULong* data_written ) 669 { 670 FT_Stream stream = face->root.stream; 671 FT_Error error; 672 673 FT_Byte buffer[256]; 674 FT_Byte *p, *plimit; 675 FT_Byte *d = data, *dlimit; 676 FT_Byte val; 677 678 FT_Bool upper_nibble, done; 679 680 681 if ( FT_STREAM_SEEK( offset ) ) 682 goto Exit; 683 684 dlimit = d + data_len; 685 p = buffer; 686 plimit = p; 687 688 upper_nibble = 1; 689 done = 0; 690 691 while ( d < dlimit ) 692 { 693 if ( p >= plimit ) 694 { 695 FT_ULong oldpos = FT_STREAM_POS(); 696 FT_ULong size = stream->size - oldpos; 697 698 699 if ( size == 0 ) 700 { 701 error = FT_THROW( Syntax_Error ); 702 goto Exit; 703 } 704 705 if ( FT_STREAM_READ( buffer, 256 > size ? size : 256 ) ) 706 goto Exit; 707 p = buffer; 708 plimit = p + FT_STREAM_POS() - oldpos; 709 } 710 711 if ( ft_isdigit( *p ) ) 712 val = (FT_Byte)( *p - '0' ); 713 else if ( *p >= 'a' && *p <= 'f' ) 714 val = (FT_Byte)( *p - 'a' + 10 ); 715 else if ( *p >= 'A' && *p <= 'F' ) 716 val = (FT_Byte)( *p - 'A' + 10 ); 717 else if ( *p == ' ' || 718 *p == '\t' || 719 *p == '\r' || 720 *p == '\n' || 721 *p == '\f' || 722 *p == '\0' ) 723 { 724 p++; 725 continue; 726 } 727 else if ( *p == '>' ) 728 { 729 val = 0; 730 done = 1; 731 } 732 else 733 { 734 error = FT_THROW( Syntax_Error ); 735 goto Exit; 736 } 737 738 if ( upper_nibble ) 739 *d = (FT_Byte)( val << 4 ); 740 else 741 { 742 *d = (FT_Byte)( *d + val ); 743 d++; 744 } 745 746 upper_nibble = (FT_Byte)( 1 - upper_nibble ); 747 748 if ( done ) 749 break; 750 751 p++; 752 } 753 754 error = FT_Err_Ok; 755 756 Exit: 757 *data_written = (FT_ULong)( d - data ); 758 return error; 759 } 760 761 762 FT_LOCAL_DEF( FT_Error ) 763 cid_face_open( CID_Face face, 764 FT_Int face_index ) 765 { 766 CID_Loader loader; 767 CID_Parser* parser; 768 FT_Memory memory = face->root.memory; 769 FT_Error error; 770 FT_UInt n; 771 772 CID_FaceInfo cid = &face->cid; 773 774 FT_ULong binary_length; 775 776 777 cid_init_loader( &loader, face ); 778 779 parser = &loader.parser; 780 error = cid_parser_new( parser, face->root.stream, face->root.memory, 781 (PSAux_Service)face->psaux ); 782 if ( error ) 783 goto Exit; 784 785 error = cid_parse_dict( face, &loader, 786 parser->postscript, 787 parser->postscript_len ); 788 if ( error ) 789 goto Exit; 790 791 if ( face_index < 0 ) 792 goto Exit; 793 794 if ( FT_NEW( face->cid_stream ) ) 795 goto Exit; 796 797 if ( parser->binary_length ) 798 { 799 if ( parser->binary_length > 800 face->root.stream->size - parser->data_offset ) 801 { 802 FT_TRACE0(( "cid_face_open: adjusting length of binary data\n" )); 803 FT_TRACE0(( " (from %lu to %lu bytes)\n", 804 parser->binary_length, 805 face->root.stream->size - parser->data_offset )); 806 parser->binary_length = face->root.stream->size - 807 parser->data_offset; 808 } 809 810 /* we must convert the data section from hexadecimal to binary */ 811 if ( FT_QALLOC( face->binary_data, parser->binary_length ) || 812 FT_SET_ERROR( cid_hex_to_binary( face->binary_data, 813 parser->binary_length, 814 parser->data_offset, 815 face, 816 &binary_length ) ) ) 817 goto Exit; 818 819 FT_Stream_OpenMemory( face->cid_stream, 820 face->binary_data, binary_length ); 821 cid->data_offset = 0; 822 } 823 else 824 { 825 *face->cid_stream = *face->root.stream; 826 cid->data_offset = loader.parser.data_offset; 827 } 828 829 /* sanity tests */ 830 831 if ( cid->gd_bytes == 0 ) 832 { 833 FT_ERROR(( "cid_face_open:" 834 " Invalid `GDBytes' value\n" )); 835 error = FT_THROW( Invalid_File_Format ); 836 goto Exit; 837 } 838 839 /* allow at most 32bit offsets */ 840 if ( cid->fd_bytes > 4 || cid->gd_bytes > 4 ) 841 { 842 FT_ERROR(( "cid_face_open:" 843 " Values of `FDBytes' or `GDBytes' larger than 4\n" )); 844 FT_ERROR(( " " 845 " are not supported\n" )); 846 error = FT_THROW( Invalid_File_Format ); 847 goto Exit; 848 } 849 850 binary_length = face->cid_stream->size - cid->data_offset; 851 852 if ( cid->cidmap_offset > binary_length ) 853 { 854 FT_ERROR(( "cid_face_open: Invalid `CIDMapOffset' value\n" )); 855 error = FT_THROW( Invalid_File_Format ); 856 goto Exit; 857 } 858 859 /* the initial pre-check prevents the multiplication overflow */ 860 if ( cid->cid_count > FT_ULONG_MAX / 8 || 861 cid->cid_count * ( cid->fd_bytes + cid->gd_bytes ) > 862 binary_length - cid->cidmap_offset ) 863 { 864 FT_ERROR(( "cid_face_open: Invalid `CIDCount' value\n" )); 865 error = FT_THROW( Invalid_File_Format ); 866 goto Exit; 867 } 868 869 870 for ( n = 0; n < cid->num_dicts; n++ ) 871 { 872 CID_FaceDict dict = cid->font_dicts + n; 873 874 875 /* the upper limits are ad-hoc values */ 876 if ( dict->private_dict.blue_shift > 1000 || 877 dict->private_dict.blue_shift < 0 ) 878 { 879 FT_TRACE2(( "cid_face_open:" 880 " setting unlikely BlueShift value %d to default (7)\n", 881 dict->private_dict.blue_shift )); 882 dict->private_dict.blue_shift = 7; 883 } 884 885 if ( dict->private_dict.blue_fuzz > 1000 || 886 dict->private_dict.blue_fuzz < 0 ) 887 { 888 FT_TRACE2(( "cid_face_open:" 889 " setting unlikely BlueFuzz value %d to default (1)\n", 890 dict->private_dict.blue_fuzz )); 891 dict->private_dict.blue_fuzz = 1; 892 } 893 894 if ( dict->num_subrs && dict->sd_bytes == 0 ) 895 { 896 FT_ERROR(( "cid_face_open: Invalid `SDBytes' value\n" )); 897 error = FT_THROW( Invalid_File_Format ); 898 goto Exit; 899 } 900 901 if ( dict->sd_bytes > 4 ) 902 { 903 FT_ERROR(( "cid_face_open:" 904 " Values of `SDBytes' larger than 4" 905 " are not supported\n" )); 906 error = FT_THROW( Invalid_File_Format ); 907 goto Exit; 908 } 909 910 if ( dict->subrmap_offset > binary_length ) 911 { 912 FT_ERROR(( "cid_face_open: Invalid `SubrMapOffset' value\n" )); 913 error = FT_THROW( Invalid_File_Format ); 914 goto Exit; 915 } 916 917 /* the initial pre-check prevents the multiplication overflow */ 918 if ( dict->num_subrs > FT_UINT_MAX / 4 || 919 dict->num_subrs * dict->sd_bytes > 920 binary_length - dict->subrmap_offset ) 921 { 922 FT_ERROR(( "cid_face_open: Invalid `SubrCount' value\n" )); 923 error = FT_THROW( Invalid_File_Format ); 924 goto Exit; 925 } 926 } 927 928 /* we can now safely proceed */ 929 error = cid_read_subrs( face ); 930 931 Exit: 932 cid_done_loader( &loader ); 933 return error; 934 } 935 936 937 /* END */