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