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