1 /***************************************************************************/ 2 /* */ 3 /* t42parse.c */ 4 /* */ 5 /* Type 42 font parser (body). */ 6 /* */ 7 /* Copyright 2002 by Roberto Alameda. */ 8 /* */ 9 /* This file is part of the FreeType project, and may only be used, */ 10 /* modified, and distributed under the terms of the FreeType project */ 11 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 12 /* this file you indicate that you have read the license and */ 13 /* understand and accept it fully. */ 14 /* */ 15 /***************************************************************************/ 16 17 18 #include "t42parse.h" 19 #include "t42error.h" 20 #include FT_INTERNAL_DEBUG_H 21 #include FT_INTERNAL_STREAM_H 22 #include FT_LIST_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_name( T42_Face face, 38 T42_Loader loader ); 39 40 static void 41 t42_parse_font_bbox( T42_Face face, 42 T42_Loader loader ); 43 44 static void 45 t42_parse_font_matrix( T42_Face face, 46 T42_Loader loader ); 47 static void 48 t42_parse_encoding( T42_Face face, 49 T42_Loader loader ); 50 51 static void 52 t42_parse_charstrings( T42_Face face, 53 T42_Loader loader ); 54 55 static void 56 t42_parse_sfnts( T42_Face face, 57 T42_Loader loader ); 58 59 60 static const 61 T1_FieldRec t42_keywords[] = { 62 63 #undef FT_STRUCTURE 64 #define FT_STRUCTURE T1_FontInfo 65 #undef T1CODE 66 #define T1CODE T1_FIELD_LOCATION_FONT_INFO 67 68 T1_FIELD_STRING ( "version", version ) 69 T1_FIELD_STRING ( "Notice", notice ) 70 T1_FIELD_STRING ( "FullName", full_name ) 71 T1_FIELD_STRING ( "FamilyName", family_name ) 72 T1_FIELD_STRING ( "Weight", weight ) 73 T1_FIELD_NUM ( "ItalicAngle", italic_angle ) 74 T1_FIELD_TYPE_BOOL( "isFixedPitch", is_fixed_pitch ) 75 T1_FIELD_NUM ( "UnderlinePosition", underline_position ) 76 T1_FIELD_NUM ( "UnderlineThickness", underline_thickness ) 77 78 #undef FT_STRUCTURE 79 #define FT_STRUCTURE T1_FontRec 80 #undef T1CODE 81 #define T1CODE T1_FIELD_LOCATION_FONT_DICT 82 83 T1_FIELD_NUM( "PaintType", paint_type ) 84 T1_FIELD_NUM( "FontType", font_type ) 85 T1_FIELD_NUM( "StrokeWidth", stroke_width ) 86 87 T1_FIELD_CALLBACK( "FontName", t42_parse_font_name ) 88 T1_FIELD_CALLBACK( "FontBBox", t42_parse_font_bbox ) 89 T1_FIELD_CALLBACK( "FontMatrix", t42_parse_font_matrix ) 90 T1_FIELD_CALLBACK( "Encoding", t42_parse_encoding ) 91 T1_FIELD_CALLBACK( "CharStrings", t42_parse_charstrings ) 92 T1_FIELD_CALLBACK( "sfnts", t42_parse_sfnts ) 93 94 { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0 } 95 }; 96 97 98 #define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l ) 99 #define T1_Done_Table( p ) \ 100 do \ 101 { \ 102 if ( (p)->funcs.done ) \ 103 (p)->funcs.done( p ); \ 104 } while ( 0 ) 105 #define T1_Release_Table( p ) \ 106 do \ 107 { \ 108 if ( (p)->funcs.release ) \ 109 (p)->funcs.release( p ); \ 110 } while ( 0 ) 111 112 #define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root ) 113 #define T1_Skip_Alpha( p ) (p)->root.funcs.skip_alpha ( &(p)->root ) 114 115 #define T1_ToInt( p ) (p)->root.funcs.to_int( &(p)->root ) 116 #define T1_ToFixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t ) 117 118 #define T1_ToCoordArray( p, m, c ) \ 119 (p)->root.funcs.to_coord_array( &(p)->root, m, c ) 120 #define T1_ToFixedArray( p, m, f, t ) \ 121 (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t ) 122 #define T1_ToToken( p, t ) \ 123 (p)->root.funcs.to_token( &(p)->root, t ) 124 #define T1_ToTokenArray( p, t, m, c ) \ 125 (p)->root.funcs.to_token_array( &(p)->root, t, m, c ) 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 = T42_Err_Ok; 142 FT_Long size; 143 144 145 psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory ); 146 147 parser->stream = stream; 148 parser->base_len = 0; 149 parser->base_dict = 0; 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 setup pointers in */ 160 /* 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 goto Exit; 168 169 size = stream->size; 170 171 /* now, try to load `size' bytes of the `base' dictionary we */ 172 /* found previously */ 173 174 /* if it is a memory-based resource, set up pointers */ 175 if ( !stream->read ) 176 { 177 parser->base_dict = (FT_Byte*)stream->base + stream->pos; 178 parser->base_len = size; 179 parser->in_memory = 1; 180 181 /* check that the `size' field is valid */ 182 if ( FT_STREAM_SKIP( size ) ) 183 goto Exit; 184 } 185 else 186 { 187 /* read segment in memory */ 188 if ( FT_ALLOC( parser->base_dict, size ) || 189 FT_STREAM_READ( parser->base_dict, size ) ) 190 goto Exit; 191 192 parser->base_len = size; 193 } 194 195 /* Now check font format; we must see `%!PS-TrueTypeFont' */ 196 if (size <= 17 || 197 ( ft_strncmp( (const char*)parser->base_dict, 198 "%!PS-TrueTypeFont", 17) ) ) 199 error = T42_Err_Unknown_File_Format; 200 else 201 { 202 parser->root.base = parser->base_dict; 203 parser->root.cursor = parser->base_dict; 204 parser->root.limit = parser->root.cursor + parser->base_len; 205 } 206 207 Exit: 208 if ( error && !parser->in_memory ) 209 FT_FREE( parser->base_dict ); 210 211 return error; 212 } 213 214 215 FT_LOCAL_DEF( void ) t42_parser_done(T42_Parser parser)216 t42_parser_done( T42_Parser parser ) 217 { 218 FT_Memory memory = parser->root.memory; 219 220 221 /* free the base dictionary only when we have a disk stream */ 222 if ( !parser->in_memory ) 223 FT_FREE( parser->base_dict ); 224 225 parser->root.funcs.done( &parser->root ); 226 } 227 228 229 static int t42_is_alpha(FT_Byte c)230 t42_is_alpha( FT_Byte c ) 231 { 232 /* Note: we must accept "+" as a valid character, as it is used in */ 233 /* embedded type1 fonts in PDF documents. */ 234 /* */ 235 return ( ft_isalnum( c ) || 236 c == '.' || 237 c == '_' || 238 c == '-' || 239 c == '+' ); 240 } 241 242 243 static int t42_is_space(FT_Byte c)244 t42_is_space( FT_Byte c ) 245 { 246 return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ); 247 } 248 249 250 static void t42_parse_font_name(T42_Face face,T42_Loader loader)251 t42_parse_font_name( T42_Face face, 252 T42_Loader loader ) 253 { 254 T42_Parser parser = &loader->parser; 255 FT_Error error; 256 FT_Memory memory = parser->root.memory; 257 FT_Int len; 258 FT_Byte* cur; 259 FT_Byte* cur2; 260 FT_Byte* limit; 261 262 263 T1_Skip_Spaces( parser ); 264 265 cur = parser->root.cursor; 266 limit = parser->root.limit; 267 268 if ( cur >= limit - 1 || 269 ( *cur != '/' && *cur != '(') ) 270 return; 271 272 cur++; 273 cur2 = cur; 274 while ( cur2 < limit && t42_is_alpha( *cur2 ) ) 275 cur2++; 276 277 len = (FT_Int)( cur2 - cur ); 278 if ( len > 0 ) 279 { 280 if ( FT_ALLOC( face->type1.font_name, len + 1 ) ) 281 { 282 parser->root.error = error; 283 return; 284 } 285 286 FT_MEM_COPY( face->type1.font_name, cur, len ); 287 face->type1.font_name[len] = '\0'; 288 } 289 parser->root.cursor = cur2; 290 } 291 292 293 static void t42_parse_font_bbox(T42_Face face,T42_Loader loader)294 t42_parse_font_bbox( T42_Face face, 295 T42_Loader loader ) 296 { 297 T42_Parser parser = &loader->parser; 298 FT_BBox* bbox = &face->type1.font_bbox; 299 300 bbox->xMin = T1_ToInt( parser ); 301 bbox->yMin = T1_ToInt( parser ); 302 bbox->xMax = T1_ToInt( parser ); 303 bbox->yMax = T1_ToInt( parser ); 304 } 305 306 307 static void t42_parse_font_matrix(T42_Face face,T42_Loader loader)308 t42_parse_font_matrix( T42_Face face, 309 T42_Loader loader ) 310 { 311 T42_Parser parser = &loader->parser; 312 FT_Matrix* matrix = &face->type1.font_matrix; 313 FT_Vector* offset = &face->type1.font_offset; 314 FT_Face root = (FT_Face)&face->root; 315 FT_Fixed temp[6]; 316 FT_Fixed temp_scale; 317 318 319 (void)T1_ToFixedArray( parser, 6, temp, 3 ); 320 321 temp_scale = ABS( temp[3] ); 322 323 /* Set Units per EM based on FontMatrix values. We set the value to */ 324 /* 1000 / temp_scale, because temp_scale was already multiplied by */ 325 /* 1000 (in t1_tofixed, from psobjs.c). */ 326 327 root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L, 328 temp_scale ) >> 16 ); 329 330 /* we need to scale the values by 1.0/temp_scale */ 331 if ( temp_scale != 0x10000L ) { 332 temp[0] = FT_DivFix( temp[0], temp_scale ); 333 temp[1] = FT_DivFix( temp[1], temp_scale ); 334 temp[2] = FT_DivFix( temp[2], temp_scale ); 335 temp[4] = FT_DivFix( temp[4], temp_scale ); 336 temp[5] = FT_DivFix( temp[5], temp_scale ); 337 temp[3] = 0x10000L; 338 } 339 340 matrix->xx = temp[0]; 341 matrix->yx = temp[1]; 342 matrix->xy = temp[2]; 343 matrix->yy = temp[3]; 344 345 /* note that the offsets must be expressed in integer font units */ 346 offset->x = temp[4] >> 16; 347 offset->y = temp[5] >> 16; 348 } 349 350 351 static void t42_parse_encoding(T42_Face face,T42_Loader loader)352 t42_parse_encoding( T42_Face face, 353 T42_Loader loader ) 354 { 355 T42_Parser parser = &loader->parser; 356 FT_Byte* cur = parser->root.cursor; 357 FT_Byte* limit = parser->root.limit; 358 359 PSAux_Service psaux = (PSAux_Service)face->psaux; 360 361 362 /* skip whitespace */ 363 while ( t42_is_space( *cur ) ) 364 { 365 cur++; 366 if ( cur >= limit ) 367 { 368 FT_ERROR(( "t42_parse_encoding: out of bounds!\n" )); 369 parser->root.error = T42_Err_Invalid_File_Format; 370 return; 371 } 372 } 373 374 /* if we have a number, then the encoding is an array, */ 375 /* and we must load it now */ 376 if ( (FT_Byte)( *cur - '0' ) < 10 ) 377 { 378 T1_Encoding encode = &face->type1.encoding; 379 FT_Int count, n; 380 PS_Table char_table = &loader->encoding_table; 381 FT_Memory memory = parser->root.memory; 382 FT_Error error; 383 384 385 /* read the number of entries in the encoding, should be 256 */ 386 count = T1_ToInt( parser ); 387 if ( parser->root.error ) 388 return; 389 390 /* we use a T1_Table to store our charnames */ 391 loader->num_chars = encode->num_chars = count; 392 if ( FT_NEW_ARRAY( encode->char_index, count ) || 393 FT_NEW_ARRAY( encode->char_name, count ) || 394 FT_SET_ERROR( psaux->ps_table_funcs->init( 395 char_table, count, memory ) ) ) 396 { 397 parser->root.error = error; 398 return; 399 } 400 401 /* We need to `zero' out encoding_table.elements */ 402 for ( n = 0; n < count; n++ ) 403 { 404 char* notdef = (char *)".notdef"; 405 406 407 T1_Add_Table( char_table, n, notdef, 8 ); 408 } 409 410 /* Now, we will need to read a record of the form */ 411 /* ... charcode /charname ... for each entry in our table */ 412 /* */ 413 /* We simply look for a number followed by an immediate */ 414 /* name. Note that this ignores correctly the sequence */ 415 /* that is often seen in type1 fonts: */ 416 /* */ 417 /* 0 1 255 { 1 index exch /.notdef put } for dup */ 418 /* */ 419 /* used to clean the encoding array before anything else. */ 420 /* */ 421 /* We stop when we encounter a `def'. */ 422 423 cur = parser->root.cursor; 424 limit = parser->root.limit; 425 n = 0; 426 427 for ( ; cur < limit; ) 428 { 429 FT_Byte c; 430 431 432 c = *cur; 433 434 /* we stop when we encounter a `def' */ 435 if ( c == 'd' && cur + 3 < limit ) 436 { 437 if ( cur[1] == 'e' && 438 cur[2] == 'f' && 439 t42_is_space( cur[-1] ) && 440 t42_is_space( cur[3] ) ) 441 { 442 FT_TRACE6(( "encoding end\n" )); 443 break; 444 } 445 } 446 447 /* otherwise, we must find a number before anything else */ 448 if ( (FT_Byte)( c - '0' ) < 10 ) 449 { 450 FT_Int charcode; 451 452 453 parser->root.cursor = cur; 454 charcode = T1_ToInt( parser ); 455 cur = parser->root.cursor; 456 457 /* skip whitespace */ 458 while ( cur < limit && t42_is_space( *cur ) ) 459 cur++; 460 461 if ( cur < limit && *cur == '/' ) 462 { 463 /* bingo, we have an immediate name -- it must be a */ 464 /* character name */ 465 FT_Byte* cur2 = cur + 1; 466 FT_Int len; 467 468 469 while ( cur2 < limit && t42_is_alpha( *cur2 ) ) 470 cur2++; 471 472 len = (FT_Int)( cur2 - cur - 1 ); 473 474 parser->root.error = T1_Add_Table( char_table, charcode, 475 cur + 1, len + 1 ); 476 char_table->elements[charcode][len] = '\0'; 477 if ( parser->root.error ) 478 return; 479 480 cur = cur2; 481 } 482 } 483 else 484 cur++; 485 } 486 487 face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; 488 parser->root.cursor = cur; 489 } 490 /* Otherwise, we should have either `StandardEncoding', */ 491 /* `ExpertEncoding', or `ISOLatin1Encoding' */ 492 else 493 { 494 if ( cur + 17 < limit && 495 ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) 496 face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; 497 498 else if ( cur + 15 < limit && 499 ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) 500 face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; 501 502 else if ( cur + 18 < limit && 503 ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) 504 face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; 505 506 else { 507 FT_ERROR(( "t42_parse_encoding: invalid token!\n" )); 508 parser->root.error = T42_Err_Invalid_File_Format; 509 } 510 } 511 } 512 513 514 static FT_UInt t42_hexval(FT_Byte v)515 t42_hexval( FT_Byte v ) 516 { 517 FT_UInt d; 518 519 d = (FT_UInt)( v - 'A' ); 520 if ( d < 6 ) 521 { 522 d += 10; 523 goto Exit; 524 } 525 526 d = (FT_UInt)( v - 'a' ); 527 if ( d < 6 ) 528 { 529 d += 10; 530 goto Exit; 531 } 532 533 d = (FT_UInt)( v - '0' ); 534 if ( d < 10 ) 535 goto Exit; 536 537 d = 0; 538 539 Exit: 540 return d; 541 } 542 543 544 static void t42_parse_sfnts(T42_Face face,T42_Loader loader)545 t42_parse_sfnts( T42_Face face, 546 T42_Loader loader ) 547 { 548 T42_Parser parser = &loader->parser; 549 FT_Memory memory = parser->root.memory; 550 FT_Byte* cur = parser->root.cursor; 551 FT_Byte* limit = parser->root.limit; 552 FT_Error error; 553 FT_Int num_tables = 0, status; 554 FT_ULong count, ttf_size = 0, string_size = 0; 555 FT_Bool in_string = 0; 556 FT_Byte v = 0; 557 558 559 /* The format is `/sfnts [ <...> <...> ... ] def' */ 560 561 while ( t42_is_space( *cur ) ) 562 cur++; 563 564 if (*cur++ == '[') 565 { 566 status = 0; 567 count = 0; 568 } 569 else 570 { 571 FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector!\n" )); 572 error = T42_Err_Invalid_File_Format; 573 goto Fail; 574 } 575 576 while ( cur < limit - 2 ) 577 { 578 while ( t42_is_space( *cur ) ) 579 cur++; 580 581 switch ( *cur ) 582 { 583 case ']': 584 parser->root.cursor = cur++; 585 return; 586 587 case '<': 588 in_string = 1; 589 string_size = 0; 590 cur++; 591 continue; 592 593 case '>': 594 if ( !in_string ) 595 { 596 FT_ERROR(( "t42_parse_sfnts: found unpaired `>'!\n" )); 597 error = T42_Err_Invalid_File_Format; 598 goto Fail; 599 } 600 601 /* A string can have, as a last byte, */ 602 /* a zero byte for padding. If so, ignore it */ 603 if ( ( v == 0 ) && ( string_size % 2 == 1 ) ) 604 count--; 605 in_string = 0; 606 cur++; 607 continue; 608 609 case '%': 610 if ( !in_string ) 611 { 612 /* Comment found; skip till end of line */ 613 while ( *cur != '\n' ) 614 cur++; 615 continue; 616 } 617 else 618 { 619 FT_ERROR(( "t42_parse_sfnts: found `%' in string!\n" )); 620 error = T42_Err_Invalid_File_Format; 621 goto Fail; 622 } 623 624 default: 625 if ( !ft_xdigit( *cur ) || !ft_xdigit( *(cur + 1) ) ) 626 { 627 FT_ERROR(( "t42_parse_sfnts: found non-hex characters in string" )); 628 error = T42_Err_Invalid_File_Format; 629 goto Fail; 630 } 631 632 v = (FT_Byte)( 16 * t42_hexval( cur[0] ) + t42_hexval( cur[1] ) ); 633 cur += 2; 634 string_size++; 635 } 636 637 switch ( status ) 638 { 639 case 0: /* The '[' was read, so load offset table, 12 bytes */ 640 if ( count < 12 ) 641 { 642 face->ttf_data[count++] = v; 643 continue; 644 } 645 else 646 { 647 num_tables = 16 * face->ttf_data[4] + face->ttf_data[5]; 648 status = 1; 649 ttf_size = 12 + 16 * num_tables; 650 651 if ( FT_REALLOC( face->ttf_data, 12, ttf_size ) ) 652 goto Fail; 653 } 654 /* No break, fall-through */ 655 656 case 1: /* The offset table is read; read now the table directory */ 657 if ( count < ttf_size ) 658 { 659 face->ttf_data[count++] = v; 660 continue; 661 } 662 else 663 { 664 int i; 665 FT_ULong len; 666 667 668 for ( i = 0; i < num_tables; i++ ) 669 { 670 FT_Byte* p = face->ttf_data + 12 + 16*i + 12; 671 672 len = FT_PEEK_ULONG( p ); 673 674 /* Pad to a 4-byte boundary length */ 675 ttf_size += ( len + 3 ) & ~3; 676 } 677 678 status = 2; 679 face->ttf_size = ttf_size; 680 681 if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables, 682 ttf_size + 1 ) ) 683 goto Fail; 684 } 685 /* No break, fall-through */ 686 687 case 2: /* We are reading normal tables; just swallow them */ 688 face->ttf_data[count++] = v; 689 690 } 691 } 692 693 /* If control reaches this point, the format was not valid */ 694 error = T42_Err_Invalid_File_Format; 695 696 Fail: 697 parser->root.error = error; 698 } 699 700 701 static void t42_parse_charstrings(T42_Face face,T42_Loader loader)702 t42_parse_charstrings( T42_Face face, 703 T42_Loader loader ) 704 { 705 T42_Parser parser = &loader->parser; 706 PS_Table code_table = &loader->charstrings; 707 PS_Table name_table = &loader->glyph_names; 708 FT_Memory memory = parser->root.memory; 709 FT_Error error; 710 711 PSAux_Service psaux = (PSAux_Service)face->psaux; 712 713 FT_Byte* cur; 714 FT_Byte* limit = parser->root.limit; 715 FT_Int n; 716 717 718 loader->num_glyphs = T1_ToInt( parser ); 719 if ( parser->root.error ) 720 return; 721 722 /* initialize tables */ 723 724 error = psaux->ps_table_funcs->init( code_table, 725 loader->num_glyphs, 726 memory ); 727 if ( error ) 728 goto Fail; 729 730 error = psaux->ps_table_funcs->init( name_table, 731 loader->num_glyphs, 732 memory ); 733 if ( error ) 734 goto Fail; 735 736 n = 0; 737 738 for (;;) 739 { 740 /* the format is simple: */ 741 /* `/glyphname' + index + def */ 742 /* */ 743 /* note that we stop when we find an `end' */ 744 /* */ 745 T1_Skip_Spaces( parser ); 746 747 cur = parser->root.cursor; 748 if ( cur >= limit ) 749 break; 750 751 /* we stop when we find an `end' keyword */ 752 if ( *cur == 'e' && 753 cur + 3 < limit && 754 cur[1] == 'n' && 755 cur[2] == 'd' ) 756 break; 757 758 if ( *cur != '/' ) 759 T1_Skip_Alpha( parser ); 760 else 761 { 762 FT_Byte* cur2 = cur + 1; 763 FT_Int len; 764 765 766 while ( cur2 < limit && t42_is_alpha( *cur2 ) ) 767 cur2++; 768 len = (FT_Int)( cur2 - cur - 1 ); 769 770 error = T1_Add_Table( name_table, n, cur + 1, len + 1 ); 771 if ( error ) 772 goto Fail; 773 774 /* add a trailing zero to the name table */ 775 name_table->elements[n][len] = '\0'; 776 777 parser->root.cursor = cur2; 778 T1_Skip_Spaces( parser ); 779 780 cur2 = cur = parser->root.cursor; 781 if ( cur >= limit ) 782 break; 783 784 while ( cur2 < limit && t42_is_alpha( *cur2 ) ) 785 cur2++; 786 len = (FT_Int)( cur2 - cur ); 787 788 error = T1_Add_Table( code_table, n, cur, len + 1 ); 789 if ( error ) 790 goto Fail; 791 792 code_table->elements[n][len] = '\0'; 793 794 n++; 795 if ( n >= loader->num_glyphs ) 796 break; 797 } 798 } 799 800 /* Index 0 must be a .notdef element */ 801 if ( ft_strcmp( (char *)name_table->elements[0], ".notdef" ) ) 802 { 803 FT_ERROR(( "t42_parse_charstrings: Index 0 is not `.notdef'!\n" )); 804 error = T42_Err_Invalid_File_Format; 805 goto Fail; 806 } 807 808 loader->num_glyphs = n; 809 return; 810 811 Fail: 812 parser->root.error = error; 813 } 814 815 816 static FT_Error t42_load_keyword(T42_Face face,T42_Loader loader,T1_Field field)817 t42_load_keyword( T42_Face face, 818 T42_Loader loader, 819 T1_Field field ) 820 { 821 FT_Error error; 822 void* dummy_object; 823 void** objects; 824 FT_UInt max_objects = 0; 825 826 827 /* if the keyword has a dedicated callback, call it */ 828 if ( field->type == T1_FIELD_TYPE_CALLBACK ) { 829 field->reader( (FT_Face)face, loader ); 830 error = loader->parser.root.error; 831 goto Exit; 832 } 833 834 /* now, the keyword is either a simple field, or a table of fields; */ 835 /* we are now going to take care of it */ 836 switch ( field->location ) 837 { 838 case T1_FIELD_LOCATION_FONT_INFO: 839 dummy_object = &face->type1.font_info; 840 objects = &dummy_object; 841 break; 842 843 default: 844 dummy_object = &face->type1; 845 objects = &dummy_object; 846 } 847 848 if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || 849 field->type == T1_FIELD_TYPE_FIXED_ARRAY ) 850 error = T1_Load_Field_Table( &loader->parser, field, 851 objects, max_objects, 0 ); 852 else 853 error = T1_Load_Field( &loader->parser, field, 854 objects, max_objects, 0 ); 855 856 Exit: 857 return error; 858 } 859 860 861 FT_LOCAL_DEF( FT_Error ) t42_parse_dict(T42_Face face,T42_Loader loader,FT_Byte * base,FT_Long size)862 t42_parse_dict( T42_Face face, 863 T42_Loader loader, 864 FT_Byte* base, 865 FT_Long size ) 866 { 867 T42_Parser parser = &loader->parser; 868 FT_Byte* cur = base; 869 FT_Byte* limit = cur + size; 870 FT_UInt n_keywords = sizeof ( t42_keywords ) / 871 sizeof ( t42_keywords[0] ); 872 873 874 parser->root.cursor = base; 875 parser->root.limit = base + size; 876 parser->root.error = 0; 877 878 for ( ; cur < limit; cur++ ) 879 { 880 /* look for `FontDirectory', which causes problems on some fonts */ 881 if ( *cur == 'F' && cur + 25 < limit && 882 ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 ) 883 { 884 FT_Byte* cur2; 885 886 887 /* skip the `FontDirectory' keyword */ 888 cur += 13; 889 cur2 = cur; 890 891 /* lookup the `known' keyword */ 892 while ( cur < limit && *cur != 'k' && 893 ft_strncmp( (char*)cur, "known", 5 ) ) 894 cur++; 895 896 if ( cur < limit ) 897 { 898 T1_TokenRec token; 899 900 901 /* skip the `known' keyword and the token following it */ 902 cur += 5; 903 loader->parser.root.cursor = cur; 904 T1_ToToken( &loader->parser, &token ); 905 906 /* if the last token was an array, skip it! */ 907 if ( token.type == T1_TOKEN_TYPE_ARRAY ) 908 cur2 = parser->root.cursor; 909 } 910 cur = cur2; 911 } 912 /* look for immediates */ 913 else if ( *cur == '/' && cur + 2 < limit ) 914 { 915 FT_Byte* cur2; 916 FT_UInt i, len; 917 918 919 cur++; 920 cur2 = cur; 921 while ( cur2 < limit && t42_is_alpha( *cur2 ) ) 922 cur2++; 923 924 len = (FT_UInt)( cur2 - cur ); 925 if ( len > 0 && len < 22 ) /* XXX What shall it this 22? */ 926 { 927 /* now, compare the immediate name to the keyword table */ 928 929 /* Loop through all known keywords */ 930 for ( i = 0; i < n_keywords; i++ ) 931 { 932 T1_Field keyword = (T1_Field)&t42_keywords[i]; 933 FT_Byte *name = (FT_Byte*)keyword->ident; 934 935 936 if ( !name ) 937 continue; 938 939 if ( ( len == ft_strlen( (const char *)name ) ) && 940 ( ft_memcmp( cur, name, len ) == 0 ) ) 941 { 942 /* we found it -- run the parsing callback! */ 943 parser->root.cursor = cur2; 944 T1_Skip_Spaces( parser ); 945 parser->root.error = t42_load_keyword(face, 946 loader, 947 keyword ); 948 if ( parser->root.error ) 949 return parser->root.error; 950 cur = parser->root.cursor; 951 break; 952 } 953 } 954 } 955 } 956 } 957 return parser->root.error; 958 } 959 960 961 FT_LOCAL_DEF( void ) t42_loader_init(T42_Loader loader,T42_Face face)962 t42_loader_init( T42_Loader loader, 963 T42_Face face ) 964 { 965 FT_UNUSED( face ); 966 967 FT_MEM_ZERO( loader, sizeof ( *loader ) ); 968 loader->num_glyphs = 0; 969 loader->num_chars = 0; 970 971 /* initialize the tables -- simply set their `init' field to 0 */ 972 loader->encoding_table.init = 0; 973 loader->charstrings.init = 0; 974 loader->glyph_names.init = 0; 975 } 976 977 978 FT_LOCAL_DEF( void ) t42_loader_done(T42_Loader loader)979 t42_loader_done( T42_Loader loader ) 980 { 981 T42_Parser parser = &loader->parser; 982 983 984 /* finalize tables */ 985 T1_Release_Table( &loader->encoding_table ); 986 T1_Release_Table( &loader->charstrings ); 987 T1_Release_Table( &loader->glyph_names ); 988 989 /* finalize parser */ 990 t42_parser_done( parser ); 991 } 992 993 994 /* END */ 995