1 /***************************************************************************/ 2 /* */ 3 /* ttload.c */ 4 /* */ 5 /* Load the basic TrueType tables, i.e., tables that can be either in */ 6 /* TTF or OTF fonts (body). */ 7 /* */ 8 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */ 9 /* 2010 by */ 10 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 11 /* */ 12 /* This file is part of the FreeType project, and may only be used, */ 13 /* modified, and distributed under the terms of the FreeType project */ 14 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 15 /* this file you indicate that you have read the license and */ 16 /* understand and accept it fully. */ 17 /* */ 18 /***************************************************************************/ 19 20 21 #include <ft2build.h> 22 #include FT_INTERNAL_DEBUG_H 23 #include FT_INTERNAL_STREAM_H 24 #include FT_TRUETYPE_TAGS_H 25 #include "ttload.h" 26 27 #include "sferrors.h" 28 29 30 /*************************************************************************/ 31 /* */ 32 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 33 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 34 /* messages during execution. */ 35 /* */ 36 #undef FT_COMPONENT 37 #define FT_COMPONENT trace_ttload 38 39 40 /*************************************************************************/ 41 /* */ 42 /* <Function> */ 43 /* tt_face_lookup_table */ 44 /* */ 45 /* <Description> */ 46 /* Looks for a TrueType table by name. */ 47 /* */ 48 /* <Input> */ 49 /* face :: A face object handle. */ 50 /* */ 51 /* tag :: The searched tag. */ 52 /* */ 53 /* <Return> */ 54 /* A pointer to the table directory entry. 0 if not found. */ 55 /* */ 56 FT_LOCAL_DEF( TT_Table ) tt_face_lookup_table(TT_Face face,FT_ULong tag)57 tt_face_lookup_table( TT_Face face, 58 FT_ULong tag ) 59 { 60 TT_Table entry; 61 TT_Table limit; 62 #ifdef FT_DEBUG_LEVEL_TRACE 63 FT_Bool zero_length = FALSE; 64 #endif 65 66 67 FT_TRACE4(( "tt_face_lookup_table: %08p, `%c%c%c%c' -- ", 68 face, 69 (FT_Char)( tag >> 24 ), 70 (FT_Char)( tag >> 16 ), 71 (FT_Char)( tag >> 8 ), 72 (FT_Char)( tag ) )); 73 74 entry = face->dir_tables; 75 limit = entry + face->num_tables; 76 77 for ( ; entry < limit; entry++ ) 78 { 79 /* For compatibility with Windows, we consider */ 80 /* zero-length tables the same as missing tables. */ 81 if ( entry->Tag == tag ) 82 { 83 if ( entry->Length != 0 ) 84 { 85 FT_TRACE4(( "found table.\n" )); 86 return entry; 87 } 88 #ifdef FT_DEBUG_LEVEL_TRACE 89 zero_length = TRUE; 90 #endif 91 } 92 } 93 94 #ifdef FT_DEBUG_LEVEL_TRACE 95 if ( zero_length ) 96 FT_TRACE4(( "ignoring empty table\n" )); 97 else 98 FT_TRACE4(( "could not find table\n" )); 99 #endif 100 101 return NULL; 102 } 103 104 105 /*************************************************************************/ 106 /* */ 107 /* <Function> */ 108 /* tt_face_goto_table */ 109 /* */ 110 /* <Description> */ 111 /* Looks for a TrueType table by name, then seek a stream to it. */ 112 /* */ 113 /* <Input> */ 114 /* face :: A face object handle. */ 115 /* */ 116 /* tag :: The searched tag. */ 117 /* */ 118 /* stream :: The stream to seek when the table is found. */ 119 /* */ 120 /* <Output> */ 121 /* length :: The length of the table if found, undefined otherwise. */ 122 /* */ 123 /* <Return> */ 124 /* FreeType error code. 0 means success. */ 125 /* */ 126 FT_LOCAL_DEF( FT_Error ) tt_face_goto_table(TT_Face face,FT_ULong tag,FT_Stream stream,FT_ULong * length)127 tt_face_goto_table( TT_Face face, 128 FT_ULong tag, 129 FT_Stream stream, 130 FT_ULong* length ) 131 { 132 TT_Table table; 133 FT_Error error; 134 135 136 table = tt_face_lookup_table( face, tag ); 137 if ( table ) 138 { 139 if ( length ) 140 *length = table->Length; 141 142 if ( FT_STREAM_SEEK( table->Offset ) ) 143 goto Exit; 144 } 145 else 146 error = SFNT_Err_Table_Missing; 147 148 Exit: 149 return error; 150 } 151 152 153 /* Here, we */ 154 /* */ 155 /* - check that `num_tables' is valid (and adjust it if necessary) */ 156 /* */ 157 /* - look for a `head' table, check its size, and parse it to check */ 158 /* whether its `magic' field is correctly set */ 159 /* */ 160 /* - errors (except errors returned by stream handling) */ 161 /* */ 162 /* SFNT_Err_Unknown_File_Format: */ 163 /* no table is defined in directory, it is not sfnt-wrapped */ 164 /* data */ 165 /* SFNT_Err_Table_Missing: */ 166 /* table directory is valid, but essential tables */ 167 /* (head/bhed/SING) are missing */ 168 /* */ 169 static FT_Error check_table_dir(SFNT_Header sfnt,FT_Stream stream)170 check_table_dir( SFNT_Header sfnt, 171 FT_Stream stream ) 172 { 173 FT_Error error; 174 FT_UShort nn, valid_entries = 0; 175 FT_UInt has_head = 0, has_sing = 0, has_meta = 0; 176 FT_ULong offset = sfnt->offset + 12; 177 178 static const FT_Frame_Field table_dir_entry_fields[] = 179 { 180 #undef FT_STRUCTURE 181 #define FT_STRUCTURE TT_TableRec 182 183 FT_FRAME_START( 16 ), 184 FT_FRAME_ULONG( Tag ), 185 FT_FRAME_ULONG( CheckSum ), 186 FT_FRAME_ULONG( Offset ), 187 FT_FRAME_ULONG( Length ), 188 FT_FRAME_END 189 }; 190 191 192 if ( FT_STREAM_SEEK( offset ) ) 193 goto Exit; 194 195 for ( nn = 0; nn < sfnt->num_tables; nn++ ) 196 { 197 TT_TableRec table; 198 199 200 if ( FT_STREAM_READ_FIELDS( table_dir_entry_fields, &table ) ) 201 { 202 nn--; 203 FT_TRACE2(( "check_table_dir:" 204 " can read only %d table%s in font (instead of %d)\n", 205 nn, nn == 1 ? "" : "s", sfnt->num_tables )); 206 sfnt->num_tables = nn; 207 break; 208 } 209 210 /* we ignore invalid tables */ 211 if ( table.Offset + table.Length > stream->size ) 212 { 213 FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn )); 214 continue; 215 } 216 else 217 valid_entries++; 218 219 if ( table.Tag == TTAG_head || table.Tag == TTAG_bhed ) 220 { 221 FT_UInt32 magic; 222 223 224 #ifndef TT_CONFIG_OPTION_EMBEDDED_BITMAPS 225 if ( table.Tag == TTAG_head ) 226 #endif 227 has_head = 1; 228 229 /* 230 * The table length should be 0x36, but certain font tools make it 231 * 0x38, so we will just check that it is greater. 232 * 233 * Note that according to the specification, the table must be 234 * padded to 32-bit lengths, but this doesn't apply to the value of 235 * its `Length' field! 236 * 237 */ 238 if ( table.Length < 0x36 ) 239 { 240 FT_TRACE2(( "check_table_dir: `head' table too small\n" )); 241 error = SFNT_Err_Table_Missing; 242 goto Exit; 243 } 244 245 if ( FT_STREAM_SEEK( table.Offset + 12 ) || 246 FT_READ_ULONG( magic ) ) 247 goto Exit; 248 249 if ( magic != 0x5F0F3CF5UL ) 250 { 251 FT_TRACE2(( "check_table_dir:" 252 " no magic number found in `head' table\n")); 253 error = SFNT_Err_Table_Missing; 254 goto Exit; 255 } 256 257 if ( FT_STREAM_SEEK( offset + ( nn + 1 ) * 16 ) ) 258 goto Exit; 259 } 260 else if ( table.Tag == TTAG_SING ) 261 has_sing = 1; 262 else if ( table.Tag == TTAG_META ) 263 has_meta = 1; 264 } 265 266 sfnt->num_tables = valid_entries; 267 268 if ( sfnt->num_tables == 0 ) 269 { 270 FT_TRACE2(( "check_table_dir: no tables found\n" )); 271 error = SFNT_Err_Unknown_File_Format; 272 goto Exit; 273 } 274 275 /* if `sing' and `meta' tables are present, there is no `head' table */ 276 if ( has_head || ( has_sing && has_meta ) ) 277 { 278 error = SFNT_Err_Ok; 279 goto Exit; 280 } 281 else 282 { 283 FT_TRACE2(( "check_table_dir:" )); 284 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS 285 FT_TRACE2(( " neither `head', `bhed', nor `sing' table found\n" )); 286 #else 287 FT_TRACE2(( " neither `head' nor `sing' table found\n" )); 288 #endif 289 error = SFNT_Err_Table_Missing; 290 } 291 292 Exit: 293 return error; 294 } 295 296 297 /*************************************************************************/ 298 /* */ 299 /* <Function> */ 300 /* tt_face_load_font_dir */ 301 /* */ 302 /* <Description> */ 303 /* Loads the header of a SFNT font file. */ 304 /* */ 305 /* <Input> */ 306 /* face :: A handle to the target face object. */ 307 /* */ 308 /* stream :: The input stream. */ 309 /* */ 310 /* <Output> */ 311 /* sfnt :: The SFNT header. */ 312 /* */ 313 /* <Return> */ 314 /* FreeType error code. 0 means success. */ 315 /* */ 316 /* <Note> */ 317 /* The stream cursor must be at the beginning of the font directory. */ 318 /* */ 319 FT_LOCAL_DEF( FT_Error ) tt_face_load_font_dir(TT_Face face,FT_Stream stream)320 tt_face_load_font_dir( TT_Face face, 321 FT_Stream stream ) 322 { 323 SFNT_HeaderRec sfnt; 324 FT_Error error; 325 FT_Memory memory = stream->memory; 326 TT_TableRec* entry; 327 FT_Int nn; 328 329 static const FT_Frame_Field offset_table_fields[] = 330 { 331 #undef FT_STRUCTURE 332 #define FT_STRUCTURE SFNT_HeaderRec 333 334 FT_FRAME_START( 8 ), 335 FT_FRAME_USHORT( num_tables ), 336 FT_FRAME_USHORT( search_range ), 337 FT_FRAME_USHORT( entry_selector ), 338 FT_FRAME_USHORT( range_shift ), 339 FT_FRAME_END 340 }; 341 342 343 FT_TRACE2(( "tt_face_load_font_dir: %08p\n", face )); 344 345 /* read the offset table */ 346 347 sfnt.offset = FT_STREAM_POS(); 348 349 if ( FT_READ_ULONG( sfnt.format_tag ) || 350 FT_STREAM_READ_FIELDS( offset_table_fields, &sfnt ) ) 351 goto Exit; 352 353 /* many fonts don't have these fields set correctly */ 354 #if 0 355 if ( sfnt.search_range != 1 << ( sfnt.entry_selector + 4 ) || 356 sfnt.search_range + sfnt.range_shift != sfnt.num_tables << 4 ) 357 return SFNT_Err_Unknown_File_Format; 358 #endif 359 360 /* load the table directory */ 361 362 FT_TRACE2(( "-- Number of tables: %10u\n", sfnt.num_tables )); 363 FT_TRACE2(( "-- Format version: 0x%08lx\n", sfnt.format_tag )); 364 365 /* check first */ 366 error = check_table_dir( &sfnt, stream ); 367 if ( error ) 368 { 369 FT_TRACE2(( "tt_face_load_font_dir:" 370 " invalid table directory for TrueType\n" )); 371 372 goto Exit; 373 } 374 375 face->num_tables = sfnt.num_tables; 376 face->format_tag = sfnt.format_tag; 377 378 if ( FT_QNEW_ARRAY( face->dir_tables, face->num_tables ) ) 379 goto Exit; 380 381 if ( FT_STREAM_SEEK( sfnt.offset + 12 ) || 382 FT_FRAME_ENTER( face->num_tables * 16L ) ) 383 goto Exit; 384 385 entry = face->dir_tables; 386 387 for ( nn = 0; nn < sfnt.num_tables; nn++ ) 388 { 389 entry->Tag = FT_GET_TAG4(); 390 entry->CheckSum = FT_GET_ULONG(); 391 entry->Offset = FT_GET_LONG(); 392 entry->Length = FT_GET_LONG(); 393 394 /* ignore invalid tables */ 395 if ( entry->Offset + entry->Length > stream->size ) 396 continue; 397 else 398 { 399 FT_TRACE2(( " %c%c%c%c - %08lx - %08lx\n", 400 (FT_Char)( entry->Tag >> 24 ), 401 (FT_Char)( entry->Tag >> 16 ), 402 (FT_Char)( entry->Tag >> 8 ), 403 (FT_Char)( entry->Tag ), 404 entry->Offset, 405 entry->Length )); 406 entry++; 407 } 408 } 409 410 FT_FRAME_EXIT(); 411 412 FT_TRACE2(( "table directory loaded\n\n" )); 413 414 Exit: 415 return error; 416 } 417 418 419 /*************************************************************************/ 420 /* */ 421 /* <Function> */ 422 /* tt_face_load_any */ 423 /* */ 424 /* <Description> */ 425 /* Loads any font table into client memory. */ 426 /* */ 427 /* <Input> */ 428 /* face :: The face object to look for. */ 429 /* */ 430 /* tag :: The tag of table to load. Use the value 0 if you want */ 431 /* to access the whole font file, else set this parameter */ 432 /* to a valid TrueType table tag that you can forge with */ 433 /* the MAKE_TT_TAG macro. */ 434 /* */ 435 /* offset :: The starting offset in the table (or the file if */ 436 /* tag == 0). */ 437 /* */ 438 /* length :: The address of the decision variable: */ 439 /* */ 440 /* If length == NULL: */ 441 /* Loads the whole table. Returns an error if */ 442 /* `offset' == 0! */ 443 /* */ 444 /* If *length == 0: */ 445 /* Exits immediately; returning the length of the given */ 446 /* table or of the font file, depending on the value of */ 447 /* `tag'. */ 448 /* */ 449 /* If *length != 0: */ 450 /* Loads the next `length' bytes of table or font, */ 451 /* starting at offset `offset' (in table or font too). */ 452 /* */ 453 /* <Output> */ 454 /* buffer :: The address of target buffer. */ 455 /* */ 456 /* <Return> */ 457 /* FreeType error code. 0 means success. */ 458 /* */ 459 FT_LOCAL_DEF( FT_Error ) tt_face_load_any(TT_Face face,FT_ULong tag,FT_Long offset,FT_Byte * buffer,FT_ULong * length)460 tt_face_load_any( TT_Face face, 461 FT_ULong tag, 462 FT_Long offset, 463 FT_Byte* buffer, 464 FT_ULong* length ) 465 { 466 FT_Error error; 467 FT_Stream stream; 468 TT_Table table; 469 FT_ULong size; 470 471 472 if ( tag != 0 ) 473 { 474 /* look for tag in font directory */ 475 table = tt_face_lookup_table( face, tag ); 476 if ( !table ) 477 { 478 error = SFNT_Err_Table_Missing; 479 goto Exit; 480 } 481 482 offset += table->Offset; 483 size = table->Length; 484 } 485 else 486 /* tag == 0 -- the user wants to access the font file directly */ 487 size = face->root.stream->size; 488 489 if ( length && *length == 0 ) 490 { 491 *length = size; 492 493 return SFNT_Err_Ok; 494 } 495 496 if ( length ) 497 size = *length; 498 499 stream = face->root.stream; 500 /* the `if' is syntactic sugar for picky compilers */ 501 if ( FT_STREAM_READ_AT( offset, buffer, size ) ) 502 goto Exit; 503 504 Exit: 505 return error; 506 } 507 508 509 /*************************************************************************/ 510 /* */ 511 /* <Function> */ 512 /* tt_face_load_generic_header */ 513 /* */ 514 /* <Description> */ 515 /* Loads the TrueType table `head' or `bhed'. */ 516 /* */ 517 /* <Input> */ 518 /* face :: A handle to the target face object. */ 519 /* */ 520 /* stream :: The input stream. */ 521 /* */ 522 /* <Return> */ 523 /* FreeType error code. 0 means success. */ 524 /* */ 525 static FT_Error tt_face_load_generic_header(TT_Face face,FT_Stream stream,FT_ULong tag)526 tt_face_load_generic_header( TT_Face face, 527 FT_Stream stream, 528 FT_ULong tag ) 529 { 530 FT_Error error; 531 TT_Header* header; 532 533 static const FT_Frame_Field header_fields[] = 534 { 535 #undef FT_STRUCTURE 536 #define FT_STRUCTURE TT_Header 537 538 FT_FRAME_START( 54 ), 539 FT_FRAME_ULONG ( Table_Version ), 540 FT_FRAME_ULONG ( Font_Revision ), 541 FT_FRAME_LONG ( CheckSum_Adjust ), 542 FT_FRAME_LONG ( Magic_Number ), 543 FT_FRAME_USHORT( Flags ), 544 FT_FRAME_USHORT( Units_Per_EM ), 545 FT_FRAME_LONG ( Created[0] ), 546 FT_FRAME_LONG ( Created[1] ), 547 FT_FRAME_LONG ( Modified[0] ), 548 FT_FRAME_LONG ( Modified[1] ), 549 FT_FRAME_SHORT ( xMin ), 550 FT_FRAME_SHORT ( yMin ), 551 FT_FRAME_SHORT ( xMax ), 552 FT_FRAME_SHORT ( yMax ), 553 FT_FRAME_USHORT( Mac_Style ), 554 FT_FRAME_USHORT( Lowest_Rec_PPEM ), 555 FT_FRAME_SHORT ( Font_Direction ), 556 FT_FRAME_SHORT ( Index_To_Loc_Format ), 557 FT_FRAME_SHORT ( Glyph_Data_Format ), 558 FT_FRAME_END 559 }; 560 561 562 error = face->goto_table( face, tag, stream, 0 ); 563 if ( error ) 564 goto Exit; 565 566 header = &face->header; 567 568 if ( FT_STREAM_READ_FIELDS( header_fields, header ) ) 569 goto Exit; 570 571 FT_TRACE3(( "Units per EM: %4u\n", header->Units_Per_EM )); 572 FT_TRACE3(( "IndexToLoc: %4d\n", header->Index_To_Loc_Format )); 573 574 Exit: 575 return error; 576 } 577 578 579 FT_LOCAL_DEF( FT_Error ) tt_face_load_head(TT_Face face,FT_Stream stream)580 tt_face_load_head( TT_Face face, 581 FT_Stream stream ) 582 { 583 return tt_face_load_generic_header( face, stream, TTAG_head ); 584 } 585 586 587 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS 588 589 FT_LOCAL_DEF( FT_Error ) tt_face_load_bhed(TT_Face face,FT_Stream stream)590 tt_face_load_bhed( TT_Face face, 591 FT_Stream stream ) 592 { 593 return tt_face_load_generic_header( face, stream, TTAG_bhed ); 594 } 595 596 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ 597 598 599 /*************************************************************************/ 600 /* */ 601 /* <Function> */ 602 /* tt_face_load_max_profile */ 603 /* */ 604 /* <Description> */ 605 /* Loads the maximum profile into a face object. */ 606 /* */ 607 /* <Input> */ 608 /* face :: A handle to the target face object. */ 609 /* */ 610 /* stream :: The input stream. */ 611 /* */ 612 /* <Return> */ 613 /* FreeType error code. 0 means success. */ 614 /* */ 615 FT_LOCAL_DEF( FT_Error ) tt_face_load_maxp(TT_Face face,FT_Stream stream)616 tt_face_load_maxp( TT_Face face, 617 FT_Stream stream ) 618 { 619 FT_Error error; 620 TT_MaxProfile* maxProfile = &face->max_profile; 621 622 const FT_Frame_Field maxp_fields[] = 623 { 624 #undef FT_STRUCTURE 625 #define FT_STRUCTURE TT_MaxProfile 626 627 FT_FRAME_START( 6 ), 628 FT_FRAME_LONG ( version ), 629 FT_FRAME_USHORT( numGlyphs ), 630 FT_FRAME_END 631 }; 632 633 const FT_Frame_Field maxp_fields_extra[] = 634 { 635 FT_FRAME_START( 26 ), 636 FT_FRAME_USHORT( maxPoints ), 637 FT_FRAME_USHORT( maxContours ), 638 FT_FRAME_USHORT( maxCompositePoints ), 639 FT_FRAME_USHORT( maxCompositeContours ), 640 FT_FRAME_USHORT( maxZones ), 641 FT_FRAME_USHORT( maxTwilightPoints ), 642 FT_FRAME_USHORT( maxStorage ), 643 FT_FRAME_USHORT( maxFunctionDefs ), 644 FT_FRAME_USHORT( maxInstructionDefs ), 645 FT_FRAME_USHORT( maxStackElements ), 646 FT_FRAME_USHORT( maxSizeOfInstructions ), 647 FT_FRAME_USHORT( maxComponentElements ), 648 FT_FRAME_USHORT( maxComponentDepth ), 649 FT_FRAME_END 650 }; 651 652 653 error = face->goto_table( face, TTAG_maxp, stream, 0 ); 654 if ( error ) 655 goto Exit; 656 657 if ( FT_STREAM_READ_FIELDS( maxp_fields, maxProfile ) ) 658 goto Exit; 659 660 maxProfile->maxPoints = 0; 661 maxProfile->maxContours = 0; 662 maxProfile->maxCompositePoints = 0; 663 maxProfile->maxCompositeContours = 0; 664 maxProfile->maxZones = 0; 665 maxProfile->maxTwilightPoints = 0; 666 maxProfile->maxStorage = 0; 667 maxProfile->maxFunctionDefs = 0; 668 maxProfile->maxInstructionDefs = 0; 669 maxProfile->maxStackElements = 0; 670 maxProfile->maxSizeOfInstructions = 0; 671 maxProfile->maxComponentElements = 0; 672 maxProfile->maxComponentDepth = 0; 673 674 if ( maxProfile->version >= 0x10000L ) 675 { 676 if ( FT_STREAM_READ_FIELDS( maxp_fields_extra, maxProfile ) ) 677 goto Exit; 678 679 /* XXX: an adjustment that is necessary to load certain */ 680 /* broken fonts like `Keystrokes MT' :-( */ 681 /* */ 682 /* We allocate 64 function entries by default when */ 683 /* the maxFunctionDefs field is null. */ 684 685 if ( maxProfile->maxFunctionDefs == 0 ) 686 maxProfile->maxFunctionDefs = 64; 687 688 /* we add 4 phantom points later */ 689 if ( maxProfile->maxTwilightPoints > ( 0xFFFFU - 4 ) ) 690 { 691 FT_TRACE0(( "tt_face_load_maxp:" 692 " too much twilight points in `maxp' table;\n" 693 " " 694 " some glyphs might be rendered incorrectly\n" )); 695 696 maxProfile->maxTwilightPoints = 0xFFFFU - 4; 697 } 698 699 /* we arbitrarily limit recursion to avoid stack exhaustion */ 700 if ( maxProfile->maxComponentDepth > 100 ) 701 { 702 FT_TRACE0(( "tt_face_load_maxp:" 703 " abnormally large component depth (%d) set to 100\n", 704 maxProfile->maxComponentDepth )); 705 maxProfile->maxComponentDepth = 100; 706 } 707 } 708 709 FT_TRACE3(( "numGlyphs: %u\n", maxProfile->numGlyphs )); 710 711 Exit: 712 return error; 713 } 714 715 716 /*************************************************************************/ 717 /* */ 718 /* <Function> */ 719 /* tt_face_load_names */ 720 /* */ 721 /* <Description> */ 722 /* Loads the name records. */ 723 /* */ 724 /* <Input> */ 725 /* face :: A handle to the target face object. */ 726 /* */ 727 /* stream :: The input stream. */ 728 /* */ 729 /* <Return> */ 730 /* FreeType error code. 0 means success. */ 731 /* */ 732 FT_LOCAL_DEF( FT_Error ) tt_face_load_name(TT_Face face,FT_Stream stream)733 tt_face_load_name( TT_Face face, 734 FT_Stream stream ) 735 { 736 FT_Error error; 737 FT_Memory memory = stream->memory; 738 FT_ULong table_pos, table_len; 739 FT_ULong storage_start, storage_limit; 740 FT_UInt count; 741 TT_NameTable table; 742 743 static const FT_Frame_Field name_table_fields[] = 744 { 745 #undef FT_STRUCTURE 746 #define FT_STRUCTURE TT_NameTableRec 747 748 FT_FRAME_START( 6 ), 749 FT_FRAME_USHORT( format ), 750 FT_FRAME_USHORT( numNameRecords ), 751 FT_FRAME_USHORT( storageOffset ), 752 FT_FRAME_END 753 }; 754 755 static const FT_Frame_Field name_record_fields[] = 756 { 757 #undef FT_STRUCTURE 758 #define FT_STRUCTURE TT_NameEntryRec 759 760 /* no FT_FRAME_START */ 761 FT_FRAME_USHORT( platformID ), 762 FT_FRAME_USHORT( encodingID ), 763 FT_FRAME_USHORT( languageID ), 764 FT_FRAME_USHORT( nameID ), 765 FT_FRAME_USHORT( stringLength ), 766 FT_FRAME_USHORT( stringOffset ), 767 FT_FRAME_END 768 }; 769 770 771 table = &face->name_table; 772 table->stream = stream; 773 774 error = face->goto_table( face, TTAG_name, stream, &table_len ); 775 if ( error ) 776 goto Exit; 777 778 table_pos = FT_STREAM_POS(); 779 780 781 if ( FT_STREAM_READ_FIELDS( name_table_fields, table ) ) 782 goto Exit; 783 784 /* Some popular Asian fonts have an invalid `storageOffset' value */ 785 /* (it should be at least "6 + 12*num_names"). However, the string */ 786 /* offsets, computed as "storageOffset + entry->stringOffset", are */ 787 /* valid pointers within the name table... */ 788 /* */ 789 /* We thus can't check `storageOffset' right now. */ 790 /* */ 791 storage_start = table_pos + 6 + 12*table->numNameRecords; 792 storage_limit = table_pos + table_len; 793 794 if ( storage_start > storage_limit ) 795 { 796 FT_ERROR(( "tt_face_load_name: invalid `name' table\n" )); 797 error = SFNT_Err_Name_Table_Missing; 798 goto Exit; 799 } 800 801 /* Allocate the array of name records. */ 802 count = table->numNameRecords; 803 table->numNameRecords = 0; 804 805 if ( FT_NEW_ARRAY( table->names, count ) || 806 FT_FRAME_ENTER( count * 12 ) ) 807 goto Exit; 808 809 /* Load the name records and determine how much storage is needed */ 810 /* to hold the strings themselves. */ 811 { 812 TT_NameEntryRec* entry = table->names; 813 814 815 for ( ; count > 0; count-- ) 816 { 817 if ( FT_STREAM_READ_FIELDS( name_record_fields, entry ) ) 818 continue; 819 820 /* check that the name is not empty */ 821 if ( entry->stringLength == 0 ) 822 continue; 823 824 /* check that the name string is within the table */ 825 entry->stringOffset += table_pos + table->storageOffset; 826 if ( entry->stringOffset < storage_start || 827 entry->stringOffset + entry->stringLength > storage_limit ) 828 { 829 /* invalid entry - ignore it */ 830 entry->stringOffset = 0; 831 entry->stringLength = 0; 832 continue; 833 } 834 835 entry++; 836 } 837 838 table->numNameRecords = (FT_UInt)( entry - table->names ); 839 } 840 841 FT_FRAME_EXIT(); 842 843 /* everything went well, update face->num_names */ 844 face->num_names = (FT_UShort) table->numNameRecords; 845 846 Exit: 847 return error; 848 } 849 850 851 /*************************************************************************/ 852 /* */ 853 /* <Function> */ 854 /* tt_face_free_names */ 855 /* */ 856 /* <Description> */ 857 /* Frees the name records. */ 858 /* */ 859 /* <Input> */ 860 /* face :: A handle to the target face object. */ 861 /* */ 862 FT_LOCAL_DEF( void ) tt_face_free_name(TT_Face face)863 tt_face_free_name( TT_Face face ) 864 { 865 FT_Memory memory = face->root.driver->root.memory; 866 TT_NameTable table = &face->name_table; 867 TT_NameEntry entry = table->names; 868 FT_UInt count = table->numNameRecords; 869 870 871 if ( table->names ) 872 { 873 for ( ; count > 0; count--, entry++ ) 874 { 875 FT_FREE( entry->string ); 876 entry->stringLength = 0; 877 } 878 879 /* free strings table */ 880 FT_FREE( table->names ); 881 } 882 883 table->numNameRecords = 0; 884 table->format = 0; 885 table->storageOffset = 0; 886 } 887 888 889 /*************************************************************************/ 890 /* */ 891 /* <Function> */ 892 /* tt_face_load_cmap */ 893 /* */ 894 /* <Description> */ 895 /* Loads the cmap directory in a face object. The cmaps themselves */ 896 /* are loaded on demand in the `ttcmap.c' module. */ 897 /* */ 898 /* <Input> */ 899 /* face :: A handle to the target face object. */ 900 /* */ 901 /* stream :: A handle to the input stream. */ 902 /* */ 903 /* <Return> */ 904 /* FreeType error code. 0 means success. */ 905 /* */ 906 907 FT_LOCAL_DEF( FT_Error ) tt_face_load_cmap(TT_Face face,FT_Stream stream)908 tt_face_load_cmap( TT_Face face, 909 FT_Stream stream ) 910 { 911 FT_Error error; 912 913 914 error = face->goto_table( face, TTAG_cmap, stream, &face->cmap_size ); 915 if ( error ) 916 goto Exit; 917 918 if ( FT_FRAME_EXTRACT( face->cmap_size, face->cmap_table ) ) 919 face->cmap_size = 0; 920 921 Exit: 922 return error; 923 } 924 925 926 927 /*************************************************************************/ 928 /* */ 929 /* <Function> */ 930 /* tt_face_load_os2 */ 931 /* */ 932 /* <Description> */ 933 /* Loads the OS2 table. */ 934 /* */ 935 /* <Input> */ 936 /* face :: A handle to the target face object. */ 937 /* */ 938 /* stream :: A handle to the input stream. */ 939 /* */ 940 /* <Return> */ 941 /* FreeType error code. 0 means success. */ 942 /* */ 943 FT_LOCAL_DEF( FT_Error ) tt_face_load_os2(TT_Face face,FT_Stream stream)944 tt_face_load_os2( TT_Face face, 945 FT_Stream stream ) 946 { 947 FT_Error error; 948 TT_OS2* os2; 949 950 const FT_Frame_Field os2_fields[] = 951 { 952 #undef FT_STRUCTURE 953 #define FT_STRUCTURE TT_OS2 954 955 FT_FRAME_START( 78 ), 956 FT_FRAME_USHORT( version ), 957 FT_FRAME_SHORT ( xAvgCharWidth ), 958 FT_FRAME_USHORT( usWeightClass ), 959 FT_FRAME_USHORT( usWidthClass ), 960 FT_FRAME_SHORT ( fsType ), 961 FT_FRAME_SHORT ( ySubscriptXSize ), 962 FT_FRAME_SHORT ( ySubscriptYSize ), 963 FT_FRAME_SHORT ( ySubscriptXOffset ), 964 FT_FRAME_SHORT ( ySubscriptYOffset ), 965 FT_FRAME_SHORT ( ySuperscriptXSize ), 966 FT_FRAME_SHORT ( ySuperscriptYSize ), 967 FT_FRAME_SHORT ( ySuperscriptXOffset ), 968 FT_FRAME_SHORT ( ySuperscriptYOffset ), 969 FT_FRAME_SHORT ( yStrikeoutSize ), 970 FT_FRAME_SHORT ( yStrikeoutPosition ), 971 FT_FRAME_SHORT ( sFamilyClass ), 972 FT_FRAME_BYTE ( panose[0] ), 973 FT_FRAME_BYTE ( panose[1] ), 974 FT_FRAME_BYTE ( panose[2] ), 975 FT_FRAME_BYTE ( panose[3] ), 976 FT_FRAME_BYTE ( panose[4] ), 977 FT_FRAME_BYTE ( panose[5] ), 978 FT_FRAME_BYTE ( panose[6] ), 979 FT_FRAME_BYTE ( panose[7] ), 980 FT_FRAME_BYTE ( panose[8] ), 981 FT_FRAME_BYTE ( panose[9] ), 982 FT_FRAME_ULONG ( ulUnicodeRange1 ), 983 FT_FRAME_ULONG ( ulUnicodeRange2 ), 984 FT_FRAME_ULONG ( ulUnicodeRange3 ), 985 FT_FRAME_ULONG ( ulUnicodeRange4 ), 986 FT_FRAME_BYTE ( achVendID[0] ), 987 FT_FRAME_BYTE ( achVendID[1] ), 988 FT_FRAME_BYTE ( achVendID[2] ), 989 FT_FRAME_BYTE ( achVendID[3] ), 990 991 FT_FRAME_USHORT( fsSelection ), 992 FT_FRAME_USHORT( usFirstCharIndex ), 993 FT_FRAME_USHORT( usLastCharIndex ), 994 FT_FRAME_SHORT ( sTypoAscender ), 995 FT_FRAME_SHORT ( sTypoDescender ), 996 FT_FRAME_SHORT ( sTypoLineGap ), 997 FT_FRAME_USHORT( usWinAscent ), 998 FT_FRAME_USHORT( usWinDescent ), 999 FT_FRAME_END 1000 }; 1001 1002 const FT_Frame_Field os2_fields_extra[] = 1003 { 1004 FT_FRAME_START( 8 ), 1005 FT_FRAME_ULONG( ulCodePageRange1 ), 1006 FT_FRAME_ULONG( ulCodePageRange2 ), 1007 FT_FRAME_END 1008 }; 1009 1010 const FT_Frame_Field os2_fields_extra2[] = 1011 { 1012 FT_FRAME_START( 10 ), 1013 FT_FRAME_SHORT ( sxHeight ), 1014 FT_FRAME_SHORT ( sCapHeight ), 1015 FT_FRAME_USHORT( usDefaultChar ), 1016 FT_FRAME_USHORT( usBreakChar ), 1017 FT_FRAME_USHORT( usMaxContext ), 1018 FT_FRAME_END 1019 }; 1020 1021 1022 /* We now support old Mac fonts where the OS/2 table doesn't */ 1023 /* exist. Simply put, we set the `version' field to 0xFFFF */ 1024 /* and test this value each time we need to access the table. */ 1025 error = face->goto_table( face, TTAG_OS2, stream, 0 ); 1026 if ( error ) 1027 goto Exit; 1028 1029 os2 = &face->os2; 1030 1031 if ( FT_STREAM_READ_FIELDS( os2_fields, os2 ) ) 1032 goto Exit; 1033 1034 os2->ulCodePageRange1 = 0; 1035 os2->ulCodePageRange2 = 0; 1036 os2->sxHeight = 0; 1037 os2->sCapHeight = 0; 1038 os2->usDefaultChar = 0; 1039 os2->usBreakChar = 0; 1040 os2->usMaxContext = 0; 1041 1042 if ( os2->version >= 0x0001 ) 1043 { 1044 /* only version 1 tables */ 1045 if ( FT_STREAM_READ_FIELDS( os2_fields_extra, os2 ) ) 1046 goto Exit; 1047 1048 if ( os2->version >= 0x0002 ) 1049 { 1050 /* only version 2 tables */ 1051 if ( FT_STREAM_READ_FIELDS( os2_fields_extra2, os2 ) ) 1052 goto Exit; 1053 } 1054 } 1055 1056 FT_TRACE3(( "sTypoAscender: %4d\n", os2->sTypoAscender )); 1057 FT_TRACE3(( "sTypoDescender: %4d\n", os2->sTypoDescender )); 1058 FT_TRACE3(( "usWinAscent: %4u\n", os2->usWinAscent )); 1059 FT_TRACE3(( "usWinDescent: %4u\n", os2->usWinDescent )); 1060 FT_TRACE3(( "fsSelection: 0x%2x\n", os2->fsSelection )); 1061 1062 Exit: 1063 return error; 1064 } 1065 1066 1067 /*************************************************************************/ 1068 /* */ 1069 /* <Function> */ 1070 /* tt_face_load_postscript */ 1071 /* */ 1072 /* <Description> */ 1073 /* Loads the Postscript table. */ 1074 /* */ 1075 /* <Input> */ 1076 /* face :: A handle to the target face object. */ 1077 /* */ 1078 /* stream :: A handle to the input stream. */ 1079 /* */ 1080 /* <Return> */ 1081 /* FreeType error code. 0 means success. */ 1082 /* */ 1083 FT_LOCAL_DEF( FT_Error ) tt_face_load_post(TT_Face face,FT_Stream stream)1084 tt_face_load_post( TT_Face face, 1085 FT_Stream stream ) 1086 { 1087 FT_Error error; 1088 TT_Postscript* post = &face->postscript; 1089 1090 static const FT_Frame_Field post_fields[] = 1091 { 1092 #undef FT_STRUCTURE 1093 #define FT_STRUCTURE TT_Postscript 1094 1095 FT_FRAME_START( 32 ), 1096 FT_FRAME_ULONG( FormatType ), 1097 FT_FRAME_ULONG( italicAngle ), 1098 FT_FRAME_SHORT( underlinePosition ), 1099 FT_FRAME_SHORT( underlineThickness ), 1100 FT_FRAME_ULONG( isFixedPitch ), 1101 FT_FRAME_ULONG( minMemType42 ), 1102 FT_FRAME_ULONG( maxMemType42 ), 1103 FT_FRAME_ULONG( minMemType1 ), 1104 FT_FRAME_ULONG( maxMemType1 ), 1105 FT_FRAME_END 1106 }; 1107 1108 1109 error = face->goto_table( face, TTAG_post, stream, 0 ); 1110 if ( error ) 1111 return error; 1112 1113 if ( FT_STREAM_READ_FIELDS( post_fields, post ) ) 1114 return error; 1115 1116 /* we don't load the glyph names, we do that in another */ 1117 /* module (ttpost). */ 1118 1119 FT_TRACE3(( "FormatType: 0x%x\n", post->FormatType )); 1120 FT_TRACE3(( "isFixedPitch: %s\n", post->isFixedPitch 1121 ? " yes" : " no" )); 1122 1123 return SFNT_Err_Ok; 1124 } 1125 1126 1127 /*************************************************************************/ 1128 /* */ 1129 /* <Function> */ 1130 /* tt_face_load_pclt */ 1131 /* */ 1132 /* <Description> */ 1133 /* Loads the PCL 5 Table. */ 1134 /* */ 1135 /* <Input> */ 1136 /* face :: A handle to the target face object. */ 1137 /* */ 1138 /* stream :: A handle to the input stream. */ 1139 /* */ 1140 /* <Return> */ 1141 /* FreeType error code. 0 means success. */ 1142 /* */ 1143 FT_LOCAL_DEF( FT_Error ) tt_face_load_pclt(TT_Face face,FT_Stream stream)1144 tt_face_load_pclt( TT_Face face, 1145 FT_Stream stream ) 1146 { 1147 static const FT_Frame_Field pclt_fields[] = 1148 { 1149 #undef FT_STRUCTURE 1150 #define FT_STRUCTURE TT_PCLT 1151 1152 FT_FRAME_START( 54 ), 1153 FT_FRAME_ULONG ( Version ), 1154 FT_FRAME_ULONG ( FontNumber ), 1155 FT_FRAME_USHORT( Pitch ), 1156 FT_FRAME_USHORT( xHeight ), 1157 FT_FRAME_USHORT( Style ), 1158 FT_FRAME_USHORT( TypeFamily ), 1159 FT_FRAME_USHORT( CapHeight ), 1160 FT_FRAME_BYTES ( TypeFace, 16 ), 1161 FT_FRAME_BYTES ( CharacterComplement, 8 ), 1162 FT_FRAME_BYTES ( FileName, 6 ), 1163 FT_FRAME_CHAR ( StrokeWeight ), 1164 FT_FRAME_CHAR ( WidthType ), 1165 FT_FRAME_BYTE ( SerifStyle ), 1166 FT_FRAME_BYTE ( Reserved ), 1167 FT_FRAME_END 1168 }; 1169 1170 FT_Error error; 1171 TT_PCLT* pclt = &face->pclt; 1172 1173 1174 /* optional table */ 1175 error = face->goto_table( face, TTAG_PCLT, stream, 0 ); 1176 if ( error ) 1177 goto Exit; 1178 1179 if ( FT_STREAM_READ_FIELDS( pclt_fields, pclt ) ) 1180 goto Exit; 1181 1182 Exit: 1183 return error; 1184 } 1185 1186 1187 /*************************************************************************/ 1188 /* */ 1189 /* <Function> */ 1190 /* tt_face_load_gasp */ 1191 /* */ 1192 /* <Description> */ 1193 /* Loads the `gasp' table into a face object. */ 1194 /* */ 1195 /* <Input> */ 1196 /* face :: A handle to the target face object. */ 1197 /* */ 1198 /* stream :: The input stream. */ 1199 /* */ 1200 /* <Return> */ 1201 /* FreeType error code. 0 means success. */ 1202 /* */ 1203 FT_LOCAL_DEF( FT_Error ) tt_face_load_gasp(TT_Face face,FT_Stream stream)1204 tt_face_load_gasp( TT_Face face, 1205 FT_Stream stream ) 1206 { 1207 FT_Error error; 1208 FT_Memory memory = stream->memory; 1209 1210 FT_UInt j,num_ranges; 1211 TT_GaspRange gaspranges; 1212 1213 1214 /* the gasp table is optional */ 1215 error = face->goto_table( face, TTAG_gasp, stream, 0 ); 1216 if ( error ) 1217 goto Exit; 1218 1219 if ( FT_FRAME_ENTER( 4L ) ) 1220 goto Exit; 1221 1222 face->gasp.version = FT_GET_USHORT(); 1223 face->gasp.numRanges = FT_GET_USHORT(); 1224 1225 FT_FRAME_EXIT(); 1226 1227 /* only support versions 0 and 1 of the table */ 1228 if ( face->gasp.version >= 2 ) 1229 { 1230 face->gasp.numRanges = 0; 1231 error = SFNT_Err_Invalid_Table; 1232 goto Exit; 1233 } 1234 1235 num_ranges = face->gasp.numRanges; 1236 FT_TRACE3(( "numRanges: %u\n", num_ranges )); 1237 1238 if ( FT_QNEW_ARRAY( gaspranges, num_ranges ) || 1239 FT_FRAME_ENTER( num_ranges * 4L ) ) 1240 goto Exit; 1241 1242 face->gasp.gaspRanges = gaspranges; 1243 1244 for ( j = 0; j < num_ranges; j++ ) 1245 { 1246 gaspranges[j].maxPPEM = FT_GET_USHORT(); 1247 gaspranges[j].gaspFlag = FT_GET_USHORT(); 1248 1249 FT_TRACE3(( "gaspRange %d: rangeMaxPPEM %5d, rangeGaspBehavior 0x%x\n", 1250 j, 1251 gaspranges[j].maxPPEM, 1252 gaspranges[j].gaspFlag )); 1253 } 1254 1255 FT_FRAME_EXIT(); 1256 1257 Exit: 1258 return error; 1259 } 1260 1261 1262 /* END */ 1263