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