1 /**************************************************************************** 2 * 3 * cidload.c 4 * 5 * CID-keyed Type1 font loader (body). 6 * 7 * Copyright 1996-2018 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 FT_INTERNAL_DEBUG_H 21 #include FT_CONFIG_CONFIG_H 22 #include FT_MULTIPLE_MASTERS_H 23 #include FT_INTERNAL_TYPE1_TYPES_H 24 #include FT_INTERNAL_POSTSCRIPT_AUX_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 trace_cidload 39 40 41 /* read a single offset */ 42 FT_LOCAL_DEF( FT_ULong ) cid_get_offset(FT_Byte ** start,FT_Byte offsize)43 cid_get_offset( FT_Byte* *start, 44 FT_Byte 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 cid_load_keyword(CID_Face face,CID_Loader * loader,const T1_Field keyword)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 < 0 || 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( FT_Error ) cid_parse_font_matrix(CID_Face face,CID_Parser * parser)158 cid_parse_font_matrix( CID_Face face, 159 CID_Parser* parser ) 160 { 161 CID_FaceDict dict; 162 FT_Face root = (FT_Face)&face->root; 163 FT_Fixed temp[6]; 164 FT_Fixed temp_scale; 165 166 167 if ( parser->num_dict >= 0 && parser->num_dict < face->cid.num_dicts ) 168 { 169 FT_Matrix* matrix; 170 FT_Vector* offset; 171 FT_Int result; 172 173 174 dict = face->cid.font_dicts + parser->num_dict; 175 matrix = &dict->font_matrix; 176 offset = &dict->font_offset; 177 178 /* input is scaled by 1000 to accommodate default FontMatrix */ 179 result = cid_parser_to_fixed_array( parser, 6, temp, 3 ); 180 181 if ( result < 6 ) 182 return FT_THROW( Invalid_File_Format ); 183 184 FT_TRACE4(( " [%f %f %f %f %f %f]\n", 185 (double)temp[0] / 65536 / 1000, 186 (double)temp[1] / 65536 / 1000, 187 (double)temp[2] / 65536 / 1000, 188 (double)temp[3] / 65536 / 1000, 189 (double)temp[4] / 65536 / 1000, 190 (double)temp[5] / 65536 / 1000 )); 191 192 temp_scale = FT_ABS( temp[3] ); 193 194 if ( temp_scale == 0 ) 195 { 196 FT_ERROR(( "cid_parse_font_matrix: invalid font matrix\n" )); 197 return FT_THROW( Invalid_File_Format ); 198 } 199 200 /* atypical case */ 201 if ( temp_scale != 0x10000L ) 202 { 203 /* set units per EM based on FontMatrix values */ 204 root->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale ); 205 206 temp[0] = FT_DivFix( temp[0], temp_scale ); 207 temp[1] = FT_DivFix( temp[1], temp_scale ); 208 temp[2] = FT_DivFix( temp[2], temp_scale ); 209 temp[4] = FT_DivFix( temp[4], temp_scale ); 210 temp[5] = FT_DivFix( temp[5], temp_scale ); 211 temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L; 212 } 213 214 matrix->xx = temp[0]; 215 matrix->yx = temp[1]; 216 matrix->xy = temp[2]; 217 matrix->yy = temp[3]; 218 219 if ( !FT_Matrix_Check( matrix ) ) 220 { 221 FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" )); 222 parser->root.error = FT_THROW( Invalid_File_Format ); 223 return FT_THROW( Invalid_File_Format ); 224 } 225 226 /* note that the font offsets are expressed in integer font units */ 227 offset->x = temp[4] >> 16; 228 offset->y = temp[5] >> 16; 229 } 230 231 return FT_Err_Ok; 232 } 233 234 235 FT_CALLBACK_DEF( FT_Error ) parse_fd_array(CID_Face face,CID_Parser * parser)236 parse_fd_array( CID_Face face, 237 CID_Parser* parser ) 238 { 239 CID_FaceInfo cid = &face->cid; 240 FT_Memory memory = face->root.memory; 241 FT_Stream stream = parser->stream; 242 FT_Error error = FT_Err_Ok; 243 FT_Long num_dicts; 244 245 246 num_dicts = cid_parser_to_int( parser ); 247 if ( num_dicts < 0 ) 248 { 249 FT_ERROR(( "parse_fd_array: invalid number of dictionaries\n" )); 250 error = FT_THROW( Invalid_File_Format ); 251 goto Exit; 252 } 253 254 FT_TRACE4(( " %d\n", num_dicts )); 255 256 /* 257 * A single entry in the FDArray must (at least) contain the following 258 * structure elements. 259 * 260 * %ADOBeginFontDict 18 261 * X dict begin 13 262 * /FontMatrix [X X X X] 22 263 * /Private X dict begin 22 264 * end 4 265 * end 4 266 * %ADOEndFontDict 16 267 * 268 * This needs 18+13+22+22+4+4+16=99 bytes or more. Normally, you also 269 * need a `dup X' at the very beginning and a `put' at the end, so a 270 * rough guess using 100 bytes as the minimum is justified. 271 */ 272 if ( (FT_ULong)num_dicts > stream->size / 100 ) 273 { 274 FT_TRACE0(( "parse_fd_array: adjusting FDArray size" 275 " (from %d to %d)\n", 276 num_dicts, 277 stream->size / 100 )); 278 num_dicts = (FT_Long)( stream->size / 100 ); 279 } 280 281 if ( !cid->font_dicts ) 282 { 283 FT_Int n; 284 285 286 if ( FT_NEW_ARRAY( cid->font_dicts, num_dicts ) ) 287 goto Exit; 288 289 cid->num_dicts = num_dicts; 290 291 /* set some default values (the same as for Type 1 fonts) */ 292 for ( n = 0; n < cid->num_dicts; n++ ) 293 { 294 CID_FaceDict dict = cid->font_dicts + n; 295 296 297 dict->private_dict.blue_shift = 7; 298 dict->private_dict.blue_fuzz = 1; 299 dict->private_dict.lenIV = 4; 300 dict->private_dict.expansion_factor = (FT_Fixed)( 0.06 * 0x10000L ); 301 dict->private_dict.blue_scale = (FT_Fixed)( 302 0.039625 * 0x10000L * 1000 ); 303 } 304 } 305 306 Exit: 307 return error; 308 } 309 310 311 /* By mistake, `expansion_factor' appears both in PS_PrivateRec */ 312 /* and CID_FaceDictRec (both are public header files and can't */ 313 /* changed). We simply copy the value. */ 314 315 FT_CALLBACK_DEF( FT_Error ) parse_expansion_factor(CID_Face face,CID_Parser * parser)316 parse_expansion_factor( CID_Face face, 317 CID_Parser* parser ) 318 { 319 CID_FaceDict dict; 320 321 322 if ( parser->num_dict >= 0 && parser->num_dict < face->cid.num_dicts ) 323 { 324 dict = face->cid.font_dicts + parser->num_dict; 325 326 dict->expansion_factor = cid_parser_to_fixed( parser, 0 ); 327 dict->private_dict.expansion_factor = dict->expansion_factor; 328 329 FT_TRACE4(( "%d\n", dict->expansion_factor )); 330 } 331 332 return FT_Err_Ok; 333 } 334 335 336 /* By mistake, `CID_FaceDictRec' doesn't contain a field for the */ 337 /* `FontName' keyword. FreeType doesn't need it, but it is nice */ 338 /* to catch it for producing better trace output. */ 339 340 FT_CALLBACK_DEF( FT_Error ) parse_font_name(CID_Face face,CID_Parser * parser)341 parse_font_name( CID_Face face, 342 CID_Parser* parser ) 343 { 344 #ifdef FT_DEBUG_LEVEL_TRACE 345 if ( parser->num_dict >= 0 && parser->num_dict < face->cid.num_dicts ) 346 { 347 T1_TokenRec token; 348 FT_UInt len; 349 350 351 cid_parser_to_token( parser, &token ); 352 353 len = (FT_UInt)( token.limit - token.start ); 354 if ( len ) 355 FT_TRACE4(( " %.*s\n", len, token.start )); 356 else 357 FT_TRACE4(( " <no value>\n" )); 358 } 359 #else 360 FT_UNUSED( face ); 361 FT_UNUSED( parser ); 362 #endif 363 364 return FT_Err_Ok; 365 } 366 367 368 static 369 const T1_FieldRec cid_field_records[] = 370 { 371 372 #include "cidtoken.h" 373 374 T1_FIELD_CALLBACK( "FDArray", parse_fd_array, 0 ) 375 T1_FIELD_CALLBACK( "FontMatrix", cid_parse_font_matrix, 0 ) 376 T1_FIELD_CALLBACK( "ExpansionFactor", parse_expansion_factor, 0 ) 377 T1_FIELD_CALLBACK( "FontName", parse_font_name, 0 ) 378 379 { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } 380 }; 381 382 383 static FT_Error cid_parse_dict(CID_Face face,CID_Loader * loader,FT_Byte * base,FT_ULong size)384 cid_parse_dict( CID_Face face, 385 CID_Loader* loader, 386 FT_Byte* base, 387 FT_ULong size ) 388 { 389 CID_Parser* parser = &loader->parser; 390 391 392 parser->root.cursor = base; 393 parser->root.limit = base + size; 394 parser->root.error = FT_Err_Ok; 395 396 { 397 FT_Byte* cur = base; 398 FT_Byte* limit = cur + size; 399 400 401 for (;;) 402 { 403 FT_Byte* newlimit; 404 405 406 parser->root.cursor = cur; 407 cid_parser_skip_spaces( parser ); 408 409 if ( parser->root.cursor >= limit ) 410 newlimit = limit - 1 - 17; 411 else 412 newlimit = parser->root.cursor - 17; 413 414 /* look for `%ADOBeginFontDict' */ 415 for ( ; cur < newlimit; cur++ ) 416 { 417 if ( *cur == '%' && 418 ft_strncmp( (char*)cur, "%ADOBeginFontDict", 17 ) == 0 ) 419 { 420 /* if /FDArray was found, then cid->num_dicts is > 0, and */ 421 /* we can start increasing parser->num_dict */ 422 if ( face->cid.num_dicts > 0 ) 423 { 424 parser->num_dict++; 425 426 #ifdef FT_DEBUG_LEVEL_TRACE 427 FT_TRACE4(( " FontDict %d", parser->num_dict )); 428 if ( parser->num_dict > face->cid.num_dicts ) 429 FT_TRACE4(( " (ignored)" )); 430 FT_TRACE4(( "\n" )); 431 #endif 432 } 433 } 434 } 435 436 cur = parser->root.cursor; 437 /* no error can occur in cid_parser_skip_spaces */ 438 if ( cur >= limit ) 439 break; 440 441 cid_parser_skip_PS_token( parser ); 442 if ( parser->root.cursor >= limit || parser->root.error ) 443 break; 444 445 /* look for immediates */ 446 if ( *cur == '/' && cur + 2 < limit ) 447 { 448 FT_UInt len; 449 450 451 cur++; 452 len = (FT_UInt)( parser->root.cursor - cur ); 453 454 if ( len > 0 && len < 22 ) 455 { 456 /* now compare the immediate name to the keyword table */ 457 T1_Field keyword = (T1_Field)cid_field_records; 458 459 460 for (;;) 461 { 462 FT_Byte* name; 463 464 465 name = (FT_Byte*)keyword->ident; 466 if ( !name ) 467 break; 468 469 if ( cur[0] == name[0] && 470 len == ft_strlen( (const char*)name ) ) 471 { 472 FT_UInt n; 473 474 475 for ( n = 1; n < len; n++ ) 476 if ( cur[n] != name[n] ) 477 break; 478 479 if ( n >= len ) 480 { 481 /* we found it - run the parsing callback */ 482 parser->root.error = cid_load_keyword( face, 483 loader, 484 keyword ); 485 if ( parser->root.error ) 486 return parser->root.error; 487 break; 488 } 489 } 490 keyword++; 491 } 492 } 493 } 494 495 cur = parser->root.cursor; 496 } 497 498 if ( !face->cid.num_dicts ) 499 { 500 FT_ERROR(( "cid_parse_dict: No font dictionary found\n" )); 501 return FT_THROW( Invalid_File_Format ); 502 } 503 } 504 505 return parser->root.error; 506 } 507 508 509 /* read the subrmap and the subrs of each font dict */ 510 static FT_Error cid_read_subrs(CID_Face face)511 cid_read_subrs( CID_Face face ) 512 { 513 CID_FaceInfo cid = &face->cid; 514 FT_Memory memory = face->root.memory; 515 FT_Stream stream = face->cid_stream; 516 FT_Error error; 517 FT_Int n; 518 CID_Subrs subr; 519 FT_UInt max_offsets = 0; 520 FT_ULong* offsets = NULL; 521 PSAux_Service psaux = (PSAux_Service)face->psaux; 522 523 524 if ( FT_NEW_ARRAY( face->subrs, cid->num_dicts ) ) 525 goto Exit; 526 527 subr = face->subrs; 528 for ( n = 0; n < cid->num_dicts; n++, subr++ ) 529 { 530 CID_FaceDict dict = cid->font_dicts + n; 531 FT_Int lenIV = dict->private_dict.lenIV; 532 FT_UInt count, num_subrs = dict->num_subrs; 533 FT_ULong data_len; 534 FT_Byte* p; 535 536 537 if ( !num_subrs ) 538 continue; 539 540 /* reallocate offsets array if needed */ 541 if ( num_subrs + 1 > max_offsets ) 542 { 543 FT_UInt new_max = FT_PAD_CEIL( num_subrs + 1, 4 ); 544 545 546 if ( new_max <= max_offsets ) 547 { 548 error = FT_THROW( Syntax_Error ); 549 goto Fail; 550 } 551 552 if ( FT_RENEW_ARRAY( offsets, max_offsets, new_max ) ) 553 goto Fail; 554 555 max_offsets = new_max; 556 } 557 558 /* read the subrmap's offsets */ 559 if ( FT_STREAM_SEEK( cid->data_offset + dict->subrmap_offset ) || 560 FT_FRAME_ENTER( ( num_subrs + 1 ) * (FT_UInt)dict->sd_bytes ) ) 561 goto Fail; 562 563 p = (FT_Byte*)stream->cursor; 564 for ( count = 0; count <= num_subrs; count++ ) 565 offsets[count] = cid_get_offset( &p, (FT_Byte)dict->sd_bytes ); 566 567 FT_FRAME_EXIT(); 568 569 /* offsets must be ordered */ 570 for ( count = 1; count <= num_subrs; count++ ) 571 if ( offsets[count - 1] > offsets[count] ) 572 { 573 FT_ERROR(( "cid_read_subrs: offsets are not ordered\n" )); 574 error = FT_THROW( Invalid_File_Format ); 575 goto Fail; 576 } 577 578 if ( offsets[num_subrs] > stream->size - cid->data_offset ) 579 { 580 FT_ERROR(( "cid_read_subrs: too large `subrs' offsets\n" )); 581 error = FT_THROW( Invalid_File_Format ); 582 goto Fail; 583 } 584 585 /* now, compute the size of subrs charstrings, */ 586 /* allocate, and read them */ 587 data_len = offsets[num_subrs] - offsets[0]; 588 589 if ( FT_NEW_ARRAY( subr->code, num_subrs + 1 ) || 590 FT_ALLOC( subr->code[0], data_len ) ) 591 goto Fail; 592 593 if ( FT_STREAM_SEEK( cid->data_offset + offsets[0] ) || 594 FT_STREAM_READ( subr->code[0], data_len ) ) 595 goto Fail; 596 597 /* set up pointers */ 598 for ( count = 1; count <= num_subrs; count++ ) 599 { 600 FT_ULong len; 601 602 603 len = offsets[count] - offsets[count - 1]; 604 subr->code[count] = subr->code[count - 1] + len; 605 } 606 607 /* decrypt subroutines, but only if lenIV >= 0 */ 608 if ( lenIV >= 0 ) 609 { 610 for ( count = 0; count < num_subrs; count++ ) 611 { 612 FT_ULong len; 613 614 615 len = offsets[count + 1] - offsets[count]; 616 psaux->t1_decrypt( subr->code[count], len, 4330 ); 617 } 618 } 619 620 subr->num_subrs = (FT_Int)num_subrs; 621 } 622 623 Exit: 624 FT_FREE( offsets ); 625 return error; 626 627 Fail: 628 if ( face->subrs ) 629 { 630 for ( n = 0; n < cid->num_dicts; n++ ) 631 { 632 if ( face->subrs[n].code ) 633 FT_FREE( face->subrs[n].code[0] ); 634 635 FT_FREE( face->subrs[n].code ); 636 } 637 FT_FREE( face->subrs ); 638 } 639 goto Exit; 640 } 641 642 643 static void cid_init_loader(CID_Loader * loader,CID_Face face)644 cid_init_loader( CID_Loader* loader, 645 CID_Face face ) 646 { 647 FT_UNUSED( face ); 648 649 FT_ZERO( loader ); 650 } 651 652 653 static void cid_done_loader(CID_Loader * loader)654 cid_done_loader( CID_Loader* loader ) 655 { 656 CID_Parser* parser = &loader->parser; 657 658 659 /* finalize parser */ 660 cid_parser_done( parser ); 661 } 662 663 664 static FT_Error cid_hex_to_binary(FT_Byte * data,FT_ULong data_len,FT_ULong offset,CID_Face face)665 cid_hex_to_binary( FT_Byte* data, 666 FT_ULong data_len, 667 FT_ULong offset, 668 CID_Face face ) 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, *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 d = data; 685 dlimit = d + data_len; 686 p = buffer; 687 plimit = p; 688 689 upper_nibble = 1; 690 done = 0; 691 692 while ( d < dlimit ) 693 { 694 if ( p >= plimit ) 695 { 696 FT_ULong oldpos = FT_STREAM_POS(); 697 FT_ULong size = stream->size - oldpos; 698 699 700 if ( size == 0 ) 701 { 702 error = FT_THROW( Syntax_Error ); 703 goto Exit; 704 } 705 706 if ( FT_STREAM_READ( buffer, 256 > size ? size : 256 ) ) 707 goto Exit; 708 p = buffer; 709 plimit = p + FT_STREAM_POS() - oldpos; 710 } 711 712 if ( ft_isdigit( *p ) ) 713 val = (FT_Byte)( *p - '0' ); 714 else if ( *p >= 'a' && *p <= 'f' ) 715 val = (FT_Byte)( *p - 'a' ); 716 else if ( *p >= 'A' && *p <= 'F' ) 717 val = (FT_Byte)( *p - 'A' + 10 ); 718 else if ( *p == ' ' || 719 *p == '\t' || 720 *p == '\r' || 721 *p == '\n' || 722 *p == '\f' || 723 *p == '\0' ) 724 { 725 p++; 726 continue; 727 } 728 else if ( *p == '>' ) 729 { 730 val = 0; 731 done = 1; 732 } 733 else 734 { 735 error = FT_THROW( Syntax_Error ); 736 goto Exit; 737 } 738 739 if ( upper_nibble ) 740 *d = (FT_Byte)( val << 4 ); 741 else 742 { 743 *d = (FT_Byte)( *d + val ); 744 d++; 745 } 746 747 upper_nibble = (FT_Byte)( 1 - upper_nibble ); 748 749 if ( done ) 750 break; 751 752 p++; 753 } 754 755 error = FT_Err_Ok; 756 757 Exit: 758 return error; 759 } 760 761 762 FT_LOCAL_DEF( FT_Error ) cid_face_open(CID_Face face,FT_Int face_index)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_Int n; 771 772 CID_FaceInfo cid = &face->cid; 773 774 FT_ULong binary_length; 775 FT_ULong entry_len; 776 777 778 cid_init_loader( &loader, face ); 779 780 parser = &loader.parser; 781 error = cid_parser_new( parser, face->root.stream, face->root.memory, 782 (PSAux_Service)face->psaux ); 783 if ( error ) 784 goto Exit; 785 786 error = cid_parse_dict( face, &loader, 787 parser->postscript, 788 parser->postscript_len ); 789 if ( error ) 790 goto Exit; 791 792 if ( face_index < 0 ) 793 goto Exit; 794 795 if ( FT_NEW( face->cid_stream ) ) 796 goto Exit; 797 798 if ( parser->binary_length ) 799 { 800 if ( parser->binary_length > 801 face->root.stream->size - parser->data_offset ) 802 { 803 FT_TRACE0(( "cid_face_open: adjusting length of binary data\n" 804 " (from %d to %d bytes)\n", 805 parser->binary_length, 806 face->root.stream->size - parser->data_offset )); 807 parser->binary_length = face->root.stream->size - 808 parser->data_offset; 809 } 810 811 /* we must convert the data section from hexadecimal to binary */ 812 if ( FT_ALLOC( face->binary_data, parser->binary_length ) || 813 FT_SET_ERROR( cid_hex_to_binary( face->binary_data, 814 parser->binary_length, 815 parser->data_offset, 816 face ) ) ) 817 goto Exit; 818 819 FT_Stream_OpenMemory( face->cid_stream, 820 face->binary_data, parser->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->fd_bytes < 0 || cid->gd_bytes < 1 ) 832 { 833 FT_ERROR(( "cid_face_open:" 834 " Invalid `FDBytes' or `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 " " 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 entry_len = (FT_ULong)( cid->fd_bytes + cid->gd_bytes ); 852 853 for ( n = 0; n < cid->num_dicts; n++ ) 854 { 855 CID_FaceDict dict = cid->font_dicts + n; 856 857 858 /* the upper limits are ad-hoc values */ 859 if ( dict->private_dict.blue_shift > 1000 || 860 dict->private_dict.blue_shift < 0 ) 861 { 862 FT_TRACE2(( "cid_face_open:" 863 " setting unlikely BlueShift value %d to default (7)\n", 864 dict->private_dict.blue_shift )); 865 dict->private_dict.blue_shift = 7; 866 } 867 868 if ( dict->private_dict.blue_fuzz > 1000 || 869 dict->private_dict.blue_fuzz < 0 ) 870 { 871 FT_TRACE2(( "cid_face_open:" 872 " setting unlikely BlueFuzz value %d to default (1)\n", 873 dict->private_dict.blue_fuzz )); 874 dict->private_dict.blue_fuzz = 1; 875 } 876 877 if ( dict->sd_bytes < 0 || 878 ( dict->num_subrs && dict->sd_bytes < 1 ) ) 879 { 880 FT_ERROR(( "cid_face_open: Invalid `SDBytes' value\n" )); 881 error = FT_THROW( Invalid_File_Format ); 882 goto Exit; 883 } 884 885 if ( dict->sd_bytes > 4 ) 886 { 887 FT_ERROR(( "cid_face_open:" 888 " Values of `SDBytes' larger than 4" 889 " are not supported\n" )); 890 error = FT_THROW( Invalid_File_Format ); 891 goto Exit; 892 } 893 894 if ( dict->subrmap_offset > binary_length ) 895 { 896 FT_ERROR(( "cid_face_open: Invalid `SubrMapOffset' value\n" )); 897 error = FT_THROW( Invalid_File_Format ); 898 goto Exit; 899 } 900 901 /* `num_subrs' is scanned as a signed integer */ 902 if ( (FT_Int)dict->num_subrs < 0 || 903 ( dict->sd_bytes && 904 dict->num_subrs > ( binary_length - dict->subrmap_offset ) / 905 (FT_UInt)dict->sd_bytes ) ) 906 { 907 FT_ERROR(( "cid_face_open: Invalid `SubrCount' value\n" )); 908 error = FT_THROW( Invalid_File_Format ); 909 goto Exit; 910 } 911 } 912 913 if ( cid->cidmap_offset > binary_length ) 914 { 915 FT_ERROR(( "cid_face_open: Invalid `CIDMapOffset' value\n" )); 916 error = FT_THROW( Invalid_File_Format ); 917 goto Exit; 918 } 919 920 if ( entry_len && 921 cid->cid_count > 922 ( binary_length - cid->cidmap_offset ) / entry_len ) 923 { 924 FT_ERROR(( "cid_face_open: Invalid `CIDCount' value\n" )); 925 error = FT_THROW( Invalid_File_Format ); 926 goto Exit; 927 } 928 929 /* we can now safely proceed */ 930 error = cid_read_subrs( face ); 931 932 Exit: 933 cid_done_loader( &loader ); 934 return error; 935 } 936 937 938 /* END */ 939