1 /***************************************************************************/ 2 /* */ 3 /* t42parse.c */ 4 /* */ 5 /* Type 42 font parser (body). */ 6 /* */ 7 /* Copyright 2002-2018 by */ 8 /* Roberto Alameda. */ 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 "t42parse.h" 20 #include "t42error.h" 21 #include FT_INTERNAL_DEBUG_H 22 #include FT_INTERNAL_STREAM_H 23 #include FT_INTERNAL_POSTSCRIPT_AUX_H 24 25 26 /*************************************************************************/ 27 /* */ 28 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 29 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 30 /* messages during execution. */ 31 /* */ 32 #undef FT_COMPONENT 33 #define FT_COMPONENT trace_t42 34 35 36 static void 37 t42_parse_font_matrix( T42_Face face, 38 T42_Loader loader ); 39 static void 40 t42_parse_encoding( T42_Face face, 41 T42_Loader loader ); 42 43 static void 44 t42_parse_charstrings( T42_Face face, 45 T42_Loader loader ); 46 47 static void 48 t42_parse_sfnts( T42_Face face, 49 T42_Loader loader ); 50 51 52 /* as Type42 fonts have no Private dict, */ 53 /* we set the last argument of T1_FIELD_XXX to 0 */ 54 static const 55 T1_FieldRec t42_keywords[] = 56 { 57 58 #undef FT_STRUCTURE 59 #define FT_STRUCTURE T1_FontInfo 60 #undef T1CODE 61 #define T1CODE T1_FIELD_LOCATION_FONT_INFO 62 63 T1_FIELD_STRING( "version", version, 0 ) 64 T1_FIELD_STRING( "Notice", notice, 0 ) 65 T1_FIELD_STRING( "FullName", full_name, 0 ) 66 T1_FIELD_STRING( "FamilyName", family_name, 0 ) 67 T1_FIELD_STRING( "Weight", weight, 0 ) 68 T1_FIELD_NUM ( "ItalicAngle", italic_angle, 0 ) 69 T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch, 0 ) 70 T1_FIELD_NUM ( "UnderlinePosition", underline_position, 0 ) 71 T1_FIELD_NUM ( "UnderlineThickness", underline_thickness, 0 ) 72 73 #undef FT_STRUCTURE 74 #define FT_STRUCTURE PS_FontExtraRec 75 #undef T1CODE 76 #define T1CODE T1_FIELD_LOCATION_FONT_EXTRA 77 78 T1_FIELD_NUM ( "FSType", fs_type, 0 ) 79 80 #undef FT_STRUCTURE 81 #define FT_STRUCTURE T1_FontRec 82 #undef T1CODE 83 #define T1CODE T1_FIELD_LOCATION_FONT_DICT 84 85 T1_FIELD_KEY ( "FontName", font_name, 0 ) 86 T1_FIELD_NUM ( "PaintType", paint_type, 0 ) 87 T1_FIELD_NUM ( "FontType", font_type, 0 ) 88 T1_FIELD_FIXED( "StrokeWidth", stroke_width, 0 ) 89 90 #undef FT_STRUCTURE 91 #define FT_STRUCTURE FT_BBox 92 #undef T1CODE 93 #define T1CODE T1_FIELD_LOCATION_BBOX 94 95 T1_FIELD_BBOX("FontBBox", xMin, 0 ) 96 97 T1_FIELD_CALLBACK( "FontMatrix", t42_parse_font_matrix, 0 ) 98 T1_FIELD_CALLBACK( "Encoding", t42_parse_encoding, 0 ) 99 T1_FIELD_CALLBACK( "CharStrings", t42_parse_charstrings, 0 ) 100 T1_FIELD_CALLBACK( "sfnts", t42_parse_sfnts, 0 ) 101 102 { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } 103 }; 104 105 106 #define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l ) 107 #define T1_Release_Table( p ) \ 108 do \ 109 { \ 110 if ( (p)->funcs.release ) \ 111 (p)->funcs.release( p ); \ 112 } while ( 0 ) 113 114 #define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root ) 115 #define T1_Skip_PS_Token( p ) (p)->root.funcs.skip_PS_token( &(p)->root ) 116 117 #define T1_ToInt( p ) \ 118 (p)->root.funcs.to_int( &(p)->root ) 119 #define T1_ToBytes( p, b, m, n, d ) \ 120 (p)->root.funcs.to_bytes( &(p)->root, b, m, n, d ) 121 122 #define T1_ToFixedArray( p, m, f, t ) \ 123 (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t ) 124 #define T1_ToToken( p, t ) \ 125 (p)->root.funcs.to_token( &(p)->root, t ) 126 127 #define T1_Load_Field( p, f, o, m, pf ) \ 128 (p)->root.funcs.load_field( &(p)->root, f, o, m, pf ) 129 #define T1_Load_Field_Table( p, f, o, m, pf ) \ 130 (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf ) 131 132 133 /********************* Parsing Functions ******************/ 134 135 FT_LOCAL_DEF( FT_Error ) 136 t42_parser_init( T42_Parser parser, 137 FT_Stream stream, 138 FT_Memory memory, 139 PSAux_Service psaux ) 140 { 141 FT_Error error = FT_Err_Ok; 142 FT_Long size; 143 144 145 psaux->ps_parser_funcs->init( &parser->root, NULL, NULL, memory ); 146 147 parser->stream = stream; 148 parser->base_len = 0; 149 parser->base_dict = NULL; 150 parser->in_memory = 0; 151 152 /*******************************************************************/ 153 /* */ 154 /* Here a short summary of what is going on: */ 155 /* */ 156 /* When creating a new Type 42 parser, we try to locate and load */ 157 /* the base dictionary, loading the whole font into memory. */ 158 /* */ 159 /* When `loading' the base dictionary, we only set up pointers */ 160 /* in the case of a memory-based stream. Otherwise, we allocate */ 161 /* and load the base dictionary in it. */ 162 /* */ 163 /* parser->in_memory is set if we have a memory stream. */ 164 /* */ 165 166 if ( FT_STREAM_SEEK( 0L ) || 167 FT_FRAME_ENTER( 17 ) ) 168 goto Exit; 169 170 if ( ft_memcmp( stream->cursor, "%!PS-TrueTypeFont", 17 ) != 0 ) 171 { 172 FT_TRACE2(( " not a Type42 font\n" )); 173 error = FT_THROW( Unknown_File_Format ); 174 } 175 176 FT_FRAME_EXIT(); 177 178 if ( error || FT_STREAM_SEEK( 0 ) ) 179 goto Exit; 180 181 size = (FT_Long)stream->size; 182 183 /* now, try to load `size' bytes of the `base' dictionary we */ 184 /* found previously */ 185 186 /* if it is a memory-based resource, set up pointers */ 187 if ( !stream->read ) 188 { 189 parser->base_dict = (FT_Byte*)stream->base + stream->pos; 190 parser->base_len = size; 191 parser->in_memory = 1; 192 193 /* check that the `size' field is valid */ 194 if ( FT_STREAM_SKIP( size ) ) 195 goto Exit; 196 } 197 else 198 { 199 /* read segment in memory */ 200 if ( FT_ALLOC( parser->base_dict, size ) || 201 FT_STREAM_READ( parser->base_dict, size ) ) 202 goto Exit; 203 204 parser->base_len = size; 205 } 206 207 parser->root.base = parser->base_dict; 208 parser->root.cursor = parser->base_dict; 209 parser->root.limit = parser->root.cursor + parser->base_len; 210 211 Exit: 212 if ( error && !parser->in_memory ) 213 FT_FREE( parser->base_dict ); 214 215 return error; 216 } 217 218 219 FT_LOCAL_DEF( void ) 220 t42_parser_done( T42_Parser parser ) 221 { 222 FT_Memory memory = parser->root.memory; 223 224 225 /* free the base dictionary only when we have a disk stream */ 226 if ( !parser->in_memory ) 227 FT_FREE( parser->base_dict ); 228 229 parser->root.funcs.done( &parser->root ); 230 } 231 232 233 static int 234 t42_is_space( FT_Byte c ) 235 { 236 return ( c == ' ' || c == '\t' || 237 c == '\r' || c == '\n' || c == '\f' || 238 c == '\0' ); 239 } 240 241 242 static void 243 t42_parse_font_matrix( T42_Face face, 244 T42_Loader loader ) 245 { 246 T42_Parser parser = &loader->parser; 247 FT_Matrix* matrix = &face->type1.font_matrix; 248 FT_Vector* offset = &face->type1.font_offset; 249 FT_Fixed temp[6]; 250 FT_Fixed temp_scale; 251 FT_Int result; 252 253 254 result = T1_ToFixedArray( parser, 6, temp, 0 ); 255 256 if ( result < 6 ) 257 { 258 parser->root.error = FT_THROW( Invalid_File_Format ); 259 return; 260 } 261 262 temp_scale = FT_ABS( temp[3] ); 263 264 if ( temp_scale == 0 ) 265 { 266 FT_ERROR(( "t42_parse_font_matrix: invalid font matrix\n" )); 267 parser->root.error = FT_THROW( Invalid_File_Format ); 268 return; 269 } 270 271 /* atypical case */ 272 if ( temp_scale != 0x10000L ) 273 { 274 temp[0] = FT_DivFix( temp[0], temp_scale ); 275 temp[1] = FT_DivFix( temp[1], temp_scale ); 276 temp[2] = FT_DivFix( temp[2], temp_scale ); 277 temp[4] = FT_DivFix( temp[4], temp_scale ); 278 temp[5] = FT_DivFix( temp[5], temp_scale ); 279 temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L; 280 } 281 282 matrix->xx = temp[0]; 283 matrix->yx = temp[1]; 284 matrix->xy = temp[2]; 285 matrix->yy = temp[3]; 286 287 /* note that the offsets must be expressed in integer font units */ 288 offset->x = temp[4] >> 16; 289 offset->y = temp[5] >> 16; 290 } 291 292 293 static void 294 t42_parse_encoding( T42_Face face, 295 T42_Loader loader ) 296 { 297 T42_Parser parser = &loader->parser; 298 FT_Byte* cur; 299 FT_Byte* limit = parser->root.limit; 300 301 PSAux_Service psaux = (PSAux_Service)face->psaux; 302 303 304 T1_Skip_Spaces( parser ); 305 cur = parser->root.cursor; 306 if ( cur >= limit ) 307 { 308 FT_ERROR(( "t42_parse_encoding: out of bounds\n" )); 309 parser->root.error = FT_THROW( Invalid_File_Format ); 310 return; 311 } 312 313 /* if we have a number or `[', the encoding is an array, */ 314 /* and we must load it now */ 315 if ( ft_isdigit( *cur ) || *cur == '[' ) 316 { 317 T1_Encoding encode = &face->type1.encoding; 318 FT_Int count, n; 319 PS_Table char_table = &loader->encoding_table; 320 FT_Memory memory = parser->root.memory; 321 FT_Error error; 322 FT_Bool only_immediates = 0; 323 324 325 /* read the number of entries in the encoding; should be 256 */ 326 if ( *cur == '[' ) 327 { 328 count = 256; 329 only_immediates = 1; 330 parser->root.cursor++; 331 } 332 else 333 count = (FT_Int)T1_ToInt( parser ); 334 335 /* only composite fonts (which we don't support) */ 336 /* can have larger values */ 337 if ( count > 256 ) 338 { 339 FT_ERROR(( "t42_parse_encoding: invalid encoding array size\n" )); 340 parser->root.error = FT_THROW( Invalid_File_Format ); 341 return; 342 } 343 344 T1_Skip_Spaces( parser ); 345 if ( parser->root.cursor >= limit ) 346 return; 347 348 /* PostScript happily allows overwriting of encoding arrays */ 349 if ( encode->char_index ) 350 { 351 FT_FREE( encode->char_index ); 352 FT_FREE( encode->char_name ); 353 T1_Release_Table( char_table ); 354 } 355 356 /* we use a T1_Table to store our charnames */ 357 loader->num_chars = encode->num_chars = count; 358 if ( FT_NEW_ARRAY( encode->char_index, count ) || 359 FT_NEW_ARRAY( encode->char_name, count ) || 360 FT_SET_ERROR( psaux->ps_table_funcs->init( 361 char_table, count, memory ) ) ) 362 { 363 parser->root.error = error; 364 return; 365 } 366 367 /* We need to `zero' out encoding_table.elements */ 368 for ( n = 0; n < count; n++ ) 369 { 370 char* notdef = (char *)".notdef"; 371 372 373 (void)T1_Add_Table( char_table, n, notdef, 8 ); 374 } 375 376 /* Now we need to read records of the form */ 377 /* */ 378 /* ... charcode /charname ... */ 379 /* */ 380 /* for each entry in our table. */ 381 /* */ 382 /* We simply look for a number followed by an immediate */ 383 /* name. Note that this ignores correctly the sequence */ 384 /* that is often seen in type42 fonts: */ 385 /* */ 386 /* 0 1 255 { 1 index exch /.notdef put } for dup */ 387 /* */ 388 /* used to clean the encoding array before anything else. */ 389 /* */ 390 /* Alternatively, if the array is directly given as */ 391 /* */ 392 /* /Encoding [ ... ] */ 393 /* */ 394 /* we only read immediates. */ 395 396 n = 0; 397 T1_Skip_Spaces( parser ); 398 399 while ( parser->root.cursor < limit ) 400 { 401 cur = parser->root.cursor; 402 403 /* we stop when we encounter `def' or `]' */ 404 if ( *cur == 'd' && cur + 3 < limit ) 405 { 406 if ( cur[1] == 'e' && 407 cur[2] == 'f' && 408 t42_is_space( cur[3] ) ) 409 { 410 FT_TRACE6(( "encoding end\n" )); 411 cur += 3; 412 break; 413 } 414 } 415 if ( *cur == ']' ) 416 { 417 FT_TRACE6(( "encoding end\n" )); 418 cur++; 419 break; 420 } 421 422 /* check whether we have found an entry */ 423 if ( ft_isdigit( *cur ) || only_immediates ) 424 { 425 FT_Int charcode; 426 427 428 if ( only_immediates ) 429 charcode = n; 430 else 431 { 432 charcode = (FT_Int)T1_ToInt( parser ); 433 T1_Skip_Spaces( parser ); 434 435 /* protect against invalid charcode */ 436 if ( cur == parser->root.cursor ) 437 { 438 parser->root.error = FT_THROW( Unknown_File_Format ); 439 return; 440 } 441 } 442 443 cur = parser->root.cursor; 444 445 if ( cur + 2 < limit && *cur == '/' && n < count ) 446 { 447 FT_UInt len; 448 449 450 cur++; 451 452 parser->root.cursor = cur; 453 T1_Skip_PS_Token( parser ); 454 if ( parser->root.cursor >= limit ) 455 return; 456 if ( parser->root.error ) 457 return; 458 459 len = (FT_UInt)( parser->root.cursor - cur ); 460 461 parser->root.error = T1_Add_Table( char_table, charcode, 462 cur, len + 1 ); 463 if ( parser->root.error ) 464 return; 465 char_table->elements[charcode][len] = '\0'; 466 467 n++; 468 } 469 else if ( only_immediates ) 470 { 471 /* Since the current position is not updated for */ 472 /* immediates-only mode we would get an infinite loop if */ 473 /* we don't do anything here. */ 474 /* */ 475 /* This encoding array is not valid according to the */ 476 /* type42 specification (it might be an encoding for a CID */ 477 /* type42 font, however), so we conclude that this font is */ 478 /* NOT a type42 font. */ 479 parser->root.error = FT_THROW( Unknown_File_Format ); 480 return; 481 } 482 } 483 else 484 { 485 T1_Skip_PS_Token( parser ); 486 if ( parser->root.error ) 487 return; 488 } 489 490 T1_Skip_Spaces( parser ); 491 } 492 493 face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; 494 parser->root.cursor = cur; 495 } 496 497 /* Otherwise, we should have either `StandardEncoding', */ 498 /* `ExpertEncoding', or `ISOLatin1Encoding' */ 499 else 500 { 501 if ( cur + 17 < limit && 502 ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) 503 face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; 504 505 else if ( cur + 15 < limit && 506 ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) 507 face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; 508 509 else if ( cur + 18 < limit && 510 ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) 511 face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; 512 513 else 514 parser->root.error = FT_ERR( Ignore ); 515 } 516 } 517 518 519 typedef enum T42_Load_Status_ 520 { 521 BEFORE_START, 522 BEFORE_TABLE_DIR, 523 OTHER_TABLES 524 525 } T42_Load_Status; 526 527 528 static void 529 t42_parse_sfnts( T42_Face face, 530 T42_Loader loader ) 531 { 532 T42_Parser parser = &loader->parser; 533 FT_Memory memory = parser->root.memory; 534 FT_Byte* cur; 535 FT_Byte* limit = parser->root.limit; 536 FT_Error error; 537 FT_Int num_tables = 0; 538 FT_Long count; 539 540 FT_ULong n, string_size, old_string_size, real_size; 541 FT_Byte* string_buf = NULL; 542 FT_Bool allocated = 0; 543 544 T42_Load_Status status; 545 546 547 /* The format is */ 548 /* */ 549 /* /sfnts [ <hexstring> <hexstring> ... ] def */ 550 /* */ 551 /* or */ 552 /* */ 553 /* /sfnts [ */ 554 /* <num_bin_bytes> RD <binary data> */ 555 /* <num_bin_bytes> RD <binary data> */ 556 /* ... */ 557 /* ] def */ 558 /* */ 559 /* with exactly one space after the `RD' token. */ 560 561 T1_Skip_Spaces( parser ); 562 563 if ( parser->root.cursor >= limit || *parser->root.cursor++ != '[' ) 564 { 565 FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector\n" )); 566 error = FT_THROW( Invalid_File_Format ); 567 goto Fail; 568 } 569 570 T1_Skip_Spaces( parser ); 571 status = BEFORE_START; 572 string_size = 0; 573 old_string_size = 0; 574 count = 0; 575 576 while ( parser->root.cursor < limit ) 577 { 578 FT_ULong size; 579 580 581 cur = parser->root.cursor; 582 583 if ( *cur == ']' ) 584 { 585 parser->root.cursor++; 586 goto Exit; 587 } 588 589 else if ( *cur == '<' ) 590 { 591 T1_Skip_PS_Token( parser ); 592 if ( parser->root.error ) 593 goto Exit; 594 595 /* don't include delimiters */ 596 string_size = (FT_ULong)( ( parser->root.cursor - cur - 2 + 1 ) / 2 ); 597 if ( !string_size ) 598 { 599 FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" )); 600 error = FT_THROW( Invalid_File_Format ); 601 goto Fail; 602 } 603 if ( FT_REALLOC( string_buf, old_string_size, string_size ) ) 604 goto Fail; 605 606 allocated = 1; 607 608 parser->root.cursor = cur; 609 (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 ); 610 old_string_size = string_size; 611 string_size = real_size; 612 } 613 614 else if ( ft_isdigit( *cur ) ) 615 { 616 FT_Long tmp; 617 618 619 if ( allocated ) 620 { 621 FT_ERROR(( "t42_parse_sfnts: " 622 "can't handle mixed binary and hex strings\n" )); 623 error = FT_THROW( Invalid_File_Format ); 624 goto Fail; 625 } 626 627 tmp = T1_ToInt( parser ); 628 if ( tmp < 0 ) 629 { 630 FT_ERROR(( "t42_parse_sfnts: invalid string size\n" )); 631 error = FT_THROW( Invalid_File_Format ); 632 goto Fail; 633 } 634 else 635 string_size = (FT_ULong)tmp; 636 637 T1_Skip_PS_Token( parser ); /* `RD' */ 638 if ( parser->root.error ) 639 return; 640 641 string_buf = parser->root.cursor + 1; /* one space after `RD' */ 642 643 if ( (FT_ULong)( limit - parser->root.cursor ) <= string_size ) 644 { 645 FT_ERROR(( "t42_parse_sfnts: too much binary data\n" )); 646 error = FT_THROW( Invalid_File_Format ); 647 goto Fail; 648 } 649 else 650 parser->root.cursor += string_size + 1; 651 } 652 653 if ( !string_buf ) 654 { 655 FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" )); 656 error = FT_THROW( Invalid_File_Format ); 657 goto Fail; 658 } 659 660 /* A string can have a trailing zero (odd) byte for padding. */ 661 /* Ignore it. */ 662 if ( ( string_size & 1 ) && string_buf[string_size - 1] == 0 ) 663 string_size--; 664 665 if ( !string_size ) 666 { 667 FT_ERROR(( "t42_parse_sfnts: invalid string\n" )); 668 error = FT_THROW( Invalid_File_Format ); 669 goto Fail; 670 } 671 672 /* The whole TTF is now loaded into `string_buf'. We are */ 673 /* checking its contents while copying it to `ttf_data'. */ 674 675 size = (FT_ULong)( limit - parser->root.cursor ); 676 677 for ( n = 0; n < string_size; n++ ) 678 { 679 switch ( status ) 680 { 681 case BEFORE_START: 682 /* load offset table, 12 bytes */ 683 if ( count < 12 ) 684 { 685 face->ttf_data[count++] = string_buf[n]; 686 continue; 687 } 688 else 689 { 690 num_tables = 16 * face->ttf_data[4] + face->ttf_data[5]; 691 status = BEFORE_TABLE_DIR; 692 face->ttf_size = 12 + 16 * num_tables; 693 694 if ( (FT_Long)size < face->ttf_size ) 695 { 696 FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" )); 697 error = FT_THROW( Invalid_File_Format ); 698 goto Fail; 699 } 700 701 if ( FT_REALLOC( face->ttf_data, 12, face->ttf_size ) ) 702 goto Fail; 703 } 704 /* fall through */ 705 706 case BEFORE_TABLE_DIR: 707 /* the offset table is read; read the table directory */ 708 if ( count < face->ttf_size ) 709 { 710 face->ttf_data[count++] = string_buf[n]; 711 continue; 712 } 713 else 714 { 715 int i; 716 FT_ULong len; 717 718 719 for ( i = 0; i < num_tables; i++ ) 720 { 721 FT_Byte* p = face->ttf_data + 12 + 16 * i + 12; 722 723 724 len = FT_PEEK_ULONG( p ); 725 if ( len > size || 726 face->ttf_size > (FT_Long)( size - len ) ) 727 { 728 FT_ERROR(( "t42_parse_sfnts:" 729 " invalid data in sfnts array\n" )); 730 error = FT_THROW( Invalid_File_Format ); 731 goto Fail; 732 } 733 734 /* Pad to a 4-byte boundary length */ 735 face->ttf_size += (FT_Long)( ( len + 3 ) & ~3U ); 736 } 737 738 status = OTHER_TABLES; 739 740 if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables, 741 face->ttf_size + 1 ) ) 742 goto Fail; 743 } 744 /* fall through */ 745 746 case OTHER_TABLES: 747 /* all other tables are just copied */ 748 if ( count >= face->ttf_size ) 749 { 750 FT_ERROR(( "t42_parse_sfnts: too much binary data\n" )); 751 error = FT_THROW( Invalid_File_Format ); 752 goto Fail; 753 } 754 face->ttf_data[count++] = string_buf[n]; 755 } 756 } 757 758 T1_Skip_Spaces( parser ); 759 } 760 761 /* if control reaches this point, the format was not valid */ 762 error = FT_THROW( Invalid_File_Format ); 763 764 Fail: 765 parser->root.error = error; 766 767 Exit: 768 if ( allocated ) 769 FT_FREE( string_buf ); 770 } 771 772 773 static void 774 t42_parse_charstrings( T42_Face face, 775 T42_Loader loader ) 776 { 777 T42_Parser parser = &loader->parser; 778 PS_Table code_table = &loader->charstrings; 779 PS_Table name_table = &loader->glyph_names; 780 PS_Table swap_table = &loader->swap_table; 781 FT_Memory memory = parser->root.memory; 782 FT_Error error; 783 784 PSAux_Service psaux = (PSAux_Service)face->psaux; 785 786 FT_Byte* cur; 787 FT_Byte* limit = parser->root.limit; 788 FT_Int n; 789 FT_Int notdef_index = 0; 790 FT_Byte notdef_found = 0; 791 792 793 T1_Skip_Spaces( parser ); 794 795 if ( parser->root.cursor >= limit ) 796 { 797 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); 798 error = FT_THROW( Invalid_File_Format ); 799 goto Fail; 800 } 801 802 if ( ft_isdigit( *parser->root.cursor ) ) 803 { 804 loader->num_glyphs = T1_ToInt( parser ); 805 if ( parser->root.error ) 806 return; 807 if ( loader->num_glyphs < 0 ) 808 { 809 FT_ERROR(( "t42_parse_encoding: invalid number of glyphs\n" )); 810 error = FT_THROW( Invalid_File_Format ); 811 goto Fail; 812 } 813 814 /* we certainly need more than 4 bytes per glyph */ 815 if ( loader->num_glyphs > ( limit - parser->root.cursor ) >> 2 ) 816 { 817 FT_TRACE0(( "t42_parse_charstrings: adjusting number of glyphs" 818 " (from %d to %d)\n", 819 loader->num_glyphs, 820 ( limit - parser->root.cursor ) >> 2 )); 821 loader->num_glyphs = ( limit - parser->root.cursor ) >> 2; 822 } 823 824 } 825 else if ( *parser->root.cursor == '<' ) 826 { 827 /* We have `<< ... >>'. Count the number of `/' in the dictionary */ 828 /* to get its size. */ 829 FT_Int count = 0; 830 831 832 T1_Skip_PS_Token( parser ); 833 if ( parser->root.error ) 834 return; 835 T1_Skip_Spaces( parser ); 836 cur = parser->root.cursor; 837 838 while ( parser->root.cursor < limit ) 839 { 840 if ( *parser->root.cursor == '/' ) 841 count++; 842 else if ( *parser->root.cursor == '>' ) 843 { 844 loader->num_glyphs = count; 845 parser->root.cursor = cur; /* rewind */ 846 break; 847 } 848 T1_Skip_PS_Token( parser ); 849 if ( parser->root.error ) 850 return; 851 T1_Skip_Spaces( parser ); 852 } 853 } 854 else 855 { 856 FT_ERROR(( "t42_parse_charstrings: invalid token\n" )); 857 error = FT_THROW( Invalid_File_Format ); 858 goto Fail; 859 } 860 861 if ( parser->root.cursor >= limit ) 862 { 863 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); 864 error = FT_THROW( Invalid_File_Format ); 865 goto Fail; 866 } 867 868 /* initialize tables */ 869 870 /* contrary to Type1, we disallow multiple CharStrings arrays */ 871 if ( swap_table->init ) 872 { 873 FT_ERROR(( "t42_parse_charstrings:" 874 " only one CharStrings array allowed\n" )); 875 error = FT_THROW( Invalid_File_Format ); 876 goto Fail; 877 } 878 879 error = psaux->ps_table_funcs->init( code_table, 880 loader->num_glyphs, 881 memory ); 882 if ( error ) 883 goto Fail; 884 885 error = psaux->ps_table_funcs->init( name_table, 886 loader->num_glyphs, 887 memory ); 888 if ( error ) 889 goto Fail; 890 891 /* Initialize table for swapping index notdef_index and */ 892 /* index 0 names and codes (if necessary). */ 893 894 error = psaux->ps_table_funcs->init( swap_table, 4, memory ); 895 if ( error ) 896 goto Fail; 897 898 n = 0; 899 900 for (;;) 901 { 902 /* We support two formats. */ 903 /* */ 904 /* `/glyphname' + index [+ `def'] */ 905 /* `(glyphname)' [+ `cvn'] + index [+ `def'] */ 906 /* */ 907 /* The latter format gets created by the */ 908 /* LilyPond typesetting program. */ 909 910 T1_Skip_Spaces( parser ); 911 912 cur = parser->root.cursor; 913 if ( cur >= limit ) 914 break; 915 916 /* We stop when we find an `end' keyword or '>' */ 917 if ( *cur == 'e' && 918 cur + 3 < limit && 919 cur[1] == 'n' && 920 cur[2] == 'd' && 921 t42_is_space( cur[3] ) ) 922 break; 923 if ( *cur == '>' ) 924 break; 925 926 T1_Skip_PS_Token( parser ); 927 if ( parser->root.cursor >= limit ) 928 { 929 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); 930 error = FT_THROW( Invalid_File_Format ); 931 goto Fail; 932 } 933 if ( parser->root.error ) 934 return; 935 936 if ( *cur == '/' || *cur == '(' ) 937 { 938 FT_UInt len; 939 FT_Bool have_literal = FT_BOOL( *cur == '(' ); 940 941 942 if ( cur + ( have_literal ? 3 : 2 ) >= limit ) 943 { 944 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); 945 error = FT_THROW( Invalid_File_Format ); 946 goto Fail; 947 } 948 949 cur++; /* skip `/' */ 950 len = (FT_UInt)( parser->root.cursor - cur ); 951 if ( have_literal ) 952 len--; 953 954 error = T1_Add_Table( name_table, n, cur, len + 1 ); 955 if ( error ) 956 goto Fail; 957 958 /* add a trailing zero to the name table */ 959 name_table->elements[n][len] = '\0'; 960 961 /* record index of /.notdef */ 962 if ( *cur == '.' && 963 ft_strcmp( ".notdef", 964 (const char*)(name_table->elements[n]) ) == 0 ) 965 { 966 notdef_index = n; 967 notdef_found = 1; 968 } 969 970 T1_Skip_Spaces( parser ); 971 972 if ( have_literal ) 973 T1_Skip_PS_Token( parser ); 974 975 cur = parser->root.cursor; 976 977 (void)T1_ToInt( parser ); 978 if ( parser->root.cursor >= limit ) 979 { 980 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); 981 error = FT_THROW( Invalid_File_Format ); 982 goto Fail; 983 } 984 985 len = (FT_UInt)( parser->root.cursor - cur ); 986 987 error = T1_Add_Table( code_table, n, cur, len + 1 ); 988 if ( error ) 989 goto Fail; 990 991 code_table->elements[n][len] = '\0'; 992 993 n++; 994 if ( n >= loader->num_glyphs ) 995 break; 996 } 997 } 998 999 loader->num_glyphs = n; 1000 1001 if ( !notdef_found ) 1002 { 1003 FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph\n" )); 1004 error = FT_THROW( Invalid_File_Format ); 1005 goto Fail; 1006 } 1007 1008 /* if /.notdef does not occupy index 0, do our magic. */ 1009 if ( ft_strcmp( (const char*)".notdef", 1010 (const char*)name_table->elements[0] ) ) 1011 { 1012 /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ 1013 /* name and code entries to swap_table. Then place notdef_index */ 1014 /* name and code entries into swap_table. Then swap name and code */ 1015 /* entries at indices notdef_index and 0 using values stored in */ 1016 /* swap_table. */ 1017 1018 /* Index 0 name */ 1019 error = T1_Add_Table( swap_table, 0, 1020 name_table->elements[0], 1021 name_table->lengths [0] ); 1022 if ( error ) 1023 goto Fail; 1024 1025 /* Index 0 code */ 1026 error = T1_Add_Table( swap_table, 1, 1027 code_table->elements[0], 1028 code_table->lengths [0] ); 1029 if ( error ) 1030 goto Fail; 1031 1032 /* Index notdef_index name */ 1033 error = T1_Add_Table( swap_table, 2, 1034 name_table->elements[notdef_index], 1035 name_table->lengths [notdef_index] ); 1036 if ( error ) 1037 goto Fail; 1038 1039 /* Index notdef_index code */ 1040 error = T1_Add_Table( swap_table, 3, 1041 code_table->elements[notdef_index], 1042 code_table->lengths [notdef_index] ); 1043 if ( error ) 1044 goto Fail; 1045 1046 error = T1_Add_Table( name_table, notdef_index, 1047 swap_table->elements[0], 1048 swap_table->lengths [0] ); 1049 if ( error ) 1050 goto Fail; 1051 1052 error = T1_Add_Table( code_table, notdef_index, 1053 swap_table->elements[1], 1054 swap_table->lengths [1] ); 1055 if ( error ) 1056 goto Fail; 1057 1058 error = T1_Add_Table( name_table, 0, 1059 swap_table->elements[2], 1060 swap_table->lengths [2] ); 1061 if ( error ) 1062 goto Fail; 1063 1064 error = T1_Add_Table( code_table, 0, 1065 swap_table->elements[3], 1066 swap_table->lengths [3] ); 1067 if ( error ) 1068 goto Fail; 1069 1070 } 1071 1072 return; 1073 1074 Fail: 1075 parser->root.error = error; 1076 } 1077 1078 1079 static FT_Error 1080 t42_load_keyword( T42_Face face, 1081 T42_Loader loader, 1082 T1_Field field ) 1083 { 1084 FT_Error error; 1085 void* dummy_object; 1086 void** objects; 1087 FT_UInt max_objects = 0; 1088 1089 1090 /* if the keyword has a dedicated callback, call it */ 1091 if ( field->type == T1_FIELD_TYPE_CALLBACK ) 1092 { 1093 field->reader( (FT_Face)face, loader ); 1094 error = loader->parser.root.error; 1095 goto Exit; 1096 } 1097 1098 /* now the keyword is either a simple field or a table of fields; */ 1099 /* we are now going to take care of it */ 1100 1101 switch ( field->location ) 1102 { 1103 case T1_FIELD_LOCATION_FONT_INFO: 1104 dummy_object = &face->type1.font_info; 1105 break; 1106 1107 case T1_FIELD_LOCATION_FONT_EXTRA: 1108 dummy_object = &face->type1.font_extra; 1109 break; 1110 1111 case T1_FIELD_LOCATION_BBOX: 1112 dummy_object = &face->type1.font_bbox; 1113 break; 1114 1115 default: 1116 dummy_object = &face->type1; 1117 } 1118 1119 objects = &dummy_object; 1120 1121 if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || 1122 field->type == T1_FIELD_TYPE_FIXED_ARRAY ) 1123 error = T1_Load_Field_Table( &loader->parser, field, 1124 objects, max_objects, 0 ); 1125 else 1126 error = T1_Load_Field( &loader->parser, field, 1127 objects, max_objects, 0 ); 1128 1129 Exit: 1130 return error; 1131 } 1132 1133 1134 FT_LOCAL_DEF( FT_Error ) 1135 t42_parse_dict( T42_Face face, 1136 T42_Loader loader, 1137 FT_Byte* base, 1138 FT_Long size ) 1139 { 1140 T42_Parser parser = &loader->parser; 1141 FT_Byte* limit; 1142 FT_Int n_keywords = (FT_Int)( sizeof ( t42_keywords ) / 1143 sizeof ( t42_keywords[0] ) ); 1144 1145 1146 parser->root.cursor = base; 1147 parser->root.limit = base + size; 1148 parser->root.error = FT_Err_Ok; 1149 1150 limit = parser->root.limit; 1151 1152 T1_Skip_Spaces( parser ); 1153 1154 while ( parser->root.cursor < limit ) 1155 { 1156 FT_Byte* cur; 1157 1158 1159 cur = parser->root.cursor; 1160 1161 /* look for `FontDirectory' which causes problems for some fonts */ 1162 if ( *cur == 'F' && cur + 25 < limit && 1163 ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 ) 1164 { 1165 FT_Byte* cur2; 1166 1167 1168 /* skip the `FontDirectory' keyword */ 1169 T1_Skip_PS_Token( parser ); 1170 T1_Skip_Spaces ( parser ); 1171 cur = cur2 = parser->root.cursor; 1172 1173 /* look up the `known' keyword */ 1174 while ( cur < limit ) 1175 { 1176 if ( *cur == 'k' && cur + 5 < limit && 1177 ft_strncmp( (char*)cur, "known", 5 ) == 0 ) 1178 break; 1179 1180 T1_Skip_PS_Token( parser ); 1181 if ( parser->root.error ) 1182 goto Exit; 1183 T1_Skip_Spaces ( parser ); 1184 cur = parser->root.cursor; 1185 } 1186 1187 if ( cur < limit ) 1188 { 1189 T1_TokenRec token; 1190 1191 1192 /* skip the `known' keyword and the token following it */ 1193 T1_Skip_PS_Token( parser ); 1194 T1_ToToken( parser, &token ); 1195 1196 /* if the last token was an array, skip it! */ 1197 if ( token.type == T1_TOKEN_TYPE_ARRAY ) 1198 cur2 = parser->root.cursor; 1199 } 1200 parser->root.cursor = cur2; 1201 } 1202 1203 /* look for immediates */ 1204 else if ( *cur == '/' && cur + 2 < limit ) 1205 { 1206 FT_UInt len; 1207 1208 1209 cur++; 1210 1211 parser->root.cursor = cur; 1212 T1_Skip_PS_Token( parser ); 1213 if ( parser->root.error ) 1214 goto Exit; 1215 1216 len = (FT_UInt)( parser->root.cursor - cur ); 1217 1218 if ( len > 0 && len < 22 && parser->root.cursor < limit ) 1219 { 1220 int i; 1221 1222 1223 /* now compare the immediate name to the keyword table */ 1224 1225 /* loop through all known keywords */ 1226 for ( i = 0; i < n_keywords; i++ ) 1227 { 1228 T1_Field keyword = (T1_Field)&t42_keywords[i]; 1229 FT_Byte *name = (FT_Byte*)keyword->ident; 1230 1231 1232 if ( !name ) 1233 continue; 1234 1235 if ( cur[0] == name[0] && 1236 len == ft_strlen( (const char *)name ) && 1237 ft_memcmp( cur, name, len ) == 0 ) 1238 { 1239 /* we found it -- run the parsing callback! */ 1240 parser->root.error = t42_load_keyword( face, 1241 loader, 1242 keyword ); 1243 if ( parser->root.error ) 1244 return parser->root.error; 1245 break; 1246 } 1247 } 1248 } 1249 } 1250 else 1251 { 1252 T1_Skip_PS_Token( parser ); 1253 if ( parser->root.error ) 1254 goto Exit; 1255 } 1256 1257 T1_Skip_Spaces( parser ); 1258 } 1259 1260 Exit: 1261 return parser->root.error; 1262 } 1263 1264 1265 FT_LOCAL_DEF( void ) 1266 t42_loader_init( T42_Loader loader, 1267 T42_Face face ) 1268 { 1269 FT_UNUSED( face ); 1270 1271 FT_ZERO( loader ); 1272 loader->num_glyphs = 0; 1273 loader->num_chars = 0; 1274 1275 /* initialize the tables -- simply set their `init' field to 0 */ 1276 loader->encoding_table.init = 0; 1277 loader->charstrings.init = 0; 1278 loader->glyph_names.init = 0; 1279 } 1280 1281 1282 FT_LOCAL_DEF( void ) 1283 t42_loader_done( T42_Loader loader ) 1284 { 1285 T42_Parser parser = &loader->parser; 1286 1287 1288 /* finalize tables */ 1289 T1_Release_Table( &loader->encoding_table ); 1290 T1_Release_Table( &loader->charstrings ); 1291 T1_Release_Table( &loader->glyph_names ); 1292 T1_Release_Table( &loader->swap_table ); 1293 1294 /* finalize parser */ 1295 t42_parser_done( parser ); 1296 } 1297 1298 1299 /* END */ 1300