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