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