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-2019 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 ) tt_face_lookup_table(TT_Face face,FT_ULong tag)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 ) tt_face_goto_table(TT_Face face,FT_ULong tag,FT_Stream stream,FT_ULong * length)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 check_table_dir(SFNT_Header sfnt,FT_Stream stream,FT_UShort * valid)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 ) tt_face_load_font_dir(TT_Face face,FT_Stream stream)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 valid_entries = sfnt.num_tables; 401 402 face->num_tables = valid_entries; 403 face->format_tag = sfnt.format_tag; 404 405 if ( FT_QNEW_ARRAY( face->dir_tables, face->num_tables ) ) 406 goto Exit; 407 408 if ( FT_STREAM_SEEK( sfnt.offset + 12 ) || 409 FT_FRAME_ENTER( sfnt.num_tables * 16L ) ) 410 goto Exit; 411 412 FT_TRACE2(( "\n" 413 " tag offset length checksum\n" 414 " ----------------------------------\n" )); 415 416 valid_entries = 0; 417 for ( nn = 0; nn < sfnt.num_tables; nn++ ) 418 { 419 TT_TableRec entry; 420 FT_UShort i; 421 FT_Bool duplicate; 422 423 424 entry.Tag = FT_GET_TAG4(); 425 entry.CheckSum = FT_GET_ULONG(); 426 entry.Offset = FT_GET_ULONG(); 427 entry.Length = FT_GET_ULONG(); 428 429 /* ignore invalid tables that can't be sanitized */ 430 431 if ( entry.Offset > stream->size ) 432 continue; 433 else if ( entry.Length > stream->size - entry.Offset ) 434 { 435 if ( entry.Tag == TTAG_hmtx || 436 entry.Tag == TTAG_vmtx ) 437 { 438 #ifdef FT_DEBUG_LEVEL_TRACE 439 FT_ULong old_length = entry.Length; 440 #endif 441 442 443 /* make metrics table length a multiple of 4 */ 444 entry.Length = ( stream->size - entry.Offset ) & ~3U; 445 446 FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx" 447 " (sanitized; original length %08lx)", 448 (FT_Char)( entry.Tag >> 24 ), 449 (FT_Char)( entry.Tag >> 16 ), 450 (FT_Char)( entry.Tag >> 8 ), 451 (FT_Char)( entry.Tag ), 452 entry.Offset, 453 entry.Length, 454 entry.CheckSum, 455 old_length )); 456 } 457 else 458 continue; 459 } 460 #ifdef FT_DEBUG_LEVEL_TRACE 461 else 462 FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx", 463 (FT_Char)( entry.Tag >> 24 ), 464 (FT_Char)( entry.Tag >> 16 ), 465 (FT_Char)( entry.Tag >> 8 ), 466 (FT_Char)( entry.Tag ), 467 entry.Offset, 468 entry.Length, 469 entry.CheckSum )); 470 #endif 471 472 /* ignore duplicate tables – the first one wins */ 473 duplicate = 0; 474 for ( i = 0; i < valid_entries; i++ ) 475 { 476 if ( face->dir_tables[i].Tag == entry.Tag ) 477 { 478 duplicate = 1; 479 break; 480 } 481 } 482 if ( duplicate ) 483 { 484 FT_TRACE2(( " (duplicate, ignored)\n" )); 485 continue; 486 } 487 else 488 { 489 FT_TRACE2(( "\n" )); 490 491 /* we finally have a valid entry */ 492 face->dir_tables[valid_entries++] = entry; 493 } 494 } 495 496 /* final adjustment to number of tables */ 497 face->num_tables = valid_entries; 498 499 FT_FRAME_EXIT(); 500 501 FT_TRACE2(( "table directory loaded\n\n" )); 502 503 Exit: 504 return error; 505 } 506 507 508 /************************************************************************** 509 * 510 * @Function: 511 * tt_face_load_any 512 * 513 * @Description: 514 * Loads any font table into client memory. 515 * 516 * @Input: 517 * face :: 518 * The face object to look for. 519 * 520 * tag :: 521 * The tag of table to load. Use the value 0 if you want 522 * to access the whole font file, else set this parameter 523 * to a valid TrueType table tag that you can forge with 524 * the MAKE_TT_TAG macro. 525 * 526 * offset :: 527 * The starting offset in the table (or the file if 528 * tag == 0). 529 * 530 * length :: 531 * The address of the decision variable: 532 * 533 * If length == NULL: 534 * Loads the whole table. Returns an error if 535 * `offset' == 0! 536 * 537 * If *length == 0: 538 * Exits immediately; returning the length of the given 539 * table or of the font file, depending on the value of 540 * `tag'. 541 * 542 * If *length != 0: 543 * Loads the next `length' bytes of table or font, 544 * starting at offset `offset' (in table or font too). 545 * 546 * @Output: 547 * buffer :: 548 * The address of target buffer. 549 * 550 * @Return: 551 * FreeType error code. 0 means success. 552 */ 553 FT_LOCAL_DEF( FT_Error ) tt_face_load_any(TT_Face face,FT_ULong tag,FT_Long offset,FT_Byte * buffer,FT_ULong * length)554 tt_face_load_any( TT_Face face, 555 FT_ULong tag, 556 FT_Long offset, 557 FT_Byte* buffer, 558 FT_ULong* length ) 559 { 560 FT_Error error; 561 FT_Stream stream; 562 TT_Table table; 563 FT_ULong size; 564 565 566 if ( tag != 0 ) 567 { 568 /* look for tag in font directory */ 569 table = tt_face_lookup_table( face, tag ); 570 if ( !table ) 571 { 572 error = FT_THROW( Table_Missing ); 573 goto Exit; 574 } 575 576 offset += table->Offset; 577 size = table->Length; 578 } 579 else 580 /* tag == 0 -- the user wants to access the font file directly */ 581 size = face->root.stream->size; 582 583 if ( length && *length == 0 ) 584 { 585 *length = size; 586 587 return FT_Err_Ok; 588 } 589 590 if ( length ) 591 size = *length; 592 593 stream = face->root.stream; 594 /* the `if' is syntactic sugar for picky compilers */ 595 if ( FT_STREAM_READ_AT( offset, buffer, size ) ) 596 goto Exit; 597 598 Exit: 599 return error; 600 } 601 602 603 /************************************************************************** 604 * 605 * @Function: 606 * tt_face_load_generic_header 607 * 608 * @Description: 609 * Loads the TrueType table `head' or `bhed'. 610 * 611 * @Input: 612 * face :: 613 * A handle to the target face object. 614 * 615 * stream :: 616 * The input stream. 617 * 618 * @Return: 619 * FreeType error code. 0 means success. 620 */ 621 static FT_Error tt_face_load_generic_header(TT_Face face,FT_Stream stream,FT_ULong tag)622 tt_face_load_generic_header( TT_Face face, 623 FT_Stream stream, 624 FT_ULong tag ) 625 { 626 FT_Error error; 627 TT_Header* header; 628 629 static const FT_Frame_Field header_fields[] = 630 { 631 #undef FT_STRUCTURE 632 #define FT_STRUCTURE TT_Header 633 634 FT_FRAME_START( 54 ), 635 FT_FRAME_ULONG ( Table_Version ), 636 FT_FRAME_ULONG ( Font_Revision ), 637 FT_FRAME_LONG ( CheckSum_Adjust ), 638 FT_FRAME_LONG ( Magic_Number ), 639 FT_FRAME_USHORT( Flags ), 640 FT_FRAME_USHORT( Units_Per_EM ), 641 FT_FRAME_ULONG ( Created[0] ), 642 FT_FRAME_ULONG ( Created[1] ), 643 FT_FRAME_ULONG ( Modified[0] ), 644 FT_FRAME_ULONG ( Modified[1] ), 645 FT_FRAME_SHORT ( xMin ), 646 FT_FRAME_SHORT ( yMin ), 647 FT_FRAME_SHORT ( xMax ), 648 FT_FRAME_SHORT ( yMax ), 649 FT_FRAME_USHORT( Mac_Style ), 650 FT_FRAME_USHORT( Lowest_Rec_PPEM ), 651 FT_FRAME_SHORT ( Font_Direction ), 652 FT_FRAME_SHORT ( Index_To_Loc_Format ), 653 FT_FRAME_SHORT ( Glyph_Data_Format ), 654 FT_FRAME_END 655 }; 656 657 658 error = face->goto_table( face, tag, stream, 0 ); 659 if ( error ) 660 goto Exit; 661 662 header = &face->header; 663 664 if ( FT_STREAM_READ_FIELDS( header_fields, header ) ) 665 goto Exit; 666 667 FT_TRACE3(( "Units per EM: %4u\n", header->Units_Per_EM )); 668 FT_TRACE3(( "IndexToLoc: %4d\n", header->Index_To_Loc_Format )); 669 670 Exit: 671 return error; 672 } 673 674 675 FT_LOCAL_DEF( FT_Error ) tt_face_load_head(TT_Face face,FT_Stream stream)676 tt_face_load_head( TT_Face face, 677 FT_Stream stream ) 678 { 679 return tt_face_load_generic_header( face, stream, TTAG_head ); 680 } 681 682 683 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS 684 685 FT_LOCAL_DEF( FT_Error ) tt_face_load_bhed(TT_Face face,FT_Stream stream)686 tt_face_load_bhed( TT_Face face, 687 FT_Stream stream ) 688 { 689 return tt_face_load_generic_header( face, stream, TTAG_bhed ); 690 } 691 692 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ 693 694 695 /************************************************************************** 696 * 697 * @Function: 698 * tt_face_load_maxp 699 * 700 * @Description: 701 * Loads the maximum profile into a face object. 702 * 703 * @Input: 704 * face :: 705 * A handle to the target face object. 706 * 707 * stream :: 708 * The input stream. 709 * 710 * @Return: 711 * FreeType error code. 0 means success. 712 */ 713 FT_LOCAL_DEF( FT_Error ) tt_face_load_maxp(TT_Face face,FT_Stream stream)714 tt_face_load_maxp( TT_Face face, 715 FT_Stream stream ) 716 { 717 FT_Error error; 718 TT_MaxProfile* maxProfile = &face->max_profile; 719 720 static const FT_Frame_Field maxp_fields[] = 721 { 722 #undef FT_STRUCTURE 723 #define FT_STRUCTURE TT_MaxProfile 724 725 FT_FRAME_START( 6 ), 726 FT_FRAME_LONG ( version ), 727 FT_FRAME_USHORT( numGlyphs ), 728 FT_FRAME_END 729 }; 730 731 static const FT_Frame_Field maxp_fields_extra[] = 732 { 733 FT_FRAME_START( 26 ), 734 FT_FRAME_USHORT( maxPoints ), 735 FT_FRAME_USHORT( maxContours ), 736 FT_FRAME_USHORT( maxCompositePoints ), 737 FT_FRAME_USHORT( maxCompositeContours ), 738 FT_FRAME_USHORT( maxZones ), 739 FT_FRAME_USHORT( maxTwilightPoints ), 740 FT_FRAME_USHORT( maxStorage ), 741 FT_FRAME_USHORT( maxFunctionDefs ), 742 FT_FRAME_USHORT( maxInstructionDefs ), 743 FT_FRAME_USHORT( maxStackElements ), 744 FT_FRAME_USHORT( maxSizeOfInstructions ), 745 FT_FRAME_USHORT( maxComponentElements ), 746 FT_FRAME_USHORT( maxComponentDepth ), 747 FT_FRAME_END 748 }; 749 750 751 error = face->goto_table( face, TTAG_maxp, stream, 0 ); 752 if ( error ) 753 goto Exit; 754 755 if ( FT_STREAM_READ_FIELDS( maxp_fields, maxProfile ) ) 756 goto Exit; 757 758 maxProfile->maxPoints = 0; 759 maxProfile->maxContours = 0; 760 maxProfile->maxCompositePoints = 0; 761 maxProfile->maxCompositeContours = 0; 762 maxProfile->maxZones = 0; 763 maxProfile->maxTwilightPoints = 0; 764 maxProfile->maxStorage = 0; 765 maxProfile->maxFunctionDefs = 0; 766 maxProfile->maxInstructionDefs = 0; 767 maxProfile->maxStackElements = 0; 768 maxProfile->maxSizeOfInstructions = 0; 769 maxProfile->maxComponentElements = 0; 770 maxProfile->maxComponentDepth = 0; 771 772 if ( maxProfile->version >= 0x10000L ) 773 { 774 if ( FT_STREAM_READ_FIELDS( maxp_fields_extra, maxProfile ) ) 775 goto Exit; 776 777 /* XXX: an adjustment that is necessary to load certain */ 778 /* broken fonts like `Keystrokes MT' :-( */ 779 /* */ 780 /* We allocate 64 function entries by default when */ 781 /* the maxFunctionDefs value is smaller. */ 782 783 if ( maxProfile->maxFunctionDefs < 64 ) 784 maxProfile->maxFunctionDefs = 64; 785 786 /* we add 4 phantom points later */ 787 if ( maxProfile->maxTwilightPoints > ( 0xFFFFU - 4 ) ) 788 { 789 FT_TRACE0(( "tt_face_load_maxp:" 790 " too much twilight points in `maxp' table;\n" 791 " " 792 " some glyphs might be rendered incorrectly\n" )); 793 794 maxProfile->maxTwilightPoints = 0xFFFFU - 4; 795 } 796 } 797 798 FT_TRACE3(( "numGlyphs: %u\n", maxProfile->numGlyphs )); 799 800 Exit: 801 return error; 802 } 803 804 805 /************************************************************************** 806 * 807 * @Function: 808 * tt_face_load_name 809 * 810 * @Description: 811 * Loads the name records. 812 * 813 * @Input: 814 * face :: 815 * A handle to the target face object. 816 * 817 * stream :: 818 * The input stream. 819 * 820 * @Return: 821 * FreeType error code. 0 means success. 822 */ 823 FT_LOCAL_DEF( FT_Error ) tt_face_load_name(TT_Face face,FT_Stream stream)824 tt_face_load_name( TT_Face face, 825 FT_Stream stream ) 826 { 827 FT_Error error; 828 FT_Memory memory = stream->memory; 829 FT_ULong table_pos, table_len; 830 FT_ULong storage_start, storage_limit; 831 TT_NameTable table; 832 833 static const FT_Frame_Field name_table_fields[] = 834 { 835 #undef FT_STRUCTURE 836 #define FT_STRUCTURE TT_NameTableRec 837 838 FT_FRAME_START( 6 ), 839 FT_FRAME_USHORT( format ), 840 FT_FRAME_USHORT( numNameRecords ), 841 FT_FRAME_USHORT( storageOffset ), 842 FT_FRAME_END 843 }; 844 845 static const FT_Frame_Field name_record_fields[] = 846 { 847 #undef FT_STRUCTURE 848 #define FT_STRUCTURE TT_NameRec 849 850 /* no FT_FRAME_START */ 851 FT_FRAME_USHORT( platformID ), 852 FT_FRAME_USHORT( encodingID ), 853 FT_FRAME_USHORT( languageID ), 854 FT_FRAME_USHORT( nameID ), 855 FT_FRAME_USHORT( stringLength ), 856 FT_FRAME_USHORT( stringOffset ), 857 FT_FRAME_END 858 }; 859 860 static const FT_Frame_Field langTag_record_fields[] = 861 { 862 #undef FT_STRUCTURE 863 #define FT_STRUCTURE TT_LangTagRec 864 865 /* no FT_FRAME_START */ 866 FT_FRAME_USHORT( stringLength ), 867 FT_FRAME_USHORT( stringOffset ), 868 FT_FRAME_END 869 }; 870 871 872 table = &face->name_table; 873 table->stream = stream; 874 875 error = face->goto_table( face, TTAG_name, stream, &table_len ); 876 if ( error ) 877 goto Exit; 878 879 table_pos = FT_STREAM_POS(); 880 881 if ( FT_STREAM_READ_FIELDS( name_table_fields, table ) ) 882 goto Exit; 883 884 /* Some popular Asian fonts have an invalid `storageOffset' value (it */ 885 /* should be at least `6 + 12*numNameRecords'). However, the string */ 886 /* offsets, computed as `storageOffset + entry->stringOffset', are */ 887 /* valid pointers within the name table... */ 888 /* */ 889 /* We thus can't check `storageOffset' right now. */ 890 /* */ 891 storage_start = table_pos + 6 + 12 * table->numNameRecords; 892 storage_limit = table_pos + table_len; 893 894 if ( storage_start > storage_limit ) 895 { 896 FT_ERROR(( "tt_face_load_name: invalid `name' table\n" )); 897 error = FT_THROW( Name_Table_Missing ); 898 goto Exit; 899 } 900 901 /* `name' format 1 contains additional language tag records, */ 902 /* which we load first */ 903 if ( table->format == 1 ) 904 { 905 if ( FT_STREAM_SEEK( storage_start ) || 906 FT_READ_USHORT( table->numLangTagRecords ) ) 907 goto Exit; 908 909 storage_start += 2 + 4 * table->numLangTagRecords; 910 911 /* allocate language tag records array */ 912 if ( FT_NEW_ARRAY( table->langTags, table->numLangTagRecords ) || 913 FT_FRAME_ENTER( table->numLangTagRecords * 4 ) ) 914 goto Exit; 915 916 /* load language tags */ 917 { 918 TT_LangTag entry = table->langTags; 919 TT_LangTag limit = entry + table->numLangTagRecords; 920 921 922 for ( ; entry < limit; entry++ ) 923 { 924 (void)FT_STREAM_READ_FIELDS( langTag_record_fields, entry ); 925 926 /* check that the langTag string is within the table */ 927 entry->stringOffset += table_pos + table->storageOffset; 928 if ( entry->stringOffset < storage_start || 929 entry->stringOffset + entry->stringLength > storage_limit ) 930 { 931 /* invalid entry; ignore it */ 932 entry->stringLength = 0; 933 } 934 } 935 } 936 937 FT_FRAME_EXIT(); 938 939 (void)FT_STREAM_SEEK( table_pos + 6 ); 940 } 941 942 /* allocate name records array */ 943 if ( FT_NEW_ARRAY( table->names, table->numNameRecords ) || 944 FT_FRAME_ENTER( table->numNameRecords * 12 ) ) 945 goto Exit; 946 947 /* load name records */ 948 { 949 TT_Name entry = table->names; 950 FT_UInt count = table->numNameRecords; 951 952 953 for ( ; count > 0; count-- ) 954 { 955 if ( FT_STREAM_READ_FIELDS( name_record_fields, entry ) ) 956 continue; 957 958 /* check that the name is not empty */ 959 if ( entry->stringLength == 0 ) 960 continue; 961 962 /* check that the name string is within the table */ 963 entry->stringOffset += table_pos + table->storageOffset; 964 if ( entry->stringOffset < storage_start || 965 entry->stringOffset + entry->stringLength > storage_limit ) 966 { 967 /* invalid entry; ignore it */ 968 continue; 969 } 970 971 /* assure that we have a valid language tag ID, and */ 972 /* that the corresponding langTag entry is valid, too */ 973 if ( table->format == 1 && entry->languageID >= 0x8000U ) 974 { 975 if ( entry->languageID - 0x8000U >= table->numLangTagRecords || 976 !table->langTags[entry->languageID - 0x8000U].stringLength ) 977 { 978 /* invalid entry; ignore it */ 979 continue; 980 } 981 } 982 983 entry++; 984 } 985 986 /* reduce array size to the actually used elements */ 987 count = (FT_UInt)( entry - table->names ); 988 (void)FT_RENEW_ARRAY( table->names, 989 table->numNameRecords, 990 count ); 991 table->numNameRecords = count; 992 } 993 994 FT_FRAME_EXIT(); 995 996 /* everything went well, update face->num_names */ 997 face->num_names = (FT_UShort)table->numNameRecords; 998 999 Exit: 1000 return error; 1001 } 1002 1003 1004 /************************************************************************** 1005 * 1006 * @Function: 1007 * tt_face_free_name 1008 * 1009 * @Description: 1010 * Frees the name records. 1011 * 1012 * @Input: 1013 * face :: 1014 * A handle to the target face object. 1015 */ 1016 FT_LOCAL_DEF( void ) tt_face_free_name(TT_Face face)1017 tt_face_free_name( TT_Face face ) 1018 { 1019 FT_Memory memory = face->root.driver->root.memory; 1020 TT_NameTable table = &face->name_table; 1021 1022 1023 if ( table->names ) 1024 { 1025 TT_Name entry = table->names; 1026 TT_Name limit = entry + table->numNameRecords; 1027 1028 1029 for ( ; entry < limit; entry++ ) 1030 FT_FREE( entry->string ); 1031 1032 FT_FREE( table->names ); 1033 } 1034 1035 if ( table->langTags ) 1036 { 1037 TT_LangTag entry = table->langTags; 1038 TT_LangTag limit = entry + table->numLangTagRecords; 1039 1040 1041 for ( ; entry < limit; entry++ ) 1042 FT_FREE( entry->string ); 1043 1044 FT_FREE( table->langTags ); 1045 } 1046 1047 table->numNameRecords = 0; 1048 table->numLangTagRecords = 0; 1049 table->format = 0; 1050 table->storageOffset = 0; 1051 } 1052 1053 1054 /************************************************************************** 1055 * 1056 * @Function: 1057 * tt_face_load_cmap 1058 * 1059 * @Description: 1060 * Loads the cmap directory in a face object. The cmaps themselves 1061 * are loaded on demand in the `ttcmap.c' module. 1062 * 1063 * @Input: 1064 * face :: 1065 * A handle to the target face object. 1066 * 1067 * stream :: 1068 * A handle to the input stream. 1069 * 1070 * @Return: 1071 * FreeType error code. 0 means success. 1072 */ 1073 1074 FT_LOCAL_DEF( FT_Error ) tt_face_load_cmap(TT_Face face,FT_Stream stream)1075 tt_face_load_cmap( TT_Face face, 1076 FT_Stream stream ) 1077 { 1078 FT_Error error; 1079 1080 1081 error = face->goto_table( face, TTAG_cmap, stream, &face->cmap_size ); 1082 if ( error ) 1083 goto Exit; 1084 1085 if ( FT_FRAME_EXTRACT( face->cmap_size, face->cmap_table ) ) 1086 face->cmap_size = 0; 1087 1088 Exit: 1089 return error; 1090 } 1091 1092 1093 1094 /************************************************************************** 1095 * 1096 * @Function: 1097 * tt_face_load_os2 1098 * 1099 * @Description: 1100 * Loads the OS2 table. 1101 * 1102 * @Input: 1103 * face :: 1104 * A handle to the target face object. 1105 * 1106 * stream :: 1107 * A handle to the input stream. 1108 * 1109 * @Return: 1110 * FreeType error code. 0 means success. 1111 */ 1112 FT_LOCAL_DEF( FT_Error ) tt_face_load_os2(TT_Face face,FT_Stream stream)1113 tt_face_load_os2( TT_Face face, 1114 FT_Stream stream ) 1115 { 1116 FT_Error error; 1117 TT_OS2* os2; 1118 1119 static const FT_Frame_Field os2_fields[] = 1120 { 1121 #undef FT_STRUCTURE 1122 #define FT_STRUCTURE TT_OS2 1123 1124 FT_FRAME_START( 78 ), 1125 FT_FRAME_USHORT( version ), 1126 FT_FRAME_SHORT ( xAvgCharWidth ), 1127 FT_FRAME_USHORT( usWeightClass ), 1128 FT_FRAME_USHORT( usWidthClass ), 1129 FT_FRAME_SHORT ( fsType ), 1130 FT_FRAME_SHORT ( ySubscriptXSize ), 1131 FT_FRAME_SHORT ( ySubscriptYSize ), 1132 FT_FRAME_SHORT ( ySubscriptXOffset ), 1133 FT_FRAME_SHORT ( ySubscriptYOffset ), 1134 FT_FRAME_SHORT ( ySuperscriptXSize ), 1135 FT_FRAME_SHORT ( ySuperscriptYSize ), 1136 FT_FRAME_SHORT ( ySuperscriptXOffset ), 1137 FT_FRAME_SHORT ( ySuperscriptYOffset ), 1138 FT_FRAME_SHORT ( yStrikeoutSize ), 1139 FT_FRAME_SHORT ( yStrikeoutPosition ), 1140 FT_FRAME_SHORT ( sFamilyClass ), 1141 FT_FRAME_BYTE ( panose[0] ), 1142 FT_FRAME_BYTE ( panose[1] ), 1143 FT_FRAME_BYTE ( panose[2] ), 1144 FT_FRAME_BYTE ( panose[3] ), 1145 FT_FRAME_BYTE ( panose[4] ), 1146 FT_FRAME_BYTE ( panose[5] ), 1147 FT_FRAME_BYTE ( panose[6] ), 1148 FT_FRAME_BYTE ( panose[7] ), 1149 FT_FRAME_BYTE ( panose[8] ), 1150 FT_FRAME_BYTE ( panose[9] ), 1151 FT_FRAME_ULONG ( ulUnicodeRange1 ), 1152 FT_FRAME_ULONG ( ulUnicodeRange2 ), 1153 FT_FRAME_ULONG ( ulUnicodeRange3 ), 1154 FT_FRAME_ULONG ( ulUnicodeRange4 ), 1155 FT_FRAME_BYTE ( achVendID[0] ), 1156 FT_FRAME_BYTE ( achVendID[1] ), 1157 FT_FRAME_BYTE ( achVendID[2] ), 1158 FT_FRAME_BYTE ( achVendID[3] ), 1159 1160 FT_FRAME_USHORT( fsSelection ), 1161 FT_FRAME_USHORT( usFirstCharIndex ), 1162 FT_FRAME_USHORT( usLastCharIndex ), 1163 FT_FRAME_SHORT ( sTypoAscender ), 1164 FT_FRAME_SHORT ( sTypoDescender ), 1165 FT_FRAME_SHORT ( sTypoLineGap ), 1166 FT_FRAME_USHORT( usWinAscent ), 1167 FT_FRAME_USHORT( usWinDescent ), 1168 FT_FRAME_END 1169 }; 1170 1171 /* `OS/2' version 1 and newer */ 1172 static const FT_Frame_Field os2_fields_extra1[] = 1173 { 1174 FT_FRAME_START( 8 ), 1175 FT_FRAME_ULONG( ulCodePageRange1 ), 1176 FT_FRAME_ULONG( ulCodePageRange2 ), 1177 FT_FRAME_END 1178 }; 1179 1180 /* `OS/2' version 2 and newer */ 1181 static const FT_Frame_Field os2_fields_extra2[] = 1182 { 1183 FT_FRAME_START( 10 ), 1184 FT_FRAME_SHORT ( sxHeight ), 1185 FT_FRAME_SHORT ( sCapHeight ), 1186 FT_FRAME_USHORT( usDefaultChar ), 1187 FT_FRAME_USHORT( usBreakChar ), 1188 FT_FRAME_USHORT( usMaxContext ), 1189 FT_FRAME_END 1190 }; 1191 1192 /* `OS/2' version 5 and newer */ 1193 static const FT_Frame_Field os2_fields_extra5[] = 1194 { 1195 FT_FRAME_START( 4 ), 1196 FT_FRAME_USHORT( usLowerOpticalPointSize ), 1197 FT_FRAME_USHORT( usUpperOpticalPointSize ), 1198 FT_FRAME_END 1199 }; 1200 1201 1202 /* We now support old Mac fonts where the OS/2 table doesn't */ 1203 /* exist. Simply put, we set the `version' field to 0xFFFF */ 1204 /* and test this value each time we need to access the table. */ 1205 error = face->goto_table( face, TTAG_OS2, stream, 0 ); 1206 if ( error ) 1207 goto Exit; 1208 1209 os2 = &face->os2; 1210 1211 if ( FT_STREAM_READ_FIELDS( os2_fields, os2 ) ) 1212 goto Exit; 1213 1214 os2->ulCodePageRange1 = 0; 1215 os2->ulCodePageRange2 = 0; 1216 os2->sxHeight = 0; 1217 os2->sCapHeight = 0; 1218 os2->usDefaultChar = 0; 1219 os2->usBreakChar = 0; 1220 os2->usMaxContext = 0; 1221 os2->usLowerOpticalPointSize = 0; 1222 os2->usUpperOpticalPointSize = 0xFFFF; 1223 1224 if ( os2->version >= 0x0001 ) 1225 { 1226 /* only version 1 tables */ 1227 if ( FT_STREAM_READ_FIELDS( os2_fields_extra1, os2 ) ) 1228 goto Exit; 1229 1230 if ( os2->version >= 0x0002 ) 1231 { 1232 /* only version 2 tables */ 1233 if ( FT_STREAM_READ_FIELDS( os2_fields_extra2, os2 ) ) 1234 goto Exit; 1235 1236 if ( os2->version >= 0x0005 ) 1237 { 1238 /* only version 5 tables */ 1239 if ( FT_STREAM_READ_FIELDS( os2_fields_extra5, os2 ) ) 1240 goto Exit; 1241 } 1242 } 1243 } 1244 1245 FT_TRACE3(( "sTypoAscender: %4d\n", os2->sTypoAscender )); 1246 FT_TRACE3(( "sTypoDescender: %4d\n", os2->sTypoDescender )); 1247 FT_TRACE3(( "usWinAscent: %4u\n", os2->usWinAscent )); 1248 FT_TRACE3(( "usWinDescent: %4u\n", os2->usWinDescent )); 1249 FT_TRACE3(( "fsSelection: 0x%2x\n", os2->fsSelection )); 1250 1251 Exit: 1252 return error; 1253 } 1254 1255 1256 /************************************************************************** 1257 * 1258 * @Function: 1259 * tt_face_load_postscript 1260 * 1261 * @Description: 1262 * Loads the Postscript table. 1263 * 1264 * @Input: 1265 * face :: 1266 * A handle to the target face object. 1267 * 1268 * stream :: 1269 * A handle to the input stream. 1270 * 1271 * @Return: 1272 * FreeType error code. 0 means success. 1273 */ 1274 FT_LOCAL_DEF( FT_Error ) tt_face_load_post(TT_Face face,FT_Stream stream)1275 tt_face_load_post( TT_Face face, 1276 FT_Stream stream ) 1277 { 1278 FT_Error error; 1279 TT_Postscript* post = &face->postscript; 1280 1281 static const FT_Frame_Field post_fields[] = 1282 { 1283 #undef FT_STRUCTURE 1284 #define FT_STRUCTURE TT_Postscript 1285 1286 FT_FRAME_START( 32 ), 1287 FT_FRAME_LONG ( FormatType ), 1288 FT_FRAME_LONG ( italicAngle ), 1289 FT_FRAME_SHORT( underlinePosition ), 1290 FT_FRAME_SHORT( underlineThickness ), 1291 FT_FRAME_ULONG( isFixedPitch ), 1292 FT_FRAME_ULONG( minMemType42 ), 1293 FT_FRAME_ULONG( maxMemType42 ), 1294 FT_FRAME_ULONG( minMemType1 ), 1295 FT_FRAME_ULONG( maxMemType1 ), 1296 FT_FRAME_END 1297 }; 1298 1299 1300 error = face->goto_table( face, TTAG_post, stream, 0 ); 1301 if ( error ) 1302 return error; 1303 1304 if ( FT_STREAM_READ_FIELDS( post_fields, post ) ) 1305 return error; 1306 1307 /* we don't load the glyph names, we do that in another */ 1308 /* module (ttpost). */ 1309 1310 FT_TRACE3(( "FormatType: 0x%x\n", post->FormatType )); 1311 FT_TRACE3(( "isFixedPitch: %s\n", post->isFixedPitch 1312 ? " yes" : " no" )); 1313 1314 return FT_Err_Ok; 1315 } 1316 1317 1318 /************************************************************************** 1319 * 1320 * @Function: 1321 * tt_face_load_pclt 1322 * 1323 * @Description: 1324 * Loads the PCL 5 Table. 1325 * 1326 * @Input: 1327 * face :: 1328 * A handle to the target face object. 1329 * 1330 * stream :: 1331 * A handle to the input stream. 1332 * 1333 * @Return: 1334 * FreeType error code. 0 means success. 1335 */ 1336 FT_LOCAL_DEF( FT_Error ) tt_face_load_pclt(TT_Face face,FT_Stream stream)1337 tt_face_load_pclt( TT_Face face, 1338 FT_Stream stream ) 1339 { 1340 static const FT_Frame_Field pclt_fields[] = 1341 { 1342 #undef FT_STRUCTURE 1343 #define FT_STRUCTURE TT_PCLT 1344 1345 FT_FRAME_START( 54 ), 1346 FT_FRAME_ULONG ( Version ), 1347 FT_FRAME_ULONG ( FontNumber ), 1348 FT_FRAME_USHORT( Pitch ), 1349 FT_FRAME_USHORT( xHeight ), 1350 FT_FRAME_USHORT( Style ), 1351 FT_FRAME_USHORT( TypeFamily ), 1352 FT_FRAME_USHORT( CapHeight ), 1353 FT_FRAME_USHORT( SymbolSet ), 1354 FT_FRAME_BYTES ( TypeFace, 16 ), 1355 FT_FRAME_BYTES ( CharacterComplement, 8 ), 1356 FT_FRAME_BYTES ( FileName, 6 ), 1357 FT_FRAME_CHAR ( StrokeWeight ), 1358 FT_FRAME_CHAR ( WidthType ), 1359 FT_FRAME_BYTE ( SerifStyle ), 1360 FT_FRAME_BYTE ( Reserved ), 1361 FT_FRAME_END 1362 }; 1363 1364 FT_Error error; 1365 TT_PCLT* pclt = &face->pclt; 1366 1367 1368 /* optional table */ 1369 error = face->goto_table( face, TTAG_PCLT, stream, 0 ); 1370 if ( error ) 1371 goto Exit; 1372 1373 if ( FT_STREAM_READ_FIELDS( pclt_fields, pclt ) ) 1374 goto Exit; 1375 1376 Exit: 1377 return error; 1378 } 1379 1380 1381 /************************************************************************** 1382 * 1383 * @Function: 1384 * tt_face_load_gasp 1385 * 1386 * @Description: 1387 * Loads the `gasp' table into a face object. 1388 * 1389 * @Input: 1390 * face :: 1391 * A handle to the target face object. 1392 * 1393 * stream :: 1394 * The input stream. 1395 * 1396 * @Return: 1397 * FreeType error code. 0 means success. 1398 */ 1399 FT_LOCAL_DEF( FT_Error ) tt_face_load_gasp(TT_Face face,FT_Stream stream)1400 tt_face_load_gasp( TT_Face face, 1401 FT_Stream stream ) 1402 { 1403 FT_Error error; 1404 FT_Memory memory = stream->memory; 1405 1406 FT_UInt j,num_ranges; 1407 TT_GaspRange gaspranges = NULL; 1408 1409 1410 /* the gasp table is optional */ 1411 error = face->goto_table( face, TTAG_gasp, stream, 0 ); 1412 if ( error ) 1413 goto Exit; 1414 1415 if ( FT_FRAME_ENTER( 4L ) ) 1416 goto Exit; 1417 1418 face->gasp.version = FT_GET_USHORT(); 1419 face->gasp.numRanges = FT_GET_USHORT(); 1420 1421 FT_FRAME_EXIT(); 1422 1423 /* only support versions 0 and 1 of the table */ 1424 if ( face->gasp.version >= 2 ) 1425 { 1426 face->gasp.numRanges = 0; 1427 error = FT_THROW( Invalid_Table ); 1428 goto Exit; 1429 } 1430 1431 num_ranges = face->gasp.numRanges; 1432 FT_TRACE3(( "numRanges: %u\n", num_ranges )); 1433 1434 if ( FT_QNEW_ARRAY( face->gasp.gaspRanges, num_ranges ) || 1435 FT_FRAME_ENTER( num_ranges * 4L ) ) 1436 goto Exit; 1437 1438 gaspranges = face->gasp.gaspRanges; 1439 1440 for ( j = 0; j < num_ranges; j++ ) 1441 { 1442 gaspranges[j].maxPPEM = FT_GET_USHORT(); 1443 gaspranges[j].gaspFlag = FT_GET_USHORT(); 1444 1445 FT_TRACE3(( "gaspRange %d: rangeMaxPPEM %5d, rangeGaspBehavior 0x%x\n", 1446 j, 1447 gaspranges[j].maxPPEM, 1448 gaspranges[j].gaspFlag )); 1449 } 1450 1451 FT_FRAME_EXIT(); 1452 1453 Exit: 1454 return error; 1455 } 1456 1457 1458 /* END */ 1459