1 /******************************************************************* 2 * 3 * ftxgpos.c 4 * 5 * TrueType Open GPOS 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 /* XXX There is *a lot* of duplicated code (cf. formats 7 and 8), but 19 I don't care currently. I believe that it would be possible to 20 save about 50% of TTO code by carefully designing the structures, 21 sharing as much as possible with extensive use of macros. This 22 is something for a volunteer :-) */ 23 24 #include "tttypes.h" 25 #include "tttags.h" 26 #include "ttload.h" 27 #include "ttextend.h" 28 #include "ttmemory.h" 29 #include "ttfile.h" 30 31 #include "ftxopen.h" 32 #include "ftxopenf.h" 33 34 35 #define GPOS_ID Build_Extension_ID( 'G', 'P', 'O', 'S' ) 36 37 38 39 /********************** 40 * Extension Functions 41 **********************/ 42 43 GPOS_Create(void * ext,PFace face)44 static TT_Error GPOS_Create( void* ext, 45 PFace face ) 46 { 47 DEFINE_LOAD_LOCALS( face->stream ); 48 49 TTO_GPOSHeader* gpos = (TTO_GPOSHeader*)ext; 50 Long table; 51 52 53 /* by convention */ 54 55 if ( !gpos ) 56 return TT_Err_Ok; 57 58 /* a null offset indicates that there is no GPOS table */ 59 60 gpos->offset = 0; 61 62 /* we store the start offset and the size of the subtable */ 63 64 table = TT_LookUp_Table( face, TTAG_GPOS ); 65 if ( table < 0 ) 66 return TT_Err_Ok; /* The table is optional */ 67 68 if ( FILE_Seek( face->dirTables[table].Offset ) || 69 ACCESS_Frame( 4L ) ) 70 return error; 71 72 gpos->offset = FILE_Pos() - 4L; /* undo ACCESS_Frame() */ 73 gpos->Version = GET_ULong(); 74 75 FORGET_Frame(); 76 77 gpos->loaded = FALSE; 78 79 return TT_Err_Ok; 80 } 81 82 GPOS_Destroy(void * ext,PFace face)83 static TT_Error GPOS_Destroy( void* ext, 84 PFace face ) 85 { 86 TTO_GPOSHeader* gpos = (TTO_GPOSHeader*)ext; 87 88 89 /* by convention */ 90 91 if ( !gpos ) 92 return TT_Err_Ok; 93 94 if ( gpos->loaded ) 95 { 96 Free_LookupList( &gpos->LookupList, GPOS ); 97 Free_FeatureList( &gpos->FeatureList ); 98 Free_ScriptList( &gpos->ScriptList ); 99 } 100 101 return TT_Err_Ok; 102 } 103 104 105 EXPORT_FUNC TT_Init_GPOS_Extension(TT_Engine engine)106 TT_Error TT_Init_GPOS_Extension( TT_Engine engine ) 107 { 108 PEngine_Instance _engine = HANDLE_Engine( engine ); 109 110 111 if ( !_engine ) 112 return TT_Err_Invalid_Engine; 113 114 return TT_Register_Extension( _engine, 115 GPOS_ID, 116 sizeof ( TTO_GPOSHeader ), 117 GPOS_Create, 118 GPOS_Destroy ); 119 } 120 121 122 EXPORT_FUNC TT_Load_GPOS_Table(TT_Face face,TTO_GPOSHeader * retptr,TTO_GDEFHeader * gdef)123 TT_Error TT_Load_GPOS_Table( TT_Face face, 124 TTO_GPOSHeader* retptr, 125 TTO_GDEFHeader* gdef ) 126 { 127 ULong cur_offset, new_offset, base_offset; 128 129 TT_UShort i, num_lookups; 130 TT_Error error; 131 TT_Stream stream; 132 TTO_GPOSHeader* gpos; 133 TTO_Lookup* lo; 134 135 PFace faze = HANDLE_Face( face ); 136 137 138 if ( !retptr ) 139 return TT_Err_Invalid_Argument; 140 141 if ( !faze ) 142 return TT_Err_Invalid_Face_Handle; 143 144 error = TT_Extension_Get( faze, GPOS_ID, (void**)&gpos ); 145 if ( error ) 146 return error; 147 148 if ( gpos->offset == 0 ) 149 return TT_Err_Table_Missing; /* no GPOS table; nothing to do */ 150 151 /* now access stream */ 152 153 if ( USE_Stream( faze->stream, stream ) ) 154 return error; 155 156 base_offset = gpos->offset; 157 158 /* skip version */ 159 160 if ( FILE_Seek( base_offset + 4L ) || 161 ACCESS_Frame( 2L ) ) 162 return error; 163 164 new_offset = GET_UShort() + base_offset; 165 166 FORGET_Frame(); 167 168 cur_offset = FILE_Pos(); 169 if ( FILE_Seek( new_offset ) || 170 ( error = Load_ScriptList( &gpos->ScriptList, 171 faze ) ) != TT_Err_Ok ) 172 return error; 173 (void)FILE_Seek( cur_offset ); 174 175 if ( ACCESS_Frame( 2L ) ) 176 goto Fail3; 177 178 new_offset = GET_UShort() + base_offset; 179 180 FORGET_Frame(); 181 182 cur_offset = FILE_Pos(); 183 if ( FILE_Seek( new_offset ) || 184 ( error = Load_FeatureList( &gpos->FeatureList, 185 faze ) ) != TT_Err_Ok ) 186 goto Fail3; 187 (void)FILE_Seek( cur_offset ); 188 189 if ( ACCESS_Frame( 2L ) ) 190 goto Fail2; 191 192 new_offset = GET_UShort() + base_offset; 193 194 FORGET_Frame(); 195 196 cur_offset = FILE_Pos(); 197 if ( FILE_Seek( new_offset ) || 198 ( error = Load_LookupList( &gpos->LookupList, 199 faze, GPOS ) ) != TT_Err_Ok ) 200 goto Fail2; 201 202 gpos->gdef = gdef; /* can be NULL */ 203 204 /* We now check the LookupFlags for values larger than 0xFF to find 205 out whether we need to load the `MarkAttachClassDef' field of the 206 GDEF table -- this hack is necessary for OpenType 1.2 tables since 207 the version field of the GDEF table hasn't been incremented. 208 209 For constructed GDEF tables, we only load it if 210 `MarkAttachClassDef_offset' is not zero (nevertheless, a build of 211 a constructed mark attach table is not supported currently). */ 212 213 if ( gdef && 214 gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded ) 215 { 216 lo = gpos->LookupList.Lookup; 217 num_lookups = gpos->LookupList.LookupCount; 218 219 for ( i = 0; i < num_lookups; i++ ) 220 { 221 if ( lo[i].LookupFlag & IGNORE_SPECIAL_MARKS ) 222 { 223 if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) || 224 ACCESS_Frame( 2L ) ) 225 goto Fail1; 226 227 new_offset = GET_UShort(); 228 229 FORGET_Frame(); 230 231 if ( !new_offset ) 232 return TTO_Err_Invalid_GDEF_SubTable; 233 234 new_offset += base_offset; 235 236 if ( FILE_Seek( new_offset ) || 237 ( error = Load_ClassDefinition( &gdef->MarkAttachClassDef, 238 256, faze ) ) != TT_Err_Ok ) 239 goto Fail1; 240 241 break; 242 } 243 } 244 } 245 246 gpos->loaded = TRUE; 247 *retptr = *gpos; 248 DONE_Stream( stream ); 249 250 return TT_Err_Ok; 251 252 Fail1: 253 Free_LookupList( &gpos->LookupList, GPOS ); 254 255 Fail2: 256 Free_FeatureList( &gpos->FeatureList ); 257 258 Fail3: 259 Free_ScriptList( &gpos->ScriptList ); 260 261 /* release stream */ 262 263 DONE_Stream( stream ); 264 265 return error; 266 } 267 268 269 270 /***************************** 271 * SubTable related functions 272 *****************************/ 273 274 /* shared tables */ 275 276 /* ValueRecord */ 277 Load_ValueRecord(TTO_ValueRecord * vr,TT_UShort format,PFace input)278 static TT_Error Load_ValueRecord( TTO_ValueRecord* vr, 279 TT_UShort format, 280 PFace input ) 281 { 282 DEFINE_LOAD_LOCALS( input->stream ); 283 284 ULong cur_offset, new_offset, base_offset; 285 286 287 base_offset = FILE_Pos(); 288 289 if ( format & HAVE_X_PLACEMENT ) 290 { 291 if ( ACCESS_Frame( 2L ) ) 292 return error; 293 294 vr->XPlacement = GET_Short(); 295 296 FORGET_Frame(); 297 } 298 else 299 vr->XPlacement = 0; 300 301 if ( format & HAVE_Y_PLACEMENT ) 302 { 303 if ( ACCESS_Frame( 2L ) ) 304 return error; 305 306 vr->YPlacement = GET_Short(); 307 308 FORGET_Frame(); 309 } 310 else 311 vr->YPlacement = 0; 312 313 if ( format & HAVE_X_ADVANCE ) 314 { 315 if ( ACCESS_Frame( 2L ) ) 316 return error; 317 318 vr->XAdvance = GET_Short(); 319 320 FORGET_Frame(); 321 } 322 else 323 vr->XAdvance = 0; 324 325 if ( format & HAVE_Y_ADVANCE ) 326 { 327 if ( ACCESS_Frame( 2L ) ) 328 return error; 329 330 vr->YAdvance = GET_Short(); 331 332 FORGET_Frame(); 333 } 334 else 335 vr->YAdvance = 0; 336 337 if ( format & HAVE_X_PLACEMENT_DEVICE ) 338 { 339 if ( ACCESS_Frame( 2L ) ) 340 return error; 341 342 new_offset = GET_UShort() + base_offset; 343 344 FORGET_Frame(); 345 346 cur_offset = FILE_Pos(); 347 if ( FILE_Seek( new_offset ) || 348 ( error = Load_Device( &vr->XPlacementDevice, 349 input ) ) != TT_Err_Ok ) 350 return error; 351 (void)FILE_Seek( cur_offset ); 352 } 353 else 354 { 355 vr->XPlacementDevice.StartSize = 0; 356 vr->XPlacementDevice.EndSize = 0; 357 vr->XPlacementDevice.DeltaValue = NULL; 358 } 359 360 if ( format & HAVE_Y_PLACEMENT_DEVICE ) 361 { 362 if ( ACCESS_Frame( 2L ) ) 363 goto Fail3; 364 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_Device( &vr->YPlacementDevice, 372 input ) ) != TT_Err_Ok ) 373 goto Fail3; 374 (void)FILE_Seek( cur_offset ); 375 } 376 else 377 { 378 vr->YPlacementDevice.StartSize = 0; 379 vr->YPlacementDevice.EndSize = 0; 380 vr->YPlacementDevice.DeltaValue = NULL; 381 } 382 383 if ( format & HAVE_X_ADVANCE_DEVICE ) 384 { 385 if ( ACCESS_Frame( 2L ) ) 386 goto Fail2; 387 388 new_offset = GET_UShort() + base_offset; 389 390 FORGET_Frame(); 391 392 cur_offset = FILE_Pos(); 393 if ( FILE_Seek( new_offset ) || 394 ( error = Load_Device( &vr->XAdvanceDevice, 395 input ) ) != TT_Err_Ok ) 396 goto Fail2; 397 (void)FILE_Seek( cur_offset ); 398 } 399 else 400 { 401 vr->XAdvanceDevice.StartSize = 0; 402 vr->XAdvanceDevice.EndSize = 0; 403 vr->XAdvanceDevice.DeltaValue = NULL; 404 } 405 406 if ( format & HAVE_Y_ADVANCE_DEVICE ) 407 { 408 if ( ACCESS_Frame( 2L ) ) 409 goto Fail1; 410 411 new_offset = GET_UShort() + base_offset; 412 413 FORGET_Frame(); 414 415 cur_offset = FILE_Pos(); 416 if ( FILE_Seek( new_offset ) || 417 ( error = Load_Device( &vr->YAdvanceDevice, 418 input ) ) != TT_Err_Ok ) 419 goto Fail1; 420 (void)FILE_Seek( cur_offset ); 421 } 422 else 423 { 424 vr->YAdvanceDevice.StartSize = 0; 425 vr->YAdvanceDevice.EndSize = 0; 426 vr->YAdvanceDevice.DeltaValue = NULL; 427 } 428 429 if ( format & HAVE_X_ID_PLACEMENT ) 430 { 431 if ( ACCESS_Frame( 2L ) ) 432 goto Fail1; 433 434 vr->XIdPlacement = GET_UShort(); 435 436 FORGET_Frame(); 437 } 438 else 439 vr->XIdPlacement = 0; 440 441 if ( format & HAVE_Y_ID_PLACEMENT ) 442 { 443 if ( ACCESS_Frame( 2L ) ) 444 goto Fail1; 445 446 vr->YIdPlacement = GET_UShort(); 447 448 FORGET_Frame(); 449 } 450 else 451 vr->YIdPlacement = 0; 452 453 if ( format & HAVE_X_ID_ADVANCE ) 454 { 455 if ( ACCESS_Frame( 2L ) ) 456 goto Fail1; 457 458 vr->XIdAdvance = GET_UShort(); 459 460 FORGET_Frame(); 461 } 462 else 463 vr->XIdAdvance = 0; 464 465 if ( format & HAVE_Y_ID_ADVANCE ) 466 { 467 if ( ACCESS_Frame( 2L ) ) 468 goto Fail1; 469 470 vr->YIdAdvance = GET_UShort(); 471 472 FORGET_Frame(); 473 } 474 else 475 vr->YIdAdvance = 0; 476 477 return TT_Err_Ok; 478 479 Fail1: 480 Free_Device( &vr->YAdvanceDevice ); 481 482 Fail2: 483 Free_Device( &vr->XAdvanceDevice ); 484 485 Fail3: 486 Free_Device( &vr->YPlacementDevice ); 487 return error; 488 } 489 490 Free_ValueRecord(TTO_ValueRecord * vr,UShort format)491 static void Free_ValueRecord( TTO_ValueRecord* vr, 492 UShort format ) 493 { 494 if ( format & HAVE_Y_ADVANCE_DEVICE ) 495 Free_Device( &vr->YAdvanceDevice ); 496 if ( format & HAVE_X_ADVANCE_DEVICE ) 497 Free_Device( &vr->XAdvanceDevice ); 498 if ( format & HAVE_Y_PLACEMENT_DEVICE ) 499 Free_Device( &vr->YPlacementDevice ); 500 if ( format & HAVE_X_PLACEMENT_DEVICE ) 501 Free_Device( &vr->XPlacementDevice ); 502 } 503 504 505 /* AnchorFormat1 */ 506 /* AnchorFormat2 */ 507 /* AnchorFormat3 */ 508 /* AnchorFormat4 */ 509 Load_Anchor(TTO_Anchor * an,PFace input)510 static TT_Error Load_Anchor( TTO_Anchor* an, 511 PFace input ) 512 { 513 DEFINE_LOAD_LOCALS( input->stream ); 514 515 ULong cur_offset, new_offset, base_offset; 516 517 518 base_offset = FILE_Pos(); 519 520 if ( ACCESS_Frame( 2L ) ) 521 return error; 522 523 an->PosFormat = GET_UShort(); 524 525 FORGET_Frame(); 526 527 switch ( an->PosFormat ) 528 { 529 case 1: 530 if ( ACCESS_Frame( 4L ) ) 531 return error; 532 533 an->af.af1.XCoordinate = GET_Short(); 534 an->af.af1.YCoordinate = GET_Short(); 535 536 FORGET_Frame(); 537 break; 538 539 case 2: 540 if ( ACCESS_Frame( 6L ) ) 541 return error; 542 543 an->af.af2.XCoordinate = GET_Short(); 544 an->af.af2.YCoordinate = GET_Short(); 545 an->af.af2.AnchorPoint = GET_UShort(); 546 547 FORGET_Frame(); 548 break; 549 550 case 3: 551 if ( ACCESS_Frame( 6L ) ) 552 return error; 553 554 an->af.af3.XCoordinate = GET_Short(); 555 an->af.af3.YCoordinate = GET_Short(); 556 557 new_offset = GET_UShort(); 558 559 FORGET_Frame(); 560 561 if ( new_offset ) 562 { 563 new_offset += base_offset; 564 565 cur_offset = FILE_Pos(); 566 if ( FILE_Seek( new_offset ) || 567 ( error = Load_Device( &an->af.af3.XDeviceTable, 568 input ) ) != TT_Err_Ok ) 569 return error; 570 (void)FILE_Seek( cur_offset ); 571 } 572 else 573 { 574 an->af.af3.XDeviceTable.StartSize = 0; 575 an->af.af3.XDeviceTable.EndSize = 0; 576 an->af.af3.XDeviceTable.DeltaValue = 0; 577 } 578 579 if ( ACCESS_Frame( 2L ) ) 580 goto Fail; 581 582 new_offset = GET_UShort(); 583 584 FORGET_Frame(); 585 586 if ( new_offset ) 587 { 588 new_offset += base_offset; 589 590 cur_offset = FILE_Pos(); 591 if ( FILE_Seek( new_offset ) || 592 ( error = Load_Device( &an->af.af3.YDeviceTable, 593 input ) ) != TT_Err_Ok ) 594 goto Fail; 595 (void)FILE_Seek( cur_offset ); 596 } 597 else 598 { 599 an->af.af3.YDeviceTable.StartSize = 0; 600 an->af.af3.YDeviceTable.EndSize = 0; 601 an->af.af3.YDeviceTable.DeltaValue = 0; 602 } 603 break; 604 605 case 4: 606 if ( ACCESS_Frame( 4L ) ) 607 return error; 608 609 an->af.af4.XIdAnchor = GET_UShort(); 610 an->af.af4.YIdAnchor = GET_UShort(); 611 612 FORGET_Frame(); 613 break; 614 615 default: 616 return TTO_Err_Invalid_GPOS_SubTable_Format; 617 } 618 619 return TT_Err_Ok; 620 621 Fail: 622 Free_Device( &an->af.af3.XDeviceTable ); 623 return error; 624 } 625 626 Free_Anchor(TTO_Anchor * an)627 static void Free_Anchor( TTO_Anchor* an ) 628 { 629 if ( an->PosFormat == 3 ) 630 { 631 Free_Device( &an->af.af3.YDeviceTable ); 632 Free_Device( &an->af.af3.XDeviceTable ); 633 } 634 } 635 636 637 /* MarkArray */ 638 Load_MarkArray(TTO_MarkArray * ma,PFace input)639 static TT_Error Load_MarkArray ( TTO_MarkArray* ma, 640 PFace input ) 641 { 642 DEFINE_LOAD_LOCALS( input->stream ); 643 644 UShort n, count; 645 ULong cur_offset, new_offset, base_offset; 646 647 TTO_MarkRecord* mr; 648 649 650 base_offset = FILE_Pos(); 651 652 if ( ACCESS_Frame( 2L ) ) 653 return error; 654 655 count = ma->MarkCount = GET_UShort(); 656 657 FORGET_Frame(); 658 659 ma->MarkRecord = NULL; 660 661 if ( ALLOC_ARRAY( ma->MarkRecord, count, TTO_MarkRecord ) ) 662 return error; 663 664 mr = ma->MarkRecord; 665 666 for ( n = 0; n < count; n++ ) 667 { 668 if ( ACCESS_Frame( 4L ) ) 669 goto Fail; 670 671 mr[n].Class = GET_UShort(); 672 new_offset = GET_UShort() + base_offset; 673 674 FORGET_Frame(); 675 676 cur_offset = FILE_Pos(); 677 if ( FILE_Seek( new_offset ) || 678 ( error = Load_Anchor( &mr[n].MarkAnchor, input ) ) != TT_Err_Ok ) 679 goto Fail; 680 (void)FILE_Seek( cur_offset ); 681 } 682 683 return TT_Err_Ok; 684 685 Fail: 686 for ( n = 0; n < count; n++ ) 687 Free_Anchor( &mr[n].MarkAnchor ); 688 689 FREE( mr ); 690 return error; 691 } 692 693 Free_MarkArray(TTO_MarkArray * ma)694 static void Free_MarkArray( TTO_MarkArray* ma ) 695 { 696 UShort n, count; 697 698 TTO_MarkRecord* mr; 699 700 701 if ( ma->MarkRecord ) 702 { 703 count = ma->MarkCount; 704 mr = ma->MarkRecord; 705 706 for ( n = 0; n < count; n++ ) 707 Free_Anchor( &mr[n].MarkAnchor ); 708 709 FREE( mr ); 710 } 711 } 712 713 714 /* LookupType 1 */ 715 716 /* SinglePosFormat1 */ 717 /* SinglePosFormat2 */ 718 Load_SinglePos(TTO_SinglePos * sp,PFace input)719 TT_Error Load_SinglePos( TTO_SinglePos* sp, 720 PFace input ) 721 { 722 DEFINE_LOAD_LOCALS( input->stream ); 723 724 UShort n, count, format; 725 ULong cur_offset, new_offset, base_offset; 726 727 TTO_ValueRecord* v; 728 729 730 base_offset = FILE_Pos(); 731 732 if ( ACCESS_Frame( 6L ) ) 733 return error; 734 735 sp->PosFormat = GET_UShort(); 736 new_offset = GET_UShort() + base_offset; 737 738 format = sp->ValueFormat = GET_UShort(); 739 740 FORGET_Frame(); 741 742 if ( !format ) 743 return TTO_Err_Invalid_GPOS_SubTable; 744 745 cur_offset = FILE_Pos(); 746 if ( FILE_Seek( new_offset ) || 747 ( error = Load_Coverage( &sp->Coverage, input ) ) != TT_Err_Ok ) 748 return error; 749 (void)FILE_Seek( cur_offset ); 750 751 switch ( sp->PosFormat ) 752 { 753 case 1: 754 error = Load_ValueRecord( &sp->spf.spf1.Value, format, input ); 755 if ( error ) 756 goto Fail2; 757 break; 758 759 case 2: 760 if ( ACCESS_Frame( 2L ) ) 761 goto Fail2; 762 763 count = sp->spf.spf2.ValueCount = GET_UShort(); 764 765 FORGET_Frame(); 766 767 sp->spf.spf2.Value = NULL; 768 769 if ( ALLOC_ARRAY( sp->spf.spf2.Value, count, TTO_ValueRecord ) ) 770 goto Fail2; 771 772 v = sp->spf.spf2.Value; 773 774 for ( n = 0; n < count; n++ ) 775 { 776 error = Load_ValueRecord( &v[n], format, input ); 777 if ( error ) 778 goto Fail1; 779 } 780 break; 781 782 default: 783 return TTO_Err_Invalid_GPOS_SubTable_Format; 784 } 785 786 return TT_Err_Ok; 787 788 Fail1: 789 for ( n = 0; n < count; n++ ) 790 Free_ValueRecord( &v[n], format ); 791 792 FREE( v ); 793 794 Fail2: 795 Free_Coverage( &sp->Coverage ); 796 return error; 797 } 798 799 Free_SinglePos(TTO_SinglePos * sp)800 void Free_SinglePos( TTO_SinglePos* sp ) 801 { 802 UShort n, count, format; 803 804 TTO_ValueRecord* v; 805 806 807 format = sp->ValueFormat; 808 809 switch ( sp->PosFormat ) 810 { 811 case 1: 812 Free_ValueRecord( &sp->spf.spf1.Value, format ); 813 break; 814 815 case 2: 816 if ( sp->spf.spf2.Value ) 817 { 818 count = sp->spf.spf2.ValueCount; 819 v = sp->spf.spf2.Value; 820 821 for ( n = 0; n < count; n++ ) 822 Free_ValueRecord( &v[n], format ); 823 824 FREE( v ); 825 } 826 break; 827 } 828 829 Free_Coverage( &sp->Coverage ); 830 } 831 832 833 /* LookupType 2 */ 834 835 /* PairSet */ 836 Load_PairSet(TTO_PairSet * ps,UShort format1,UShort format2,PFace input)837 static TT_Error Load_PairSet ( TTO_PairSet* ps, 838 UShort format1, 839 UShort format2, 840 PFace input ) 841 { 842 DEFINE_LOAD_LOCALS( input->stream ); 843 844 UShort n, count; 845 846 TTO_PairValueRecord* pvr; 847 848 849 if ( ACCESS_Frame( 2L ) ) 850 return error; 851 852 count = ps->PairValueCount = GET_UShort(); 853 854 FORGET_Frame(); 855 856 ps->PairValueRecord = NULL; 857 858 if ( ALLOC_ARRAY( ps->PairValueRecord, count, TTO_PairValueRecord ) ) 859 return error; 860 861 pvr = ps->PairValueRecord; 862 863 for ( n = 0; n < count; n++ ) 864 { 865 if ( ACCESS_Frame( 2L ) ) 866 goto Fail; 867 868 pvr[n].SecondGlyph = GET_UShort(); 869 870 FORGET_Frame(); 871 872 if ( format1 ) 873 { 874 error = Load_ValueRecord( &pvr[n].Value1, format1, input ); 875 if ( error ) 876 goto Fail; 877 } 878 if ( format2 ) 879 { 880 error = Load_ValueRecord( &pvr[n].Value2, format2, input ); 881 if ( error ) 882 goto Fail; 883 } 884 } 885 886 return TT_Err_Ok; 887 888 Fail: 889 for ( n = 0; n < count; n++ ) 890 { 891 if ( format1 ) 892 Free_ValueRecord( &pvr[n].Value1, format1 ); 893 if ( format2 ) 894 Free_ValueRecord( &pvr[n].Value2, format2 ); 895 } 896 897 FREE( pvr ); 898 return error; 899 } 900 901 Free_PairSet(TTO_PairSet * ps,UShort format1,UShort format2)902 static void Free_PairSet( TTO_PairSet* ps, 903 UShort format1, 904 UShort format2 ) 905 { 906 UShort n, count; 907 908 TTO_PairValueRecord* pvr; 909 910 911 if ( ps->PairValueRecord ) 912 { 913 count = ps->PairValueCount; 914 pvr = ps->PairValueRecord; 915 916 for ( n = 0; n < count; n++ ) 917 { 918 if ( format1 ) 919 Free_ValueRecord( &pvr[n].Value1, format1 ); 920 if ( format2 ) 921 Free_ValueRecord( &pvr[n].Value2, format2 ); 922 } 923 924 FREE( pvr ); 925 } 926 } 927 928 929 /* PairPosFormat1 */ 930 Load_PairPosFormat1(TTO_PairPosFormat1 * ppf1,UShort format1,UShort format2,PFace input)931 static TT_Error Load_PairPosFormat1( TTO_PairPosFormat1* ppf1, 932 UShort format1, 933 UShort format2, 934 PFace input ) 935 { 936 DEFINE_LOAD_LOCALS( input->stream ); 937 938 UShort n, count; 939 ULong cur_offset, new_offset, base_offset; 940 941 TTO_PairSet* ps; 942 943 944 base_offset = FILE_Pos() - 8L; 945 946 if ( ACCESS_Frame( 2L ) ) 947 return error; 948 949 count = ppf1->PairSetCount = GET_UShort(); 950 951 FORGET_Frame(); 952 953 ppf1->PairSet = NULL; 954 955 if ( ALLOC_ARRAY( ppf1->PairSet, count, TTO_PairSet ) ) 956 goto Fail; 957 958 ps = ppf1->PairSet; 959 960 for ( n = 0; n < count; n++ ) 961 { 962 if ( ACCESS_Frame( 2L ) ) 963 goto Fail; 964 965 new_offset = GET_UShort() + base_offset; 966 967 FORGET_Frame(); 968 969 cur_offset = FILE_Pos(); 970 if ( FILE_Seek( new_offset ) || 971 ( error = Load_PairSet( &ps[n], format1, 972 format2, input ) ) != TT_Err_Ok ) 973 goto Fail; 974 (void)FILE_Seek( cur_offset ); 975 } 976 977 return TT_Err_Ok; 978 979 Fail: 980 for ( n = 0; n < count; n++ ) 981 Free_PairSet( &ps[n], format1, format2 ); 982 983 FREE( ps ); 984 return error; 985 } 986 987 Free_PairPosFormat1(TTO_PairPosFormat1 * ppf1,UShort format1,UShort format2)988 static void Free_PairPosFormat1( TTO_PairPosFormat1* ppf1, 989 UShort format1, 990 UShort format2 ) 991 { 992 UShort n, count; 993 994 TTO_PairSet* ps; 995 996 997 if ( ppf1->PairSet ) 998 { 999 count = ppf1->PairSetCount; 1000 ps = ppf1->PairSet; 1001 1002 for ( n = 0; n < count; n++ ) 1003 Free_PairSet( &ps[n], format1, format2 ); 1004 1005 FREE( ps ); 1006 } 1007 } 1008 1009 1010 /* PairPosFormat2 */ 1011 Load_PairPosFormat2(TTO_PairPosFormat2 * ppf2,UShort format1,UShort format2,PFace input)1012 static TT_Error Load_PairPosFormat2( TTO_PairPosFormat2* ppf2, 1013 UShort format1, 1014 UShort format2, 1015 PFace input ) 1016 { 1017 DEFINE_LOAD_LOCALS( input->stream ); 1018 1019 UShort m, n, count1, count2; 1020 ULong cur_offset, new_offset1, new_offset2, base_offset; 1021 1022 TTO_Class1Record* c1r; 1023 TTO_Class2Record* c2r; 1024 1025 1026 base_offset = FILE_Pos() - 8L; 1027 1028 if ( ACCESS_Frame( 8L ) ) 1029 return error; 1030 1031 new_offset1 = GET_UShort() + base_offset; 1032 new_offset2 = GET_UShort() + base_offset; 1033 1034 /* `Class1Count' and `Class2Count' are the upper limits for class 1035 values, thus we read it now to make additional safety checks. */ 1036 1037 count1 = ppf2->Class1Count = GET_UShort(); 1038 count2 = ppf2->Class2Count = GET_UShort(); 1039 1040 FORGET_Frame(); 1041 1042 cur_offset = FILE_Pos(); 1043 if ( FILE_Seek( new_offset1 ) || 1044 ( error = Load_ClassDefinition( &ppf2->ClassDef1, count1, 1045 input ) ) != TT_Err_Ok ) 1046 return error; 1047 (void)FILE_Seek( cur_offset ); 1048 1049 cur_offset = FILE_Pos(); 1050 if ( FILE_Seek( new_offset2 ) || 1051 ( error = Load_ClassDefinition( &ppf2->ClassDef2, count2, 1052 input ) ) != TT_Err_Ok ) 1053 goto Fail2; 1054 (void)FILE_Seek( cur_offset ); 1055 1056 ppf2->Class1Record = NULL; 1057 1058 if ( ALLOC_ARRAY( ppf2->Class1Record, count1, TTO_Class1Record ) ) 1059 goto Fail1; 1060 1061 c1r = ppf2->Class1Record; 1062 1063 for ( m = 0; m < count1; m++ ) 1064 { 1065 c1r[m].Class2Record = NULL; 1066 1067 if ( ALLOC_ARRAY( c1r[m].Class2Record, count2, TTO_Class2Record ) ) 1068 goto Fail1; 1069 1070 c2r = c1r[m].Class2Record; 1071 1072 for ( n = 0; n < count2; n++ ) 1073 { 1074 if ( format1 ) 1075 { 1076 Load_ValueRecord( &c2r[n].Value1, format1, input ); 1077 if ( error ) 1078 goto Fail1; 1079 } 1080 if ( format2 ) 1081 { 1082 Load_ValueRecord( &c2r[n].Value2, format2, input ); 1083 if ( error ) 1084 goto Fail1; 1085 } 1086 } 1087 } 1088 1089 return TT_Err_Ok; 1090 1091 Fail1: 1092 for ( m = 0; m < count1; m++ ) 1093 { 1094 c2r = c1r[m].Class2Record; 1095 1096 for ( n = 0; n < count2; n++ ) 1097 { 1098 if ( format1 ) 1099 Free_ValueRecord( &c2r[n].Value1, format1 ); 1100 if ( format2 ) 1101 Free_ValueRecord( &c2r[n].Value2, format2 ); 1102 } 1103 1104 FREE( c2r ); 1105 } 1106 1107 FREE( c1r ); 1108 1109 Free_ClassDefinition( &ppf2->ClassDef2 ); 1110 1111 Fail2: 1112 Free_ClassDefinition( &ppf2->ClassDef1 ); 1113 return error; 1114 } 1115 1116 Free_PairPosFormat2(TTO_PairPosFormat2 * ppf2,UShort format1,UShort format2)1117 static void Free_PairPosFormat2( TTO_PairPosFormat2* ppf2, 1118 UShort format1, 1119 UShort format2 ) 1120 { 1121 UShort m, n, count1, count2; 1122 1123 TTO_Class1Record* c1r; 1124 TTO_Class2Record* c2r; 1125 1126 1127 if ( ppf2->Class1Record ) 1128 { 1129 c1r = ppf2->Class1Record; 1130 count1 = ppf2->Class1Count; 1131 count2 = ppf2->Class2Count; 1132 1133 for ( m = 0; m < count1; m++ ) 1134 { 1135 c2r = c1r[m].Class2Record; 1136 1137 for ( n = 0; n < count2; n++ ) 1138 { 1139 if ( format1 ) 1140 Free_ValueRecord( &c2r[n].Value1, format1 ); 1141 if ( format2 ) 1142 Free_ValueRecord( &c2r[n].Value2, format2 ); 1143 } 1144 1145 FREE( c2r ); 1146 } 1147 1148 FREE( c1r ); 1149 1150 Free_ClassDefinition( &ppf2->ClassDef2 ); 1151 Free_ClassDefinition( &ppf2->ClassDef1 ); 1152 } 1153 } 1154 1155 Load_PairPos(TTO_PairPos * pp,PFace input)1156 TT_Error Load_PairPos( TTO_PairPos* pp, 1157 PFace input ) 1158 { 1159 DEFINE_LOAD_LOCALS( input->stream ); 1160 1161 UShort format1, format2; 1162 ULong cur_offset, new_offset, base_offset; 1163 1164 1165 base_offset = FILE_Pos(); 1166 1167 if ( ACCESS_Frame( 8L ) ) 1168 return error; 1169 1170 pp->PosFormat = GET_UShort(); 1171 new_offset = GET_UShort() + base_offset; 1172 1173 format1 = pp->ValueFormat1 = GET_UShort(); 1174 format2 = pp->ValueFormat2 = GET_UShort(); 1175 1176 FORGET_Frame(); 1177 1178 cur_offset = FILE_Pos(); 1179 if ( FILE_Seek( new_offset ) || 1180 ( error = Load_Coverage( &pp->Coverage, input ) ) != TT_Err_Ok ) 1181 return error; 1182 (void)FILE_Seek( cur_offset ); 1183 1184 switch ( pp->PosFormat ) 1185 { 1186 case 1: 1187 error = Load_PairPosFormat1( &pp->ppf.ppf1, format1, format2, input ); 1188 if ( error ) 1189 goto Fail; 1190 break; 1191 1192 case 2: 1193 error = Load_PairPosFormat2( &pp->ppf.ppf2, format1, format2, input ); 1194 if ( error ) 1195 goto Fail; 1196 break; 1197 1198 default: 1199 return TTO_Err_Invalid_GPOS_SubTable_Format; 1200 } 1201 1202 return TT_Err_Ok; 1203 1204 Fail: 1205 Free_Coverage( &pp->Coverage ); 1206 return error; 1207 } 1208 1209 Free_PairPos(TTO_PairPos * pp)1210 void Free_PairPos( TTO_PairPos* pp ) 1211 { 1212 UShort format1, format2; 1213 1214 1215 format1 = pp->ValueFormat1; 1216 format2 = pp->ValueFormat2; 1217 1218 switch ( pp->PosFormat ) 1219 { 1220 case 1: 1221 Free_PairPosFormat1( &pp->ppf.ppf1, format1, format2 ); 1222 break; 1223 1224 case 2: 1225 Free_PairPosFormat2( &pp->ppf.ppf2, format1, format2 ); 1226 break; 1227 } 1228 1229 Free_Coverage( &pp->Coverage ); 1230 } 1231 1232 1233 /* LookupType 3 */ 1234 1235 /* CursivePosFormat1 */ 1236 Load_CursivePos(TTO_CursivePos * cp,PFace input)1237 TT_Error Load_CursivePos( TTO_CursivePos* cp, 1238 PFace input ) 1239 { 1240 DEFINE_LOAD_LOCALS( input->stream ); 1241 1242 UShort n, count; 1243 ULong cur_offset, new_offset, base_offset; 1244 1245 TTO_EntryExitRecord* eer; 1246 1247 1248 base_offset = FILE_Pos(); 1249 1250 if ( ACCESS_Frame( 4L ) ) 1251 return error; 1252 1253 cp->PosFormat = GET_UShort(); 1254 new_offset = GET_UShort() + base_offset; 1255 1256 FORGET_Frame(); 1257 1258 cur_offset = FILE_Pos(); 1259 if ( FILE_Seek( new_offset ) || 1260 ( error = Load_Coverage( &cp->Coverage, input ) ) != TT_Err_Ok ) 1261 return error; 1262 (void)FILE_Seek( cur_offset ); 1263 1264 if ( ACCESS_Frame( 2L ) ) 1265 goto Fail2; 1266 1267 count = cp->EntryExitCount = GET_UShort(); 1268 1269 FORGET_Frame(); 1270 1271 cp->EntryExitRecord = NULL; 1272 1273 if ( ALLOC_ARRAY( cp->EntryExitRecord, count, TTO_EntryExitRecord ) ) 1274 goto Fail2; 1275 1276 eer = cp->EntryExitRecord; 1277 1278 for ( n = 0; n < count; n++ ) 1279 { 1280 if ( ACCESS_Frame( 2L ) ) 1281 return error; 1282 1283 new_offset = GET_UShort(); 1284 1285 FORGET_Frame(); 1286 1287 if ( new_offset ) 1288 { 1289 new_offset += base_offset; 1290 1291 cur_offset = FILE_Pos(); 1292 if ( FILE_Seek( new_offset ) || 1293 ( error = Load_Anchor( &eer[n].EntryAnchor, 1294 input ) ) != TT_Err_Ok ) 1295 goto Fail1; 1296 (void)FILE_Seek( cur_offset ); 1297 } 1298 else 1299 eer[n].EntryAnchor.PosFormat = 0; 1300 1301 if ( ACCESS_Frame( 2L ) ) 1302 return error; 1303 1304 new_offset = GET_UShort(); 1305 1306 FORGET_Frame(); 1307 1308 if ( new_offset ) 1309 { 1310 new_offset += base_offset; 1311 1312 cur_offset = FILE_Pos(); 1313 if ( FILE_Seek( new_offset ) || 1314 ( error = Load_Anchor( &eer[n].ExitAnchor, 1315 input ) ) != TT_Err_Ok ) 1316 goto Fail1; 1317 (void)FILE_Seek( cur_offset ); 1318 } 1319 else 1320 eer[n].ExitAnchor.PosFormat = 0; 1321 } 1322 1323 return TT_Err_Ok; 1324 1325 Fail1: 1326 for ( n = 0; n < count; n++ ) 1327 { 1328 Free_Anchor( &eer[n].EntryAnchor ); 1329 Free_Anchor( &eer[n].ExitAnchor ); 1330 } 1331 1332 FREE( eer ); 1333 1334 Fail2: 1335 Free_Coverage( &cp->Coverage ); 1336 return error; 1337 } 1338 1339 Free_CursivePos(TTO_CursivePos * cp)1340 void Free_CursivePos( TTO_CursivePos* cp ) 1341 { 1342 UShort n, count; 1343 1344 TTO_EntryExitRecord* eer; 1345 1346 1347 if ( cp->EntryExitRecord ) 1348 { 1349 count = cp->EntryExitCount; 1350 eer = cp->EntryExitRecord; 1351 1352 for ( n = 0; n < count; n++ ) 1353 { 1354 Free_Anchor( &eer[n].EntryAnchor ); 1355 Free_Anchor( &eer[n].ExitAnchor ); 1356 } 1357 1358 FREE( eer ); 1359 } 1360 1361 Free_Coverage( &cp->Coverage ); 1362 } 1363 1364 1365 /* LookupType 4 */ 1366 1367 /* BaseArray */ 1368 Load_BaseArray(TTO_BaseArray * ba,UShort num_classes,PFace input)1369 static TT_Error Load_BaseArray( TTO_BaseArray* ba, 1370 UShort num_classes, 1371 PFace input ) 1372 { 1373 DEFINE_LOAD_LOCALS( input->stream ); 1374 1375 UShort m, n, count; 1376 ULong cur_offset, new_offset, base_offset; 1377 1378 TTO_BaseRecord* br; 1379 TTO_Anchor* ban; 1380 1381 1382 base_offset = FILE_Pos(); 1383 1384 if ( ACCESS_Frame( 2L ) ) 1385 return error; 1386 1387 count = ba->BaseCount = GET_UShort(); 1388 1389 FORGET_Frame(); 1390 1391 ba->BaseRecord = NULL; 1392 1393 if ( ALLOC_ARRAY( ba->BaseRecord, count, TTO_BaseRecord ) ) 1394 return error; 1395 1396 br = ba->BaseRecord; 1397 1398 for ( m = 0; m < count; m++ ) 1399 { 1400 br[m].BaseAnchor = NULL; 1401 1402 if ( ALLOC_ARRAY( br[m].BaseAnchor, num_classes, TTO_Anchor ) ) 1403 goto Fail; 1404 1405 ban = br[m].BaseAnchor; 1406 1407 for ( n = 0; n < num_classes; n++ ) 1408 { 1409 if ( ACCESS_Frame( 2L ) ) 1410 goto Fail; 1411 1412 new_offset = GET_UShort() + base_offset; 1413 1414 FORGET_Frame(); 1415 1416 cur_offset = FILE_Pos(); 1417 if ( FILE_Seek( new_offset ) || 1418 ( error = Load_Anchor( &ban[n], input ) ) != TT_Err_Ok ) 1419 goto Fail; 1420 (void)FILE_Seek( cur_offset ); 1421 } 1422 } 1423 1424 return TT_Err_Ok; 1425 1426 Fail: 1427 for ( m = 0; m < count; m++ ) 1428 { 1429 ban = br[m].BaseAnchor; 1430 1431 for ( n = 0; n < num_classes; n++ ) 1432 Free_Anchor( &ban[n] ); 1433 1434 FREE( ban ); 1435 } 1436 1437 FREE( br ); 1438 return error; 1439 } 1440 1441 Free_BaseArray(TTO_BaseArray * ba,UShort num_classes)1442 static void Free_BaseArray( TTO_BaseArray* ba, 1443 UShort num_classes ) 1444 { 1445 UShort m, n, count; 1446 1447 TTO_BaseRecord* br; 1448 TTO_Anchor* ban; 1449 1450 1451 if ( ba->BaseRecord ) 1452 { 1453 count = ba->BaseCount; 1454 br = ba->BaseRecord; 1455 1456 for ( m = 0; m < count; m++ ) 1457 { 1458 ban = br[m].BaseAnchor; 1459 1460 for ( n = 0; n < num_classes; n++ ) 1461 Free_Anchor( &ban[n] ); 1462 1463 FREE( ban ); 1464 } 1465 1466 FREE( br ); 1467 } 1468 } 1469 1470 1471 /* MarkBasePosFormat1 */ 1472 Load_MarkBasePos(TTO_MarkBasePos * mbp,PFace input)1473 TT_Error Load_MarkBasePos( TTO_MarkBasePos* mbp, 1474 PFace input ) 1475 { 1476 DEFINE_LOAD_LOCALS( input->stream ); 1477 1478 ULong cur_offset, new_offset, base_offset; 1479 1480 1481 base_offset = FILE_Pos(); 1482 1483 if ( ACCESS_Frame( 4L ) ) 1484 return error; 1485 1486 mbp->PosFormat = GET_UShort(); 1487 new_offset = GET_UShort() + base_offset; 1488 1489 FORGET_Frame(); 1490 1491 cur_offset = FILE_Pos(); 1492 if ( FILE_Seek( new_offset ) || 1493 ( error = Load_Coverage( &mbp->MarkCoverage, input ) ) != TT_Err_Ok ) 1494 return error; 1495 (void)FILE_Seek( cur_offset ); 1496 1497 if ( ACCESS_Frame( 2L ) ) 1498 goto Fail3; 1499 1500 new_offset = GET_UShort() + base_offset; 1501 1502 FORGET_Frame(); 1503 1504 cur_offset = FILE_Pos(); 1505 if ( FILE_Seek( new_offset ) || 1506 ( error = Load_Coverage( &mbp->BaseCoverage, input ) ) != TT_Err_Ok ) 1507 goto Fail3; 1508 (void)FILE_Seek( cur_offset ); 1509 1510 if ( ACCESS_Frame( 4L ) ) 1511 goto Fail2; 1512 1513 mbp->ClassCount = GET_UShort(); 1514 new_offset = GET_UShort() + base_offset; 1515 1516 FORGET_Frame(); 1517 1518 cur_offset = FILE_Pos(); 1519 if ( FILE_Seek( new_offset ) || 1520 ( error = Load_MarkArray( &mbp->MarkArray, input ) ) != TT_Err_Ok ) 1521 goto Fail2; 1522 (void)FILE_Seek( cur_offset ); 1523 1524 if ( ACCESS_Frame( 2L ) ) 1525 goto Fail1; 1526 1527 new_offset = GET_UShort() + base_offset; 1528 1529 FORGET_Frame(); 1530 1531 cur_offset = FILE_Pos(); 1532 if ( FILE_Seek( new_offset ) || 1533 ( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount, 1534 input ) ) != TT_Err_Ok ) 1535 goto Fail1; 1536 1537 return TT_Err_Ok; 1538 1539 Fail1: 1540 Free_MarkArray( &mbp->MarkArray ); 1541 1542 Fail2: 1543 Free_Coverage( &mbp->BaseCoverage ); 1544 1545 Fail3: 1546 Free_Coverage( &mbp->MarkCoverage ); 1547 return error; 1548 } 1549 1550 Free_MarkBasePos(TTO_MarkBasePos * mbp)1551 void Free_MarkBasePos( TTO_MarkBasePos* mbp ) 1552 { 1553 Free_BaseArray( &mbp->BaseArray, mbp->ClassCount ); 1554 Free_MarkArray( &mbp->MarkArray ); 1555 Free_Coverage( &mbp->BaseCoverage ); 1556 Free_Coverage( &mbp->MarkCoverage ); 1557 } 1558 1559 1560 /* LookupType 5 */ 1561 1562 /* LigatureAttach */ 1563 Load_LigatureAttach(TTO_LigatureAttach * lat,UShort num_classes,PFace input)1564 static TT_Error Load_LigatureAttach( TTO_LigatureAttach* lat, 1565 UShort num_classes, 1566 PFace input ) 1567 { 1568 DEFINE_LOAD_LOCALS( input->stream ); 1569 1570 UShort m, n, count; 1571 ULong cur_offset, new_offset, base_offset; 1572 1573 TTO_ComponentRecord* cr; 1574 TTO_Anchor* lan; 1575 1576 1577 base_offset = FILE_Pos(); 1578 1579 if ( ACCESS_Frame( 2L ) ) 1580 return error; 1581 1582 count = lat->ComponentCount = GET_UShort(); 1583 1584 FORGET_Frame(); 1585 1586 lat->ComponentRecord = NULL; 1587 1588 if ( ALLOC_ARRAY( lat->ComponentRecord, count, TTO_ComponentRecord ) ) 1589 return error; 1590 1591 cr = lat->ComponentRecord; 1592 1593 for ( m = 0; m < count; m++ ) 1594 { 1595 cr[m].LigatureAnchor = NULL; 1596 1597 if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, TTO_Anchor ) ) 1598 goto Fail; 1599 1600 lan = cr[m].LigatureAnchor; 1601 1602 for ( n = 0; n < num_classes; n++ ) 1603 { 1604 if ( ACCESS_Frame( 2L ) ) 1605 goto Fail; 1606 1607 new_offset = GET_UShort(); 1608 1609 FORGET_Frame(); 1610 1611 if ( new_offset ) 1612 { 1613 new_offset += base_offset; 1614 1615 cur_offset = FILE_Pos(); 1616 if ( FILE_Seek( new_offset ) || 1617 ( error = Load_Anchor( &lan[n], input ) ) != TT_Err_Ok ) 1618 goto Fail; 1619 (void)FILE_Seek( cur_offset ); 1620 } 1621 else 1622 lan[n].PosFormat = 0; 1623 } 1624 } 1625 1626 return TT_Err_Ok; 1627 1628 Fail: 1629 for ( m = 0; m < count; m++ ) 1630 { 1631 lan = cr[m].LigatureAnchor; 1632 1633 for ( n = 0; n < num_classes; n++ ) 1634 Free_Anchor( &lan[n] ); 1635 1636 FREE( lan ); 1637 } 1638 1639 FREE( cr ); 1640 return error; 1641 } 1642 1643 Free_LigatureAttach(TTO_LigatureAttach * lat,UShort num_classes)1644 static void Free_LigatureAttach( TTO_LigatureAttach* lat, 1645 UShort num_classes ) 1646 { 1647 UShort m, n, count; 1648 1649 TTO_ComponentRecord* cr; 1650 TTO_Anchor* lan; 1651 1652 1653 if ( lat->ComponentRecord ) 1654 { 1655 count = lat->ComponentCount; 1656 cr = lat->ComponentRecord; 1657 1658 for ( m = 0; m < count; m++ ) 1659 { 1660 lan = cr[m].LigatureAnchor; 1661 1662 for ( n = 0; n < num_classes; n++ ) 1663 Free_Anchor( &lan[n] ); 1664 1665 FREE( lan ); 1666 } 1667 1668 FREE( cr ); 1669 } 1670 } 1671 1672 1673 /* LigatureArray */ 1674 Load_LigatureArray(TTO_LigatureArray * la,UShort num_classes,PFace input)1675 static TT_Error Load_LigatureArray( TTO_LigatureArray* la, 1676 UShort num_classes, 1677 PFace input ) 1678 { 1679 DEFINE_LOAD_LOCALS( input->stream ); 1680 1681 UShort n, count; 1682 ULong cur_offset, new_offset, base_offset; 1683 1684 TTO_LigatureAttach* lat; 1685 1686 1687 base_offset = FILE_Pos(); 1688 1689 if ( ACCESS_Frame( 2L ) ) 1690 return error; 1691 1692 count = la->LigatureCount = GET_UShort(); 1693 1694 FORGET_Frame(); 1695 1696 la->LigatureAttach = NULL; 1697 1698 if ( ALLOC_ARRAY( la->LigatureAttach, count, TTO_LigatureAttach ) ) 1699 return error; 1700 1701 lat = la->LigatureAttach; 1702 1703 for ( n = 0; n < count; n++ ) 1704 { 1705 if ( ACCESS_Frame( 2L ) ) 1706 goto Fail; 1707 1708 new_offset = GET_UShort() + base_offset; 1709 1710 FORGET_Frame(); 1711 1712 cur_offset = FILE_Pos(); 1713 if ( FILE_Seek( new_offset ) || 1714 ( error = Load_LigatureAttach( &lat[n], num_classes, 1715 input ) ) != TT_Err_Ok ) 1716 goto Fail; 1717 (void)FILE_Seek( cur_offset ); 1718 } 1719 1720 return TT_Err_Ok; 1721 1722 Fail: 1723 for ( n = 0; n < count; n++ ) 1724 Free_LigatureAttach( &lat[n], num_classes ); 1725 1726 FREE( lat ); 1727 return error; 1728 } 1729 1730 Free_LigatureArray(TTO_LigatureArray * la,UShort num_classes)1731 static void Free_LigatureArray( TTO_LigatureArray* la, 1732 UShort num_classes ) 1733 { 1734 UShort n, count; 1735 1736 TTO_LigatureAttach* lat; 1737 1738 1739 if ( la->LigatureAttach ) 1740 { 1741 count = la->LigatureCount; 1742 lat = la->LigatureAttach; 1743 1744 for ( n = 0; n < count; n++ ) 1745 Free_LigatureAttach( &lat[n], num_classes ); 1746 1747 FREE( lat ); 1748 } 1749 } 1750 1751 1752 /* MarkLigPosFormat1 */ 1753 Load_MarkLigPos(TTO_MarkLigPos * mlp,PFace input)1754 TT_Error Load_MarkLigPos( TTO_MarkLigPos* mlp, 1755 PFace input ) 1756 { 1757 DEFINE_LOAD_LOCALS( input->stream ); 1758 1759 ULong cur_offset, new_offset, base_offset; 1760 1761 1762 base_offset = FILE_Pos(); 1763 1764 if ( ACCESS_Frame( 4L ) ) 1765 return error; 1766 1767 mlp->PosFormat = GET_UShort(); 1768 new_offset = GET_UShort() + base_offset; 1769 1770 FORGET_Frame(); 1771 1772 cur_offset = FILE_Pos(); 1773 if ( FILE_Seek( new_offset ) || 1774 ( error = Load_Coverage( &mlp->MarkCoverage, input ) ) != TT_Err_Ok ) 1775 return error; 1776 (void)FILE_Seek( cur_offset ); 1777 1778 if ( ACCESS_Frame( 2L ) ) 1779 goto Fail3; 1780 1781 new_offset = GET_UShort() + base_offset; 1782 1783 FORGET_Frame(); 1784 1785 cur_offset = FILE_Pos(); 1786 if ( FILE_Seek( new_offset ) || 1787 ( error = Load_Coverage( &mlp->LigatureCoverage, 1788 input ) ) != TT_Err_Ok ) 1789 goto Fail3; 1790 (void)FILE_Seek( cur_offset ); 1791 1792 if ( ACCESS_Frame( 4L ) ) 1793 goto Fail2; 1794 1795 mlp->ClassCount = GET_UShort(); 1796 new_offset = GET_UShort() + base_offset; 1797 1798 FORGET_Frame(); 1799 1800 cur_offset = FILE_Pos(); 1801 if ( FILE_Seek( new_offset ) || 1802 ( error = Load_MarkArray( &mlp->MarkArray, input ) ) != TT_Err_Ok ) 1803 goto Fail2; 1804 (void)FILE_Seek( cur_offset ); 1805 1806 if ( ACCESS_Frame( 2L ) ) 1807 goto Fail1; 1808 1809 new_offset = GET_UShort() + base_offset; 1810 1811 FORGET_Frame(); 1812 1813 cur_offset = FILE_Pos(); 1814 if ( FILE_Seek( new_offset ) || 1815 ( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount, 1816 input ) ) != TT_Err_Ok ) 1817 goto Fail1; 1818 1819 return TT_Err_Ok; 1820 1821 Fail1: 1822 Free_MarkArray( &mlp->MarkArray ); 1823 1824 Fail2: 1825 Free_Coverage( &mlp->LigatureCoverage ); 1826 1827 Fail3: 1828 Free_Coverage( &mlp->MarkCoverage ); 1829 return error; 1830 } 1831 1832 Free_MarkLigPos(TTO_MarkLigPos * mlp)1833 void Free_MarkLigPos( TTO_MarkLigPos* mlp ) 1834 { 1835 Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount ); 1836 Free_MarkArray( &mlp->MarkArray ); 1837 Free_Coverage( &mlp->LigatureCoverage ); 1838 Free_Coverage( &mlp->MarkCoverage ); 1839 } 1840 1841 1842 /* LookupType 6 */ 1843 1844 /* Mark2Array */ 1845 Load_Mark2Array(TTO_Mark2Array * m2a,UShort num_classes,PFace input)1846 static TT_Error Load_Mark2Array( TTO_Mark2Array* m2a, 1847 UShort num_classes, 1848 PFace input ) 1849 { 1850 DEFINE_LOAD_LOCALS( input->stream ); 1851 1852 UShort m, n, count; 1853 ULong cur_offset, new_offset, base_offset; 1854 1855 TTO_Mark2Record* m2r; 1856 TTO_Anchor* m2an; 1857 1858 1859 base_offset = FILE_Pos(); 1860 1861 if ( ACCESS_Frame( 2L ) ) 1862 return error; 1863 1864 count = m2a->Mark2Count = GET_UShort(); 1865 1866 FORGET_Frame(); 1867 1868 m2a->Mark2Record = NULL; 1869 1870 if ( ALLOC_ARRAY( m2a->Mark2Record, count, TTO_Mark2Record ) ) 1871 return error; 1872 1873 m2r = m2a->Mark2Record; 1874 1875 for ( m = 0; m < count; m++ ) 1876 { 1877 m2r[m].Mark2Anchor = NULL; 1878 1879 if ( ALLOC_ARRAY( m2r[m].Mark2Anchor, num_classes, TTO_Anchor ) ) 1880 goto Fail; 1881 1882 m2an = m2r[m].Mark2Anchor; 1883 1884 for ( n = 0; n < num_classes; n++ ) 1885 { 1886 if ( ACCESS_Frame( 2L ) ) 1887 goto Fail; 1888 1889 new_offset = GET_UShort() + base_offset; 1890 1891 FORGET_Frame(); 1892 1893 cur_offset = FILE_Pos(); 1894 if ( FILE_Seek( new_offset ) || 1895 ( error = Load_Anchor( &m2an[n], input ) ) != TT_Err_Ok ) 1896 goto Fail; 1897 (void)FILE_Seek( cur_offset ); 1898 } 1899 } 1900 1901 return TT_Err_Ok; 1902 1903 Fail: 1904 for ( m = 0; m < count; m++ ) 1905 { 1906 m2an = m2r[m].Mark2Anchor; 1907 1908 for ( n = 0; n < num_classes; n++ ) 1909 Free_Anchor( &m2an[n] ); 1910 1911 FREE( m2an ); 1912 } 1913 1914 FREE( m2r ); 1915 return error; 1916 } 1917 1918 Free_Mark2Array(TTO_Mark2Array * m2a,UShort num_classes)1919 static void Free_Mark2Array( TTO_Mark2Array* m2a, 1920 UShort num_classes ) 1921 { 1922 UShort m, n, count; 1923 1924 TTO_Mark2Record* m2r; 1925 TTO_Anchor* m2an; 1926 1927 1928 if ( m2a->Mark2Record ) 1929 { 1930 count = m2a->Mark2Count; 1931 m2r = m2a->Mark2Record; 1932 1933 for ( m = 0; m < count; m++ ) 1934 { 1935 m2an = m2r[m].Mark2Anchor; 1936 1937 for ( n = 0; n < num_classes; n++ ) 1938 Free_Anchor( &m2an[n] ); 1939 1940 FREE( m2an ); 1941 } 1942 1943 FREE( m2r ); 1944 } 1945 } 1946 1947 1948 /* MarkMarkPosFormat1 */ 1949 Load_MarkMarkPos(TTO_MarkMarkPos * mmp,PFace input)1950 TT_Error Load_MarkMarkPos( TTO_MarkMarkPos* mmp, 1951 PFace input ) 1952 { 1953 DEFINE_LOAD_LOCALS( input->stream ); 1954 1955 ULong cur_offset, new_offset, base_offset; 1956 1957 1958 base_offset = FILE_Pos(); 1959 1960 if ( ACCESS_Frame( 4L ) ) 1961 return error; 1962 1963 mmp->PosFormat = GET_UShort(); 1964 new_offset = GET_UShort() + base_offset; 1965 1966 FORGET_Frame(); 1967 1968 cur_offset = FILE_Pos(); 1969 if ( FILE_Seek( new_offset ) || 1970 ( error = Load_Coverage( &mmp->Mark1Coverage, 1971 input ) ) != TT_Err_Ok ) 1972 return error; 1973 (void)FILE_Seek( cur_offset ); 1974 1975 if ( ACCESS_Frame( 2L ) ) 1976 goto Fail3; 1977 1978 new_offset = GET_UShort() + base_offset; 1979 1980 FORGET_Frame(); 1981 1982 cur_offset = FILE_Pos(); 1983 if ( FILE_Seek( new_offset ) || 1984 ( error = Load_Coverage( &mmp->Mark2Coverage, 1985 input ) ) != TT_Err_Ok ) 1986 goto Fail3; 1987 (void)FILE_Seek( cur_offset ); 1988 1989 if ( ACCESS_Frame( 4L ) ) 1990 goto Fail2; 1991 1992 mmp->ClassCount = GET_UShort(); 1993 new_offset = GET_UShort() + base_offset; 1994 1995 FORGET_Frame(); 1996 1997 cur_offset = FILE_Pos(); 1998 if ( FILE_Seek( new_offset ) || 1999 ( error = Load_MarkArray( &mmp->Mark1Array, input ) ) != TT_Err_Ok ) 2000 goto Fail2; 2001 (void)FILE_Seek( cur_offset ); 2002 2003 if ( ACCESS_Frame( 2L ) ) 2004 goto Fail1; 2005 2006 new_offset = GET_UShort() + base_offset; 2007 2008 FORGET_Frame(); 2009 2010 cur_offset = FILE_Pos(); 2011 if ( FILE_Seek( new_offset ) || 2012 ( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount, 2013 input ) ) != TT_Err_Ok ) 2014 goto Fail1; 2015 2016 return TT_Err_Ok; 2017 2018 Fail1: 2019 Free_MarkArray( &mmp->Mark1Array ); 2020 2021 Fail2: 2022 Free_Coverage( &mmp->Mark2Coverage ); 2023 2024 Fail3: 2025 Free_Coverage( &mmp->Mark1Coverage ); 2026 return error; 2027 } 2028 2029 Free_MarkMarkPos(TTO_MarkMarkPos * mmp)2030 void Free_MarkMarkPos( TTO_MarkMarkPos* mmp ) 2031 { 2032 Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount ); 2033 Free_MarkArray( &mmp->Mark1Array ); 2034 Free_Coverage( &mmp->Mark2Coverage ); 2035 Free_Coverage( &mmp->Mark1Coverage ); 2036 } 2037 2038 2039 /* LookupType 7 */ 2040 2041 /* PosRule */ 2042 Load_PosRule(TTO_PosRule * pr,PFace input)2043 static TT_Error Load_PosRule( TTO_PosRule* pr, 2044 PFace input ) 2045 { 2046 DEFINE_LOAD_LOCALS( input->stream ); 2047 2048 UShort n, count; 2049 UShort* i; 2050 2051 TTO_PosLookupRecord* plr; 2052 2053 2054 if ( ACCESS_Frame( 4L ) ) 2055 return error; 2056 2057 pr->GlyphCount = GET_UShort(); 2058 pr->PosCount = GET_UShort(); 2059 2060 FORGET_Frame(); 2061 2062 pr->Input = NULL; 2063 2064 count = pr->GlyphCount - 1; /* only GlyphCount - 1 elements */ 2065 2066 if ( ALLOC_ARRAY( pr->Input, count, UShort ) ) 2067 return error; 2068 2069 i = pr->Input; 2070 2071 if ( ACCESS_Frame( count * 2L ) ) 2072 goto Fail2; 2073 2074 for ( n = 0; n < count; n++ ) 2075 i[n] = GET_UShort(); 2076 2077 FORGET_Frame(); 2078 2079 pr->PosLookupRecord = NULL; 2080 2081 count = pr->PosCount; 2082 2083 if ( ALLOC_ARRAY( pr->PosLookupRecord, count, TTO_PosLookupRecord ) ) 2084 goto Fail2; 2085 2086 plr = pr->PosLookupRecord; 2087 2088 if ( ACCESS_Frame( count * 4L ) ) 2089 goto Fail1; 2090 2091 for ( n = 0; n < count; n++ ) 2092 { 2093 plr[n].SequenceIndex = GET_UShort(); 2094 plr[n].LookupListIndex = GET_UShort(); 2095 } 2096 2097 FORGET_Frame(); 2098 2099 return TT_Err_Ok; 2100 2101 Fail1: 2102 FREE( plr ); 2103 2104 Fail2: 2105 FREE( i ); 2106 return error; 2107 } 2108 2109 Free_PosRule(TTO_PosRule * pr)2110 static void Free_PosRule( TTO_PosRule* pr ) 2111 { 2112 FREE( pr->PosLookupRecord ); 2113 FREE( pr->Input ); 2114 } 2115 2116 2117 /* PosRuleSet */ 2118 Load_PosRuleSet(TTO_PosRuleSet * prs,PFace input)2119 static TT_Error Load_PosRuleSet( TTO_PosRuleSet* prs, 2120 PFace input ) 2121 { 2122 DEFINE_LOAD_LOCALS( input->stream ); 2123 2124 UShort n, count; 2125 ULong cur_offset, new_offset, base_offset; 2126 2127 TTO_PosRule* pr; 2128 2129 2130 base_offset = FILE_Pos(); 2131 2132 if ( ACCESS_Frame( 2L ) ) 2133 return error; 2134 2135 count = prs->PosRuleCount = GET_UShort(); 2136 2137 FORGET_Frame(); 2138 2139 prs->PosRule = NULL; 2140 2141 if ( ALLOC_ARRAY( prs->PosRule, count, TTO_PosRule ) ) 2142 return error; 2143 2144 pr = prs->PosRule; 2145 2146 for ( n = 0; n < count; n++ ) 2147 { 2148 if ( ACCESS_Frame( 2L ) ) 2149 goto Fail; 2150 2151 new_offset = GET_UShort() + base_offset; 2152 2153 FORGET_Frame(); 2154 2155 cur_offset = FILE_Pos(); 2156 if ( FILE_Seek( new_offset ) || 2157 ( error = Load_PosRule( &pr[n], input ) ) != TT_Err_Ok ) 2158 goto Fail; 2159 (void)FILE_Seek( cur_offset ); 2160 } 2161 2162 return TT_Err_Ok; 2163 2164 Fail: 2165 for ( n = 0; n < count; n++ ) 2166 Free_PosRule( &pr[n] ); 2167 2168 FREE( pr ); 2169 return error; 2170 } 2171 2172 Free_PosRuleSet(TTO_PosRuleSet * prs)2173 static void Free_PosRuleSet( TTO_PosRuleSet* prs ) 2174 { 2175 UShort n, count; 2176 2177 TTO_PosRule* pr; 2178 2179 2180 if ( prs->PosRule ) 2181 { 2182 count = prs->PosRuleCount; 2183 pr = prs->PosRule; 2184 2185 for ( n = 0; n < count; n++ ) 2186 Free_PosRule( &pr[n] ); 2187 2188 FREE( pr ); 2189 } 2190 } 2191 2192 2193 /* ContextPosFormat1 */ 2194 Load_ContextPos1(TTO_ContextPosFormat1 * cpf1,PFace input)2195 static TT_Error Load_ContextPos1( TTO_ContextPosFormat1* cpf1, 2196 PFace input ) 2197 { 2198 DEFINE_LOAD_LOCALS( input->stream ); 2199 2200 UShort n, count; 2201 ULong cur_offset, new_offset, base_offset; 2202 2203 TTO_PosRuleSet* prs; 2204 2205 2206 base_offset = FILE_Pos() - 2L; 2207 2208 if ( ACCESS_Frame( 2L ) ) 2209 return error; 2210 2211 new_offset = GET_UShort() + base_offset; 2212 2213 FORGET_Frame(); 2214 2215 cur_offset = FILE_Pos(); 2216 if ( FILE_Seek( new_offset ) || 2217 ( error = Load_Coverage( &cpf1->Coverage, input ) ) != TT_Err_Ok ) 2218 return error; 2219 (void)FILE_Seek( cur_offset ); 2220 2221 if ( ACCESS_Frame( 2L ) ) 2222 goto Fail2; 2223 2224 count = cpf1->PosRuleSetCount = GET_UShort(); 2225 2226 FORGET_Frame(); 2227 2228 cpf1->PosRuleSet = NULL; 2229 2230 if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, TTO_PosRuleSet ) ) 2231 goto Fail2; 2232 2233 prs = cpf1->PosRuleSet; 2234 2235 for ( n = 0; n < count; n++ ) 2236 { 2237 if ( ACCESS_Frame( 2L ) ) 2238 goto Fail1; 2239 2240 new_offset = GET_UShort() + base_offset; 2241 2242 FORGET_Frame(); 2243 2244 cur_offset = FILE_Pos(); 2245 if ( FILE_Seek( new_offset ) || 2246 ( error = Load_PosRuleSet( &prs[n], input ) ) != TT_Err_Ok ) 2247 goto Fail1; 2248 (void)FILE_Seek( cur_offset ); 2249 } 2250 2251 return TT_Err_Ok; 2252 2253 Fail1: 2254 for ( n = 0; n < count; n++ ) 2255 Free_PosRuleSet( &prs[n] ); 2256 2257 FREE( prs ); 2258 2259 Fail2: 2260 Free_Coverage( &cpf1->Coverage ); 2261 return error; 2262 } 2263 2264 Free_Context1(TTO_ContextPosFormat1 * cpf1)2265 static void Free_Context1( TTO_ContextPosFormat1* cpf1 ) 2266 { 2267 UShort n, count; 2268 2269 TTO_PosRuleSet* prs; 2270 2271 2272 if ( cpf1->PosRuleSet ) 2273 { 2274 count = cpf1->PosRuleSetCount; 2275 prs = cpf1->PosRuleSet; 2276 2277 for ( n = 0; n < count; n++ ) 2278 Free_PosRuleSet( &prs[n] ); 2279 2280 FREE( prs ); 2281 } 2282 2283 Free_Coverage( &cpf1->Coverage ); 2284 } 2285 2286 2287 /* PosClassRule */ 2288 Load_PosClassRule(TTO_ContextPosFormat2 * cpf2,TTO_PosClassRule * pcr,PFace input)2289 static TT_Error Load_PosClassRule( TTO_ContextPosFormat2* cpf2, 2290 TTO_PosClassRule* pcr, 2291 PFace input ) 2292 { 2293 DEFINE_LOAD_LOCALS( input->stream ); 2294 2295 UShort n, count; 2296 2297 UShort* c; 2298 TTO_PosLookupRecord* plr; 2299 Bool* d; 2300 2301 2302 if ( ACCESS_Frame( 4L ) ) 2303 return error; 2304 2305 pcr->GlyphCount = GET_UShort(); 2306 pcr->PosCount = GET_UShort(); 2307 2308 FORGET_Frame(); 2309 2310 if ( pcr->GlyphCount > cpf2->MaxContextLength ) 2311 cpf2->MaxContextLength = pcr->GlyphCount; 2312 2313 pcr->Class = NULL; 2314 2315 count = pcr->GlyphCount - 1; /* only GlyphCount - 1 elements */ 2316 2317 if ( ALLOC_ARRAY( pcr->Class, count, UShort ) ) 2318 return error; 2319 2320 c = pcr->Class; 2321 d = cpf2->ClassDef.Defined; 2322 2323 if ( ACCESS_Frame( count * 2L ) ) 2324 goto Fail2; 2325 2326 for ( n = 0; n < count; n++ ) 2327 { 2328 c[n] = GET_UShort(); 2329 2330 /* We check whether the specific class is used at all. If not, 2331 class 0 is used instead. */ 2332 2333 if ( !d[c[n]] ) 2334 c[n] = 0; 2335 } 2336 2337 FORGET_Frame(); 2338 2339 pcr->PosLookupRecord = NULL; 2340 2341 count = pcr->PosCount; 2342 2343 if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, TTO_PosLookupRecord ) ) 2344 goto Fail2; 2345 2346 plr = pcr->PosLookupRecord; 2347 2348 if ( ACCESS_Frame( count * 4L ) ) 2349 goto Fail1; 2350 2351 for ( n = 0; n < count; n++ ) 2352 { 2353 plr[n].SequenceIndex = GET_UShort(); 2354 plr[n].LookupListIndex = GET_UShort(); 2355 } 2356 2357 FORGET_Frame(); 2358 2359 return TT_Err_Ok; 2360 2361 Fail1: 2362 FREE( plr ); 2363 2364 Fail2: 2365 FREE( c ); 2366 return error; 2367 } 2368 2369 Free_PosClassRule(TTO_PosClassRule * pcr)2370 static void Free_PosClassRule( TTO_PosClassRule* pcr ) 2371 { 2372 FREE( pcr->PosLookupRecord ); 2373 FREE( pcr->Class ); 2374 } 2375 2376 2377 /* PosClassSet */ 2378 Load_PosClassSet(TTO_ContextPosFormat2 * cpf2,TTO_PosClassSet * pcs,PFace input)2379 static TT_Error Load_PosClassSet( TTO_ContextPosFormat2* cpf2, 2380 TTO_PosClassSet* pcs, 2381 PFace input ) 2382 { 2383 DEFINE_LOAD_LOCALS( input->stream ); 2384 2385 UShort n, count; 2386 ULong cur_offset, new_offset, base_offset; 2387 2388 TTO_PosClassRule* pcr; 2389 2390 2391 base_offset = FILE_Pos(); 2392 2393 if ( ACCESS_Frame( 2L ) ) 2394 return error; 2395 2396 count = pcs->PosClassRuleCount = GET_UShort(); 2397 2398 FORGET_Frame(); 2399 2400 pcs->PosClassRule = NULL; 2401 2402 if ( ALLOC_ARRAY( pcs->PosClassRule, count, TTO_PosClassRule ) ) 2403 return error; 2404 2405 pcr = pcs->PosClassRule; 2406 2407 for ( n = 0; n < count; n++ ) 2408 { 2409 if ( ACCESS_Frame( 2L ) ) 2410 goto Fail; 2411 2412 new_offset = GET_UShort() + base_offset; 2413 2414 FORGET_Frame(); 2415 2416 cur_offset = FILE_Pos(); 2417 if ( FILE_Seek( new_offset ) || 2418 ( error = Load_PosClassRule( cpf2, &pcr[n], 2419 input ) ) != TT_Err_Ok ) 2420 goto Fail; 2421 (void)FILE_Seek( cur_offset ); 2422 } 2423 2424 return TT_Err_Ok; 2425 2426 Fail: 2427 for ( n = 0; n < count; n++ ) 2428 Free_PosClassRule( &pcr[n] ); 2429 2430 FREE( pcr ); 2431 return error; 2432 } 2433 2434 Free_PosClassSet(TTO_PosClassSet * pcs)2435 static void Free_PosClassSet( TTO_PosClassSet* pcs ) 2436 { 2437 UShort n, count; 2438 2439 TTO_PosClassRule* pcr; 2440 2441 2442 if ( pcs->PosClassRule ) 2443 { 2444 count = pcs->PosClassRuleCount; 2445 pcr = pcs->PosClassRule; 2446 2447 for ( n = 0; n < count; n++ ) 2448 Free_PosClassRule( &pcr[n] ); 2449 2450 FREE( pcr ); 2451 } 2452 } 2453 2454 2455 /* ContextPosFormat2 */ 2456 Load_ContextPos2(TTO_ContextPosFormat2 * cpf2,PFace input)2457 static TT_Error Load_ContextPos2( TTO_ContextPosFormat2* cpf2, 2458 PFace input ) 2459 { 2460 DEFINE_LOAD_LOCALS( input->stream ); 2461 2462 UShort n, count; 2463 ULong cur_offset, new_offset, base_offset; 2464 2465 TTO_PosClassSet* pcs; 2466 2467 2468 base_offset = FILE_Pos() - 2; 2469 2470 if ( ACCESS_Frame( 2L ) ) 2471 return error; 2472 2473 new_offset = GET_UShort() + base_offset; 2474 2475 FORGET_Frame(); 2476 2477 cur_offset = FILE_Pos(); 2478 if ( FILE_Seek( new_offset ) || 2479 ( error = Load_Coverage( &cpf2->Coverage, input ) ) != TT_Err_Ok ) 2480 return error; 2481 (void)FILE_Seek( cur_offset ); 2482 2483 if ( ACCESS_Frame( 4L ) ) 2484 goto Fail3; 2485 2486 new_offset = GET_UShort() + base_offset; 2487 2488 /* `PosClassSetCount' is the upper limit for class values, thus we 2489 read it now to make an additional safety check. */ 2490 2491 count = cpf2->PosClassSetCount = GET_UShort(); 2492 2493 FORGET_Frame(); 2494 2495 cur_offset = FILE_Pos(); 2496 if ( FILE_Seek( new_offset ) || 2497 ( error = Load_ClassDefinition( &cpf2->ClassDef, count, 2498 input ) ) != TT_Err_Ok ) 2499 goto Fail3; 2500 (void)FILE_Seek( cur_offset ); 2501 2502 cpf2->PosClassSet = NULL; 2503 cpf2->MaxContextLength = 0; 2504 2505 if ( ALLOC_ARRAY( cpf2->PosClassSet, count, TTO_PosClassSet ) ) 2506 goto Fail2; 2507 2508 pcs = cpf2->PosClassSet; 2509 2510 for ( n = 0; n < count; n++ ) 2511 { 2512 if ( ACCESS_Frame( 2L ) ) 2513 goto Fail1; 2514 2515 new_offset = GET_UShort() + base_offset; 2516 2517 FORGET_Frame(); 2518 2519 if ( new_offset != base_offset ) /* not a NULL offset */ 2520 { 2521 cur_offset = FILE_Pos(); 2522 if ( FILE_Seek( new_offset ) || 2523 ( error = Load_PosClassSet( cpf2, &pcs[n], 2524 input ) ) != TT_Err_Ok ) 2525 goto Fail1; 2526 (void)FILE_Seek( cur_offset ); 2527 } 2528 else 2529 { 2530 /* we create a PosClassSet table with no entries */ 2531 2532 cpf2->PosClassSet[n].PosClassRuleCount = 0; 2533 cpf2->PosClassSet[n].PosClassRule = NULL; 2534 } 2535 } 2536 2537 return TT_Err_Ok; 2538 2539 Fail1: 2540 for ( n = 0; n < count; n++ ) 2541 Free_PosClassSet( &pcs[n] ); 2542 2543 FREE( pcs ); 2544 2545 Fail2: 2546 Free_ClassDefinition( &cpf2->ClassDef ); 2547 2548 Fail3: 2549 Free_Coverage( &cpf2->Coverage ); 2550 return error; 2551 } 2552 2553 Free_Context2(TTO_ContextPosFormat2 * cpf2)2554 static void Free_Context2( TTO_ContextPosFormat2* cpf2 ) 2555 { 2556 UShort n, count; 2557 2558 TTO_PosClassSet* pcs; 2559 2560 2561 if ( cpf2->PosClassSet ) 2562 { 2563 count = cpf2->PosClassSetCount; 2564 pcs = cpf2->PosClassSet; 2565 2566 for ( n = 0; n < count; n++ ) 2567 Free_PosClassSet( &pcs[n] ); 2568 2569 FREE( pcs ); 2570 } 2571 2572 Free_ClassDefinition( &cpf2->ClassDef ); 2573 Free_Coverage( &cpf2->Coverage ); 2574 } 2575 2576 2577 /* ContextPosFormat3 */ 2578 Load_ContextPos3(TTO_ContextPosFormat3 * cpf3,PFace input)2579 static TT_Error Load_ContextPos3( TTO_ContextPosFormat3* cpf3, 2580 PFace input ) 2581 { 2582 DEFINE_LOAD_LOCALS( input->stream ); 2583 2584 UShort n, count; 2585 ULong cur_offset, new_offset, base_offset; 2586 2587 TTO_Coverage* c; 2588 TTO_PosLookupRecord* plr; 2589 2590 2591 base_offset = FILE_Pos() - 2L; 2592 2593 if ( ACCESS_Frame( 4L ) ) 2594 return error; 2595 2596 cpf3->GlyphCount = GET_UShort(); 2597 cpf3->PosCount = GET_UShort(); 2598 2599 FORGET_Frame(); 2600 2601 cpf3->Coverage = NULL; 2602 2603 count = cpf3->GlyphCount; 2604 2605 if ( ALLOC_ARRAY( cpf3->Coverage, count, TTO_Coverage ) ) 2606 return error; 2607 2608 c = cpf3->Coverage; 2609 2610 for ( n = 0; n < count; n++ ) 2611 { 2612 if ( ACCESS_Frame( 2L ) ) 2613 goto Fail2; 2614 2615 new_offset = GET_UShort() + base_offset; 2616 2617 FORGET_Frame(); 2618 2619 cur_offset = FILE_Pos(); 2620 if ( FILE_Seek( new_offset ) || 2621 ( error = Load_Coverage( &c[n], input ) ) != TT_Err_Ok ) 2622 goto Fail2; 2623 (void)FILE_Seek( cur_offset ); 2624 } 2625 2626 cpf3->PosLookupRecord = NULL; 2627 2628 count = cpf3->PosCount; 2629 2630 if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, TTO_PosLookupRecord ) ) 2631 goto Fail2; 2632 2633 plr = cpf3->PosLookupRecord; 2634 2635 if ( ACCESS_Frame( count * 4L ) ) 2636 goto Fail1; 2637 2638 for ( n = 0; n < count; n++ ) 2639 { 2640 plr[n].SequenceIndex = GET_UShort(); 2641 plr[n].LookupListIndex = GET_UShort(); 2642 } 2643 2644 FORGET_Frame(); 2645 2646 return TT_Err_Ok; 2647 2648 Fail1: 2649 FREE( plr ); 2650 2651 Fail2: 2652 for ( n = 0; n < count; n++ ) 2653 Free_Coverage( &c[n] ); 2654 2655 FREE( c ); 2656 return error; 2657 } 2658 2659 Free_Context3(TTO_ContextPosFormat3 * cpf3)2660 static void Free_Context3( TTO_ContextPosFormat3* cpf3 ) 2661 { 2662 UShort n, count; 2663 2664 TTO_Coverage* c; 2665 2666 2667 FREE( cpf3->PosLookupRecord ); 2668 2669 if ( cpf3->Coverage ) 2670 { 2671 count = cpf3->GlyphCount; 2672 c = cpf3->Coverage; 2673 2674 for ( n = 0; n < count; n++ ) 2675 Free_Coverage( &c[n] ); 2676 2677 FREE( c ); 2678 } 2679 } 2680 2681 2682 /* ContextPos */ 2683 Load_ContextPos(TTO_ContextPos * cp,PFace input)2684 TT_Error Load_ContextPos( TTO_ContextPos* cp, 2685 PFace input ) 2686 { 2687 DEFINE_LOAD_LOCALS( input->stream ); 2688 2689 2690 if ( ACCESS_Frame( 2L ) ) 2691 return error; 2692 2693 cp->PosFormat = GET_UShort(); 2694 2695 FORGET_Frame(); 2696 2697 switch ( cp->PosFormat ) 2698 { 2699 case 1: 2700 return Load_ContextPos1( &cp->cpf.cpf1, input ); 2701 2702 case 2: 2703 return Load_ContextPos2( &cp->cpf.cpf2, input ); 2704 2705 case 3: 2706 return Load_ContextPos3( &cp->cpf.cpf3, input ); 2707 2708 default: 2709 return TTO_Err_Invalid_GPOS_SubTable_Format; 2710 } 2711 2712 return TT_Err_Ok; /* never reached */ 2713 } 2714 2715 Free_ContextPos(TTO_ContextPos * cp)2716 void Free_ContextPos( TTO_ContextPos* cp ) 2717 { 2718 switch ( cp->PosFormat ) 2719 { 2720 case 1: 2721 Free_Context1( &cp->cpf.cpf1 ); 2722 break; 2723 2724 case 2: 2725 Free_Context2( &cp->cpf.cpf2 ); 2726 break; 2727 2728 case 3: 2729 Free_Context3( &cp->cpf.cpf3 ); 2730 break; 2731 } 2732 } 2733 2734 2735 /* LookupType 8 */ 2736 2737 /* ChainPosRule */ 2738 Load_ChainPosRule(TTO_ChainPosRule * cpr,PFace input)2739 static TT_Error Load_ChainPosRule( TTO_ChainPosRule* cpr, 2740 PFace input ) 2741 { 2742 DEFINE_LOAD_LOCALS( input->stream ); 2743 2744 UShort n, count; 2745 UShort* b; 2746 UShort* i; 2747 UShort* l; 2748 2749 TTO_PosLookupRecord* plr; 2750 2751 2752 if ( ACCESS_Frame( 2L ) ) 2753 return error; 2754 2755 cpr->BacktrackGlyphCount = GET_UShort(); 2756 2757 FORGET_Frame(); 2758 2759 cpr->Backtrack = NULL; 2760 2761 count = cpr->BacktrackGlyphCount; 2762 2763 if ( ALLOC_ARRAY( cpr->Backtrack, count, UShort ) ) 2764 return error; 2765 2766 b = cpr->Backtrack; 2767 2768 if ( ACCESS_Frame( count * 2L ) ) 2769 goto Fail4; 2770 2771 for ( n = 0; n < count; n++ ) 2772 b[n] = GET_UShort(); 2773 2774 FORGET_Frame(); 2775 2776 if ( ACCESS_Frame( 2L ) ) 2777 goto Fail4; 2778 2779 cpr->InputGlyphCount = GET_UShort(); 2780 2781 FORGET_Frame(); 2782 2783 cpr->Input = NULL; 2784 2785 count = cpr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */ 2786 2787 if ( ALLOC_ARRAY( cpr->Input, count, UShort ) ) 2788 goto Fail4; 2789 2790 i = cpr->Input; 2791 2792 if ( ACCESS_Frame( count * 2L ) ) 2793 goto Fail3; 2794 2795 for ( n = 0; n < count; n++ ) 2796 i[n] = GET_UShort(); 2797 2798 FORGET_Frame(); 2799 2800 if ( ACCESS_Frame( 2L ) ) 2801 goto Fail3; 2802 2803 cpr->LookaheadGlyphCount = GET_UShort(); 2804 2805 FORGET_Frame(); 2806 2807 cpr->Lookahead = NULL; 2808 2809 count = cpr->LookaheadGlyphCount; 2810 2811 if ( ALLOC_ARRAY( cpr->Lookahead, count, UShort ) ) 2812 goto Fail3; 2813 2814 l = cpr->Lookahead; 2815 2816 if ( ACCESS_Frame( count * 2L ) ) 2817 goto Fail2; 2818 2819 for ( n = 0; n < count; n++ ) 2820 l[n] = GET_UShort(); 2821 2822 FORGET_Frame(); 2823 2824 if ( ACCESS_Frame( 2L ) ) 2825 goto Fail2; 2826 2827 cpr->PosCount = GET_UShort(); 2828 2829 FORGET_Frame(); 2830 2831 cpr->PosLookupRecord = NULL; 2832 2833 count = cpr->PosCount; 2834 2835 if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, TTO_PosLookupRecord ) ) 2836 goto Fail2; 2837 2838 plr = cpr->PosLookupRecord; 2839 2840 if ( ACCESS_Frame( count * 4L ) ) 2841 goto Fail1; 2842 2843 for ( n = 0; n < count; n++ ) 2844 { 2845 plr[n].SequenceIndex = GET_UShort(); 2846 plr[n].LookupListIndex = GET_UShort(); 2847 } 2848 2849 FORGET_Frame(); 2850 2851 return TT_Err_Ok; 2852 2853 Fail1: 2854 FREE( plr ); 2855 2856 Fail2: 2857 FREE( l ); 2858 2859 Fail3: 2860 FREE( i ); 2861 2862 Fail4: 2863 FREE( b ); 2864 return error; 2865 } 2866 2867 Free_ChainPosRule(TTO_ChainPosRule * cpr)2868 static void Free_ChainPosRule( TTO_ChainPosRule* cpr ) 2869 { 2870 FREE( cpr->PosLookupRecord ); 2871 FREE( cpr->Lookahead ); 2872 FREE( cpr->Input ); 2873 FREE( cpr->Backtrack ); 2874 } 2875 2876 2877 /* ChainPosRuleSet */ 2878 Load_ChainPosRuleSet(TTO_ChainPosRuleSet * cprs,PFace input)2879 static TT_Error Load_ChainPosRuleSet( TTO_ChainPosRuleSet* cprs, 2880 PFace input ) 2881 { 2882 DEFINE_LOAD_LOCALS( input->stream ); 2883 2884 UShort n, count; 2885 ULong cur_offset, new_offset, base_offset; 2886 2887 TTO_ChainPosRule* cpr; 2888 2889 2890 base_offset = FILE_Pos(); 2891 2892 if ( ACCESS_Frame( 2L ) ) 2893 return error; 2894 2895 count = cprs->ChainPosRuleCount = GET_UShort(); 2896 2897 FORGET_Frame(); 2898 2899 cprs->ChainPosRule = NULL; 2900 2901 if ( ALLOC_ARRAY( cprs->ChainPosRule, count, TTO_ChainPosRule ) ) 2902 return error; 2903 2904 cpr = cprs->ChainPosRule; 2905 2906 for ( n = 0; n < count; n++ ) 2907 { 2908 if ( ACCESS_Frame( 2L ) ) 2909 goto Fail; 2910 2911 new_offset = GET_UShort() + base_offset; 2912 2913 FORGET_Frame(); 2914 2915 cur_offset = FILE_Pos(); 2916 if ( FILE_Seek( new_offset ) || 2917 ( error = Load_ChainPosRule( &cpr[n], input ) ) != TT_Err_Ok ) 2918 goto Fail; 2919 (void)FILE_Seek( cur_offset ); 2920 } 2921 2922 return TT_Err_Ok; 2923 2924 Fail: 2925 for ( n = 0; n < count; n++ ) 2926 Free_ChainPosRule( &cpr[n] ); 2927 2928 FREE( cpr ); 2929 return error; 2930 } 2931 2932 Free_ChainPosRuleSet(TTO_ChainPosRuleSet * cprs)2933 static void Free_ChainPosRuleSet( TTO_ChainPosRuleSet* cprs ) 2934 { 2935 UShort n, count; 2936 2937 TTO_ChainPosRule* cpr; 2938 2939 2940 if ( cprs->ChainPosRule ) 2941 { 2942 count = cprs->ChainPosRuleCount; 2943 cpr = cprs->ChainPosRule; 2944 2945 for ( n = 0; n < count; n++ ) 2946 Free_ChainPosRule( &cpr[n] ); 2947 2948 FREE( cpr ); 2949 } 2950 } 2951 2952 2953 /* ChainContextPosFormat1 */ 2954 Load_ChainContextPos1(TTO_ChainContextPosFormat1 * ccpf1,PFace input)2955 static TT_Error Load_ChainContextPos1( TTO_ChainContextPosFormat1* ccpf1, 2956 PFace input ) 2957 { 2958 DEFINE_LOAD_LOCALS( input->stream ); 2959 2960 UShort n, count; 2961 ULong cur_offset, new_offset, base_offset; 2962 2963 TTO_ChainPosRuleSet* cprs; 2964 2965 2966 base_offset = FILE_Pos() - 2L; 2967 2968 if ( ACCESS_Frame( 2L ) ) 2969 return error; 2970 2971 new_offset = GET_UShort() + base_offset; 2972 2973 FORGET_Frame(); 2974 2975 cur_offset = FILE_Pos(); 2976 if ( FILE_Seek( new_offset ) || 2977 ( error = Load_Coverage( &ccpf1->Coverage, input ) ) != TT_Err_Ok ) 2978 return error; 2979 (void)FILE_Seek( cur_offset ); 2980 2981 if ( ACCESS_Frame( 2L ) ) 2982 goto Fail2; 2983 2984 count = ccpf1->ChainPosRuleSetCount = GET_UShort(); 2985 2986 FORGET_Frame(); 2987 2988 ccpf1->ChainPosRuleSet = NULL; 2989 2990 if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, TTO_ChainPosRuleSet ) ) 2991 goto Fail2; 2992 2993 cprs = ccpf1->ChainPosRuleSet; 2994 2995 for ( n = 0; n < count; n++ ) 2996 { 2997 if ( ACCESS_Frame( 2L ) ) 2998 goto Fail1; 2999 3000 new_offset = GET_UShort() + base_offset; 3001 3002 FORGET_Frame(); 3003 3004 cur_offset = FILE_Pos(); 3005 if ( FILE_Seek( new_offset ) || 3006 ( error = Load_ChainPosRuleSet( &cprs[n], input ) ) != TT_Err_Ok ) 3007 goto Fail1; 3008 (void)FILE_Seek( cur_offset ); 3009 } 3010 3011 return TT_Err_Ok; 3012 3013 Fail1: 3014 for ( n = 0; n < count; n++ ) 3015 Free_ChainPosRuleSet( &cprs[n] ); 3016 3017 FREE( cprs ); 3018 3019 Fail2: 3020 Free_Coverage( &ccpf1->Coverage ); 3021 return error; 3022 } 3023 3024 Free_ChainContext1(TTO_ChainContextPosFormat1 * ccpf1)3025 static void Free_ChainContext1( TTO_ChainContextPosFormat1* ccpf1 ) 3026 { 3027 UShort n, count; 3028 3029 TTO_ChainPosRuleSet* cprs; 3030 3031 3032 if ( ccpf1->ChainPosRuleSet ) 3033 { 3034 count = ccpf1->ChainPosRuleSetCount; 3035 cprs = ccpf1->ChainPosRuleSet; 3036 3037 for ( n = 0; n < count; n++ ) 3038 Free_ChainPosRuleSet( &cprs[n] ); 3039 3040 FREE( cprs ); 3041 } 3042 3043 Free_Coverage( &ccpf1->Coverage ); 3044 } 3045 3046 3047 /* ChainPosClassRule */ 3048 Load_ChainPosClassRule(TTO_ChainContextPosFormat2 * ccpf2,TTO_ChainPosClassRule * cpcr,PFace input)3049 static TT_Error Load_ChainPosClassRule( 3050 TTO_ChainContextPosFormat2* ccpf2, 3051 TTO_ChainPosClassRule* cpcr, 3052 PFace input ) 3053 { 3054 DEFINE_LOAD_LOCALS( input->stream ); 3055 3056 UShort n, count; 3057 3058 UShort* b; 3059 UShort* i; 3060 UShort* l; 3061 TTO_PosLookupRecord* plr; 3062 Bool* d; 3063 3064 3065 if ( ACCESS_Frame( 2L ) ) 3066 return error; 3067 3068 cpcr->BacktrackGlyphCount = GET_UShort(); 3069 3070 FORGET_Frame(); 3071 3072 if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength ) 3073 ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount; 3074 3075 cpcr->Backtrack = NULL; 3076 3077 count = cpcr->BacktrackGlyphCount; 3078 3079 if ( ALLOC_ARRAY( cpcr->Backtrack, count, UShort ) ) 3080 return error; 3081 3082 b = cpcr->Backtrack; 3083 d = ccpf2->BacktrackClassDef.Defined; 3084 3085 if ( ACCESS_Frame( count * 2L ) ) 3086 goto Fail4; 3087 3088 for ( n = 0; n < count; n++ ) 3089 { 3090 b[n] = GET_UShort(); 3091 3092 /* We check whether the specific class is used at all. If not, 3093 class 0 is used instead. */ 3094 3095 if ( !d[b[n]] ) 3096 b[n] = 0; 3097 } 3098 3099 FORGET_Frame(); 3100 3101 if ( ACCESS_Frame( 2L ) ) 3102 goto Fail4; 3103 3104 cpcr->InputGlyphCount = GET_UShort(); 3105 3106 if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength ) 3107 ccpf2->MaxInputLength = cpcr->InputGlyphCount; 3108 3109 FORGET_Frame(); 3110 3111 cpcr->Input = NULL; 3112 3113 count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */ 3114 3115 if ( ALLOC_ARRAY( cpcr->Input, count, UShort ) ) 3116 goto Fail4; 3117 3118 i = cpcr->Input; 3119 d = ccpf2->InputClassDef.Defined; 3120 3121 if ( ACCESS_Frame( count * 2L ) ) 3122 goto Fail3; 3123 3124 for ( n = 0; n < count; n++ ) 3125 { 3126 i[n] = GET_UShort(); 3127 3128 if ( !d[i[n]] ) 3129 i[n] = 0; 3130 } 3131 3132 FORGET_Frame(); 3133 3134 if ( ACCESS_Frame( 2L ) ) 3135 goto Fail3; 3136 3137 cpcr->LookaheadGlyphCount = GET_UShort(); 3138 3139 FORGET_Frame(); 3140 3141 if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength ) 3142 ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount; 3143 3144 cpcr->Lookahead = NULL; 3145 3146 count = cpcr->LookaheadGlyphCount; 3147 3148 if ( ALLOC_ARRAY( cpcr->Lookahead, count, UShort ) ) 3149 goto Fail3; 3150 3151 l = cpcr->Lookahead; 3152 d = ccpf2->LookaheadClassDef.Defined; 3153 3154 if ( ACCESS_Frame( count * 2L ) ) 3155 goto Fail2; 3156 3157 for ( n = 0; n < count; n++ ) 3158 { 3159 l[n] = GET_UShort(); 3160 3161 if ( !d[l[n]] ) 3162 l[n] = 0; 3163 } 3164 3165 FORGET_Frame(); 3166 3167 if ( ACCESS_Frame( 2L ) ) 3168 goto Fail2; 3169 3170 cpcr->PosCount = GET_UShort(); 3171 3172 FORGET_Frame(); 3173 3174 cpcr->PosLookupRecord = NULL; 3175 3176 count = cpcr->PosCount; 3177 3178 if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, TTO_PosLookupRecord ) ) 3179 goto Fail2; 3180 3181 plr = cpcr->PosLookupRecord; 3182 3183 if ( ACCESS_Frame( count * 4L ) ) 3184 goto Fail1; 3185 3186 for ( n = 0; n < count; n++ ) 3187 { 3188 plr[n].SequenceIndex = GET_UShort(); 3189 plr[n].LookupListIndex = GET_UShort(); 3190 } 3191 3192 FORGET_Frame(); 3193 3194 return TT_Err_Ok; 3195 3196 Fail1: 3197 FREE( plr ); 3198 3199 Fail2: 3200 FREE( l ); 3201 3202 Fail3: 3203 FREE( i ); 3204 3205 Fail4: 3206 FREE( b ); 3207 return error; 3208 } 3209 3210 Free_ChainPosClassRule(TTO_ChainPosClassRule * cpcr)3211 static void Free_ChainPosClassRule( TTO_ChainPosClassRule* cpcr ) 3212 { 3213 FREE( cpcr->PosLookupRecord ); 3214 FREE( cpcr->Lookahead ); 3215 FREE( cpcr->Input ); 3216 FREE( cpcr->Backtrack ); 3217 } 3218 3219 3220 /* PosClassSet */ 3221 Load_ChainPosClassSet(TTO_ChainContextPosFormat2 * ccpf2,TTO_ChainPosClassSet * cpcs,PFace input)3222 static TT_Error Load_ChainPosClassSet( 3223 TTO_ChainContextPosFormat2* ccpf2, 3224 TTO_ChainPosClassSet* cpcs, 3225 PFace input ) 3226 { 3227 DEFINE_LOAD_LOCALS( input->stream ); 3228 3229 UShort n, count; 3230 ULong cur_offset, new_offset, base_offset; 3231 3232 TTO_ChainPosClassRule* cpcr; 3233 3234 3235 base_offset = FILE_Pos(); 3236 3237 if ( ACCESS_Frame( 2L ) ) 3238 return error; 3239 3240 count = cpcs->ChainPosClassRuleCount = GET_UShort(); 3241 3242 FORGET_Frame(); 3243 3244 cpcs->ChainPosClassRule = NULL; 3245 3246 if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count, 3247 TTO_ChainPosClassRule ) ) 3248 return error; 3249 3250 cpcr = cpcs->ChainPosClassRule; 3251 3252 for ( n = 0; n < count; n++ ) 3253 { 3254 if ( ACCESS_Frame( 2L ) ) 3255 goto Fail; 3256 3257 new_offset = GET_UShort() + base_offset; 3258 3259 FORGET_Frame(); 3260 3261 cur_offset = FILE_Pos(); 3262 if ( FILE_Seek( new_offset ) || 3263 ( error = Load_ChainPosClassRule( ccpf2, &cpcr[n], 3264 input ) ) != TT_Err_Ok ) 3265 goto Fail; 3266 (void)FILE_Seek( cur_offset ); 3267 } 3268 3269 return TT_Err_Ok; 3270 3271 Fail: 3272 for ( n = 0; n < count; n++ ) 3273 Free_ChainPosClassRule( &cpcr[n] ); 3274 3275 FREE( cpcr ); 3276 return error; 3277 } 3278 3279 Free_ChainPosClassSet(TTO_ChainPosClassSet * cpcs)3280 static void Free_ChainPosClassSet( TTO_ChainPosClassSet* cpcs ) 3281 { 3282 UShort n, count; 3283 3284 TTO_ChainPosClassRule* cpcr; 3285 3286 3287 if ( cpcs->ChainPosClassRule ) 3288 { 3289 count = cpcs->ChainPosClassRuleCount; 3290 cpcr = cpcs->ChainPosClassRule; 3291 3292 for ( n = 0; n < count; n++ ) 3293 Free_ChainPosClassRule( &cpcr[n] ); 3294 3295 FREE( cpcr ); 3296 } 3297 } 3298 3299 3300 /* ChainContextPosFormat2 */ 3301 Load_ChainContextPos2(TTO_ChainContextPosFormat2 * ccpf2,PFace input)3302 static TT_Error Load_ChainContextPos2( TTO_ChainContextPosFormat2* ccpf2, 3303 PFace input ) 3304 { 3305 DEFINE_LOAD_LOCALS( input->stream ); 3306 3307 UShort n, count; 3308 ULong cur_offset, new_offset, base_offset; 3309 ULong backtrack_offset, input_offset, lookahead_offset; 3310 3311 TTO_ChainPosClassSet* cpcs; 3312 3313 3314 base_offset = FILE_Pos() - 2; 3315 3316 if ( ACCESS_Frame( 2L ) ) 3317 return error; 3318 3319 new_offset = GET_UShort() + base_offset; 3320 3321 FORGET_Frame(); 3322 3323 cur_offset = FILE_Pos(); 3324 if ( FILE_Seek( new_offset ) || 3325 ( error = Load_Coverage( &ccpf2->Coverage, input ) ) != TT_Err_Ok ) 3326 return error; 3327 (void)FILE_Seek( cur_offset ); 3328 3329 if ( ACCESS_Frame( 8L ) ) 3330 goto Fail5; 3331 3332 backtrack_offset = GET_UShort() + base_offset; 3333 input_offset = GET_UShort() + base_offset; 3334 lookahead_offset = GET_UShort() + base_offset; 3335 3336 /* `ChainPosClassSetCount' is the upper limit for input class values, 3337 thus we read it now to make an additional safety check. */ 3338 3339 count = ccpf2->ChainPosClassSetCount = GET_UShort(); 3340 3341 FORGET_Frame(); 3342 3343 cur_offset = FILE_Pos(); 3344 if ( FILE_Seek( backtrack_offset ) || 3345 ( error = Load_ClassDefinition( &ccpf2->BacktrackClassDef, count, 3346 input ) ) != TT_Err_Ok ) 3347 goto Fail5; 3348 if ( FILE_Seek( input_offset ) || 3349 ( error = Load_ClassDefinition( &ccpf2->InputClassDef, count, 3350 input ) ) != TT_Err_Ok ) 3351 goto Fail4; 3352 if ( FILE_Seek( lookahead_offset ) || 3353 ( error = Load_ClassDefinition( &ccpf2->LookaheadClassDef, count, 3354 input ) ) != TT_Err_Ok ) 3355 goto Fail3; 3356 (void)FILE_Seek( cur_offset ); 3357 3358 ccpf2->ChainPosClassSet = NULL; 3359 ccpf2->MaxBacktrackLength = 0; 3360 ccpf2->MaxInputLength = 0; 3361 ccpf2->MaxLookaheadLength = 0; 3362 3363 if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, TTO_ChainPosClassSet ) ) 3364 goto Fail2; 3365 3366 cpcs = ccpf2->ChainPosClassSet; 3367 3368 for ( n = 0; n < count; n++ ) 3369 { 3370 if ( ACCESS_Frame( 2L ) ) 3371 goto Fail1; 3372 3373 new_offset = GET_UShort() + base_offset; 3374 3375 FORGET_Frame(); 3376 3377 if ( new_offset != base_offset ) /* not a NULL offset */ 3378 { 3379 cur_offset = FILE_Pos(); 3380 if ( FILE_Seek( new_offset ) || 3381 ( error = Load_ChainPosClassSet( ccpf2, &cpcs[n], 3382 input ) ) != TT_Err_Ok ) 3383 goto Fail1; 3384 (void)FILE_Seek( cur_offset ); 3385 } 3386 else 3387 { 3388 /* we create a ChainPosClassSet table with no entries */ 3389 3390 ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0; 3391 ccpf2->ChainPosClassSet[n].ChainPosClassRule = NULL; 3392 } 3393 } 3394 3395 return TT_Err_Ok; 3396 3397 Fail1: 3398 for ( n = 0; n < count; n++ ) 3399 Free_ChainPosClassSet( &cpcs[n] ); 3400 3401 FREE( cpcs ); 3402 3403 Fail2: 3404 Free_ClassDefinition( &ccpf2->LookaheadClassDef ); 3405 3406 Fail3: 3407 Free_ClassDefinition( &ccpf2->InputClassDef ); 3408 3409 Fail4: 3410 Free_ClassDefinition( &ccpf2->BacktrackClassDef ); 3411 3412 Fail5: 3413 Free_Coverage( &ccpf2->Coverage ); 3414 return error; 3415 } 3416 3417 Free_ChainContext2(TTO_ChainContextPosFormat2 * ccpf2)3418 static void Free_ChainContext2( TTO_ChainContextPosFormat2* ccpf2 ) 3419 { 3420 UShort n, count; 3421 3422 TTO_ChainPosClassSet* cpcs; 3423 3424 3425 if ( ccpf2->ChainPosClassSet ) 3426 { 3427 count = ccpf2->ChainPosClassSetCount; 3428 cpcs = ccpf2->ChainPosClassSet; 3429 3430 for ( n = 0; n < count; n++ ) 3431 Free_ChainPosClassSet( &cpcs[n] ); 3432 3433 FREE( cpcs ); 3434 } 3435 3436 Free_ClassDefinition( &ccpf2->LookaheadClassDef ); 3437 Free_ClassDefinition( &ccpf2->InputClassDef ); 3438 Free_ClassDefinition( &ccpf2->BacktrackClassDef ); 3439 3440 Free_Coverage( &ccpf2->Coverage ); 3441 } 3442 3443 3444 /* ChainContextPosFormat3 */ 3445 Load_ChainContextPos3(TTO_ChainContextPosFormat3 * ccpf3,PFace input)3446 static TT_Error Load_ChainContextPos3( TTO_ChainContextPosFormat3* ccpf3, 3447 PFace input ) 3448 { 3449 DEFINE_LOAD_LOCALS( input->stream ); 3450 3451 UShort n, count; 3452 UShort backtrack_count, input_count, lookahead_count; 3453 ULong cur_offset, new_offset, base_offset; 3454 3455 TTO_Coverage* b; 3456 TTO_Coverage* i; 3457 TTO_Coverage* l; 3458 TTO_PosLookupRecord* plr; 3459 3460 3461 base_offset = FILE_Pos() - 2L; 3462 3463 if ( ACCESS_Frame( 2L ) ) 3464 return error; 3465 3466 ccpf3->BacktrackGlyphCount = GET_UShort(); 3467 3468 FORGET_Frame(); 3469 3470 ccpf3->BacktrackCoverage = NULL; 3471 3472 backtrack_count = ccpf3->BacktrackGlyphCount; 3473 3474 if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count, 3475 TTO_Coverage ) ) 3476 return error; 3477 3478 b = ccpf3->BacktrackCoverage; 3479 3480 for ( n = 0; n < backtrack_count; n++ ) 3481 { 3482 if ( ACCESS_Frame( 2L ) ) 3483 goto Fail4; 3484 3485 new_offset = GET_UShort() + base_offset; 3486 3487 FORGET_Frame(); 3488 3489 cur_offset = FILE_Pos(); 3490 if ( FILE_Seek( new_offset ) || 3491 ( error = Load_Coverage( &b[n], input ) ) != TT_Err_Ok ) 3492 goto Fail4; 3493 (void)FILE_Seek( cur_offset ); 3494 } 3495 3496 if ( ACCESS_Frame( 2L ) ) 3497 goto Fail4; 3498 3499 ccpf3->InputGlyphCount = GET_UShort(); 3500 3501 FORGET_Frame(); 3502 3503 ccpf3->InputCoverage = NULL; 3504 3505 input_count = ccpf3->InputGlyphCount; 3506 3507 if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, TTO_Coverage ) ) 3508 goto Fail4; 3509 3510 i = ccpf3->InputCoverage; 3511 3512 for ( n = 0; n < input_count; n++ ) 3513 { 3514 if ( ACCESS_Frame( 2L ) ) 3515 goto Fail3; 3516 3517 new_offset = GET_UShort() + base_offset; 3518 3519 FORGET_Frame(); 3520 3521 cur_offset = FILE_Pos(); 3522 if ( FILE_Seek( new_offset ) || 3523 ( error = Load_Coverage( &i[n], input ) ) != TT_Err_Ok ) 3524 goto Fail3; 3525 (void)FILE_Seek( cur_offset ); 3526 } 3527 3528 if ( ACCESS_Frame( 2L ) ) 3529 goto Fail3; 3530 3531 ccpf3->LookaheadGlyphCount = GET_UShort(); 3532 3533 FORGET_Frame(); 3534 3535 ccpf3->LookaheadCoverage = NULL; 3536 3537 lookahead_count = ccpf3->LookaheadGlyphCount; 3538 3539 if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count, 3540 TTO_Coverage ) ) 3541 goto Fail3; 3542 3543 l = ccpf3->LookaheadCoverage; 3544 3545 for ( n = 0; n < lookahead_count; n++ ) 3546 { 3547 if ( ACCESS_Frame( 2L ) ) 3548 goto Fail2; 3549 3550 new_offset = GET_UShort() + base_offset; 3551 3552 FORGET_Frame(); 3553 3554 cur_offset = FILE_Pos(); 3555 if ( FILE_Seek( new_offset ) || 3556 ( error = Load_Coverage( &l[n], input ) ) != TT_Err_Ok ) 3557 goto Fail2; 3558 (void)FILE_Seek( cur_offset ); 3559 } 3560 3561 if ( ACCESS_Frame( 2L ) ) 3562 goto Fail2; 3563 3564 ccpf3->PosCount = GET_UShort(); 3565 3566 FORGET_Frame(); 3567 3568 ccpf3->PosLookupRecord = NULL; 3569 3570 count = ccpf3->PosCount; 3571 3572 if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, TTO_PosLookupRecord ) ) 3573 goto Fail2; 3574 3575 plr = ccpf3->PosLookupRecord; 3576 3577 if ( ACCESS_Frame( count * 4L ) ) 3578 goto Fail1; 3579 3580 for ( n = 0; n < count; n++ ) 3581 { 3582 plr[n].SequenceIndex = GET_UShort(); 3583 plr[n].LookupListIndex = GET_UShort(); 3584 } 3585 3586 FORGET_Frame(); 3587 3588 return TT_Err_Ok; 3589 3590 Fail1: 3591 FREE( plr ); 3592 3593 Fail2: 3594 for ( n = 0; n < lookahead_count; n++ ) 3595 Free_Coverage( &l[n] ); 3596 3597 FREE( l ); 3598 3599 Fail3: 3600 for ( n = 0; n < input_count; n++ ) 3601 Free_Coverage( &i[n] ); 3602 3603 FREE( i ); 3604 3605 Fail4: 3606 for ( n = 0; n < backtrack_count; n++ ) 3607 Free_Coverage( &b[n] ); 3608 3609 FREE( b ); 3610 return error; 3611 } 3612 3613 Free_ChainContext3(TTO_ChainContextPosFormat3 * ccpf3)3614 static void Free_ChainContext3( TTO_ChainContextPosFormat3* ccpf3 ) 3615 { 3616 UShort n, count; 3617 3618 TTO_Coverage* c; 3619 3620 3621 FREE( ccpf3->PosLookupRecord ); 3622 3623 if ( ccpf3->LookaheadCoverage ) 3624 { 3625 count = ccpf3->LookaheadGlyphCount; 3626 c = ccpf3->LookaheadCoverage; 3627 3628 for ( n = 0; n < count; n++ ) 3629 Free_Coverage( &c[n] ); 3630 3631 FREE( c ); 3632 } 3633 3634 if ( ccpf3->InputCoverage ) 3635 { 3636 count = ccpf3->InputGlyphCount; 3637 c = ccpf3->InputCoverage; 3638 3639 for ( n = 0; n < count; n++ ) 3640 Free_Coverage( &c[n] ); 3641 3642 FREE( c ); 3643 } 3644 3645 if ( ccpf3->BacktrackCoverage ) 3646 { 3647 count = ccpf3->BacktrackGlyphCount; 3648 c = ccpf3->BacktrackCoverage; 3649 3650 for ( n = 0; n < count; n++ ) 3651 Free_Coverage( &c[n] ); 3652 3653 FREE( c ); 3654 } 3655 } 3656 3657 3658 /* ChainContextPos */ 3659 Load_ChainContextPos(TTO_ChainContextPos * ccp,PFace input)3660 TT_Error Load_ChainContextPos( TTO_ChainContextPos* ccp, 3661 PFace input ) 3662 { 3663 DEFINE_LOAD_LOCALS( input->stream ); 3664 3665 3666 if ( ACCESS_Frame( 2L ) ) 3667 return error; 3668 3669 ccp->PosFormat = GET_UShort(); 3670 3671 FORGET_Frame(); 3672 3673 switch ( ccp->PosFormat ) 3674 { 3675 case 1: 3676 return Load_ChainContextPos1( &ccp->ccpf.ccpf1, input ); 3677 3678 case 2: 3679 return Load_ChainContextPos2( &ccp->ccpf.ccpf2, input ); 3680 3681 case 3: 3682 return Load_ChainContextPos3( &ccp->ccpf.ccpf3, input ); 3683 3684 default: 3685 return TTO_Err_Invalid_GPOS_SubTable_Format; 3686 } 3687 3688 return TT_Err_Ok; /* never reached */ 3689 } 3690 3691 Free_ChainContextPos(TTO_ChainContextPos * ccp)3692 void Free_ChainContextPos( TTO_ChainContextPos* ccp ) 3693 { 3694 switch ( ccp->PosFormat ) 3695 { 3696 case 1: 3697 Free_ChainContext1( &ccp->ccpf.ccpf1 ); 3698 break; 3699 3700 case 2: 3701 Free_ChainContext2( &ccp->ccpf.ccpf2 ); 3702 break; 3703 3704 case 3: 3705 Free_ChainContext3( &ccp->ccpf.ccpf3 ); 3706 break; 3707 } 3708 } 3709 3710 3711 3712 /*********** 3713 * GPOS API 3714 ***********/ 3715 3716 3717 EXPORT_FUNC TT_GPOS_Select_Script(TTO_GPOSHeader * gpos,TT_ULong script_tag,TT_UShort * script_index)3718 TT_Error TT_GPOS_Select_Script( TTO_GPOSHeader* gpos, 3719 TT_ULong script_tag, 3720 TT_UShort* script_index ) 3721 { 3722 UShort n; 3723 3724 TTO_ScriptList* sl; 3725 TTO_ScriptRecord* sr; 3726 3727 3728 if ( !gpos || !script_index ) 3729 return TT_Err_Invalid_Argument; 3730 3731 sl = &gpos->ScriptList; 3732 sr = sl->ScriptRecord; 3733 3734 for ( n = 0; n < sl->ScriptCount; n++ ) 3735 if ( script_tag == sr[n].ScriptTag ) 3736 { 3737 *script_index = n; 3738 3739 return TT_Err_Ok; 3740 } 3741 3742 return TTO_Err_Not_Covered; 3743 } 3744 3745 3746 EXPORT_FUNC TT_GPOS_Select_Language(TTO_GPOSHeader * gpos,TT_ULong language_tag,TT_UShort script_index,TT_UShort * language_index,TT_UShort * req_feature_index)3747 TT_Error TT_GPOS_Select_Language( TTO_GPOSHeader* gpos, 3748 TT_ULong language_tag, 3749 TT_UShort script_index, 3750 TT_UShort* language_index, 3751 TT_UShort* req_feature_index ) 3752 { 3753 UShort n; 3754 3755 TTO_ScriptList* sl; 3756 TTO_ScriptRecord* sr; 3757 TTO_Script* s; 3758 TTO_LangSysRecord* lsr; 3759 3760 3761 if ( !gpos || !language_index || !req_feature_index ) 3762 return TT_Err_Invalid_Argument; 3763 3764 sl = &gpos->ScriptList; 3765 sr = sl->ScriptRecord; 3766 3767 if ( script_index >= sl->ScriptCount ) 3768 return TT_Err_Invalid_Argument; 3769 3770 s = &sr[script_index].Script; 3771 lsr = s->LangSysRecord; 3772 3773 for ( n = 0; n < s->LangSysCount; n++ ) 3774 if ( language_tag == lsr[n].LangSysTag ) 3775 { 3776 *language_index = n; 3777 *req_feature_index = lsr[n].LangSys.ReqFeatureIndex; 3778 3779 return TT_Err_Ok; 3780 } 3781 3782 return TTO_Err_Not_Covered; 3783 } 3784 3785 3786 /* selecting 0xFFFF for language_index asks for the values of the 3787 default language (DefaultLangSys) */ 3788 3789 EXPORT_FUNC TT_GPOS_Select_Feature(TTO_GPOSHeader * gpos,TT_ULong feature_tag,TT_UShort script_index,TT_UShort language_index,TT_UShort * feature_index)3790 TT_Error TT_GPOS_Select_Feature( TTO_GPOSHeader* gpos, 3791 TT_ULong feature_tag, 3792 TT_UShort script_index, 3793 TT_UShort language_index, 3794 TT_UShort* feature_index ) 3795 { 3796 UShort n; 3797 3798 TTO_ScriptList* sl; 3799 TTO_ScriptRecord* sr; 3800 TTO_Script* s; 3801 TTO_LangSysRecord* lsr; 3802 TTO_LangSys* ls; 3803 UShort* fi; 3804 3805 TTO_FeatureList* fl; 3806 TTO_FeatureRecord* fr; 3807 3808 3809 if ( !gpos || !feature_index ) 3810 return TT_Err_Invalid_Argument; 3811 3812 sl = &gpos->ScriptList; 3813 sr = sl->ScriptRecord; 3814 3815 fl = &gpos->FeatureList; 3816 fr = fl->FeatureRecord; 3817 3818 if ( script_index >= sl->ScriptCount ) 3819 return TT_Err_Invalid_Argument; 3820 3821 s = &sr[script_index].Script; 3822 lsr = s->LangSysRecord; 3823 3824 if ( language_index == 0xFFFF ) 3825 ls = &s->DefaultLangSys; 3826 else 3827 { 3828 if ( language_index >= s->LangSysCount ) 3829 return TT_Err_Invalid_Argument; 3830 3831 ls = &lsr[language_index].LangSys; 3832 } 3833 3834 fi = ls->FeatureIndex; 3835 3836 for ( n = 0; n < ls->FeatureCount; n++ ) 3837 { 3838 if ( fi[n] >= fl->FeatureCount ) 3839 return TTO_Err_Invalid_GPOS_SubTable_Format; 3840 3841 if ( feature_tag == fr[fi[n]].FeatureTag ) 3842 { 3843 *feature_index = fi[n]; 3844 3845 return TT_Err_Ok; 3846 } 3847 } 3848 3849 return TTO_Err_Not_Covered; 3850 } 3851 3852 3853 /* The next three functions return a null-terminated list */ 3854 3855 EXPORT_FUNC TT_GPOS_Query_Scripts(TTO_GPOSHeader * gpos,TT_ULong ** script_tag_list)3856 TT_Error TT_GPOS_Query_Scripts( TTO_GPOSHeader* gpos, 3857 TT_ULong** script_tag_list ) 3858 { 3859 UShort n; 3860 TT_Error error; 3861 ULong* stl; 3862 3863 TTO_ScriptList* sl; 3864 TTO_ScriptRecord* sr; 3865 3866 3867 if ( !gpos || !script_tag_list ) 3868 return TT_Err_Invalid_Argument; 3869 3870 sl = &gpos->ScriptList; 3871 sr = sl->ScriptRecord; 3872 3873 if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, ULong ) ) 3874 return error; 3875 3876 for ( n = 0; n < sl->ScriptCount; n++ ) 3877 stl[n] = sr[n].ScriptTag; 3878 stl[n] = 0; 3879 3880 *script_tag_list = stl; 3881 3882 return TT_Err_Ok; 3883 } 3884 3885 3886 EXPORT_FUNC TT_GPOS_Query_Languages(TTO_GPOSHeader * gpos,TT_UShort script_index,TT_ULong ** language_tag_list)3887 TT_Error TT_GPOS_Query_Languages( TTO_GPOSHeader* gpos, 3888 TT_UShort script_index, 3889 TT_ULong** language_tag_list ) 3890 { 3891 UShort n; 3892 TT_Error error; 3893 ULong* ltl; 3894 3895 TTO_ScriptList* sl; 3896 TTO_ScriptRecord* sr; 3897 TTO_Script* s; 3898 TTO_LangSysRecord* lsr; 3899 3900 3901 if ( !gpos || !language_tag_list ) 3902 return TT_Err_Invalid_Argument; 3903 3904 sl = &gpos->ScriptList; 3905 sr = sl->ScriptRecord; 3906 3907 if ( script_index >= sl->ScriptCount ) 3908 return TT_Err_Invalid_Argument; 3909 3910 s = &sr[script_index].Script; 3911 lsr = s->LangSysRecord; 3912 3913 if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, ULong ) ) 3914 return error; 3915 3916 for ( n = 0; n < s->LangSysCount; n++ ) 3917 ltl[n] = lsr[n].LangSysTag; 3918 ltl[n] = 0; 3919 3920 *language_tag_list = ltl; 3921 3922 return TT_Err_Ok; 3923 } 3924 3925 3926 /* selecting 0xFFFF for language_index asks for the values of the 3927 default language (DefaultLangSys) */ 3928 3929 EXPORT_FUNC TT_GPOS_Query_Features(TTO_GPOSHeader * gpos,TT_UShort script_index,TT_UShort language_index,TT_ULong ** feature_tag_list)3930 TT_Error TT_GPOS_Query_Features( TTO_GPOSHeader* gpos, 3931 TT_UShort script_index, 3932 TT_UShort language_index, 3933 TT_ULong** feature_tag_list ) 3934 { 3935 UShort n; 3936 TT_Error error; 3937 ULong* ftl; 3938 3939 TTO_ScriptList* sl; 3940 TTO_ScriptRecord* sr; 3941 TTO_Script* s; 3942 TTO_LangSysRecord* lsr; 3943 TTO_LangSys* ls; 3944 UShort* fi; 3945 3946 TTO_FeatureList* fl; 3947 TTO_FeatureRecord* fr; 3948 3949 3950 if ( !gpos || !feature_tag_list ) 3951 return TT_Err_Invalid_Argument; 3952 3953 sl = &gpos->ScriptList; 3954 sr = sl->ScriptRecord; 3955 3956 fl = &gpos->FeatureList; 3957 fr = fl->FeatureRecord; 3958 3959 if ( script_index >= sl->ScriptCount ) 3960 return TT_Err_Invalid_Argument; 3961 3962 s = &sr[script_index].Script; 3963 lsr = s->LangSysRecord; 3964 3965 if ( language_index == 0xFFFF ) 3966 ls = &s->DefaultLangSys; 3967 else 3968 { 3969 if ( language_index >= s->LangSysCount ) 3970 return TT_Err_Invalid_Argument; 3971 3972 ls = &lsr[language_index].LangSys; 3973 } 3974 3975 fi = ls->FeatureIndex; 3976 3977 if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, ULong ) ) 3978 return error; 3979 3980 for ( n = 0; n < ls->FeatureCount; n++ ) 3981 { 3982 if ( fi[n] >= fl->FeatureCount ) 3983 { 3984 FREE( ftl ); 3985 return TTO_Err_Invalid_GPOS_SubTable_Format; 3986 } 3987 ftl[n] = fr[fi[n]].FeatureTag; 3988 } 3989 ftl[n] = 0; 3990 3991 *feature_tag_list = ftl; 3992 3993 return TT_Err_Ok; 3994 } 3995 3996 3997 EXPORT_FUNC TT_GPOS_Add_Feature(TTO_GPOSHeader * gpos,TT_UShort feature_index,TT_UShort property)3998 TT_Error TT_GPOS_Add_Feature( TTO_GPOSHeader* gpos, 3999 TT_UShort feature_index, 4000 TT_UShort property ) 4001 { 4002 UShort i; 4003 4004 TTO_Feature feature; 4005 UShort* properties; 4006 UShort* index; 4007 4008 4009 if ( !gpos || 4010 feature_index >= gpos->FeatureList.FeatureCount ) 4011 return TT_Err_Invalid_Argument; 4012 4013 properties = gpos->LookupList.Properties; 4014 4015 feature = gpos->FeatureList.FeatureRecord[feature_index].Feature; 4016 index = feature.LookupListIndex; 4017 4018 for ( i = 0; i < feature.LookupListCount; i++ ) 4019 properties[index[i]] |= property; 4020 4021 return TT_Err_Ok; 4022 } 4023 4024 4025 EXPORT_FUNC TT_GPOS_Clear_Features(TTO_GPOSHeader * gpos)4026 TT_Error TT_GPOS_Clear_Features( TTO_GPOSHeader* gpos ) 4027 { 4028 UShort i; 4029 4030 UShort* properties; 4031 4032 4033 if ( !gpos ) 4034 return TT_Err_Invalid_Argument; 4035 4036 properties = gpos->LookupList.Properties; 4037 4038 for ( i = 0; i < gpos->LookupList.LookupCount; i++ ) 4039 properties[i] = 0; 4040 4041 return TT_Err_Ok; 4042 } 4043 4044 4045 /* END */ 4046