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