1 /******************************************************************* 2 * 3 * ftxopen.c 4 * 5 * TrueType Open common table support. 6 * 7 * Copyright 1996-1999 by 8 * David Turner, Robert Wilhelm, and Werner Lemberg. 9 * 10 * This file is part of the FreeType project, and may only be used 11 * modified and distributed under the terms of the FreeType project 12 * license, LICENSE.TXT. By continuing to use, modify, or distribute 13 * this file you indicate that you have read the license and 14 * understand and accept it fully. 15 * 16 ******************************************************************/ 17 18 #include "tttypes.h" 19 #include "ttload.h" 20 #include "ttextend.h" 21 #include "ttmemory.h" 22 #include "ttfile.h" 23 24 #include "ftxopen.h" 25 #include "ftxopenf.h" 26 27 28 /*************************** 29 * Script related functions 30 ***************************/ 31 32 33 /* LangSys */ 34 Load_LangSys(TTO_LangSys * ls,PFace input)35 static TT_Error Load_LangSys( TTO_LangSys* ls, 36 PFace input ) 37 { 38 DEFINE_LOAD_LOCALS( input->stream ); 39 40 UShort n, count; 41 42 UShort* fi; 43 44 45 if ( ACCESS_Frame( 6L ) ) 46 return error; 47 48 ls->LookupOrderOffset = GET_UShort(); /* should be 0 */ 49 ls->ReqFeatureIndex = GET_UShort(); 50 count = ls->FeatureCount = GET_UShort(); 51 52 FORGET_Frame(); 53 54 ls->FeatureIndex = NULL; 55 56 if ( ALLOC_ARRAY( ls->FeatureIndex, count, UShort ) ) 57 return error; 58 59 if ( ACCESS_Frame( count * 2L ) ) 60 { 61 FREE( ls->FeatureIndex ); 62 return error; 63 } 64 65 fi = ls->FeatureIndex; 66 67 for ( n = 0; n < count; n++ ) 68 fi[n] = GET_UShort(); 69 70 FORGET_Frame(); 71 72 return TT_Err_Ok; 73 } 74 75 Free_LangSys(TTO_LangSys * ls)76 static void Free_LangSys( TTO_LangSys* ls ) 77 { 78 FREE( ls->FeatureIndex ); 79 } 80 81 82 /* Script */ 83 Load_Script(TTO_Script * s,PFace input)84 static TT_Error Load_Script( TTO_Script* s, 85 PFace input ) 86 { 87 DEFINE_LOAD_LOCALS( input->stream ); 88 89 UShort n, count; 90 ULong cur_offset, new_offset, base_offset; 91 92 TTO_LangSysRecord* lsr; 93 94 95 base_offset = FILE_Pos(); 96 97 if ( ACCESS_Frame( 2L ) ) 98 return error; 99 100 new_offset = GET_UShort() + base_offset; 101 102 FORGET_Frame(); 103 104 if ( new_offset != base_offset ) /* not a NULL offset */ 105 { 106 cur_offset = FILE_Pos(); 107 if ( FILE_Seek( new_offset ) || 108 ( error = Load_LangSys( &s->DefaultLangSys, 109 input ) ) != TT_Err_Ok ) 110 return error; 111 (void)FILE_Seek( cur_offset ); 112 } 113 else 114 { 115 /* we create a DefaultLangSys table with no entries */ 116 117 s->DefaultLangSys.LookupOrderOffset = 0; 118 s->DefaultLangSys.ReqFeatureIndex = 0xFFFF; 119 s->DefaultLangSys.FeatureCount = 0; 120 s->DefaultLangSys.FeatureIndex = NULL; 121 } 122 123 if ( ACCESS_Frame( 2L ) ) 124 goto Fail2; 125 126 count = s->LangSysCount = GET_UShort(); 127 128 /* safety check; otherwise the official handling of TrueType Open 129 fonts won't work */ 130 131 if ( s->LangSysCount == 0 && s->DefaultLangSys.FeatureCount == 0 ) 132 { 133 error = TTO_Err_Invalid_SubTable; 134 goto Fail2; 135 } 136 137 FORGET_Frame(); 138 139 s->LangSysRecord = NULL; 140 141 if ( ALLOC_ARRAY( s->LangSysRecord, count, TTO_LangSysRecord ) ) 142 goto Fail2; 143 144 lsr = s->LangSysRecord; 145 146 for ( n = 0; n < count; n++ ) 147 { 148 if ( ACCESS_Frame( 6L ) ) 149 goto Fail1; 150 151 lsr[n].LangSysTag = GET_ULong(); 152 new_offset = GET_UShort() + base_offset; 153 154 FORGET_Frame(); 155 156 cur_offset = FILE_Pos(); 157 if ( FILE_Seek( new_offset ) || 158 ( error = Load_LangSys( &lsr[n].LangSys, input ) ) != TT_Err_Ok ) 159 goto Fail1; 160 (void)FILE_Seek( cur_offset ); 161 } 162 163 return TT_Err_Ok; 164 165 Fail1: 166 for ( n = 0; n < count; n++ ) 167 Free_LangSys( &lsr[n].LangSys ); 168 169 FREE( s->LangSysRecord ); 170 171 Fail2: 172 Free_LangSys( &s->DefaultLangSys ); 173 return error; 174 } 175 176 Free_Script(TTO_Script * s)177 static void Free_Script( TTO_Script* s ) 178 { 179 UShort n, count; 180 181 TTO_LangSysRecord* lsr; 182 183 184 Free_LangSys( &s->DefaultLangSys ); 185 186 if ( s->LangSysRecord ) 187 { 188 count = s->LangSysCount; 189 lsr = s->LangSysRecord; 190 191 for ( n = 0; n < count; n++ ) 192 Free_LangSys( &lsr[n].LangSys ); 193 194 FREE( lsr ); 195 } 196 } 197 198 199 /* ScriptList */ 200 Load_ScriptList(TTO_ScriptList * sl,PFace input)201 TT_Error Load_ScriptList( TTO_ScriptList* sl, 202 PFace input ) 203 { 204 DEFINE_LOAD_LOCALS( input->stream ); 205 206 UShort n, count; 207 ULong cur_offset, new_offset, base_offset; 208 209 TTO_ScriptRecord* sr; 210 211 212 base_offset = FILE_Pos(); 213 214 if ( ACCESS_Frame( 2L ) ) 215 return error; 216 217 count = sl->ScriptCount = GET_UShort(); 218 219 FORGET_Frame(); 220 221 sl->ScriptRecord = NULL; 222 223 if ( ALLOC_ARRAY( sl->ScriptRecord, count, TTO_ScriptRecord ) ) 224 return error; 225 226 sr = sl->ScriptRecord; 227 228 for ( n = 0; n < count; n++ ) 229 { 230 if ( ACCESS_Frame( 6L ) ) 231 goto Fail; 232 233 sr[n].ScriptTag = GET_ULong(); 234 new_offset = GET_UShort() + base_offset; 235 236 FORGET_Frame(); 237 238 cur_offset = FILE_Pos(); 239 if ( FILE_Seek( new_offset ) || 240 ( error = Load_Script( &sr[n].Script, input ) ) != TT_Err_Ok ) 241 goto Fail; 242 (void)FILE_Seek( cur_offset ); 243 } 244 245 return TT_Err_Ok; 246 247 Fail: 248 for ( n = 0; n < count; n++ ) 249 Free_Script( &sr[n].Script ); 250 251 FREE( sl->ScriptRecord ); 252 return error; 253 } 254 255 Free_ScriptList(TTO_ScriptList * sl)256 void Free_ScriptList( TTO_ScriptList* sl ) 257 { 258 UShort n, count; 259 260 TTO_ScriptRecord* sr; 261 262 263 if ( sl->ScriptRecord ) 264 { 265 count = sl->ScriptCount; 266 sr = sl->ScriptRecord; 267 268 for ( n = 0; n < count; n++ ) 269 Free_Script( &sr[n].Script ); 270 271 FREE( sr ); 272 } 273 } 274 275 276 277 /********************************* 278 * Feature List related functions 279 *********************************/ 280 281 282 /* Feature */ 283 Load_Feature(TTO_Feature * f,PFace input)284 static TT_Error Load_Feature( TTO_Feature* f, 285 PFace input ) 286 { 287 DEFINE_LOAD_LOCALS( input->stream ); 288 289 UShort n, count; 290 291 UShort* lli; 292 293 294 if ( ACCESS_Frame( 4L ) ) 295 return error; 296 297 f->FeatureParams = GET_UShort(); /* should be 0 */ 298 count = f->LookupListCount = GET_UShort(); 299 300 FORGET_Frame(); 301 302 f->LookupListIndex = NULL; 303 304 if ( ALLOC_ARRAY( f->LookupListIndex, count, UShort ) ) 305 return error; 306 307 lli = f->LookupListIndex; 308 309 if ( ACCESS_Frame( count * 2L ) ) 310 { 311 FREE( f->LookupListIndex ); 312 return error; 313 } 314 315 for ( n = 0; n < count; n++ ) 316 lli[n] = GET_UShort(); 317 318 FORGET_Frame(); 319 320 return TT_Err_Ok; 321 } 322 323 Free_Feature(TTO_Feature * f)324 static void Free_Feature( TTO_Feature* f ) 325 { 326 FREE( f->LookupListIndex ); 327 } 328 329 330 /* FeatureList */ 331 Load_FeatureList(TTO_FeatureList * fl,PFace input)332 TT_Error Load_FeatureList( TTO_FeatureList* fl, 333 PFace input ) 334 { 335 DEFINE_LOAD_LOCALS( input->stream ); 336 337 UShort n, count; 338 ULong cur_offset, new_offset, base_offset; 339 340 TTO_FeatureRecord* fr; 341 342 343 base_offset = FILE_Pos(); 344 345 if ( ACCESS_Frame( 2L ) ) 346 return error; 347 348 count = fl->FeatureCount = GET_UShort(); 349 350 FORGET_Frame(); 351 352 fl->FeatureRecord = NULL; 353 354 if ( ALLOC_ARRAY( fl->FeatureRecord, count, TTO_FeatureRecord ) ) 355 return error; 356 357 fr = fl->FeatureRecord; 358 359 for ( n = 0; n < count; n++ ) 360 { 361 if ( ACCESS_Frame( 6L ) ) 362 goto Fail; 363 364 fr[n].FeatureTag = GET_ULong(); 365 new_offset = GET_UShort() + base_offset; 366 367 FORGET_Frame(); 368 369 cur_offset = FILE_Pos(); 370 if ( FILE_Seek( new_offset ) || 371 ( error = Load_Feature( &fr[n].Feature, input ) ) != TT_Err_Ok ) 372 goto Fail; 373 (void)FILE_Seek( cur_offset ); 374 } 375 376 return TT_Err_Ok; 377 378 Fail: 379 for ( n = 0; n < count; n++ ) 380 Free_Feature( &fr[n].Feature ); 381 382 FREE( fl->FeatureRecord ); 383 return error; 384 } 385 386 Free_FeatureList(TTO_FeatureList * fl)387 void Free_FeatureList( TTO_FeatureList* fl ) 388 { 389 UShort n, count; 390 391 TTO_FeatureRecord* fr; 392 393 394 if ( fl->FeatureRecord ) 395 { 396 count = fl->FeatureCount; 397 fr = fl->FeatureRecord; 398 399 for ( n = 0; n < count; n++ ) 400 Free_Feature( &fr[n].Feature ); 401 402 FREE( fr ); 403 } 404 } 405 406 407 408 /******************************** 409 * Lookup List related functions 410 ********************************/ 411 412 /* the subroutines of the following two functions are defined in 413 ftxgsub.c and ftxgpos.c respectively */ 414 415 416 /* SubTable */ 417 Load_SubTable(TTO_SubTable * st,PFace input,TTO_Type table_type,UShort lookup_type)418 static TT_Error Load_SubTable( TTO_SubTable* st, 419 PFace input, 420 TTO_Type table_type, 421 UShort lookup_type ) 422 { 423 if ( table_type == GSUB ) 424 switch ( lookup_type ) 425 { 426 case GSUB_LOOKUP_SINGLE: 427 return Load_SingleSubst( &st->st.gsub.single, input ); 428 429 case GSUB_LOOKUP_MULTIPLE: 430 return Load_MultipleSubst( &st->st.gsub.multiple, input ); 431 432 case GSUB_LOOKUP_ALTERNATE: 433 return Load_AlternateSubst( &st->st.gsub.alternate, input ); 434 435 case GSUB_LOOKUP_LIGATURE: 436 return Load_LigatureSubst( &st->st.gsub.ligature, input ); 437 438 case GSUB_LOOKUP_CONTEXT: 439 return Load_ContextSubst( &st->st.gsub.context, input ); 440 441 case GSUB_LOOKUP_CHAIN: 442 return Load_ChainContextSubst( &st->st.gsub.chain, input ); 443 444 default: 445 return TTO_Err_Invalid_GSUB_SubTable_Format; 446 } 447 else 448 switch ( lookup_type ) 449 { 450 case GPOS_LOOKUP_SINGLE: 451 return Load_SinglePos( &st->st.gpos.single, input ); 452 453 case GPOS_LOOKUP_PAIR: 454 return Load_PairPos( &st->st.gpos.pair, input ); 455 456 case GPOS_LOOKUP_CURSIVE: 457 return Load_CursivePos( &st->st.gpos.cursive, input ); 458 459 case GPOS_LOOKUP_MARKBASE: 460 return Load_MarkBasePos( &st->st.gpos.markbase, input ); 461 462 case GPOS_LOOKUP_MARKLIG: 463 return Load_MarkLigPos( &st->st.gpos.marklig, input ); 464 465 case GPOS_LOOKUP_MARKMARK: 466 return Load_MarkMarkPos( &st->st.gpos.markmark, input ); 467 468 case GPOS_LOOKUP_CONTEXT: 469 return Load_ContextPos( &st->st.gpos.context, input ); 470 471 case GPOS_LOOKUP_CHAIN: 472 return Load_ChainContextPos ( &st->st.gpos.chain, input ); 473 474 default: 475 return TTO_Err_Invalid_GPOS_SubTable_Format; 476 } 477 478 return TT_Err_Ok; /* never reached */ 479 } 480 481 Free_SubTable(TTO_SubTable * st,TTO_Type table_type,UShort lookup_type)482 static void Free_SubTable( TTO_SubTable* st, 483 TTO_Type table_type, 484 UShort lookup_type ) 485 { 486 if ( table_type == GSUB ) 487 switch ( lookup_type ) 488 { 489 case GSUB_LOOKUP_SINGLE: 490 Free_SingleSubst( &st->st.gsub.single ); 491 break; 492 493 case GSUB_LOOKUP_MULTIPLE: 494 Free_MultipleSubst( &st->st.gsub.multiple ); 495 break; 496 497 case GSUB_LOOKUP_ALTERNATE: 498 Free_AlternateSubst( &st->st.gsub.alternate ); 499 break; 500 501 case GSUB_LOOKUP_LIGATURE: 502 Free_LigatureSubst( &st->st.gsub.ligature ); 503 break; 504 505 case GSUB_LOOKUP_CONTEXT: 506 Free_ContextSubst( &st->st.gsub.context ); 507 break; 508 509 case GSUB_LOOKUP_CHAIN: 510 Free_ChainContextSubst( &st->st.gsub.chain ); 511 break; 512 } 513 else 514 switch ( lookup_type ) 515 { 516 case GPOS_LOOKUP_SINGLE: 517 Free_SinglePos( &st->st.gpos.single ); 518 break; 519 520 case GPOS_LOOKUP_PAIR: 521 Free_PairPos( &st->st.gpos.pair ); 522 break; 523 524 case GPOS_LOOKUP_CURSIVE: 525 Free_CursivePos( &st->st.gpos.cursive ); 526 break; 527 528 case GPOS_LOOKUP_MARKBASE: 529 Free_MarkBasePos( &st->st.gpos.markbase ); 530 break; 531 532 case GPOS_LOOKUP_MARKLIG: 533 Free_MarkLigPos( &st->st.gpos.marklig ); 534 break; 535 536 case GPOS_LOOKUP_MARKMARK: 537 Free_MarkMarkPos( &st->st.gpos.markmark ); 538 break; 539 540 case GPOS_LOOKUP_CONTEXT: 541 Free_ContextPos( &st->st.gpos.context ); 542 break; 543 544 case GPOS_LOOKUP_CHAIN: 545 Free_ChainContextPos ( &st->st.gpos.chain ); 546 break; 547 } 548 } 549 550 551 /* Lookup */ 552 Load_Lookup(TTO_Lookup * l,PFace input,TTO_Type type)553 static TT_Error Load_Lookup( TTO_Lookup* l, 554 PFace input, 555 TTO_Type type ) 556 { 557 DEFINE_LOAD_LOCALS( input->stream ); 558 559 UShort n, count; 560 ULong cur_offset, new_offset, base_offset; 561 562 TTO_SubTable* st; 563 564 565 base_offset = FILE_Pos(); 566 567 if ( ACCESS_Frame( 6L ) ) 568 return error; 569 570 l->LookupType = GET_UShort(); 571 l->LookupFlag = GET_UShort(); 572 count = l->SubTableCount = GET_UShort(); 573 574 FORGET_Frame(); 575 576 l->SubTable = NULL; 577 578 if ( ALLOC_ARRAY( l->SubTable, count, TTO_SubTable ) ) 579 return error; 580 581 st = l->SubTable; 582 583 for ( n = 0; n < count; n++ ) 584 { 585 if ( ACCESS_Frame( 2L ) ) 586 goto Fail; 587 588 new_offset = GET_UShort() + base_offset; 589 590 FORGET_Frame(); 591 592 cur_offset = FILE_Pos(); 593 if ( FILE_Seek( new_offset ) || 594 ( error = Load_SubTable( &st[n], input, 595 type, l->LookupType ) ) != TT_Err_Ok ) 596 goto Fail; 597 (void)FILE_Seek( cur_offset ); 598 } 599 600 return TT_Err_Ok; 601 602 Fail: 603 for ( n = 0; n < count; n++ ) 604 Free_SubTable( &st[n], type, l->LookupType ); 605 606 FREE( l->SubTable ); 607 return error; 608 } 609 610 Free_Lookup(TTO_Lookup * l,TTO_Type type)611 static void Free_Lookup( TTO_Lookup* l, 612 TTO_Type type ) 613 { 614 UShort n, count; 615 616 TTO_SubTable* st; 617 618 619 if ( l->SubTable ) 620 { 621 count = l->SubTableCount; 622 st = l->SubTable; 623 624 for ( n = 0; n < count; n++ ) 625 Free_SubTable( &st[n], type, l->LookupType ); 626 627 FREE( st ); 628 } 629 } 630 631 632 /* LookupList */ 633 Load_LookupList(TTO_LookupList * ll,PFace input,TTO_Type type)634 TT_Error Load_LookupList( TTO_LookupList* ll, 635 PFace input, 636 TTO_Type type ) 637 { 638 DEFINE_LOAD_LOCALS( input->stream ); 639 640 UShort n, count; 641 ULong cur_offset, new_offset, base_offset; 642 643 TTO_Lookup* l; 644 645 646 base_offset = FILE_Pos(); 647 648 if ( ACCESS_Frame( 2L ) ) 649 return error; 650 651 count = ll->LookupCount = GET_UShort(); 652 653 FORGET_Frame(); 654 655 ll->Lookup = NULL; 656 657 if ( ALLOC_ARRAY( ll->Lookup, count, TTO_Lookup ) ) 658 return error; 659 if ( ALLOC_ARRAY( ll->Properties, count, UShort ) ) 660 goto Fail2; 661 662 l = ll->Lookup; 663 664 for ( n = 0; n < count; n++ ) 665 { 666 if ( ACCESS_Frame( 2L ) ) 667 goto Fail1; 668 669 new_offset = GET_UShort() + base_offset; 670 671 FORGET_Frame(); 672 673 cur_offset = FILE_Pos(); 674 if ( FILE_Seek( new_offset ) || 675 ( error = Load_Lookup( &l[n], input, type ) ) != TT_Err_Ok ) 676 goto Fail1; 677 (void)FILE_Seek( cur_offset ); 678 } 679 680 return TT_Err_Ok; 681 682 Fail1: 683 FREE( ll->Properties ); 684 685 for ( n = 0; n < count; n++ ) 686 Free_Lookup( &l[n], type ); 687 688 Fail2: 689 FREE( ll->Lookup ); 690 return error; 691 } 692 693 Free_LookupList(TTO_LookupList * ll,TTO_Type type)694 void Free_LookupList( TTO_LookupList* ll, 695 TTO_Type type ) 696 { 697 UShort n, count; 698 699 TTO_Lookup* l; 700 701 702 FREE( ll->Properties ); 703 704 if ( ll->Lookup ) 705 { 706 count = ll->LookupCount; 707 l = ll->Lookup; 708 709 for ( n = 0; n < count; n++ ) 710 Free_Lookup( &l[n], type ); 711 712 FREE( l ); 713 } 714 } 715 716 717 718 /***************************** 719 * Coverage related functions 720 *****************************/ 721 722 723 /* CoverageFormat1 */ 724 Load_Coverage1(TTO_CoverageFormat1 * cf1,PFace input)725 static TT_Error Load_Coverage1( TTO_CoverageFormat1* cf1, 726 PFace input ) 727 { 728 DEFINE_LOAD_LOCALS( input->stream ); 729 730 UShort n, count; 731 732 UShort* ga; 733 734 735 if ( ACCESS_Frame( 2L ) ) 736 return error; 737 738 count = cf1->GlyphCount = GET_UShort(); 739 740 FORGET_Frame(); 741 742 cf1->GlyphArray = NULL; 743 744 if ( ALLOC_ARRAY( cf1->GlyphArray, count, UShort ) ) 745 return error; 746 747 ga = cf1->GlyphArray; 748 749 if ( ACCESS_Frame( count * 2L ) ) 750 { 751 FREE( cf1->GlyphArray ); 752 return error; 753 } 754 755 for ( n = 0; n < count; n++ ) 756 ga[n] = GET_UShort(); 757 758 FORGET_Frame(); 759 760 return TT_Err_Ok; 761 } 762 763 Free_Coverage1(TTO_CoverageFormat1 * cf1)764 static void Free_Coverage1( TTO_CoverageFormat1* cf1 ) 765 { 766 FREE( cf1->GlyphArray ); 767 } 768 769 770 /* CoverageFormat2 */ 771 Load_Coverage2(TTO_CoverageFormat2 * cf2,PFace input)772 static TT_Error Load_Coverage2( TTO_CoverageFormat2* cf2, 773 PFace input ) 774 { 775 DEFINE_LOAD_LOCALS( input->stream ); 776 777 UShort n, count; 778 779 TTO_RangeRecord* rr; 780 781 782 if ( ACCESS_Frame( 2L ) ) 783 return error; 784 785 count = cf2->RangeCount = GET_UShort(); 786 787 FORGET_Frame(); 788 789 cf2->RangeRecord = NULL; 790 791 if ( ALLOC_ARRAY( cf2->RangeRecord, count, TTO_RangeRecord ) ) 792 return error; 793 794 rr = cf2->RangeRecord; 795 796 if ( ACCESS_Frame( count * 6L ) ) 797 goto Fail; 798 799 for ( n = 0; n < count; n++ ) 800 { 801 rr[n].Start = GET_UShort(); 802 rr[n].End = GET_UShort(); 803 rr[n].StartCoverageIndex = GET_UShort(); 804 805 /* sanity check; we are limited to 16bit integers */ 806 if ( rr[n].Start > rr[n].End || 807 ( rr[n].End - rr[n].Start + (long)rr[n].StartCoverageIndex ) >= 808 0x10000L ) 809 { 810 error = TTO_Err_Invalid_SubTable; 811 goto Fail; 812 } 813 } 814 815 FORGET_Frame(); 816 817 return TT_Err_Ok; 818 819 Fail: 820 FREE( cf2->RangeRecord ); 821 return error; 822 } 823 824 Free_Coverage2(TTO_CoverageFormat2 * cf2)825 static void Free_Coverage2( TTO_CoverageFormat2* cf2 ) 826 { 827 FREE( cf2->RangeRecord ); 828 } 829 830 Load_Coverage(TTO_Coverage * c,PFace input)831 TT_Error Load_Coverage( TTO_Coverage* c, 832 PFace input ) 833 { 834 DEFINE_LOAD_LOCALS( input->stream ); 835 836 837 if ( ACCESS_Frame( 2L ) ) 838 return error; 839 840 c->CoverageFormat = GET_UShort(); 841 842 FORGET_Frame(); 843 844 switch ( c->CoverageFormat ) 845 { 846 case 1: 847 return Load_Coverage1( &c->cf.cf1, input ); 848 849 case 2: 850 return Load_Coverage2( &c->cf.cf2, input ); 851 852 default: 853 return TTO_Err_Invalid_SubTable_Format; 854 } 855 856 return TT_Err_Ok; /* never reached */ 857 } 858 859 Free_Coverage(TTO_Coverage * c)860 void Free_Coverage( TTO_Coverage* c ) 861 { 862 switch ( c->CoverageFormat ) 863 { 864 case 1: 865 Free_Coverage1( &c->cf.cf1 ); 866 break; 867 868 case 2: 869 Free_Coverage2( &c->cf.cf2 ); 870 break; 871 } 872 } 873 874 Coverage_Index1(TTO_CoverageFormat1 * cf1,UShort glyphID,UShort * index)875 static TT_Error Coverage_Index1( TTO_CoverageFormat1* cf1, 876 UShort glyphID, 877 UShort* index ) 878 { 879 UShort min, max, new_min, new_max, middle; 880 881 UShort* array = cf1->GlyphArray; 882 883 884 /* binary search */ 885 886 new_min = 0; 887 new_max = cf1->GlyphCount - 1; 888 889 do 890 { 891 min = new_min; 892 max = new_max; 893 894 /* we use (min + max) / 2 = max - (max - min) / 2 to avoid 895 overflow and rounding errors */ 896 897 middle = max - ( ( max - min ) >> 1 ); 898 899 if ( glyphID == array[middle] ) 900 { 901 *index = middle; 902 return TT_Err_Ok; 903 } 904 else if ( glyphID < array[middle] ) 905 { 906 if ( middle == min ) 907 break; 908 new_max = middle - 1; 909 } 910 else 911 { 912 if ( middle == max ) 913 break; 914 new_min = middle + 1; 915 } 916 } while ( min < max ); 917 918 return TTO_Err_Not_Covered; 919 } 920 921 Coverage_Index2(TTO_CoverageFormat2 * cf2,UShort glyphID,UShort * index)922 static TT_Error Coverage_Index2( TTO_CoverageFormat2* cf2, 923 UShort glyphID, 924 UShort* index ) 925 { 926 UShort min, max, new_min, new_max, middle; 927 928 TTO_RangeRecord* rr = cf2->RangeRecord; 929 930 931 /* binary search */ 932 933 new_min = 0; 934 new_max = cf2->RangeCount - 1; 935 936 do 937 { 938 min = new_min; 939 max = new_max; 940 941 /* we use (min + max) / 2 = max - (max - min) / 2 to avoid 942 overflow and rounding errors */ 943 944 middle = max - ( ( max - min ) >> 1 ); 945 946 if ( glyphID >= rr[middle].Start && glyphID <= rr[middle].End ) 947 { 948 *index = rr[middle].StartCoverageIndex + glyphID - rr[middle].Start; 949 return TT_Err_Ok; 950 } 951 else if ( glyphID < rr[middle].Start ) 952 { 953 if ( middle == min ) 954 break; 955 new_max = middle - 1; 956 } 957 else 958 { 959 if ( middle == max ) 960 break; 961 new_min = middle + 1; 962 } 963 } while ( min < max ); 964 965 return TTO_Err_Not_Covered; 966 } 967 968 Coverage_Index(TTO_Coverage * c,UShort glyphID,UShort * index)969 TT_Error Coverage_Index( TTO_Coverage* c, 970 UShort glyphID, 971 UShort* index ) 972 { 973 switch ( c->CoverageFormat ) 974 { 975 case 1: 976 return Coverage_Index1( &c->cf.cf1, glyphID, index ); 977 978 case 2: 979 return Coverage_Index2( &c->cf.cf2, glyphID, index ); 980 981 default: 982 return TTO_Err_Invalid_SubTable_Format; 983 } 984 985 return TT_Err_Ok; /* never reached */ 986 } 987 988 989 990 /************************************* 991 * Class Definition related functions 992 *************************************/ 993 994 995 /* ClassDefFormat1 */ 996 Load_ClassDef1(TTO_ClassDefinition * cd,UShort limit,PFace input)997 static TT_Error Load_ClassDef1( TTO_ClassDefinition* cd, 998 UShort limit, 999 PFace input ) 1000 { 1001 DEFINE_LOAD_LOCALS( input->stream ); 1002 1003 UShort n, count; 1004 1005 UShort* cva; 1006 Bool* d; 1007 1008 TTO_ClassDefFormat1* cdf1; 1009 1010 1011 cdf1 = &cd->cd.cd1; 1012 1013 if ( ACCESS_Frame( 4L ) ) 1014 return error; 1015 1016 cdf1->StartGlyph = GET_UShort(); 1017 count = cdf1->GlyphCount = GET_UShort(); 1018 1019 FORGET_Frame(); 1020 1021 /* sanity check; we are limited to 16bit integers */ 1022 1023 if ( cdf1->StartGlyph + (long)count >= 0x10000L ) 1024 return TTO_Err_Invalid_SubTable; 1025 1026 cdf1->ClassValueArray = NULL; 1027 1028 if ( ALLOC_ARRAY( cdf1->ClassValueArray, count, UShort ) ) 1029 return error; 1030 1031 d = cd->Defined; 1032 cva = cdf1->ClassValueArray; 1033 1034 if ( ACCESS_Frame( count * 2L ) ) 1035 goto Fail; 1036 1037 for ( n = 0; n < count; n++ ) 1038 { 1039 cva[n] = GET_UShort(); 1040 if ( cva[n] >= limit ) 1041 { 1042 error = TTO_Err_Invalid_SubTable; 1043 goto Fail; 1044 } 1045 d[cva[n]] = TRUE; 1046 } 1047 1048 FORGET_Frame(); 1049 1050 return TT_Err_Ok; 1051 1052 Fail: 1053 FREE( cva ); 1054 1055 return error; 1056 } 1057 1058 Free_ClassDef1(TTO_ClassDefFormat1 * cdf1)1059 static void Free_ClassDef1( TTO_ClassDefFormat1* cdf1 ) 1060 { 1061 FREE( cdf1->ClassValueArray ); 1062 } 1063 1064 1065 /* ClassDefFormat2 */ 1066 Load_ClassDef2(TTO_ClassDefinition * cd,UShort limit,PFace input)1067 static TT_Error Load_ClassDef2 ( TTO_ClassDefinition* cd, 1068 UShort limit, 1069 PFace input ) 1070 { 1071 DEFINE_LOAD_LOCALS( input->stream ); 1072 1073 UShort n, count; 1074 1075 TTO_ClassRangeRecord* crr; 1076 Bool* d; 1077 1078 TTO_ClassDefFormat2* cdf2; 1079 1080 1081 cdf2 = &cd->cd.cd2; 1082 1083 if ( ACCESS_Frame( 2L ) ) 1084 return error; 1085 1086 count = cdf2->ClassRangeCount = GET_UShort(); 1087 1088 FORGET_Frame(); 1089 1090 cdf2->ClassRangeRecord = NULL; 1091 1092 if ( ALLOC_ARRAY( cdf2->ClassRangeRecord, count, TTO_ClassRangeRecord ) ) 1093 return error; 1094 1095 d = cd->Defined; 1096 crr = cdf2->ClassRangeRecord; 1097 1098 if ( ACCESS_Frame( count * 6L ) ) 1099 goto Fail; 1100 1101 for ( n = 0; n < count; n++ ) 1102 { 1103 crr[n].Start = GET_UShort(); 1104 crr[n].End = GET_UShort(); 1105 crr[n].Class = GET_UShort(); 1106 1107 /* sanity check */ 1108 1109 if ( crr[n].Start > crr[n].End || 1110 crr[n].Class >= limit ) 1111 { 1112 error = TTO_Err_Invalid_SubTable; 1113 goto Fail; 1114 } 1115 d[crr[n].Class] = TRUE; 1116 } 1117 1118 FORGET_Frame(); 1119 1120 return TT_Err_Ok; 1121 1122 Fail: 1123 FREE( crr ); 1124 1125 return error; 1126 } 1127 1128 Free_ClassDef2(TTO_ClassDefFormat2 * cdf2)1129 static void Free_ClassDef2( TTO_ClassDefFormat2* cdf2 ) 1130 { 1131 FREE( cdf2->ClassRangeRecord ); 1132 } 1133 1134 1135 /* ClassDefinition */ 1136 Load_ClassDefinition(TTO_ClassDefinition * cd,UShort limit,PFace input)1137 TT_Error Load_ClassDefinition( TTO_ClassDefinition* cd, 1138 UShort limit, 1139 PFace input ) 1140 { 1141 DEFINE_LOAD_LOCALS( input->stream ); 1142 1143 1144 if ( ALLOC_ARRAY( cd->Defined, limit, Bool ) ) 1145 return error; 1146 1147 if ( ACCESS_Frame( 2L ) ) 1148 goto Fail; 1149 1150 cd->ClassFormat = GET_UShort(); 1151 1152 FORGET_Frame(); 1153 1154 switch ( cd->ClassFormat ) 1155 { 1156 case 1: 1157 error = Load_ClassDef1( cd, limit, input ); 1158 break; 1159 1160 case 2: 1161 error = Load_ClassDef2( cd, limit, input ); 1162 break; 1163 1164 default: 1165 error = TTO_Err_Invalid_SubTable_Format; 1166 break; 1167 } 1168 1169 if ( error ) 1170 goto Fail; 1171 1172 cd->loaded = TRUE; 1173 1174 return TT_Err_Ok; 1175 1176 Fail: 1177 FREE( cd->Defined ); 1178 return error; 1179 } 1180 1181 Free_ClassDefinition(TTO_ClassDefinition * cd)1182 void Free_ClassDefinition( TTO_ClassDefinition* cd ) 1183 { 1184 if ( !cd->loaded ) 1185 return; 1186 1187 FREE( cd->Defined ); 1188 1189 switch ( cd->ClassFormat ) 1190 { 1191 case 1: 1192 Free_ClassDef1( &cd->cd.cd1 ); 1193 break; 1194 1195 case 2: 1196 Free_ClassDef2( &cd->cd.cd2 ); 1197 break; 1198 } 1199 } 1200 1201 Get_Class1(TTO_ClassDefFormat1 * cdf1,UShort glyphID,UShort * class,UShort * index)1202 static TT_Error Get_Class1( TTO_ClassDefFormat1* cdf1, 1203 UShort glyphID, 1204 UShort* class, 1205 UShort* index ) 1206 { 1207 UShort* cva = cdf1->ClassValueArray; 1208 1209 1210 *index = 0; 1211 1212 if ( glyphID >= cdf1->StartGlyph && 1213 glyphID <= cdf1->StartGlyph + cdf1->GlyphCount ) 1214 { 1215 *class = cva[glyphID - cdf1->StartGlyph]; 1216 return TT_Err_Ok; 1217 } 1218 else 1219 { 1220 *class = 0; 1221 return TTO_Err_Not_Covered; 1222 } 1223 } 1224 1225 1226 /* we need the index value of the last searched class range record 1227 in case of failure for constructed GDEF tables */ 1228 Get_Class2(TTO_ClassDefFormat2 * cdf2,UShort glyphID,UShort * class,UShort * index)1229 static TT_Error Get_Class2( TTO_ClassDefFormat2* cdf2, 1230 UShort glyphID, 1231 UShort* class, 1232 UShort* index ) 1233 { 1234 TT_Error error = TT_Err_Ok; 1235 UShort min, max, new_min, new_max, middle; 1236 1237 TTO_ClassRangeRecord* crr = cdf2->ClassRangeRecord; 1238 1239 1240 /* binary search */ 1241 1242 new_min = 0; 1243 new_max = cdf2->ClassRangeCount - 1; 1244 1245 do 1246 { 1247 min = new_min; 1248 max = new_max; 1249 1250 /* we use (min + max) / 2 = max - (max - min) / 2 to avoid 1251 overflow and rounding errors */ 1252 1253 middle = max - ( ( max - min ) >> 1 ); 1254 1255 if ( glyphID >= crr[middle].Start && glyphID <= crr[middle].End ) 1256 { 1257 *class = crr[middle].Class; 1258 error = TT_Err_Ok; 1259 break; 1260 } 1261 else if ( glyphID < crr[middle].Start ) 1262 { 1263 if ( middle == min ) 1264 { 1265 *class = 0; 1266 error = TTO_Err_Not_Covered; 1267 break; 1268 } 1269 new_max = middle - 1; 1270 } 1271 else 1272 { 1273 if ( middle == max ) 1274 { 1275 *class = 0; 1276 error = TTO_Err_Not_Covered; 1277 break; 1278 } 1279 new_min = middle + 1; 1280 } 1281 } while ( min < max ); 1282 1283 if ( index ) 1284 *index = middle; 1285 1286 return error; 1287 } 1288 1289 Get_Class(TTO_ClassDefinition * cd,UShort glyphID,UShort * class,UShort * index)1290 TT_Error Get_Class( TTO_ClassDefinition* cd, 1291 UShort glyphID, 1292 UShort* class, 1293 UShort* index ) 1294 { 1295 switch ( cd->ClassFormat ) 1296 { 1297 case 1: 1298 return Get_Class1( &cd->cd.cd1, glyphID, class, index ); 1299 1300 case 2: 1301 return Get_Class2( &cd->cd.cd2, glyphID, class, index ); 1302 1303 default: 1304 return TTO_Err_Invalid_SubTable_Format; 1305 } 1306 1307 return TT_Err_Ok; /* never reached */ 1308 } 1309 1310 1311 1312 /*************************** 1313 * Device related functions 1314 ***************************/ 1315 1316 Load_Device(TTO_Device * d,PFace input)1317 TT_Error Load_Device( TTO_Device* d, 1318 PFace input ) 1319 { 1320 DEFINE_LOAD_LOCALS( input->stream ); 1321 1322 UShort n, count; 1323 1324 UShort* dv; 1325 1326 1327 if ( ACCESS_Frame( 6L ) ) 1328 return error; 1329 1330 d->StartSize = GET_UShort(); 1331 d->EndSize = GET_UShort(); 1332 d->DeltaFormat = GET_UShort(); 1333 1334 FORGET_Frame(); 1335 1336 if ( d->StartSize > d->EndSize || 1337 d->DeltaFormat == 0 || d->DeltaFormat > 3 ) 1338 return TTO_Err_Invalid_SubTable; 1339 1340 d->DeltaValue = NULL; 1341 1342 count = ( ( d->EndSize - d->StartSize + 1 ) >> 1343 ( 4 - d->DeltaFormat ) ) + 1; 1344 1345 if ( ALLOC_ARRAY( d->DeltaValue, count, UShort ) ) 1346 return error; 1347 1348 if ( ACCESS_Frame( count * 2L ) ) 1349 { 1350 FREE( d->DeltaValue ); 1351 return error; 1352 } 1353 1354 dv = d->DeltaValue; 1355 1356 for ( n = 0; n < count; n++ ) 1357 dv[n] = GET_UShort(); 1358 1359 FORGET_Frame(); 1360 1361 return TT_Err_Ok; 1362 } 1363 1364 Free_Device(TTO_Device * d)1365 void Free_Device( TTO_Device* d ) 1366 { 1367 FREE( d->DeltaValue ); 1368 } 1369 1370 1371 /* Since we have the delta values stored in compressed form, we must 1372 uncompress it now. To simplify the interface, the function always 1373 returns a meaningful value in `value'; the error is just for 1374 information. 1375 | 1376 format = 1: 0011223344556677|8899101112131415|... 1377 | 1378 byte 1 byte 2 1379 1380 00: (byte >> 14) & mask 1381 11: (byte >> 12) & mask 1382 ... 1383 1384 mask = 0x0003 1385 | 1386 format = 2: 0000111122223333|4444555566667777|... 1387 | 1388 byte 1 byte 2 1389 1390 0000: (byte >> 12) & mask 1391 1111: (byte >> 8) & mask 1392 ... 1393 1394 mask = 0x000F 1395 | 1396 format = 3: 0000000011111111|2222222233333333|... 1397 | 1398 byte 1 byte 2 1399 1400 00000000: (byte >> 8) & mask 1401 11111111: (byte >> 0) & mask 1402 .... 1403 1404 mask = 0x00FF */ 1405 Get_Device(TTO_Device * d,UShort size,Short * value)1406 TT_Error Get_Device( TTO_Device* d, 1407 UShort size, 1408 Short* value ) 1409 { 1410 UShort byte, bits, mask, f, s; 1411 1412 1413 f = d->DeltaFormat; 1414 1415 if ( size >= d->StartSize && size <= d->EndSize ) 1416 { 1417 s = size - d->StartSize; 1418 byte = d->DeltaValue[s >> ( 4 - f )]; 1419 bits = byte >> ( 16 - ( s % ( 1 << ( 4 - f ) ) + 1 ) * ( 1 << f ) ); 1420 mask = 0xFFFF >> ( 16 - ( 1 << f ) ); 1421 1422 *value = (Short)( bits & mask ); 1423 1424 /* conversion to a signed value */ 1425 1426 if ( *value >= ( ( mask + 1 ) >> 1 ) ) 1427 *value -= mask + 1; 1428 1429 return TT_Err_Ok; 1430 } 1431 else 1432 { 1433 *value = 0; 1434 return TTO_Err_Not_Covered; 1435 } 1436 } 1437 1438 1439 /* END */ 1440