1 /**************************************************************************** 2 * 3 * t42parse.c 4 * 5 * Type 42 font parser (body). 6 * 7 * Copyright (C) 2002-2021 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 <freetype/internal/ftdebug.h> 22 #include <freetype/internal/ftstream.h> 23 #include <freetype/internal/psaux.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_QALLOC( 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 FT_TRACE2(( "\n" )); 580 FT_TRACE2(( "t42_parse_sfnts:\n" )); 581 582 while ( parser->root.cursor < limit ) 583 { 584 FT_ULong size; 585 586 587 cur = parser->root.cursor; 588 589 if ( *cur == ']' ) 590 { 591 parser->root.cursor++; 592 goto Exit; 593 } 594 595 else if ( *cur == '<' ) 596 { 597 if ( string_buf && !allocated ) 598 { 599 FT_ERROR(( "t42_parse_sfnts: " 600 "can't handle mixed binary and hex strings\n" )); 601 error = FT_THROW( Invalid_File_Format ); 602 goto Fail; 603 } 604 605 T1_Skip_PS_Token( parser ); 606 if ( parser->root.error ) 607 goto Exit; 608 609 /* don't include delimiters */ 610 string_size = (FT_ULong)( ( parser->root.cursor - cur - 2 + 1 ) / 2 ); 611 if ( !string_size ) 612 { 613 FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" )); 614 error = FT_THROW( Invalid_File_Format ); 615 goto Fail; 616 } 617 if ( FT_QREALLOC( string_buf, old_string_size, string_size ) ) 618 goto Fail; 619 620 allocated = 1; 621 622 parser->root.cursor = cur; 623 (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 ); 624 old_string_size = string_size; 625 string_size = real_size; 626 } 627 628 else if ( ft_isdigit( *cur ) ) 629 { 630 FT_Long tmp; 631 632 633 if ( allocated ) 634 { 635 FT_ERROR(( "t42_parse_sfnts: " 636 "can't handle mixed binary and hex strings\n" )); 637 error = FT_THROW( Invalid_File_Format ); 638 goto Fail; 639 } 640 641 tmp = T1_ToInt( parser ); 642 if ( tmp < 0 ) 643 { 644 FT_ERROR(( "t42_parse_sfnts: invalid string size\n" )); 645 error = FT_THROW( Invalid_File_Format ); 646 goto Fail; 647 } 648 else 649 string_size = (FT_ULong)tmp; 650 651 T1_Skip_PS_Token( parser ); /* `RD' */ 652 if ( parser->root.error ) 653 return; 654 655 string_buf = parser->root.cursor + 1; /* one space after `RD' */ 656 657 if ( (FT_ULong)( limit - parser->root.cursor ) <= string_size ) 658 { 659 FT_ERROR(( "t42_parse_sfnts: too much binary data\n" )); 660 error = FT_THROW( Invalid_File_Format ); 661 goto Fail; 662 } 663 else 664 parser->root.cursor += string_size + 1; 665 } 666 667 if ( !string_buf ) 668 { 669 FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" )); 670 error = FT_THROW( Invalid_File_Format ); 671 goto Fail; 672 } 673 674 /* A string can have a trailing zero (odd) byte for padding. */ 675 /* Ignore it. */ 676 if ( ( string_size & 1 ) && string_buf[string_size - 1] == 0 ) 677 string_size--; 678 679 if ( !string_size ) 680 { 681 FT_ERROR(( "t42_parse_sfnts: invalid string\n" )); 682 error = FT_THROW( Invalid_File_Format ); 683 goto Fail; 684 } 685 686 FT_TRACE2(( " PS string size %5lu bytes, offset 0x%08lx (%lu)\n", 687 string_size, count, count )); 688 689 /* The whole TTF is now loaded into `string_buf'. We are */ 690 /* checking its contents while copying it to `ttf_data'. */ 691 692 size = (FT_ULong)( limit - parser->root.cursor ); 693 694 for ( n = 0; n < string_size; n++ ) 695 { 696 switch ( status ) 697 { 698 case BEFORE_START: 699 /* load offset table, 12 bytes */ 700 if ( count < 12 ) 701 { 702 face->ttf_data[count++] = string_buf[n]; 703 continue; 704 } 705 else 706 { 707 num_tables = 16 * face->ttf_data[4] + face->ttf_data[5]; 708 status = BEFORE_TABLE_DIR; 709 face->ttf_size = 12 + 16 * num_tables; 710 711 FT_TRACE2(( " SFNT directory contains %d tables\n", 712 num_tables )); 713 714 if ( (FT_Long)size < face->ttf_size ) 715 { 716 FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" )); 717 error = FT_THROW( Invalid_File_Format ); 718 goto Fail; 719 } 720 721 if ( FT_QREALLOC( face->ttf_data, 12, face->ttf_size ) ) 722 goto Fail; 723 } 724 /* fall through */ 725 726 case BEFORE_TABLE_DIR: 727 /* the offset table is read; read the table directory */ 728 if ( count < face->ttf_size ) 729 { 730 face->ttf_data[count++] = string_buf[n]; 731 continue; 732 } 733 else 734 { 735 int i; 736 FT_ULong len; 737 738 739 FT_TRACE2(( "\n" )); 740 FT_TRACE2(( " table length\n" )); 741 FT_TRACE2(( " ------------------------------\n" )); 742 743 for ( i = 0; i < num_tables; i++ ) 744 { 745 FT_Byte* p = face->ttf_data + 12 + 16 * i + 12; 746 747 748 len = FT_PEEK_ULONG( p ); 749 FT_TRACE2(( " %4i 0x%08lx (%lu)\n", i, len, len )); 750 751 if ( len > size || 752 face->ttf_size > (FT_Long)( size - len ) ) 753 { 754 FT_ERROR(( "t42_parse_sfnts:" 755 " invalid data in sfnts array\n" )); 756 error = FT_THROW( Invalid_File_Format ); 757 goto Fail; 758 } 759 760 /* Pad to a 4-byte boundary length */ 761 face->ttf_size += (FT_Long)( ( len + 3 ) & ~3U ); 762 } 763 764 status = OTHER_TABLES; 765 766 FT_TRACE2(( "\n" )); 767 FT_TRACE2(( " allocating %ld bytes\n", face->ttf_size + 1 )); 768 FT_TRACE2(( "\n" )); 769 770 if ( FT_QREALLOC( face->ttf_data, 12 + 16 * num_tables, 771 face->ttf_size + 1 ) ) 772 goto Fail; 773 } 774 /* fall through */ 775 776 case OTHER_TABLES: 777 /* all other tables are just copied */ 778 if ( count >= face->ttf_size ) 779 { 780 FT_ERROR(( "t42_parse_sfnts: too much binary data\n" )); 781 error = FT_THROW( Invalid_File_Format ); 782 goto Fail; 783 } 784 face->ttf_data[count++] = string_buf[n]; 785 } 786 } 787 788 T1_Skip_Spaces( parser ); 789 } 790 791 /* if control reaches this point, the format was not valid */ 792 error = FT_THROW( Invalid_File_Format ); 793 794 Fail: 795 parser->root.error = error; 796 797 Exit: 798 if ( allocated ) 799 FT_FREE( string_buf ); 800 } 801 802 803 static void t42_parse_charstrings(T42_Face face,T42_Loader loader)804 t42_parse_charstrings( T42_Face face, 805 T42_Loader loader ) 806 { 807 T42_Parser parser = &loader->parser; 808 PS_Table code_table = &loader->charstrings; 809 PS_Table name_table = &loader->glyph_names; 810 PS_Table swap_table = &loader->swap_table; 811 FT_Memory memory = parser->root.memory; 812 FT_Error error; 813 814 PSAux_Service psaux = (PSAux_Service)face->psaux; 815 816 FT_Byte* cur; 817 FT_Byte* limit = parser->root.limit; 818 FT_Int n; 819 FT_Int notdef_index = 0; 820 FT_Byte notdef_found = 0; 821 822 823 T1_Skip_Spaces( parser ); 824 825 if ( parser->root.cursor >= limit ) 826 { 827 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); 828 error = FT_THROW( Invalid_File_Format ); 829 goto Fail; 830 } 831 832 if ( ft_isdigit( *parser->root.cursor ) ) 833 { 834 loader->num_glyphs = T1_ToInt( parser ); 835 if ( parser->root.error ) 836 return; 837 if ( loader->num_glyphs < 0 ) 838 { 839 FT_ERROR(( "t42_parse_encoding: invalid number of glyphs\n" )); 840 error = FT_THROW( Invalid_File_Format ); 841 goto Fail; 842 } 843 844 /* we certainly need more than 4 bytes per glyph */ 845 if ( loader->num_glyphs > ( limit - parser->root.cursor ) >> 2 ) 846 { 847 FT_TRACE0(( "t42_parse_charstrings: adjusting number of glyphs" 848 " (from %d to %ld)\n", 849 loader->num_glyphs, 850 ( limit - parser->root.cursor ) >> 2 )); 851 loader->num_glyphs = ( limit - parser->root.cursor ) >> 2; 852 } 853 854 } 855 else if ( *parser->root.cursor == '<' ) 856 { 857 /* We have `<< ... >>'. Count the number of `/' in the dictionary */ 858 /* to get its size. */ 859 FT_Int count = 0; 860 861 862 T1_Skip_PS_Token( parser ); 863 if ( parser->root.error ) 864 return; 865 T1_Skip_Spaces( parser ); 866 cur = parser->root.cursor; 867 868 while ( parser->root.cursor < limit ) 869 { 870 if ( *parser->root.cursor == '/' ) 871 count++; 872 else if ( *parser->root.cursor == '>' ) 873 { 874 loader->num_glyphs = count; 875 parser->root.cursor = cur; /* rewind */ 876 break; 877 } 878 T1_Skip_PS_Token( parser ); 879 if ( parser->root.error ) 880 return; 881 T1_Skip_Spaces( parser ); 882 } 883 } 884 else 885 { 886 FT_ERROR(( "t42_parse_charstrings: invalid token\n" )); 887 error = FT_THROW( Invalid_File_Format ); 888 goto Fail; 889 } 890 891 if ( parser->root.cursor >= limit ) 892 { 893 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); 894 error = FT_THROW( Invalid_File_Format ); 895 goto Fail; 896 } 897 898 /* initialize tables */ 899 900 /* contrary to Type1, we disallow multiple CharStrings arrays */ 901 if ( swap_table->init ) 902 { 903 FT_ERROR(( "t42_parse_charstrings:" 904 " only one CharStrings array allowed\n" )); 905 error = FT_THROW( Invalid_File_Format ); 906 goto Fail; 907 } 908 909 error = psaux->ps_table_funcs->init( code_table, 910 loader->num_glyphs, 911 memory ); 912 if ( error ) 913 goto Fail; 914 915 error = psaux->ps_table_funcs->init( name_table, 916 loader->num_glyphs, 917 memory ); 918 if ( error ) 919 goto Fail; 920 921 /* Initialize table for swapping index notdef_index and */ 922 /* index 0 names and codes (if necessary). */ 923 924 error = psaux->ps_table_funcs->init( swap_table, 4, memory ); 925 if ( error ) 926 goto Fail; 927 928 n = 0; 929 930 for (;;) 931 { 932 /* We support two formats. */ 933 /* */ 934 /* `/glyphname' + index [+ `def'] */ 935 /* `(glyphname)' [+ `cvn'] + index [+ `def'] */ 936 /* */ 937 /* The latter format gets created by the */ 938 /* LilyPond typesetting program. */ 939 940 T1_Skip_Spaces( parser ); 941 942 cur = parser->root.cursor; 943 if ( cur >= limit ) 944 break; 945 946 /* We stop when we find an `end' keyword or '>' */ 947 if ( *cur == 'e' && 948 cur + 3 < limit && 949 cur[1] == 'n' && 950 cur[2] == 'd' && 951 t42_is_space( cur[3] ) ) 952 break; 953 if ( *cur == '>' ) 954 break; 955 956 T1_Skip_PS_Token( parser ); 957 if ( parser->root.cursor >= limit ) 958 { 959 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); 960 error = FT_THROW( Invalid_File_Format ); 961 goto Fail; 962 } 963 if ( parser->root.error ) 964 return; 965 966 if ( *cur == '/' || *cur == '(' ) 967 { 968 FT_UInt len; 969 FT_Bool have_literal = FT_BOOL( *cur == '(' ); 970 971 972 if ( cur + ( have_literal ? 3 : 2 ) >= limit ) 973 { 974 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); 975 error = FT_THROW( Invalid_File_Format ); 976 goto Fail; 977 } 978 979 cur++; /* skip `/' */ 980 len = (FT_UInt)( parser->root.cursor - cur ); 981 if ( have_literal ) 982 len--; 983 984 error = T1_Add_Table( name_table, n, cur, len + 1 ); 985 if ( error ) 986 goto Fail; 987 988 /* add a trailing zero to the name table */ 989 name_table->elements[n][len] = '\0'; 990 991 /* record index of /.notdef */ 992 if ( *cur == '.' && 993 ft_strcmp( ".notdef", 994 (const char*)(name_table->elements[n]) ) == 0 ) 995 { 996 notdef_index = n; 997 notdef_found = 1; 998 } 999 1000 T1_Skip_Spaces( parser ); 1001 1002 if ( have_literal ) 1003 T1_Skip_PS_Token( parser ); 1004 1005 cur = parser->root.cursor; 1006 1007 (void)T1_ToInt( parser ); 1008 if ( parser->root.cursor >= limit ) 1009 { 1010 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); 1011 error = FT_THROW( Invalid_File_Format ); 1012 goto Fail; 1013 } 1014 1015 len = (FT_UInt)( parser->root.cursor - cur ); 1016 1017 error = T1_Add_Table( code_table, n, cur, len + 1 ); 1018 if ( error ) 1019 goto Fail; 1020 1021 code_table->elements[n][len] = '\0'; 1022 1023 n++; 1024 if ( n >= loader->num_glyphs ) 1025 break; 1026 } 1027 } 1028 1029 loader->num_glyphs = n; 1030 1031 if ( !notdef_found ) 1032 { 1033 FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph\n" )); 1034 error = FT_THROW( Invalid_File_Format ); 1035 goto Fail; 1036 } 1037 1038 /* if /.notdef does not occupy index 0, do our magic. */ 1039 if ( ft_strcmp( ".notdef", (const char*)name_table->elements[0] ) ) 1040 { 1041 /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ 1042 /* name and code entries to swap_table. Then place notdef_index */ 1043 /* name and code entries into swap_table. Then swap name and code */ 1044 /* entries at indices notdef_index and 0 using values stored in */ 1045 /* swap_table. */ 1046 1047 /* Index 0 name */ 1048 error = T1_Add_Table( swap_table, 0, 1049 name_table->elements[0], 1050 name_table->lengths [0] ); 1051 if ( error ) 1052 goto Fail; 1053 1054 /* Index 0 code */ 1055 error = T1_Add_Table( swap_table, 1, 1056 code_table->elements[0], 1057 code_table->lengths [0] ); 1058 if ( error ) 1059 goto Fail; 1060 1061 /* Index notdef_index name */ 1062 error = T1_Add_Table( swap_table, 2, 1063 name_table->elements[notdef_index], 1064 name_table->lengths [notdef_index] ); 1065 if ( error ) 1066 goto Fail; 1067 1068 /* Index notdef_index code */ 1069 error = T1_Add_Table( swap_table, 3, 1070 code_table->elements[notdef_index], 1071 code_table->lengths [notdef_index] ); 1072 if ( error ) 1073 goto Fail; 1074 1075 error = T1_Add_Table( name_table, notdef_index, 1076 swap_table->elements[0], 1077 swap_table->lengths [0] ); 1078 if ( error ) 1079 goto Fail; 1080 1081 error = T1_Add_Table( code_table, notdef_index, 1082 swap_table->elements[1], 1083 swap_table->lengths [1] ); 1084 if ( error ) 1085 goto Fail; 1086 1087 error = T1_Add_Table( name_table, 0, 1088 swap_table->elements[2], 1089 swap_table->lengths [2] ); 1090 if ( error ) 1091 goto Fail; 1092 1093 error = T1_Add_Table( code_table, 0, 1094 swap_table->elements[3], 1095 swap_table->lengths [3] ); 1096 if ( error ) 1097 goto Fail; 1098 1099 } 1100 1101 return; 1102 1103 Fail: 1104 parser->root.error = error; 1105 } 1106 1107 1108 static FT_Error t42_load_keyword(T42_Face face,T42_Loader loader,T1_Field field)1109 t42_load_keyword( T42_Face face, 1110 T42_Loader loader, 1111 T1_Field field ) 1112 { 1113 FT_Error error; 1114 void* dummy_object; 1115 void** objects; 1116 FT_UInt max_objects = 0; 1117 1118 1119 /* if the keyword has a dedicated callback, call it */ 1120 if ( field->type == T1_FIELD_TYPE_CALLBACK ) 1121 { 1122 field->reader( (FT_Face)face, loader ); 1123 error = loader->parser.root.error; 1124 goto Exit; 1125 } 1126 1127 /* now the keyword is either a simple field or a table of fields; */ 1128 /* we are now going to take care of it */ 1129 1130 switch ( field->location ) 1131 { 1132 case T1_FIELD_LOCATION_FONT_INFO: 1133 dummy_object = &face->type1.font_info; 1134 break; 1135 1136 case T1_FIELD_LOCATION_FONT_EXTRA: 1137 dummy_object = &face->type1.font_extra; 1138 break; 1139 1140 case T1_FIELD_LOCATION_BBOX: 1141 dummy_object = &face->type1.font_bbox; 1142 break; 1143 1144 default: 1145 dummy_object = &face->type1; 1146 } 1147 1148 objects = &dummy_object; 1149 1150 if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || 1151 field->type == T1_FIELD_TYPE_FIXED_ARRAY ) 1152 error = T1_Load_Field_Table( &loader->parser, field, 1153 objects, max_objects, 0 ); 1154 else 1155 error = T1_Load_Field( &loader->parser, field, 1156 objects, max_objects, 0 ); 1157 1158 Exit: 1159 return error; 1160 } 1161 1162 1163 FT_LOCAL_DEF( FT_Error ) t42_parse_dict(T42_Face face,T42_Loader loader,FT_Byte * base,FT_Long size)1164 t42_parse_dict( T42_Face face, 1165 T42_Loader loader, 1166 FT_Byte* base, 1167 FT_Long size ) 1168 { 1169 T42_Parser parser = &loader->parser; 1170 FT_Byte* limit; 1171 FT_Int n_keywords = (FT_Int)( sizeof ( t42_keywords ) / 1172 sizeof ( t42_keywords[0] ) ); 1173 1174 1175 parser->root.cursor = base; 1176 parser->root.limit = base + size; 1177 parser->root.error = FT_Err_Ok; 1178 1179 limit = parser->root.limit; 1180 1181 T1_Skip_Spaces( parser ); 1182 1183 while ( parser->root.cursor < limit ) 1184 { 1185 FT_Byte* cur; 1186 1187 1188 cur = parser->root.cursor; 1189 1190 /* look for `FontDirectory' which causes problems for some fonts */ 1191 if ( *cur == 'F' && cur + 25 < limit && 1192 ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 ) 1193 { 1194 FT_Byte* cur2; 1195 1196 1197 /* skip the `FontDirectory' keyword */ 1198 T1_Skip_PS_Token( parser ); 1199 T1_Skip_Spaces ( parser ); 1200 cur = cur2 = parser->root.cursor; 1201 1202 /* look up the `known' keyword */ 1203 while ( cur < limit ) 1204 { 1205 if ( *cur == 'k' && cur + 5 < limit && 1206 ft_strncmp( (char*)cur, "known", 5 ) == 0 ) 1207 break; 1208 1209 T1_Skip_PS_Token( parser ); 1210 if ( parser->root.error ) 1211 goto Exit; 1212 T1_Skip_Spaces ( parser ); 1213 cur = parser->root.cursor; 1214 } 1215 1216 if ( cur < limit ) 1217 { 1218 T1_TokenRec token; 1219 1220 1221 /* skip the `known' keyword and the token following it */ 1222 T1_Skip_PS_Token( parser ); 1223 T1_ToToken( parser, &token ); 1224 1225 /* if the last token was an array, skip it! */ 1226 if ( token.type == T1_TOKEN_TYPE_ARRAY ) 1227 cur2 = parser->root.cursor; 1228 } 1229 parser->root.cursor = cur2; 1230 } 1231 1232 /* look for immediates */ 1233 else if ( *cur == '/' && cur + 2 < limit ) 1234 { 1235 FT_UInt len; 1236 1237 1238 cur++; 1239 1240 parser->root.cursor = cur; 1241 T1_Skip_PS_Token( parser ); 1242 if ( parser->root.error ) 1243 goto Exit; 1244 1245 len = (FT_UInt)( parser->root.cursor - cur ); 1246 1247 if ( len > 0 && len < 22 && parser->root.cursor < limit ) 1248 { 1249 int i; 1250 1251 1252 /* now compare the immediate name to the keyword table */ 1253 1254 /* loop through all known keywords */ 1255 for ( i = 0; i < n_keywords; i++ ) 1256 { 1257 T1_Field keyword = (T1_Field)&t42_keywords[i]; 1258 FT_Byte *name = (FT_Byte*)keyword->ident; 1259 1260 1261 if ( !name ) 1262 continue; 1263 1264 if ( cur[0] == name[0] && 1265 len == ft_strlen( (const char *)name ) && 1266 ft_memcmp( cur, name, len ) == 0 ) 1267 { 1268 /* we found it -- run the parsing callback! */ 1269 parser->root.error = t42_load_keyword( face, 1270 loader, 1271 keyword ); 1272 if ( parser->root.error ) 1273 return parser->root.error; 1274 break; 1275 } 1276 } 1277 } 1278 } 1279 else 1280 { 1281 T1_Skip_PS_Token( parser ); 1282 if ( parser->root.error ) 1283 goto Exit; 1284 } 1285 1286 T1_Skip_Spaces( parser ); 1287 } 1288 1289 Exit: 1290 return parser->root.error; 1291 } 1292 1293 1294 FT_LOCAL_DEF( void ) t42_loader_init(T42_Loader loader,T42_Face face)1295 t42_loader_init( T42_Loader loader, 1296 T42_Face face ) 1297 { 1298 FT_UNUSED( face ); 1299 1300 FT_ZERO( loader ); 1301 loader->num_glyphs = 0; 1302 loader->num_chars = 0; 1303 1304 /* initialize the tables -- simply set their `init' field to 0 */ 1305 loader->encoding_table.init = 0; 1306 loader->charstrings.init = 0; 1307 loader->glyph_names.init = 0; 1308 } 1309 1310 1311 FT_LOCAL_DEF( void ) t42_loader_done(T42_Loader loader)1312 t42_loader_done( T42_Loader loader ) 1313 { 1314 T42_Parser parser = &loader->parser; 1315 1316 1317 /* finalize tables */ 1318 T1_Release_Table( &loader->encoding_table ); 1319 T1_Release_Table( &loader->charstrings ); 1320 T1_Release_Table( &loader->glyph_names ); 1321 T1_Release_Table( &loader->swap_table ); 1322 1323 /* finalize parser */ 1324 t42_parser_done( parser ); 1325 } 1326 1327 1328 /* END */ 1329