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