1 /**************************************************************************** 2 * 3 * otvgsub.c 4 * 5 * OpenType GSUB table validation (body). 6 * 7 * Copyright (C) 2004-2023 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 19 #include "otvalid.h" 20 #include "otvcommn.h" 21 22 23 /************************************************************************** 24 * 25 * The macro FT_COMPONENT is used in trace mode. It is an implicit 26 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log 27 * messages during execution. 28 */ 29 #undef FT_COMPONENT 30 #define FT_COMPONENT otvgsub 31 32 33 /*************************************************************************/ 34 /*************************************************************************/ 35 /***** *****/ 36 /***** GSUB LOOKUP TYPE 1 *****/ 37 /***** *****/ 38 /*************************************************************************/ 39 /*************************************************************************/ 40 41 /* uses otvalid->glyph_count */ 42 43 static void otv_SingleSubst_validate(FT_Bytes table,OTV_Validator otvalid)44 otv_SingleSubst_validate( FT_Bytes table, 45 OTV_Validator otvalid ) 46 { 47 FT_Bytes p = table; 48 FT_UInt SubstFormat; 49 50 51 OTV_NAME_ENTER( "SingleSubst" ); 52 53 OTV_LIMIT_CHECK( 2 ); 54 SubstFormat = FT_NEXT_USHORT( p ); 55 56 OTV_TRACE(( " (format %d)\n", SubstFormat )); 57 58 switch ( SubstFormat ) 59 { 60 case 1: /* SingleSubstFormat1 */ 61 { 62 FT_Bytes Coverage; 63 FT_Int DeltaGlyphID; 64 FT_UInt first_cov, last_cov; 65 FT_UInt first_idx, last_idx; 66 67 68 OTV_LIMIT_CHECK( 4 ); 69 Coverage = table + FT_NEXT_USHORT( p ); 70 DeltaGlyphID = FT_NEXT_SHORT( p ); 71 72 otv_Coverage_validate( Coverage, otvalid, -1 ); 73 74 first_cov = otv_Coverage_get_first( Coverage ); 75 last_cov = otv_Coverage_get_last( Coverage ); 76 77 /* These additions are modulo 65536. */ 78 first_idx = (FT_UInt)( (FT_Int)first_cov + DeltaGlyphID ) & 0xFFFFU; 79 last_idx = (FT_UInt)( (FT_Int)last_cov + DeltaGlyphID ) & 0xFFFFU; 80 81 /* Since the maximum number of glyphs is 2^16 - 1 = 65535, */ 82 /* the largest possible glyph index is 65534. For this */ 83 /* reason there can't be a wrap-around region, which would */ 84 /* imply the use of the invalid glyph index 65535. */ 85 if ( first_idx > last_idx ) 86 FT_INVALID_DATA; 87 88 if ( last_idx >= otvalid->glyph_count ) 89 FT_INVALID_DATA; 90 } 91 break; 92 93 case 2: /* SingleSubstFormat2 */ 94 { 95 FT_UInt Coverage, GlyphCount; 96 97 98 OTV_LIMIT_CHECK( 4 ); 99 Coverage = FT_NEXT_USHORT( p ); 100 GlyphCount = FT_NEXT_USHORT( p ); 101 102 OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); 103 104 otv_Coverage_validate( table + Coverage, 105 otvalid, 106 (FT_Int)GlyphCount ); 107 108 OTV_LIMIT_CHECK( GlyphCount * 2 ); 109 110 /* Substitute */ 111 for ( ; GlyphCount > 0; GlyphCount-- ) 112 if ( FT_NEXT_USHORT( p ) >= otvalid->glyph_count ) 113 FT_INVALID_GLYPH_ID; 114 } 115 break; 116 117 default: 118 FT_INVALID_FORMAT; 119 } 120 121 OTV_EXIT; 122 } 123 124 125 /*************************************************************************/ 126 /*************************************************************************/ 127 /***** *****/ 128 /***** GSUB LOOKUP TYPE 2 *****/ 129 /***** *****/ 130 /*************************************************************************/ 131 /*************************************************************************/ 132 133 /* sets otvalid->extra1 (glyph count) */ 134 135 static void otv_MultipleSubst_validate(FT_Bytes table,OTV_Validator otvalid)136 otv_MultipleSubst_validate( FT_Bytes table, 137 OTV_Validator otvalid ) 138 { 139 FT_Bytes p = table; 140 FT_UInt SubstFormat; 141 142 143 OTV_NAME_ENTER( "MultipleSubst" ); 144 145 OTV_LIMIT_CHECK( 2 ); 146 SubstFormat = FT_NEXT_USHORT( p ); 147 148 OTV_TRACE(( " (format %d)\n", SubstFormat )); 149 150 switch ( SubstFormat ) 151 { 152 case 1: 153 otvalid->extra1 = otvalid->glyph_count; 154 OTV_NEST2( MultipleSubstFormat1, Sequence ); 155 OTV_RUN( table, otvalid ); 156 break; 157 158 default: 159 FT_INVALID_FORMAT; 160 } 161 162 OTV_EXIT; 163 } 164 165 166 /*************************************************************************/ 167 /*************************************************************************/ 168 /***** *****/ 169 /***** GSUB LOOKUP TYPE 3 *****/ 170 /***** *****/ 171 /*************************************************************************/ 172 /*************************************************************************/ 173 174 /* sets otvalid->extra1 (glyph count) */ 175 176 static void otv_AlternateSubst_validate(FT_Bytes table,OTV_Validator otvalid)177 otv_AlternateSubst_validate( FT_Bytes table, 178 OTV_Validator otvalid ) 179 { 180 FT_Bytes p = table; 181 FT_UInt SubstFormat; 182 183 184 OTV_NAME_ENTER( "AlternateSubst" ); 185 186 OTV_LIMIT_CHECK( 2 ); 187 SubstFormat = FT_NEXT_USHORT( p ); 188 189 OTV_TRACE(( " (format %d)\n", SubstFormat )); 190 191 switch ( SubstFormat ) 192 { 193 case 1: 194 otvalid->extra1 = otvalid->glyph_count; 195 OTV_NEST2( AlternateSubstFormat1, AlternateSet ); 196 OTV_RUN( table, otvalid ); 197 break; 198 199 default: 200 FT_INVALID_FORMAT; 201 } 202 203 OTV_EXIT; 204 } 205 206 207 /*************************************************************************/ 208 /*************************************************************************/ 209 /***** *****/ 210 /***** GSUB LOOKUP TYPE 4 *****/ 211 /***** *****/ 212 /*************************************************************************/ 213 /*************************************************************************/ 214 215 #define LigatureFunc otv_Ligature_validate 216 217 /* uses otvalid->glyph_count */ 218 219 static void otv_Ligature_validate(FT_Bytes table,OTV_Validator otvalid)220 otv_Ligature_validate( FT_Bytes table, 221 OTV_Validator otvalid ) 222 { 223 FT_Bytes p = table; 224 FT_UInt LigatureGlyph, CompCount; 225 226 227 OTV_ENTER; 228 229 OTV_LIMIT_CHECK( 4 ); 230 LigatureGlyph = FT_NEXT_USHORT( p ); 231 if ( LigatureGlyph >= otvalid->glyph_count ) 232 FT_INVALID_DATA; 233 234 CompCount = FT_NEXT_USHORT( p ); 235 236 OTV_TRACE(( " (CompCount = %d)\n", CompCount )); 237 238 if ( CompCount == 0 ) 239 FT_INVALID_DATA; 240 241 CompCount--; 242 243 OTV_LIMIT_CHECK( CompCount * 2 ); /* Component */ 244 245 /* no need to check the Component glyph indices */ 246 247 OTV_EXIT; 248 } 249 250 251 static void otv_LigatureSubst_validate(FT_Bytes table,OTV_Validator otvalid)252 otv_LigatureSubst_validate( FT_Bytes table, 253 OTV_Validator otvalid ) 254 { 255 FT_Bytes p = table; 256 FT_UInt SubstFormat; 257 258 259 OTV_NAME_ENTER( "LigatureSubst" ); 260 261 OTV_LIMIT_CHECK( 2 ); 262 SubstFormat = FT_NEXT_USHORT( p ); 263 264 OTV_TRACE(( " (format %d)\n", SubstFormat )); 265 266 switch ( SubstFormat ) 267 { 268 case 1: 269 OTV_NEST3( LigatureSubstFormat1, LigatureSet, Ligature ); 270 OTV_RUN( table, otvalid ); 271 break; 272 273 default: 274 FT_INVALID_FORMAT; 275 } 276 277 OTV_EXIT; 278 } 279 280 281 /*************************************************************************/ 282 /*************************************************************************/ 283 /***** *****/ 284 /***** GSUB LOOKUP TYPE 5 *****/ 285 /***** *****/ 286 /*************************************************************************/ 287 /*************************************************************************/ 288 289 /* sets otvalid->extra1 (lookup count) */ 290 291 static void otv_ContextSubst_validate(FT_Bytes table,OTV_Validator otvalid)292 otv_ContextSubst_validate( FT_Bytes table, 293 OTV_Validator otvalid ) 294 { 295 FT_Bytes p = table; 296 FT_UInt SubstFormat; 297 298 299 OTV_NAME_ENTER( "ContextSubst" ); 300 301 OTV_LIMIT_CHECK( 2 ); 302 SubstFormat = FT_NEXT_USHORT( p ); 303 304 OTV_TRACE(( " (format %d)\n", SubstFormat )); 305 306 switch ( SubstFormat ) 307 { 308 case 1: 309 /* no need to check glyph indices/classes used as input for these */ 310 /* context rules since even invalid glyph indices/classes return */ 311 /* meaningful results */ 312 313 otvalid->extra1 = otvalid->lookup_count; 314 OTV_NEST3( ContextSubstFormat1, SubRuleSet, SubRule ); 315 OTV_RUN( table, otvalid ); 316 break; 317 318 case 2: 319 /* no need to check glyph indices/classes used as input for these */ 320 /* context rules since even invalid glyph indices/classes return */ 321 /* meaningful results */ 322 323 OTV_NEST3( ContextSubstFormat2, SubClassSet, SubClassRule ); 324 OTV_RUN( table, otvalid ); 325 break; 326 327 case 3: 328 OTV_NEST1( ContextSubstFormat3 ); 329 OTV_RUN( table, otvalid ); 330 break; 331 332 default: 333 FT_INVALID_FORMAT; 334 } 335 336 OTV_EXIT; 337 } 338 339 340 /*************************************************************************/ 341 /*************************************************************************/ 342 /***** *****/ 343 /***** GSUB LOOKUP TYPE 6 *****/ 344 /***** *****/ 345 /*************************************************************************/ 346 /*************************************************************************/ 347 348 /* sets otvalid->extra1 (lookup count) */ 349 350 static void otv_ChainContextSubst_validate(FT_Bytes table,OTV_Validator otvalid)351 otv_ChainContextSubst_validate( FT_Bytes table, 352 OTV_Validator otvalid ) 353 { 354 FT_Bytes p = table; 355 FT_UInt SubstFormat; 356 357 358 OTV_NAME_ENTER( "ChainContextSubst" ); 359 360 OTV_LIMIT_CHECK( 2 ); 361 SubstFormat = FT_NEXT_USHORT( p ); 362 363 OTV_TRACE(( " (format %d)\n", SubstFormat )); 364 365 switch ( SubstFormat ) 366 { 367 case 1: 368 /* no need to check glyph indices/classes used as input for these */ 369 /* context rules since even invalid glyph indices/classes return */ 370 /* meaningful results */ 371 372 otvalid->extra1 = otvalid->lookup_count; 373 OTV_NEST3( ChainContextSubstFormat1, 374 ChainSubRuleSet, ChainSubRule ); 375 OTV_RUN( table, otvalid ); 376 break; 377 378 case 2: 379 /* no need to check glyph indices/classes used as input for these */ 380 /* context rules since even invalid glyph indices/classes return */ 381 /* meaningful results */ 382 383 OTV_NEST3( ChainContextSubstFormat2, 384 ChainSubClassSet, ChainSubClassRule ); 385 OTV_RUN( table, otvalid ); 386 break; 387 388 case 3: 389 OTV_NEST1( ChainContextSubstFormat3 ); 390 OTV_RUN( table, otvalid ); 391 break; 392 393 default: 394 FT_INVALID_FORMAT; 395 } 396 397 OTV_EXIT; 398 } 399 400 401 /*************************************************************************/ 402 /*************************************************************************/ 403 /***** *****/ 404 /***** GSUB LOOKUP TYPE 7 *****/ 405 /***** *****/ 406 /*************************************************************************/ 407 /*************************************************************************/ 408 409 /* uses otvalid->type_funcs */ 410 411 static void otv_ExtensionSubst_validate(FT_Bytes table,OTV_Validator otvalid)412 otv_ExtensionSubst_validate( FT_Bytes table, 413 OTV_Validator otvalid ) 414 { 415 FT_Bytes p = table; 416 FT_UInt SubstFormat; 417 418 419 OTV_NAME_ENTER( "ExtensionSubst" ); 420 421 OTV_LIMIT_CHECK( 2 ); 422 SubstFormat = FT_NEXT_USHORT( p ); 423 424 OTV_TRACE(( " (format %d)\n", SubstFormat )); 425 426 switch ( SubstFormat ) 427 { 428 case 1: /* ExtensionSubstFormat1 */ 429 { 430 FT_UInt ExtensionLookupType; 431 FT_ULong ExtensionOffset; 432 OTV_Validate_Func validate; 433 434 435 OTV_LIMIT_CHECK( 6 ); 436 ExtensionLookupType = FT_NEXT_USHORT( p ); 437 ExtensionOffset = FT_NEXT_ULONG( p ); 438 439 if ( ExtensionLookupType == 0 || 440 ExtensionLookupType == 7 || 441 ExtensionLookupType > 8 ) 442 FT_INVALID_DATA; 443 444 validate = otvalid->type_funcs[ExtensionLookupType - 1]; 445 validate( table + ExtensionOffset, otvalid ); 446 } 447 break; 448 449 default: 450 FT_INVALID_FORMAT; 451 } 452 453 OTV_EXIT; 454 } 455 456 457 /*************************************************************************/ 458 /*************************************************************************/ 459 /***** *****/ 460 /***** GSUB LOOKUP TYPE 8 *****/ 461 /***** *****/ 462 /*************************************************************************/ 463 /*************************************************************************/ 464 465 /* uses otvalid->glyph_count */ 466 467 static void otv_ReverseChainSingleSubst_validate(FT_Bytes table,OTV_Validator otvalid)468 otv_ReverseChainSingleSubst_validate( FT_Bytes table, 469 OTV_Validator otvalid ) 470 { 471 FT_Bytes p = table, Coverage; 472 FT_UInt SubstFormat; 473 FT_UInt BacktrackGlyphCount, LookaheadGlyphCount, GlyphCount; 474 475 476 OTV_NAME_ENTER( "ReverseChainSingleSubst" ); 477 478 OTV_LIMIT_CHECK( 2 ); 479 SubstFormat = FT_NEXT_USHORT( p ); 480 481 OTV_TRACE(( " (format %d)\n", SubstFormat )); 482 483 switch ( SubstFormat ) 484 { 485 case 1: /* ReverseChainSingleSubstFormat1 */ 486 OTV_LIMIT_CHECK( 4 ); 487 Coverage = table + FT_NEXT_USHORT( p ); 488 BacktrackGlyphCount = FT_NEXT_USHORT( p ); 489 490 OTV_TRACE(( " (BacktrackGlyphCount = %d)\n", BacktrackGlyphCount )); 491 492 otv_Coverage_validate( Coverage, otvalid, -1 ); 493 494 OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 ); 495 496 for ( ; BacktrackGlyphCount > 0; BacktrackGlyphCount-- ) 497 otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 ); 498 499 LookaheadGlyphCount = FT_NEXT_USHORT( p ); 500 501 OTV_TRACE(( " (LookaheadGlyphCount = %d)\n", LookaheadGlyphCount )); 502 503 OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 ); 504 505 for ( ; LookaheadGlyphCount > 0; LookaheadGlyphCount-- ) 506 otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 ); 507 508 GlyphCount = FT_NEXT_USHORT( p ); 509 510 OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); 511 512 if ( GlyphCount != otv_Coverage_get_count( Coverage ) ) 513 FT_INVALID_DATA; 514 515 OTV_LIMIT_CHECK( GlyphCount * 2 ); 516 517 /* Substitute */ 518 for ( ; GlyphCount > 0; GlyphCount-- ) 519 if ( FT_NEXT_USHORT( p ) >= otvalid->glyph_count ) 520 FT_INVALID_DATA; 521 522 break; 523 524 default: 525 FT_INVALID_FORMAT; 526 } 527 528 OTV_EXIT; 529 } 530 531 532 static const OTV_Validate_Func otv_gsub_validate_funcs[8] = 533 { 534 otv_SingleSubst_validate, 535 otv_MultipleSubst_validate, 536 otv_AlternateSubst_validate, 537 otv_LigatureSubst_validate, 538 otv_ContextSubst_validate, 539 otv_ChainContextSubst_validate, 540 otv_ExtensionSubst_validate, 541 otv_ReverseChainSingleSubst_validate 542 }; 543 544 545 /*************************************************************************/ 546 /*************************************************************************/ 547 /***** *****/ 548 /***** GSUB TABLE *****/ 549 /***** *****/ 550 /*************************************************************************/ 551 /*************************************************************************/ 552 553 /* sets otvalid->type_count */ 554 /* sets otvalid->type_funcs */ 555 /* sets otvalid->glyph_count */ 556 557 FT_LOCAL_DEF( void ) otv_GSUB_validate(FT_Bytes table,FT_UInt glyph_count,FT_Validator ftvalid)558 otv_GSUB_validate( FT_Bytes table, 559 FT_UInt glyph_count, 560 FT_Validator ftvalid ) 561 { 562 OTV_ValidatorRec otvalidrec; 563 OTV_Validator otvalid = &otvalidrec; 564 FT_Bytes p = table; 565 FT_UInt table_size; 566 FT_UShort version; 567 FT_UInt ScriptList, FeatureList, LookupList; 568 569 OTV_OPTIONAL_TABLE32( featureVariations ); 570 571 572 otvalid->root = ftvalid; 573 574 FT_TRACE3(( "validating GSUB table\n" )); 575 OTV_INIT; 576 577 OTV_LIMIT_CHECK( 4 ); 578 579 if ( FT_NEXT_USHORT( p ) != 1 ) /* majorVersion */ 580 FT_INVALID_FORMAT; 581 582 version = FT_NEXT_USHORT( p ); /* minorVersion */ 583 584 table_size = 10; 585 switch ( version ) 586 { 587 case 0: 588 OTV_LIMIT_CHECK( 6 ); 589 break; 590 591 case 1: 592 OTV_LIMIT_CHECK( 10 ); 593 table_size += 4; 594 break; 595 596 default: 597 FT_INVALID_FORMAT; 598 } 599 600 ScriptList = FT_NEXT_USHORT( p ); 601 FeatureList = FT_NEXT_USHORT( p ); 602 LookupList = FT_NEXT_USHORT( p ); 603 604 otvalid->type_count = 8; 605 otvalid->type_funcs = (OTV_Validate_Func*)otv_gsub_validate_funcs; 606 otvalid->glyph_count = glyph_count; 607 608 otv_LookupList_validate( table + LookupList, 609 otvalid ); 610 otv_FeatureList_validate( table + FeatureList, table + LookupList, 611 otvalid ); 612 otv_ScriptList_validate( table + ScriptList, table + FeatureList, 613 otvalid ); 614 615 if ( version > 0 ) 616 { 617 OTV_OPTIONAL_OFFSET32( featureVariations ); 618 OTV_SIZE_CHECK32( featureVariations ); 619 if ( featureVariations ) 620 OTV_TRACE(( " [omitting featureVariations validation]\n" )); /* XXX */ 621 } 622 623 FT_TRACE4(( "\n" )); 624 } 625 626 627 /* END */ 628