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