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 ) t42_parser_init(T42_Parser parser,FT_Stream stream,FT_Memory memory,PSAux_Service psaux)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 ) t42_parser_done(T42_Parser parser)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 t42_is_space(FT_Byte c)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 t42_parse_font_matrix(T42_Face face,T42_Loader loader)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 if ( !FT_Matrix_Check( matrix ) ) 288 { 289 FT_ERROR(( "t42_parse_font_matrix: invalid font matrix\n" )); 290 parser->root.error = FT_THROW( Invalid_File_Format ); 291 return; 292 } 293 294 /* note that the offsets must be expressed in integer font units */ 295 offset->x = temp[4] >> 16; 296 offset->y = temp[5] >> 16; 297 } 298 299 300 static void t42_parse_encoding(T42_Face face,T42_Loader loader)301 t42_parse_encoding( T42_Face face, 302 T42_Loader loader ) 303 { 304 T42_Parser parser = &loader->parser; 305 FT_Byte* cur; 306 FT_Byte* limit = parser->root.limit; 307 308 PSAux_Service psaux = (PSAux_Service)face->psaux; 309 310 311 T1_Skip_Spaces( parser ); 312 cur = parser->root.cursor; 313 if ( cur >= limit ) 314 { 315 FT_ERROR(( "t42_parse_encoding: out of bounds\n" )); 316 parser->root.error = FT_THROW( Invalid_File_Format ); 317 return; 318 } 319 320 /* if we have a number or `[', the encoding is an array, */ 321 /* and we must load it now */ 322 if ( ft_isdigit( *cur ) || *cur == '[' ) 323 { 324 T1_Encoding encode = &face->type1.encoding; 325 FT_Int count, n; 326 PS_Table char_table = &loader->encoding_table; 327 FT_Memory memory = parser->root.memory; 328 FT_Error error; 329 FT_Bool only_immediates = 0; 330 331 332 /* read the number of entries in the encoding; should be 256 */ 333 if ( *cur == '[' ) 334 { 335 count = 256; 336 only_immediates = 1; 337 parser->root.cursor++; 338 } 339 else 340 count = (FT_Int)T1_ToInt( parser ); 341 342 /* only composite fonts (which we don't support) */ 343 /* can have larger values */ 344 if ( count > 256 ) 345 { 346 FT_ERROR(( "t42_parse_encoding: invalid encoding array size\n" )); 347 parser->root.error = FT_THROW( Invalid_File_Format ); 348 return; 349 } 350 351 T1_Skip_Spaces( parser ); 352 if ( parser->root.cursor >= limit ) 353 return; 354 355 /* PostScript happily allows overwriting of encoding arrays */ 356 if ( encode->char_index ) 357 { 358 FT_FREE( encode->char_index ); 359 FT_FREE( encode->char_name ); 360 T1_Release_Table( char_table ); 361 } 362 363 /* we use a T1_Table to store our charnames */ 364 loader->num_chars = encode->num_chars = count; 365 if ( FT_NEW_ARRAY( encode->char_index, count ) || 366 FT_NEW_ARRAY( encode->char_name, count ) || 367 FT_SET_ERROR( psaux->ps_table_funcs->init( 368 char_table, count, memory ) ) ) 369 { 370 parser->root.error = error; 371 return; 372 } 373 374 /* We need to `zero' out encoding_table.elements */ 375 for ( n = 0; n < count; n++ ) 376 { 377 char* notdef = (char *)".notdef"; 378 379 380 (void)T1_Add_Table( char_table, n, notdef, 8 ); 381 } 382 383 /* Now we need to read records of the form */ 384 /* */ 385 /* ... charcode /charname ... */ 386 /* */ 387 /* for each entry in our table. */ 388 /* */ 389 /* We simply look for a number followed by an immediate */ 390 /* name. Note that this ignores correctly the sequence */ 391 /* that is often seen in type42 fonts: */ 392 /* */ 393 /* 0 1 255 { 1 index exch /.notdef put } for dup */ 394 /* */ 395 /* used to clean the encoding array before anything else. */ 396 /* */ 397 /* Alternatively, if the array is directly given as */ 398 /* */ 399 /* /Encoding [ ... ] */ 400 /* */ 401 /* we only read immediates. */ 402 403 n = 0; 404 T1_Skip_Spaces( parser ); 405 406 while ( parser->root.cursor < limit ) 407 { 408 cur = parser->root.cursor; 409 410 /* we stop when we encounter `def' or `]' */ 411 if ( *cur == 'd' && cur + 3 < limit ) 412 { 413 if ( cur[1] == 'e' && 414 cur[2] == 'f' && 415 t42_is_space( cur[3] ) ) 416 { 417 FT_TRACE6(( "encoding end\n" )); 418 cur += 3; 419 break; 420 } 421 } 422 if ( *cur == ']' ) 423 { 424 FT_TRACE6(( "encoding end\n" )); 425 cur++; 426 break; 427 } 428 429 /* check whether we have found an entry */ 430 if ( ft_isdigit( *cur ) || only_immediates ) 431 { 432 FT_Int charcode; 433 434 435 if ( only_immediates ) 436 charcode = n; 437 else 438 { 439 charcode = (FT_Int)T1_ToInt( parser ); 440 T1_Skip_Spaces( parser ); 441 442 /* protect against invalid charcode */ 443 if ( cur == parser->root.cursor ) 444 { 445 parser->root.error = FT_THROW( Unknown_File_Format ); 446 return; 447 } 448 } 449 450 cur = parser->root.cursor; 451 452 if ( cur + 2 < limit && *cur == '/' && n < count ) 453 { 454 FT_UInt len; 455 456 457 cur++; 458 459 parser->root.cursor = cur; 460 T1_Skip_PS_Token( parser ); 461 if ( parser->root.cursor >= limit ) 462 return; 463 if ( parser->root.error ) 464 return; 465 466 len = (FT_UInt)( parser->root.cursor - cur ); 467 468 parser->root.error = T1_Add_Table( char_table, charcode, 469 cur, len + 1 ); 470 if ( parser->root.error ) 471 return; 472 char_table->elements[charcode][len] = '\0'; 473 474 n++; 475 } 476 else if ( only_immediates ) 477 { 478 /* Since the current position is not updated for */ 479 /* immediates-only mode we would get an infinite loop if */ 480 /* we don't do anything here. */ 481 /* */ 482 /* This encoding array is not valid according to the */ 483 /* type42 specification (it might be an encoding for a CID */ 484 /* type42 font, however), so we conclude that this font is */ 485 /* NOT a type42 font. */ 486 parser->root.error = FT_THROW( Unknown_File_Format ); 487 return; 488 } 489 } 490 else 491 { 492 T1_Skip_PS_Token( parser ); 493 if ( parser->root.error ) 494 return; 495 } 496 497 T1_Skip_Spaces( parser ); 498 } 499 500 face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; 501 parser->root.cursor = cur; 502 } 503 504 /* Otherwise, we should have either `StandardEncoding', */ 505 /* `ExpertEncoding', or `ISOLatin1Encoding' */ 506 else 507 { 508 if ( cur + 17 < limit && 509 ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) 510 face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; 511 512 else if ( cur + 15 < limit && 513 ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) 514 face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; 515 516 else if ( cur + 18 < limit && 517 ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) 518 face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; 519 520 else 521 parser->root.error = FT_ERR( Ignore ); 522 } 523 } 524 525 526 typedef enum T42_Load_Status_ 527 { 528 BEFORE_START, 529 BEFORE_TABLE_DIR, 530 OTHER_TABLES 531 532 } T42_Load_Status; 533 534 535 static void t42_parse_sfnts(T42_Face face,T42_Loader loader)536 t42_parse_sfnts( T42_Face face, 537 T42_Loader loader ) 538 { 539 T42_Parser parser = &loader->parser; 540 FT_Memory memory = parser->root.memory; 541 FT_Byte* cur; 542 FT_Byte* limit = parser->root.limit; 543 FT_Error error; 544 FT_Int num_tables = 0; 545 FT_Long count; 546 547 FT_ULong n, string_size, old_string_size, real_size; 548 FT_Byte* string_buf = NULL; 549 FT_Bool allocated = 0; 550 551 T42_Load_Status status; 552 553 554 /* The format is */ 555 /* */ 556 /* /sfnts [ <hexstring> <hexstring> ... ] def */ 557 /* */ 558 /* or */ 559 /* */ 560 /* /sfnts [ */ 561 /* <num_bin_bytes> RD <binary data> */ 562 /* <num_bin_bytes> RD <binary data> */ 563 /* ... */ 564 /* ] def */ 565 /* */ 566 /* with exactly one space after the `RD' token. */ 567 568 T1_Skip_Spaces( parser ); 569 570 if ( parser->root.cursor >= limit || *parser->root.cursor++ != '[' ) 571 { 572 FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector\n" )); 573 error = FT_THROW( Invalid_File_Format ); 574 goto Fail; 575 } 576 577 T1_Skip_Spaces( parser ); 578 status = BEFORE_START; 579 string_size = 0; 580 old_string_size = 0; 581 count = 0; 582 583 while ( parser->root.cursor < limit ) 584 { 585 FT_ULong size; 586 587 588 cur = parser->root.cursor; 589 590 if ( *cur == ']' ) 591 { 592 parser->root.cursor++; 593 goto Exit; 594 } 595 596 else if ( *cur == '<' ) 597 { 598 T1_Skip_PS_Token( parser ); 599 if ( parser->root.error ) 600 goto Exit; 601 602 /* don't include delimiters */ 603 string_size = (FT_ULong)( ( parser->root.cursor - cur - 2 + 1 ) / 2 ); 604 if ( !string_size ) 605 { 606 FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" )); 607 error = FT_THROW( Invalid_File_Format ); 608 goto Fail; 609 } 610 if ( FT_REALLOC( string_buf, old_string_size, string_size ) ) 611 goto Fail; 612 613 allocated = 1; 614 615 parser->root.cursor = cur; 616 (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 ); 617 old_string_size = string_size; 618 string_size = real_size; 619 } 620 621 else if ( ft_isdigit( *cur ) ) 622 { 623 FT_Long tmp; 624 625 626 if ( allocated ) 627 { 628 FT_ERROR(( "t42_parse_sfnts: " 629 "can't handle mixed binary and hex strings\n" )); 630 error = FT_THROW( Invalid_File_Format ); 631 goto Fail; 632 } 633 634 tmp = T1_ToInt( parser ); 635 if ( tmp < 0 ) 636 { 637 FT_ERROR(( "t42_parse_sfnts: invalid string size\n" )); 638 error = FT_THROW( Invalid_File_Format ); 639 goto Fail; 640 } 641 else 642 string_size = (FT_ULong)tmp; 643 644 T1_Skip_PS_Token( parser ); /* `RD' */ 645 if ( parser->root.error ) 646 return; 647 648 string_buf = parser->root.cursor + 1; /* one space after `RD' */ 649 650 if ( (FT_ULong)( limit - parser->root.cursor ) <= string_size ) 651 { 652 FT_ERROR(( "t42_parse_sfnts: too much binary data\n" )); 653 error = FT_THROW( Invalid_File_Format ); 654 goto Fail; 655 } 656 else 657 parser->root.cursor += string_size + 1; 658 } 659 660 if ( !string_buf ) 661 { 662 FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" )); 663 error = FT_THROW( Invalid_File_Format ); 664 goto Fail; 665 } 666 667 /* A string can have a trailing zero (odd) byte for padding. */ 668 /* Ignore it. */ 669 if ( ( string_size & 1 ) && string_buf[string_size - 1] == 0 ) 670 string_size--; 671 672 if ( !string_size ) 673 { 674 FT_ERROR(( "t42_parse_sfnts: invalid string\n" )); 675 error = FT_THROW( Invalid_File_Format ); 676 goto Fail; 677 } 678 679 /* The whole TTF is now loaded into `string_buf'. We are */ 680 /* checking its contents while copying it to `ttf_data'. */ 681 682 size = (FT_ULong)( limit - parser->root.cursor ); 683 684 for ( n = 0; n < string_size; n++ ) 685 { 686 switch ( status ) 687 { 688 case BEFORE_START: 689 /* load offset table, 12 bytes */ 690 if ( count < 12 ) 691 { 692 face->ttf_data[count++] = string_buf[n]; 693 continue; 694 } 695 else 696 { 697 num_tables = 16 * face->ttf_data[4] + face->ttf_data[5]; 698 status = BEFORE_TABLE_DIR; 699 face->ttf_size = 12 + 16 * num_tables; 700 701 if ( (FT_Long)size < face->ttf_size ) 702 { 703 FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" )); 704 error = FT_THROW( Invalid_File_Format ); 705 goto Fail; 706 } 707 708 if ( FT_REALLOC( face->ttf_data, 12, face->ttf_size ) ) 709 goto Fail; 710 } 711 /* fall through */ 712 713 case BEFORE_TABLE_DIR: 714 /* the offset table is read; read the table directory */ 715 if ( count < face->ttf_size ) 716 { 717 face->ttf_data[count++] = string_buf[n]; 718 continue; 719 } 720 else 721 { 722 int i; 723 FT_ULong len; 724 725 726 for ( i = 0; i < num_tables; i++ ) 727 { 728 FT_Byte* p = face->ttf_data + 12 + 16 * i + 12; 729 730 731 len = FT_PEEK_ULONG( p ); 732 if ( len > size || 733 face->ttf_size > (FT_Long)( size - len ) ) 734 { 735 FT_ERROR(( "t42_parse_sfnts:" 736 " invalid data in sfnts array\n" )); 737 error = FT_THROW( Invalid_File_Format ); 738 goto Fail; 739 } 740 741 /* Pad to a 4-byte boundary length */ 742 face->ttf_size += (FT_Long)( ( len + 3 ) & ~3U ); 743 } 744 745 status = OTHER_TABLES; 746 747 if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables, 748 face->ttf_size + 1 ) ) 749 goto Fail; 750 } 751 /* fall through */ 752 753 case OTHER_TABLES: 754 /* all other tables are just copied */ 755 if ( count >= face->ttf_size ) 756 { 757 FT_ERROR(( "t42_parse_sfnts: too much binary data\n" )); 758 error = FT_THROW( Invalid_File_Format ); 759 goto Fail; 760 } 761 face->ttf_data[count++] = string_buf[n]; 762 } 763 } 764 765 T1_Skip_Spaces( parser ); 766 } 767 768 /* if control reaches this point, the format was not valid */ 769 error = FT_THROW( Invalid_File_Format ); 770 771 Fail: 772 parser->root.error = error; 773 774 Exit: 775 if ( allocated ) 776 FT_FREE( string_buf ); 777 } 778 779 780 static void t42_parse_charstrings(T42_Face face,T42_Loader loader)781 t42_parse_charstrings( T42_Face face, 782 T42_Loader loader ) 783 { 784 T42_Parser parser = &loader->parser; 785 PS_Table code_table = &loader->charstrings; 786 PS_Table name_table = &loader->glyph_names; 787 PS_Table swap_table = &loader->swap_table; 788 FT_Memory memory = parser->root.memory; 789 FT_Error error; 790 791 PSAux_Service psaux = (PSAux_Service)face->psaux; 792 793 FT_Byte* cur; 794 FT_Byte* limit = parser->root.limit; 795 FT_Int n; 796 FT_Int notdef_index = 0; 797 FT_Byte notdef_found = 0; 798 799 800 T1_Skip_Spaces( parser ); 801 802 if ( parser->root.cursor >= limit ) 803 { 804 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); 805 error = FT_THROW( Invalid_File_Format ); 806 goto Fail; 807 } 808 809 if ( ft_isdigit( *parser->root.cursor ) ) 810 { 811 loader->num_glyphs = T1_ToInt( parser ); 812 if ( parser->root.error ) 813 return; 814 if ( loader->num_glyphs < 0 ) 815 { 816 FT_ERROR(( "t42_parse_encoding: invalid number of glyphs\n" )); 817 error = FT_THROW( Invalid_File_Format ); 818 goto Fail; 819 } 820 821 /* we certainly need more than 4 bytes per glyph */ 822 if ( loader->num_glyphs > ( limit - parser->root.cursor ) >> 2 ) 823 { 824 FT_TRACE0(( "t42_parse_charstrings: adjusting number of glyphs" 825 " (from %d to %d)\n", 826 loader->num_glyphs, 827 ( limit - parser->root.cursor ) >> 2 )); 828 loader->num_glyphs = ( limit - parser->root.cursor ) >> 2; 829 } 830 831 } 832 else if ( *parser->root.cursor == '<' ) 833 { 834 /* We have `<< ... >>'. Count the number of `/' in the dictionary */ 835 /* to get its size. */ 836 FT_Int count = 0; 837 838 839 T1_Skip_PS_Token( parser ); 840 if ( parser->root.error ) 841 return; 842 T1_Skip_Spaces( parser ); 843 cur = parser->root.cursor; 844 845 while ( parser->root.cursor < limit ) 846 { 847 if ( *parser->root.cursor == '/' ) 848 count++; 849 else if ( *parser->root.cursor == '>' ) 850 { 851 loader->num_glyphs = count; 852 parser->root.cursor = cur; /* rewind */ 853 break; 854 } 855 T1_Skip_PS_Token( parser ); 856 if ( parser->root.error ) 857 return; 858 T1_Skip_Spaces( parser ); 859 } 860 } 861 else 862 { 863 FT_ERROR(( "t42_parse_charstrings: invalid token\n" )); 864 error = FT_THROW( Invalid_File_Format ); 865 goto Fail; 866 } 867 868 if ( parser->root.cursor >= limit ) 869 { 870 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); 871 error = FT_THROW( Invalid_File_Format ); 872 goto Fail; 873 } 874 875 /* initialize tables */ 876 877 /* contrary to Type1, we disallow multiple CharStrings arrays */ 878 if ( swap_table->init ) 879 { 880 FT_ERROR(( "t42_parse_charstrings:" 881 " only one CharStrings array allowed\n" )); 882 error = FT_THROW( Invalid_File_Format ); 883 goto Fail; 884 } 885 886 error = psaux->ps_table_funcs->init( code_table, 887 loader->num_glyphs, 888 memory ); 889 if ( error ) 890 goto Fail; 891 892 error = psaux->ps_table_funcs->init( name_table, 893 loader->num_glyphs, 894 memory ); 895 if ( error ) 896 goto Fail; 897 898 /* Initialize table for swapping index notdef_index and */ 899 /* index 0 names and codes (if necessary). */ 900 901 error = psaux->ps_table_funcs->init( swap_table, 4, memory ); 902 if ( error ) 903 goto Fail; 904 905 n = 0; 906 907 for (;;) 908 { 909 /* We support two formats. */ 910 /* */ 911 /* `/glyphname' + index [+ `def'] */ 912 /* `(glyphname)' [+ `cvn'] + index [+ `def'] */ 913 /* */ 914 /* The latter format gets created by the */ 915 /* LilyPond typesetting program. */ 916 917 T1_Skip_Spaces( parser ); 918 919 cur = parser->root.cursor; 920 if ( cur >= limit ) 921 break; 922 923 /* We stop when we find an `end' keyword or '>' */ 924 if ( *cur == 'e' && 925 cur + 3 < limit && 926 cur[1] == 'n' && 927 cur[2] == 'd' && 928 t42_is_space( cur[3] ) ) 929 break; 930 if ( *cur == '>' ) 931 break; 932 933 T1_Skip_PS_Token( parser ); 934 if ( parser->root.cursor >= limit ) 935 { 936 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); 937 error = FT_THROW( Invalid_File_Format ); 938 goto Fail; 939 } 940 if ( parser->root.error ) 941 return; 942 943 if ( *cur == '/' || *cur == '(' ) 944 { 945 FT_UInt len; 946 FT_Bool have_literal = FT_BOOL( *cur == '(' ); 947 948 949 if ( cur + ( have_literal ? 3 : 2 ) >= limit ) 950 { 951 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); 952 error = FT_THROW( Invalid_File_Format ); 953 goto Fail; 954 } 955 956 cur++; /* skip `/' */ 957 len = (FT_UInt)( parser->root.cursor - cur ); 958 if ( have_literal ) 959 len--; 960 961 error = T1_Add_Table( name_table, n, cur, len + 1 ); 962 if ( error ) 963 goto Fail; 964 965 /* add a trailing zero to the name table */ 966 name_table->elements[n][len] = '\0'; 967 968 /* record index of /.notdef */ 969 if ( *cur == '.' && 970 ft_strcmp( ".notdef", 971 (const char*)(name_table->elements[n]) ) == 0 ) 972 { 973 notdef_index = n; 974 notdef_found = 1; 975 } 976 977 T1_Skip_Spaces( parser ); 978 979 if ( have_literal ) 980 T1_Skip_PS_Token( parser ); 981 982 cur = parser->root.cursor; 983 984 (void)T1_ToInt( parser ); 985 if ( parser->root.cursor >= limit ) 986 { 987 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); 988 error = FT_THROW( Invalid_File_Format ); 989 goto Fail; 990 } 991 992 len = (FT_UInt)( parser->root.cursor - cur ); 993 994 error = T1_Add_Table( code_table, n, cur, len + 1 ); 995 if ( error ) 996 goto Fail; 997 998 code_table->elements[n][len] = '\0'; 999 1000 n++; 1001 if ( n >= loader->num_glyphs ) 1002 break; 1003 } 1004 } 1005 1006 loader->num_glyphs = n; 1007 1008 if ( !notdef_found ) 1009 { 1010 FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph\n" )); 1011 error = FT_THROW( Invalid_File_Format ); 1012 goto Fail; 1013 } 1014 1015 /* if /.notdef does not occupy index 0, do our magic. */ 1016 if ( ft_strcmp( (const char*)".notdef", 1017 (const char*)name_table->elements[0] ) ) 1018 { 1019 /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ 1020 /* name and code entries to swap_table. Then place notdef_index */ 1021 /* name and code entries into swap_table. Then swap name and code */ 1022 /* entries at indices notdef_index and 0 using values stored in */ 1023 /* swap_table. */ 1024 1025 /* Index 0 name */ 1026 error = T1_Add_Table( swap_table, 0, 1027 name_table->elements[0], 1028 name_table->lengths [0] ); 1029 if ( error ) 1030 goto Fail; 1031 1032 /* Index 0 code */ 1033 error = T1_Add_Table( swap_table, 1, 1034 code_table->elements[0], 1035 code_table->lengths [0] ); 1036 if ( error ) 1037 goto Fail; 1038 1039 /* Index notdef_index name */ 1040 error = T1_Add_Table( swap_table, 2, 1041 name_table->elements[notdef_index], 1042 name_table->lengths [notdef_index] ); 1043 if ( error ) 1044 goto Fail; 1045 1046 /* Index notdef_index code */ 1047 error = T1_Add_Table( swap_table, 3, 1048 code_table->elements[notdef_index], 1049 code_table->lengths [notdef_index] ); 1050 if ( error ) 1051 goto Fail; 1052 1053 error = T1_Add_Table( name_table, notdef_index, 1054 swap_table->elements[0], 1055 swap_table->lengths [0] ); 1056 if ( error ) 1057 goto Fail; 1058 1059 error = T1_Add_Table( code_table, notdef_index, 1060 swap_table->elements[1], 1061 swap_table->lengths [1] ); 1062 if ( error ) 1063 goto Fail; 1064 1065 error = T1_Add_Table( name_table, 0, 1066 swap_table->elements[2], 1067 swap_table->lengths [2] ); 1068 if ( error ) 1069 goto Fail; 1070 1071 error = T1_Add_Table( code_table, 0, 1072 swap_table->elements[3], 1073 swap_table->lengths [3] ); 1074 if ( error ) 1075 goto Fail; 1076 1077 } 1078 1079 return; 1080 1081 Fail: 1082 parser->root.error = error; 1083 } 1084 1085 1086 static FT_Error t42_load_keyword(T42_Face face,T42_Loader loader,T1_Field field)1087 t42_load_keyword( T42_Face face, 1088 T42_Loader loader, 1089 T1_Field field ) 1090 { 1091 FT_Error error; 1092 void* dummy_object; 1093 void** objects; 1094 FT_UInt max_objects = 0; 1095 1096 1097 /* if the keyword has a dedicated callback, call it */ 1098 if ( field->type == T1_FIELD_TYPE_CALLBACK ) 1099 { 1100 field->reader( (FT_Face)face, loader ); 1101 error = loader->parser.root.error; 1102 goto Exit; 1103 } 1104 1105 /* now the keyword is either a simple field or a table of fields; */ 1106 /* we are now going to take care of it */ 1107 1108 switch ( field->location ) 1109 { 1110 case T1_FIELD_LOCATION_FONT_INFO: 1111 dummy_object = &face->type1.font_info; 1112 break; 1113 1114 case T1_FIELD_LOCATION_FONT_EXTRA: 1115 dummy_object = &face->type1.font_extra; 1116 break; 1117 1118 case T1_FIELD_LOCATION_BBOX: 1119 dummy_object = &face->type1.font_bbox; 1120 break; 1121 1122 default: 1123 dummy_object = &face->type1; 1124 } 1125 1126 objects = &dummy_object; 1127 1128 if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || 1129 field->type == T1_FIELD_TYPE_FIXED_ARRAY ) 1130 error = T1_Load_Field_Table( &loader->parser, field, 1131 objects, max_objects, 0 ); 1132 else 1133 error = T1_Load_Field( &loader->parser, field, 1134 objects, max_objects, 0 ); 1135 1136 Exit: 1137 return error; 1138 } 1139 1140 1141 FT_LOCAL_DEF( FT_Error ) t42_parse_dict(T42_Face face,T42_Loader loader,FT_Byte * base,FT_Long size)1142 t42_parse_dict( T42_Face face, 1143 T42_Loader loader, 1144 FT_Byte* base, 1145 FT_Long size ) 1146 { 1147 T42_Parser parser = &loader->parser; 1148 FT_Byte* limit; 1149 FT_Int n_keywords = (FT_Int)( sizeof ( t42_keywords ) / 1150 sizeof ( t42_keywords[0] ) ); 1151 1152 1153 parser->root.cursor = base; 1154 parser->root.limit = base + size; 1155 parser->root.error = FT_Err_Ok; 1156 1157 limit = parser->root.limit; 1158 1159 T1_Skip_Spaces( parser ); 1160 1161 while ( parser->root.cursor < limit ) 1162 { 1163 FT_Byte* cur; 1164 1165 1166 cur = parser->root.cursor; 1167 1168 /* look for `FontDirectory' which causes problems for some fonts */ 1169 if ( *cur == 'F' && cur + 25 < limit && 1170 ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 ) 1171 { 1172 FT_Byte* cur2; 1173 1174 1175 /* skip the `FontDirectory' keyword */ 1176 T1_Skip_PS_Token( parser ); 1177 T1_Skip_Spaces ( parser ); 1178 cur = cur2 = parser->root.cursor; 1179 1180 /* look up the `known' keyword */ 1181 while ( cur < limit ) 1182 { 1183 if ( *cur == 'k' && cur + 5 < limit && 1184 ft_strncmp( (char*)cur, "known", 5 ) == 0 ) 1185 break; 1186 1187 T1_Skip_PS_Token( parser ); 1188 if ( parser->root.error ) 1189 goto Exit; 1190 T1_Skip_Spaces ( parser ); 1191 cur = parser->root.cursor; 1192 } 1193 1194 if ( cur < limit ) 1195 { 1196 T1_TokenRec token; 1197 1198 1199 /* skip the `known' keyword and the token following it */ 1200 T1_Skip_PS_Token( parser ); 1201 T1_ToToken( parser, &token ); 1202 1203 /* if the last token was an array, skip it! */ 1204 if ( token.type == T1_TOKEN_TYPE_ARRAY ) 1205 cur2 = parser->root.cursor; 1206 } 1207 parser->root.cursor = cur2; 1208 } 1209 1210 /* look for immediates */ 1211 else if ( *cur == '/' && cur + 2 < limit ) 1212 { 1213 FT_UInt len; 1214 1215 1216 cur++; 1217 1218 parser->root.cursor = cur; 1219 T1_Skip_PS_Token( parser ); 1220 if ( parser->root.error ) 1221 goto Exit; 1222 1223 len = (FT_UInt)( parser->root.cursor - cur ); 1224 1225 if ( len > 0 && len < 22 && parser->root.cursor < limit ) 1226 { 1227 int i; 1228 1229 1230 /* now compare the immediate name to the keyword table */ 1231 1232 /* loop through all known keywords */ 1233 for ( i = 0; i < n_keywords; i++ ) 1234 { 1235 T1_Field keyword = (T1_Field)&t42_keywords[i]; 1236 FT_Byte *name = (FT_Byte*)keyword->ident; 1237 1238 1239 if ( !name ) 1240 continue; 1241 1242 if ( cur[0] == name[0] && 1243 len == ft_strlen( (const char *)name ) && 1244 ft_memcmp( cur, name, len ) == 0 ) 1245 { 1246 /* we found it -- run the parsing callback! */ 1247 parser->root.error = t42_load_keyword( face, 1248 loader, 1249 keyword ); 1250 if ( parser->root.error ) 1251 return parser->root.error; 1252 break; 1253 } 1254 } 1255 } 1256 } 1257 else 1258 { 1259 T1_Skip_PS_Token( parser ); 1260 if ( parser->root.error ) 1261 goto Exit; 1262 } 1263 1264 T1_Skip_Spaces( parser ); 1265 } 1266 1267 Exit: 1268 return parser->root.error; 1269 } 1270 1271 1272 FT_LOCAL_DEF( void ) t42_loader_init(T42_Loader loader,T42_Face face)1273 t42_loader_init( T42_Loader loader, 1274 T42_Face face ) 1275 { 1276 FT_UNUSED( face ); 1277 1278 FT_ZERO( loader ); 1279 loader->num_glyphs = 0; 1280 loader->num_chars = 0; 1281 1282 /* initialize the tables -- simply set their `init' field to 0 */ 1283 loader->encoding_table.init = 0; 1284 loader->charstrings.init = 0; 1285 loader->glyph_names.init = 0; 1286 } 1287 1288 1289 FT_LOCAL_DEF( void ) t42_loader_done(T42_Loader loader)1290 t42_loader_done( T42_Loader loader ) 1291 { 1292 T42_Parser parser = &loader->parser; 1293 1294 1295 /* finalize tables */ 1296 T1_Release_Table( &loader->encoding_table ); 1297 T1_Release_Table( &loader->charstrings ); 1298 T1_Release_Table( &loader->glyph_names ); 1299 T1_Release_Table( &loader->swap_table ); 1300 1301 /* finalize parser */ 1302 t42_parser_done( parser ); 1303 } 1304 1305 1306 /* END */ 1307