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