1 /***************************************************************************/ 2 /* */ 3 /* gxvcommn.c */ 4 /* */ 5 /* TrueTypeGX/AAT common tables validation (body). */ 6 /* */ 7 /* Copyright 2004, 2005, 2009, 2010, 2013 */ 8 /* by suzuki toshiya, Masatake YAMATO, Red Hat K.K., */ 9 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 10 /* */ 11 /* This file is part of the FreeType project, and may only be used, */ 12 /* modified, and distributed under the terms of the FreeType project */ 13 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 14 /* this file you indicate that you have read the license and */ 15 /* understand and accept it fully. */ 16 /* */ 17 /***************************************************************************/ 18 19 /***************************************************************************/ 20 /* */ 21 /* gxvalid is derived from both gxlayout module and otvalid module. */ 22 /* Development of gxlayout is supported by the Information-technology */ 23 /* Promotion Agency(IPA), Japan. */ 24 /* */ 25 /***************************************************************************/ 26 27 28 #include "gxvcommn.h" 29 30 31 /*************************************************************************/ 32 /* */ 33 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 34 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 35 /* messages during execution. */ 36 /* */ 37 #undef FT_COMPONENT 38 #define FT_COMPONENT trace_gxvcommon 39 40 41 /*************************************************************************/ 42 /*************************************************************************/ 43 /***** *****/ 44 /***** 16bit offset sorter *****/ 45 /***** *****/ 46 /*************************************************************************/ 47 /*************************************************************************/ 48 49 static int gxv_compare_ushort_offset(FT_UShort * a,FT_UShort * b)50 gxv_compare_ushort_offset( FT_UShort* a, 51 FT_UShort* b ) 52 { 53 if ( *a < *b ) 54 return -1; 55 else if ( *a > *b ) 56 return 1; 57 else 58 return 0; 59 } 60 61 62 FT_LOCAL_DEF( void ) gxv_set_length_by_ushort_offset(FT_UShort * offset,FT_UShort ** length,FT_UShort * buff,FT_UInt nmemb,FT_UShort limit,GXV_Validator valid)63 gxv_set_length_by_ushort_offset( FT_UShort* offset, 64 FT_UShort** length, 65 FT_UShort* buff, 66 FT_UInt nmemb, 67 FT_UShort limit, 68 GXV_Validator valid ) 69 { 70 FT_UInt i; 71 72 73 for ( i = 0; i < nmemb; i++ ) 74 *(length[i]) = 0; 75 76 for ( i = 0; i < nmemb; i++ ) 77 buff[i] = offset[i]; 78 buff[nmemb] = limit; 79 80 ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_UShort ), 81 ( int(*)(const void*, const void*) )gxv_compare_ushort_offset ); 82 83 if ( buff[nmemb] > limit ) 84 FT_INVALID_OFFSET; 85 86 for ( i = 0; i < nmemb; i++ ) 87 { 88 FT_UInt j; 89 90 91 for ( j = 0; j < nmemb; j++ ) 92 if ( buff[j] == offset[i] ) 93 break; 94 95 if ( j == nmemb ) 96 FT_INVALID_OFFSET; 97 98 *(length[i]) = (FT_UShort)( buff[j + 1] - buff[j] ); 99 100 if ( 0 != offset[i] && 0 == *(length[i]) ) 101 FT_INVALID_OFFSET; 102 } 103 } 104 105 106 /*************************************************************************/ 107 /*************************************************************************/ 108 /***** *****/ 109 /***** 32bit offset sorter *****/ 110 /***** *****/ 111 /*************************************************************************/ 112 /*************************************************************************/ 113 114 static int gxv_compare_ulong_offset(FT_ULong * a,FT_ULong * b)115 gxv_compare_ulong_offset( FT_ULong* a, 116 FT_ULong* b ) 117 { 118 if ( *a < *b ) 119 return -1; 120 else if ( *a > *b ) 121 return 1; 122 else 123 return 0; 124 } 125 126 127 FT_LOCAL_DEF( void ) gxv_set_length_by_ulong_offset(FT_ULong * offset,FT_ULong ** length,FT_ULong * buff,FT_UInt nmemb,FT_ULong limit,GXV_Validator valid)128 gxv_set_length_by_ulong_offset( FT_ULong* offset, 129 FT_ULong** length, 130 FT_ULong* buff, 131 FT_UInt nmemb, 132 FT_ULong limit, 133 GXV_Validator valid) 134 { 135 FT_UInt i; 136 137 138 for ( i = 0; i < nmemb; i++ ) 139 *(length[i]) = 0; 140 141 for ( i = 0; i < nmemb; i++ ) 142 buff[i] = offset[i]; 143 buff[nmemb] = limit; 144 145 ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_ULong ), 146 ( int(*)(const void*, const void*) )gxv_compare_ulong_offset ); 147 148 if ( buff[nmemb] > limit ) 149 FT_INVALID_OFFSET; 150 151 for ( i = 0; i < nmemb; i++ ) 152 { 153 FT_UInt j; 154 155 156 for ( j = 0; j < nmemb; j++ ) 157 if ( buff[j] == offset[i] ) 158 break; 159 160 if ( j == nmemb ) 161 FT_INVALID_OFFSET; 162 163 *(length[i]) = buff[j + 1] - buff[j]; 164 165 if ( 0 != offset[i] && 0 == *(length[i]) ) 166 FT_INVALID_OFFSET; 167 } 168 } 169 170 171 /*************************************************************************/ 172 /*************************************************************************/ 173 /***** *****/ 174 /***** scan value array and get min & max *****/ 175 /***** *****/ 176 /*************************************************************************/ 177 /*************************************************************************/ 178 179 180 FT_LOCAL_DEF( void ) gxv_array_getlimits_byte(FT_Bytes table,FT_Bytes limit,FT_Byte * min,FT_Byte * max,GXV_Validator valid)181 gxv_array_getlimits_byte( FT_Bytes table, 182 FT_Bytes limit, 183 FT_Byte* min, 184 FT_Byte* max, 185 GXV_Validator valid ) 186 { 187 FT_Bytes p = table; 188 189 190 *min = 0xFF; 191 *max = 0x00; 192 193 while ( p < limit ) 194 { 195 FT_Byte val; 196 197 198 GXV_LIMIT_CHECK( 1 ); 199 val = FT_NEXT_BYTE( p ); 200 201 *min = (FT_Byte)FT_MIN( *min, val ); 202 *max = (FT_Byte)FT_MAX( *max, val ); 203 } 204 205 valid->subtable_length = p - table; 206 } 207 208 209 FT_LOCAL_DEF( void ) gxv_array_getlimits_ushort(FT_Bytes table,FT_Bytes limit,FT_UShort * min,FT_UShort * max,GXV_Validator valid)210 gxv_array_getlimits_ushort( FT_Bytes table, 211 FT_Bytes limit, 212 FT_UShort* min, 213 FT_UShort* max, 214 GXV_Validator valid ) 215 { 216 FT_Bytes p = table; 217 218 219 *min = 0xFFFFU; 220 *max = 0x0000; 221 222 while ( p < limit ) 223 { 224 FT_UShort val; 225 226 227 GXV_LIMIT_CHECK( 2 ); 228 val = FT_NEXT_USHORT( p ); 229 230 *min = (FT_Byte)FT_MIN( *min, val ); 231 *max = (FT_Byte)FT_MAX( *max, val ); 232 } 233 234 valid->subtable_length = p - table; 235 } 236 237 238 /*************************************************************************/ 239 /*************************************************************************/ 240 /***** *****/ 241 /***** BINSEARCHHEADER *****/ 242 /***** *****/ 243 /*************************************************************************/ 244 /*************************************************************************/ 245 246 typedef struct GXV_BinSrchHeader_ 247 { 248 FT_UShort unitSize; 249 FT_UShort nUnits; 250 FT_UShort searchRange; 251 FT_UShort entrySelector; 252 FT_UShort rangeShift; 253 254 } GXV_BinSrchHeader; 255 256 257 static void gxv_BinSrchHeader_check_consistency(GXV_BinSrchHeader * binSrchHeader,GXV_Validator valid)258 gxv_BinSrchHeader_check_consistency( GXV_BinSrchHeader* binSrchHeader, 259 GXV_Validator valid ) 260 { 261 FT_UShort searchRange; 262 FT_UShort entrySelector; 263 FT_UShort rangeShift; 264 265 266 if ( binSrchHeader->unitSize == 0 ) 267 FT_INVALID_DATA; 268 269 if ( binSrchHeader->nUnits == 0 ) 270 { 271 if ( binSrchHeader->searchRange == 0 && 272 binSrchHeader->entrySelector == 0 && 273 binSrchHeader->rangeShift == 0 ) 274 return; 275 else 276 FT_INVALID_DATA; 277 } 278 279 for ( searchRange = 1, entrySelector = 1; 280 ( searchRange * 2 ) <= binSrchHeader->nUnits && 281 searchRange < 0x8000U; 282 searchRange *= 2, entrySelector++ ) 283 ; 284 285 entrySelector--; 286 searchRange = (FT_UShort)( searchRange * binSrchHeader->unitSize ); 287 rangeShift = (FT_UShort)( binSrchHeader->nUnits * binSrchHeader->unitSize 288 - searchRange ); 289 290 if ( searchRange != binSrchHeader->searchRange || 291 entrySelector != binSrchHeader->entrySelector || 292 rangeShift != binSrchHeader->rangeShift ) 293 { 294 GXV_TRACE(( "Inconsistency found in BinSrchHeader\n" )); 295 GXV_TRACE(( "originally: unitSize=%d, nUnits=%d, " 296 "searchRange=%d, entrySelector=%d, " 297 "rangeShift=%d\n", 298 binSrchHeader->unitSize, binSrchHeader->nUnits, 299 binSrchHeader->searchRange, binSrchHeader->entrySelector, 300 binSrchHeader->rangeShift )); 301 GXV_TRACE(( "calculated: unitSize=%d, nUnits=%d, " 302 "searchRange=%d, entrySelector=%d, " 303 "rangeShift=%d\n", 304 binSrchHeader->unitSize, binSrchHeader->nUnits, 305 searchRange, entrySelector, rangeShift )); 306 307 GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); 308 } 309 } 310 311 312 /* 313 * parser & validator of BinSrchHeader 314 * which is used in LookupTable format 2, 4, 6. 315 * 316 * Essential parameters (unitSize, nUnits) are returned by 317 * given pointer, others (searchRange, entrySelector, rangeShift) 318 * can be calculated by essential parameters, so they are just 319 * validated and discarded. 320 * 321 * However, wrong values in searchRange, entrySelector, rangeShift 322 * won't cause fatal errors, because these parameters might be 323 * only used in old m68k font driver in MacOS. 324 * -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp> 325 */ 326 327 FT_LOCAL_DEF( void ) gxv_BinSrchHeader_validate(FT_Bytes table,FT_Bytes limit,FT_UShort * unitSize_p,FT_UShort * nUnits_p,GXV_Validator valid)328 gxv_BinSrchHeader_validate( FT_Bytes table, 329 FT_Bytes limit, 330 FT_UShort* unitSize_p, 331 FT_UShort* nUnits_p, 332 GXV_Validator valid ) 333 { 334 FT_Bytes p = table; 335 GXV_BinSrchHeader binSrchHeader; 336 337 338 GXV_NAME_ENTER( "BinSrchHeader validate" ); 339 340 if ( *unitSize_p == 0 ) 341 { 342 GXV_LIMIT_CHECK( 2 ); 343 binSrchHeader.unitSize = FT_NEXT_USHORT( p ); 344 } 345 else 346 binSrchHeader.unitSize = *unitSize_p; 347 348 if ( *nUnits_p == 0 ) 349 { 350 GXV_LIMIT_CHECK( 2 ); 351 binSrchHeader.nUnits = FT_NEXT_USHORT( p ); 352 } 353 else 354 binSrchHeader.nUnits = *nUnits_p; 355 356 GXV_LIMIT_CHECK( 2 + 2 + 2 ); 357 binSrchHeader.searchRange = FT_NEXT_USHORT( p ); 358 binSrchHeader.entrySelector = FT_NEXT_USHORT( p ); 359 binSrchHeader.rangeShift = FT_NEXT_USHORT( p ); 360 GXV_TRACE(( "nUnits %d\n", binSrchHeader.nUnits )); 361 362 gxv_BinSrchHeader_check_consistency( &binSrchHeader, valid ); 363 364 if ( *unitSize_p == 0 ) 365 *unitSize_p = binSrchHeader.unitSize; 366 367 if ( *nUnits_p == 0 ) 368 *nUnits_p = binSrchHeader.nUnits; 369 370 valid->subtable_length = p - table; 371 GXV_EXIT; 372 } 373 374 375 /*************************************************************************/ 376 /*************************************************************************/ 377 /***** *****/ 378 /***** LOOKUP TABLE *****/ 379 /***** *****/ 380 /*************************************************************************/ 381 /*************************************************************************/ 382 383 #define GXV_LOOKUP_VALUE_LOAD( P, SIGNSPEC ) \ 384 ( P += 2, gxv_lookup_value_load( P - 2, SIGNSPEC ) ) 385 386 static GXV_LookupValueDesc gxv_lookup_value_load(FT_Bytes p,int signspec)387 gxv_lookup_value_load( FT_Bytes p, 388 int signspec ) 389 { 390 GXV_LookupValueDesc v; 391 392 393 if ( signspec == GXV_LOOKUPVALUE_UNSIGNED ) 394 v.u = FT_NEXT_USHORT( p ); 395 else 396 v.s = FT_NEXT_SHORT( p ); 397 398 return v; 399 } 400 401 402 #define GXV_UNITSIZE_VALIDATE( FORMAT, UNITSIZE, NUNITS, CORRECTSIZE ) \ 403 FT_BEGIN_STMNT \ 404 if ( UNITSIZE != CORRECTSIZE ) \ 405 { \ 406 FT_ERROR(( "unitSize=%d differs from" \ 407 " expected unitSize=%d" \ 408 " in LookupTable %s\n", \ 409 UNITSIZE, CORRECTSIZE, FORMAT )); \ 410 if ( UNITSIZE != 0 && NUNITS != 0 ) \ 411 { \ 412 FT_ERROR(( " cannot validate anymore\n" )); \ 413 FT_INVALID_FORMAT; \ 414 } \ 415 else \ 416 FT_ERROR(( " forcibly continues\n" )); \ 417 } \ 418 FT_END_STMNT 419 420 421 /* ================= Simple Array Format 0 Lookup Table ================ */ 422 static void gxv_LookupTable_fmt0_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator valid)423 gxv_LookupTable_fmt0_validate( FT_Bytes table, 424 FT_Bytes limit, 425 GXV_Validator valid ) 426 { 427 FT_Bytes p = table; 428 FT_UShort i; 429 430 GXV_LookupValueDesc value; 431 432 433 GXV_NAME_ENTER( "LookupTable format 0" ); 434 435 GXV_LIMIT_CHECK( 2 * valid->face->num_glyphs ); 436 437 for ( i = 0; i < valid->face->num_glyphs; i++ ) 438 { 439 GXV_LIMIT_CHECK( 2 ); 440 if ( p + 2 >= limit ) /* some fonts have too-short fmt0 array */ 441 { 442 GXV_TRACE(( "too short, glyphs %d - %d are missing\n", 443 i, valid->face->num_glyphs )); 444 GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); 445 break; 446 } 447 448 value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign ); 449 valid->lookupval_func( i, &value, valid ); 450 } 451 452 valid->subtable_length = p - table; 453 GXV_EXIT; 454 } 455 456 457 /* ================= Segment Single Format 2 Loolup Table ============== */ 458 /* 459 * Apple spec says: 460 * 461 * To guarantee that a binary search terminates, you must include one or 462 * more special `end of search table' values at the end of the data to 463 * be searched. The number of termination values that need to be 464 * included is table-specific. The value that indicates binary search 465 * termination is 0xFFFF. 466 * 467 * The problem is that nUnits does not include this end-marker. It's 468 * quite difficult to discriminate whether the following 0xFFFF comes from 469 * the end-marker or some next data. 470 * 471 * -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp> 472 */ 473 static void gxv_LookupTable_fmt2_skip_endmarkers(FT_Bytes table,FT_UShort unitSize,GXV_Validator valid)474 gxv_LookupTable_fmt2_skip_endmarkers( FT_Bytes table, 475 FT_UShort unitSize, 476 GXV_Validator valid ) 477 { 478 FT_Bytes p = table; 479 480 481 while ( ( p + 4 ) < valid->root->limit ) 482 { 483 if ( p[0] != 0xFF || p[1] != 0xFF || /* lastGlyph */ 484 p[2] != 0xFF || p[3] != 0xFF ) /* firstGlyph */ 485 break; 486 p += unitSize; 487 } 488 489 valid->subtable_length = p - table; 490 } 491 492 493 static void gxv_LookupTable_fmt2_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator valid)494 gxv_LookupTable_fmt2_validate( FT_Bytes table, 495 FT_Bytes limit, 496 GXV_Validator valid ) 497 { 498 FT_Bytes p = table; 499 FT_UShort gid; 500 501 FT_UShort unitSize; 502 FT_UShort nUnits; 503 FT_UShort unit; 504 FT_UShort lastGlyph; 505 FT_UShort firstGlyph; 506 GXV_LookupValueDesc value; 507 508 509 GXV_NAME_ENTER( "LookupTable format 2" ); 510 511 unitSize = nUnits = 0; 512 gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, valid ); 513 p += valid->subtable_length; 514 515 GXV_UNITSIZE_VALIDATE( "format2", unitSize, nUnits, 6 ); 516 517 for ( unit = 0, gid = 0; unit < nUnits; unit++ ) 518 { 519 GXV_LIMIT_CHECK( 2 + 2 + 2 ); 520 lastGlyph = FT_NEXT_USHORT( p ); 521 firstGlyph = FT_NEXT_USHORT( p ); 522 value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign ); 523 524 gxv_glyphid_validate( firstGlyph, valid ); 525 gxv_glyphid_validate( lastGlyph, valid ); 526 527 if ( lastGlyph < gid ) 528 { 529 GXV_TRACE(( "reverse ordered segment specification:" 530 " lastGlyph[%d]=%d < lastGlyph[%d]=%d\n", 531 unit, lastGlyph, unit - 1 , gid )); 532 GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); 533 } 534 535 if ( lastGlyph < firstGlyph ) 536 { 537 GXV_TRACE(( "reverse ordered range specification at unit %d:", 538 " lastGlyph %d < firstGlyph %d ", 539 unit, lastGlyph, firstGlyph )); 540 GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); 541 542 if ( valid->root->level == FT_VALIDATE_TIGHT ) 543 continue; /* ftxvalidator silently skips such an entry */ 544 545 FT_TRACE4(( "continuing with exchanged values\n" )); 546 gid = firstGlyph; 547 firstGlyph = lastGlyph; 548 lastGlyph = gid; 549 } 550 551 for ( gid = firstGlyph; gid <= lastGlyph; gid++ ) 552 valid->lookupval_func( gid, &value, valid ); 553 } 554 555 gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, valid ); 556 p += valid->subtable_length; 557 558 valid->subtable_length = p - table; 559 GXV_EXIT; 560 } 561 562 563 /* ================= Segment Array Format 4 Lookup Table =============== */ 564 static void gxv_LookupTable_fmt4_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator valid)565 gxv_LookupTable_fmt4_validate( FT_Bytes table, 566 FT_Bytes limit, 567 GXV_Validator valid ) 568 { 569 FT_Bytes p = table; 570 FT_UShort unit; 571 FT_UShort gid; 572 573 FT_UShort unitSize; 574 FT_UShort nUnits; 575 FT_UShort lastGlyph; 576 FT_UShort firstGlyph; 577 GXV_LookupValueDesc base_value; 578 GXV_LookupValueDesc value; 579 580 581 GXV_NAME_ENTER( "LookupTable format 4" ); 582 583 unitSize = nUnits = 0; 584 gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, valid ); 585 p += valid->subtable_length; 586 587 GXV_UNITSIZE_VALIDATE( "format4", unitSize, nUnits, 6 ); 588 589 for ( unit = 0, gid = 0; unit < nUnits; unit++ ) 590 { 591 GXV_LIMIT_CHECK( 2 + 2 ); 592 lastGlyph = FT_NEXT_USHORT( p ); 593 firstGlyph = FT_NEXT_USHORT( p ); 594 595 gxv_glyphid_validate( firstGlyph, valid ); 596 gxv_glyphid_validate( lastGlyph, valid ); 597 598 if ( lastGlyph < gid ) 599 { 600 GXV_TRACE(( "reverse ordered segment specification:" 601 " lastGlyph[%d]=%d < lastGlyph[%d]=%d\n", 602 unit, lastGlyph, unit - 1 , gid )); 603 GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); 604 } 605 606 if ( lastGlyph < firstGlyph ) 607 { 608 GXV_TRACE(( "reverse ordered range specification at unit %d:", 609 " lastGlyph %d < firstGlyph %d ", 610 unit, lastGlyph, firstGlyph )); 611 GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); 612 613 if ( valid->root->level == FT_VALIDATE_TIGHT ) 614 continue; /* ftxvalidator silently skips such an entry */ 615 616 FT_TRACE4(( "continuing with exchanged values\n" )); 617 gid = firstGlyph; 618 firstGlyph = lastGlyph; 619 lastGlyph = gid; 620 } 621 622 GXV_LIMIT_CHECK( 2 ); 623 base_value = GXV_LOOKUP_VALUE_LOAD( p, GXV_LOOKUPVALUE_UNSIGNED ); 624 625 for ( gid = firstGlyph; gid <= lastGlyph; gid++ ) 626 { 627 value = valid->lookupfmt4_trans( (FT_UShort)( gid - firstGlyph ), 628 &base_value, 629 limit, 630 valid ); 631 632 valid->lookupval_func( gid, &value, valid ); 633 } 634 } 635 636 gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, valid ); 637 p += valid->subtable_length; 638 639 valid->subtable_length = p - table; 640 GXV_EXIT; 641 } 642 643 644 /* ================= Segment Table Format 6 Lookup Table =============== */ 645 static void gxv_LookupTable_fmt6_skip_endmarkers(FT_Bytes table,FT_UShort unitSize,GXV_Validator valid)646 gxv_LookupTable_fmt6_skip_endmarkers( FT_Bytes table, 647 FT_UShort unitSize, 648 GXV_Validator valid ) 649 { 650 FT_Bytes p = table; 651 652 653 while ( p < valid->root->limit ) 654 { 655 if ( p[0] != 0xFF || p[1] != 0xFF ) 656 break; 657 p += unitSize; 658 } 659 660 valid->subtable_length = p - table; 661 } 662 663 664 static void gxv_LookupTable_fmt6_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator valid)665 gxv_LookupTable_fmt6_validate( FT_Bytes table, 666 FT_Bytes limit, 667 GXV_Validator valid ) 668 { 669 FT_Bytes p = table; 670 FT_UShort unit; 671 FT_UShort prev_glyph; 672 673 FT_UShort unitSize; 674 FT_UShort nUnits; 675 FT_UShort glyph; 676 GXV_LookupValueDesc value; 677 678 679 GXV_NAME_ENTER( "LookupTable format 6" ); 680 681 unitSize = nUnits = 0; 682 gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, valid ); 683 p += valid->subtable_length; 684 685 GXV_UNITSIZE_VALIDATE( "format6", unitSize, nUnits, 4 ); 686 687 for ( unit = 0, prev_glyph = 0; unit < nUnits; unit++ ) 688 { 689 GXV_LIMIT_CHECK( 2 + 2 ); 690 glyph = FT_NEXT_USHORT( p ); 691 value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign ); 692 693 if ( gxv_glyphid_validate( glyph, valid ) ) 694 GXV_TRACE(( " endmarker found within defined range" 695 " (entry %d < nUnits=%d)\n", 696 unit, nUnits )); 697 698 if ( prev_glyph > glyph ) 699 { 700 GXV_TRACE(( "current gid 0x%04x < previous gid 0x%04x\n", 701 glyph, prev_glyph )); 702 GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); 703 } 704 prev_glyph = glyph; 705 706 valid->lookupval_func( glyph, &value, valid ); 707 } 708 709 gxv_LookupTable_fmt6_skip_endmarkers( p, unitSize, valid ); 710 p += valid->subtable_length; 711 712 valid->subtable_length = p - table; 713 GXV_EXIT; 714 } 715 716 717 /* ================= Trimmed Array Format 8 Lookup Table =============== */ 718 static void gxv_LookupTable_fmt8_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator valid)719 gxv_LookupTable_fmt8_validate( FT_Bytes table, 720 FT_Bytes limit, 721 GXV_Validator valid ) 722 { 723 FT_Bytes p = table; 724 FT_UShort i; 725 726 GXV_LookupValueDesc value; 727 FT_UShort firstGlyph; 728 FT_UShort glyphCount; 729 730 731 GXV_NAME_ENTER( "LookupTable format 8" ); 732 733 /* firstGlyph + glyphCount */ 734 GXV_LIMIT_CHECK( 2 + 2 ); 735 firstGlyph = FT_NEXT_USHORT( p ); 736 glyphCount = FT_NEXT_USHORT( p ); 737 738 gxv_glyphid_validate( firstGlyph, valid ); 739 gxv_glyphid_validate( (FT_UShort)( firstGlyph + glyphCount ), valid ); 740 741 /* valueArray */ 742 for ( i = 0; i < glyphCount; i++ ) 743 { 744 GXV_LIMIT_CHECK( 2 ); 745 value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign ); 746 valid->lookupval_func( (FT_UShort)( firstGlyph + i ), &value, valid ); 747 } 748 749 valid->subtable_length = p - table; 750 GXV_EXIT; 751 } 752 753 754 FT_LOCAL_DEF( void ) gxv_LookupTable_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator valid)755 gxv_LookupTable_validate( FT_Bytes table, 756 FT_Bytes limit, 757 GXV_Validator valid ) 758 { 759 FT_Bytes p = table; 760 FT_UShort format; 761 762 GXV_Validate_Func fmt_funcs_table[] = 763 { 764 gxv_LookupTable_fmt0_validate, /* 0 */ 765 NULL, /* 1 */ 766 gxv_LookupTable_fmt2_validate, /* 2 */ 767 NULL, /* 3 */ 768 gxv_LookupTable_fmt4_validate, /* 4 */ 769 NULL, /* 5 */ 770 gxv_LookupTable_fmt6_validate, /* 6 */ 771 NULL, /* 7 */ 772 gxv_LookupTable_fmt8_validate, /* 8 */ 773 }; 774 775 GXV_Validate_Func func; 776 777 778 GXV_NAME_ENTER( "LookupTable" ); 779 780 /* lookuptbl_head may be used in fmt4 transit function. */ 781 valid->lookuptbl_head = table; 782 783 /* format */ 784 GXV_LIMIT_CHECK( 2 ); 785 format = FT_NEXT_USHORT( p ); 786 GXV_TRACE(( " (format %d)\n", format )); 787 788 if ( format > 8 ) 789 FT_INVALID_FORMAT; 790 791 func = fmt_funcs_table[format]; 792 if ( func == NULL ) 793 FT_INVALID_FORMAT; 794 795 func( p, limit, valid ); 796 p += valid->subtable_length; 797 798 valid->subtable_length = p - table; 799 800 GXV_EXIT; 801 } 802 803 804 /*************************************************************************/ 805 /*************************************************************************/ 806 /***** *****/ 807 /***** Glyph ID *****/ 808 /***** *****/ 809 /*************************************************************************/ 810 /*************************************************************************/ 811 812 FT_LOCAL_DEF( FT_Int ) gxv_glyphid_validate(FT_UShort gid,GXV_Validator valid)813 gxv_glyphid_validate( FT_UShort gid, 814 GXV_Validator valid ) 815 { 816 FT_Face face; 817 818 819 if ( gid == 0xFFFFU ) 820 { 821 GXV_EXIT; 822 return 1; 823 } 824 825 face = valid->face; 826 if ( face->num_glyphs < gid ) 827 { 828 GXV_TRACE(( " gxv_glyphid_check() gid overflow: num_glyphs %d < %d\n", 829 face->num_glyphs, gid )); 830 GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); 831 } 832 833 return 0; 834 } 835 836 837 /*************************************************************************/ 838 /*************************************************************************/ 839 /***** *****/ 840 /***** CONTROL POINT *****/ 841 /***** *****/ 842 /*************************************************************************/ 843 /*************************************************************************/ 844 845 FT_LOCAL_DEF( void ) gxv_ctlPoint_validate(FT_UShort gid,FT_Short ctl_point,GXV_Validator valid)846 gxv_ctlPoint_validate( FT_UShort gid, 847 FT_Short ctl_point, 848 GXV_Validator valid ) 849 { 850 FT_Face face; 851 FT_Error error; 852 853 FT_GlyphSlot glyph; 854 FT_Outline outline; 855 short n_points; 856 857 858 face = valid->face; 859 860 error = FT_Load_Glyph( face, 861 gid, 862 FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM ); 863 if ( error ) 864 FT_INVALID_GLYPH_ID; 865 866 glyph = face->glyph; 867 outline = glyph->outline; 868 n_points = outline.n_points; 869 870 871 if ( !( ctl_point < n_points ) ) 872 FT_INVALID_DATA; 873 } 874 875 876 /*************************************************************************/ 877 /*************************************************************************/ 878 /***** *****/ 879 /***** SFNT NAME *****/ 880 /***** *****/ 881 /*************************************************************************/ 882 /*************************************************************************/ 883 884 FT_LOCAL_DEF( void ) gxv_sfntName_validate(FT_UShort name_index,FT_UShort min_index,FT_UShort max_index,GXV_Validator valid)885 gxv_sfntName_validate( FT_UShort name_index, 886 FT_UShort min_index, 887 FT_UShort max_index, 888 GXV_Validator valid ) 889 { 890 FT_SfntName name; 891 FT_UInt i; 892 FT_UInt nnames; 893 894 895 GXV_NAME_ENTER( "sfntName" ); 896 897 if ( name_index < min_index || max_index < name_index ) 898 FT_INVALID_FORMAT; 899 900 nnames = FT_Get_Sfnt_Name_Count( valid->face ); 901 for ( i = 0; i < nnames; i++ ) 902 { 903 if ( FT_Get_Sfnt_Name( valid->face, i, &name ) != FT_Err_Ok ) 904 continue ; 905 906 if ( name.name_id == name_index ) 907 goto Out; 908 } 909 910 GXV_TRACE(( " nameIndex = %d (UNTITLED)\n", name_index )); 911 FT_INVALID_DATA; 912 goto Exit; /* make compiler happy */ 913 914 Out: 915 FT_TRACE1(( " nameIndex = %d (", name_index )); 916 GXV_TRACE_HEXDUMP_SFNTNAME( name ); 917 FT_TRACE1(( ")\n" )); 918 919 Exit: 920 GXV_EXIT; 921 } 922 923 924 /*************************************************************************/ 925 /*************************************************************************/ 926 /***** *****/ 927 /***** STATE TABLE *****/ 928 /***** *****/ 929 /*************************************************************************/ 930 /*************************************************************************/ 931 932 /* -------------------------- Class Table --------------------------- */ 933 934 /* 935 * highestClass specifies how many classes are defined in this 936 * Class Subtable. Apple spec does not mention whether undefined 937 * holes in the class (e.g.: 0-3 are predefined, 4 is unused, 5 is used) 938 * are permitted. At present, holes in a defined class are not checked. 939 * -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp> 940 */ 941 942 static void gxv_ClassTable_validate(FT_Bytes table,FT_UShort * length_p,FT_UShort stateSize,FT_Byte * maxClassID_p,GXV_Validator valid)943 gxv_ClassTable_validate( FT_Bytes table, 944 FT_UShort* length_p, 945 FT_UShort stateSize, 946 FT_Byte* maxClassID_p, 947 GXV_Validator valid ) 948 { 949 FT_Bytes p = table; 950 FT_Bytes limit = table + *length_p; 951 FT_UShort firstGlyph; 952 FT_UShort nGlyphs; 953 954 955 GXV_NAME_ENTER( "ClassTable" ); 956 957 *maxClassID_p = 3; /* Classes 0, 2, and 3 are predefined */ 958 959 GXV_LIMIT_CHECK( 2 + 2 ); 960 firstGlyph = FT_NEXT_USHORT( p ); 961 nGlyphs = FT_NEXT_USHORT( p ); 962 963 GXV_TRACE(( " (firstGlyph = %d, nGlyphs = %d)\n", firstGlyph, nGlyphs )); 964 965 if ( !nGlyphs ) 966 goto Out; 967 968 gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs ), valid ); 969 970 { 971 FT_Byte nGlyphInClass[256]; 972 FT_Byte classID; 973 FT_UShort i; 974 975 976 ft_memset( nGlyphInClass, 0, 256 ); 977 978 979 for ( i = 0; i < nGlyphs; i++ ) 980 { 981 GXV_LIMIT_CHECK( 1 ); 982 classID = FT_NEXT_BYTE( p ); 983 switch ( classID ) 984 { 985 /* following classes should not appear in class array */ 986 case 0: /* end of text */ 987 case 2: /* out of bounds */ 988 case 3: /* end of line */ 989 FT_INVALID_DATA; 990 break; 991 992 case 1: /* out of bounds */ 993 default: /* user-defined: 4 - ( stateSize - 1 ) */ 994 if ( classID >= stateSize ) 995 FT_INVALID_DATA; /* assign glyph to undefined state */ 996 997 nGlyphInClass[classID]++; 998 break; 999 } 1000 } 1001 *length_p = (FT_UShort)( p - table ); 1002 1003 /* scan max ClassID in use */ 1004 for ( i = 0; i < stateSize; i++ ) 1005 if ( ( 3 < i ) && ( nGlyphInClass[i] > 0 ) ) 1006 *maxClassID_p = (FT_Byte)i; /* XXX: Check Range? */ 1007 } 1008 1009 Out: 1010 GXV_TRACE(( "Declared stateSize=0x%02x, Used maxClassID=0x%02x\n", 1011 stateSize, *maxClassID_p )); 1012 GXV_EXIT; 1013 } 1014 1015 1016 /* --------------------------- State Array ----------------------------- */ 1017 1018 static void gxv_StateArray_validate(FT_Bytes table,FT_UShort * length_p,FT_Byte maxClassID,FT_UShort stateSize,FT_Byte * maxState_p,FT_Byte * maxEntry_p,GXV_Validator valid)1019 gxv_StateArray_validate( FT_Bytes table, 1020 FT_UShort* length_p, 1021 FT_Byte maxClassID, 1022 FT_UShort stateSize, 1023 FT_Byte* maxState_p, 1024 FT_Byte* maxEntry_p, 1025 GXV_Validator valid ) 1026 { 1027 FT_Bytes p = table; 1028 FT_Bytes limit = table + *length_p; 1029 FT_Byte clazz; 1030 FT_Byte entry; 1031 1032 FT_UNUSED( stateSize ); /* for the non-debugging case */ 1033 1034 1035 GXV_NAME_ENTER( "StateArray" ); 1036 1037 GXV_TRACE(( "parse %d bytes by stateSize=%d maxClassID=%d\n", 1038 (int)(*length_p), stateSize, (int)(maxClassID) )); 1039 1040 /* 1041 * 2 states are predefined and must be described in StateArray: 1042 * state 0 (start of text), 1 (start of line) 1043 */ 1044 GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 ); 1045 1046 *maxState_p = 0; 1047 *maxEntry_p = 0; 1048 1049 /* read if enough to read another state */ 1050 while ( p + ( 1 + maxClassID ) <= limit ) 1051 { 1052 (*maxState_p)++; 1053 for ( clazz = 0; clazz <= maxClassID; clazz++ ) 1054 { 1055 entry = FT_NEXT_BYTE( p ); 1056 *maxEntry_p = (FT_Byte)FT_MAX( *maxEntry_p, entry ); 1057 } 1058 } 1059 GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n", 1060 *maxState_p, *maxEntry_p )); 1061 1062 *length_p = (FT_UShort)( p - table ); 1063 1064 GXV_EXIT; 1065 } 1066 1067 1068 /* --------------------------- Entry Table ----------------------------- */ 1069 1070 static void gxv_EntryTable_validate(FT_Bytes table,FT_UShort * length_p,FT_Byte maxEntry,FT_UShort stateArray,FT_UShort stateArray_length,FT_Byte maxClassID,FT_Bytes statetable_table,FT_Bytes statetable_limit,GXV_Validator valid)1071 gxv_EntryTable_validate( FT_Bytes table, 1072 FT_UShort* length_p, 1073 FT_Byte maxEntry, 1074 FT_UShort stateArray, 1075 FT_UShort stateArray_length, 1076 FT_Byte maxClassID, 1077 FT_Bytes statetable_table, 1078 FT_Bytes statetable_limit, 1079 GXV_Validator valid ) 1080 { 1081 FT_Bytes p = table; 1082 FT_Bytes limit = table + *length_p; 1083 FT_Byte entry; 1084 FT_Byte state; 1085 FT_Int entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( statetable ); 1086 1087 GXV_XStateTable_GlyphOffsetDesc glyphOffset; 1088 1089 1090 GXV_NAME_ENTER( "EntryTable" ); 1091 1092 GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize )); 1093 1094 if ( ( maxEntry + 1 ) * entrySize > *length_p ) 1095 { 1096 GXV_SET_ERR_IF_PARANOID( FT_INVALID_TOO_SHORT ); 1097 1098 /* ftxvalidator and FontValidator both warn and continue */ 1099 maxEntry = (FT_Byte)( *length_p / entrySize - 1 ); 1100 GXV_TRACE(( "too large maxEntry, shrinking to %d fit EntryTable length\n", 1101 maxEntry )); 1102 } 1103 1104 for ( entry = 0; entry <= maxEntry; entry++ ) 1105 { 1106 FT_UShort newState; 1107 FT_UShort flags; 1108 1109 1110 GXV_LIMIT_CHECK( 2 + 2 ); 1111 newState = FT_NEXT_USHORT( p ); 1112 flags = FT_NEXT_USHORT( p ); 1113 1114 1115 if ( newState < stateArray || 1116 stateArray + stateArray_length < newState ) 1117 { 1118 GXV_TRACE(( " newState offset 0x%04x is out of stateArray\n", 1119 newState )); 1120 GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); 1121 continue; 1122 } 1123 1124 if ( 0 != ( ( newState - stateArray ) % ( 1 + maxClassID ) ) ) 1125 { 1126 GXV_TRACE(( " newState offset 0x%04x is not aligned to %d-classes\n", 1127 newState, 1 + maxClassID )); 1128 GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); 1129 continue; 1130 } 1131 1132 state = (FT_Byte)( ( newState - stateArray ) / ( 1 + maxClassID ) ); 1133 1134 switch ( GXV_GLYPHOFFSET_FMT( statetable ) ) 1135 { 1136 case GXV_GLYPHOFFSET_NONE: 1137 glyphOffset.uc = 0; /* make compiler happy */ 1138 break; 1139 1140 case GXV_GLYPHOFFSET_UCHAR: 1141 glyphOffset.uc = FT_NEXT_BYTE( p ); 1142 break; 1143 1144 case GXV_GLYPHOFFSET_CHAR: 1145 glyphOffset.c = FT_NEXT_CHAR( p ); 1146 break; 1147 1148 case GXV_GLYPHOFFSET_USHORT: 1149 glyphOffset.u = FT_NEXT_USHORT( p ); 1150 break; 1151 1152 case GXV_GLYPHOFFSET_SHORT: 1153 glyphOffset.s = FT_NEXT_SHORT( p ); 1154 break; 1155 1156 case GXV_GLYPHOFFSET_ULONG: 1157 glyphOffset.ul = FT_NEXT_ULONG( p ); 1158 break; 1159 1160 case GXV_GLYPHOFFSET_LONG: 1161 glyphOffset.l = FT_NEXT_LONG( p ); 1162 break; 1163 1164 default: 1165 GXV_SET_ERR_IF_PARANOID( FT_INVALID_FORMAT ); 1166 goto Exit; 1167 } 1168 1169 if ( NULL != valid->statetable.entry_validate_func ) 1170 valid->statetable.entry_validate_func( state, 1171 flags, 1172 &glyphOffset, 1173 statetable_table, 1174 statetable_limit, 1175 valid ); 1176 } 1177 1178 Exit: 1179 *length_p = (FT_UShort)( p - table ); 1180 1181 GXV_EXIT; 1182 } 1183 1184 1185 /* =========================== State Table ============================= */ 1186 1187 FT_LOCAL_DEF( void ) gxv_StateTable_subtable_setup(FT_UShort table_size,FT_UShort classTable,FT_UShort stateArray,FT_UShort entryTable,FT_UShort * classTable_length_p,FT_UShort * stateArray_length_p,FT_UShort * entryTable_length_p,GXV_Validator valid)1188 gxv_StateTable_subtable_setup( FT_UShort table_size, 1189 FT_UShort classTable, 1190 FT_UShort stateArray, 1191 FT_UShort entryTable, 1192 FT_UShort* classTable_length_p, 1193 FT_UShort* stateArray_length_p, 1194 FT_UShort* entryTable_length_p, 1195 GXV_Validator valid ) 1196 { 1197 FT_UShort o[3]; 1198 FT_UShort* l[3]; 1199 FT_UShort buff[4]; 1200 1201 1202 o[0] = classTable; 1203 o[1] = stateArray; 1204 o[2] = entryTable; 1205 l[0] = classTable_length_p; 1206 l[1] = stateArray_length_p; 1207 l[2] = entryTable_length_p; 1208 1209 gxv_set_length_by_ushort_offset( o, l, buff, 3, table_size, valid ); 1210 } 1211 1212 1213 FT_LOCAL_DEF( void ) gxv_StateTable_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator valid)1214 gxv_StateTable_validate( FT_Bytes table, 1215 FT_Bytes limit, 1216 GXV_Validator valid ) 1217 { 1218 FT_UShort stateSize; 1219 FT_UShort classTable; /* offset to Class(Sub)Table */ 1220 FT_UShort stateArray; /* offset to StateArray */ 1221 FT_UShort entryTable; /* offset to EntryTable */ 1222 1223 FT_UShort classTable_length; 1224 FT_UShort stateArray_length; 1225 FT_UShort entryTable_length; 1226 FT_Byte maxClassID; 1227 FT_Byte maxState; 1228 FT_Byte maxEntry; 1229 1230 GXV_StateTable_Subtable_Setup_Func setup_func; 1231 1232 FT_Bytes p = table; 1233 1234 1235 GXV_NAME_ENTER( "StateTable" ); 1236 1237 GXV_TRACE(( "StateTable header\n" )); 1238 1239 GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 ); 1240 stateSize = FT_NEXT_USHORT( p ); 1241 classTable = FT_NEXT_USHORT( p ); 1242 stateArray = FT_NEXT_USHORT( p ); 1243 entryTable = FT_NEXT_USHORT( p ); 1244 1245 GXV_TRACE(( "stateSize=0x%04x\n", stateSize )); 1246 GXV_TRACE(( "offset to classTable=0x%04x\n", classTable )); 1247 GXV_TRACE(( "offset to stateArray=0x%04x\n", stateArray )); 1248 GXV_TRACE(( "offset to entryTable=0x%04x\n", entryTable )); 1249 1250 if ( stateSize > 0xFF ) 1251 FT_INVALID_DATA; 1252 1253 if ( valid->statetable.optdata_load_func != NULL ) 1254 valid->statetable.optdata_load_func( p, limit, valid ); 1255 1256 if ( valid->statetable.subtable_setup_func != NULL) 1257 setup_func = valid->statetable.subtable_setup_func; 1258 else 1259 setup_func = gxv_StateTable_subtable_setup; 1260 1261 setup_func( (FT_UShort)( limit - table ), 1262 classTable, 1263 stateArray, 1264 entryTable, 1265 &classTable_length, 1266 &stateArray_length, 1267 &entryTable_length, 1268 valid ); 1269 1270 GXV_TRACE(( "StateTable Subtables\n" )); 1271 1272 if ( classTable != 0 ) 1273 gxv_ClassTable_validate( table + classTable, 1274 &classTable_length, 1275 stateSize, 1276 &maxClassID, 1277 valid ); 1278 else 1279 maxClassID = (FT_Byte)( stateSize - 1 ); 1280 1281 if ( stateArray != 0 ) 1282 gxv_StateArray_validate( table + stateArray, 1283 &stateArray_length, 1284 maxClassID, 1285 stateSize, 1286 &maxState, 1287 &maxEntry, 1288 valid ); 1289 else 1290 { 1291 #if 0 1292 maxState = 1; /* 0:start of text, 1:start of line are predefined */ 1293 #endif 1294 maxEntry = 0; 1295 } 1296 1297 if ( maxEntry > 0 && entryTable == 0 ) 1298 FT_INVALID_OFFSET; 1299 1300 if ( entryTable != 0 ) 1301 gxv_EntryTable_validate( table + entryTable, 1302 &entryTable_length, 1303 maxEntry, 1304 stateArray, 1305 stateArray_length, 1306 maxClassID, 1307 table, 1308 limit, 1309 valid ); 1310 1311 GXV_EXIT; 1312 } 1313 1314 1315 /* ================= eXtended State Table (for morx) =================== */ 1316 1317 FT_LOCAL_DEF( void ) gxv_XStateTable_subtable_setup(FT_ULong table_size,FT_ULong classTable,FT_ULong stateArray,FT_ULong entryTable,FT_ULong * classTable_length_p,FT_ULong * stateArray_length_p,FT_ULong * entryTable_length_p,GXV_Validator valid)1318 gxv_XStateTable_subtable_setup( FT_ULong table_size, 1319 FT_ULong classTable, 1320 FT_ULong stateArray, 1321 FT_ULong entryTable, 1322 FT_ULong* classTable_length_p, 1323 FT_ULong* stateArray_length_p, 1324 FT_ULong* entryTable_length_p, 1325 GXV_Validator valid ) 1326 { 1327 FT_ULong o[3]; 1328 FT_ULong* l[3]; 1329 FT_ULong buff[4]; 1330 1331 1332 o[0] = classTable; 1333 o[1] = stateArray; 1334 o[2] = entryTable; 1335 l[0] = classTable_length_p; 1336 l[1] = stateArray_length_p; 1337 l[2] = entryTable_length_p; 1338 1339 gxv_set_length_by_ulong_offset( o, l, buff, 3, table_size, valid ); 1340 } 1341 1342 1343 static void gxv_XClassTable_lookupval_validate(FT_UShort glyph,GXV_LookupValueCPtr value_p,GXV_Validator valid)1344 gxv_XClassTable_lookupval_validate( FT_UShort glyph, 1345 GXV_LookupValueCPtr value_p, 1346 GXV_Validator valid ) 1347 { 1348 FT_UNUSED( glyph ); 1349 1350 if ( value_p->u >= valid->xstatetable.nClasses ) 1351 FT_INVALID_DATA; 1352 if ( value_p->u > valid->xstatetable.maxClassID ) 1353 valid->xstatetable.maxClassID = value_p->u; 1354 } 1355 1356 1357 /* 1358 +===============+ --------+ 1359 | lookup header | | 1360 +===============+ | 1361 | BinSrchHeader | | 1362 +===============+ | 1363 | lastGlyph[0] | | 1364 +---------------+ | 1365 | firstGlyph[0] | | head of lookup table 1366 +---------------+ | + 1367 | offset[0] | -> | offset [byte] 1368 +===============+ | + 1369 | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] 1370 +---------------+ | 1371 | firstGlyph[1] | | 1372 +---------------+ | 1373 | offset[1] | | 1374 +===============+ | 1375 | 1376 .... | 1377 | 1378 16bit value array | 1379 +===============+ | 1380 | value | <-------+ 1381 .... 1382 */ 1383 static GXV_LookupValueDesc gxv_XClassTable_lookupfmt4_transit(FT_UShort relative_gindex,GXV_LookupValueCPtr base_value_p,FT_Bytes lookuptbl_limit,GXV_Validator valid)1384 gxv_XClassTable_lookupfmt4_transit( FT_UShort relative_gindex, 1385 GXV_LookupValueCPtr base_value_p, 1386 FT_Bytes lookuptbl_limit, 1387 GXV_Validator valid ) 1388 { 1389 FT_Bytes p; 1390 FT_Bytes limit; 1391 FT_UShort offset; 1392 GXV_LookupValueDesc value; 1393 1394 /* XXX: check range? */ 1395 offset = (FT_UShort)( base_value_p->u + 1396 relative_gindex * sizeof ( FT_UShort ) ); 1397 1398 p = valid->lookuptbl_head + offset; 1399 limit = lookuptbl_limit; 1400 1401 GXV_LIMIT_CHECK ( 2 ); 1402 value.u = FT_NEXT_USHORT( p ); 1403 1404 return value; 1405 } 1406 1407 1408 static void gxv_XStateArray_validate(FT_Bytes table,FT_ULong * length_p,FT_UShort maxClassID,FT_ULong stateSize,FT_UShort * maxState_p,FT_UShort * maxEntry_p,GXV_Validator valid)1409 gxv_XStateArray_validate( FT_Bytes table, 1410 FT_ULong* length_p, 1411 FT_UShort maxClassID, 1412 FT_ULong stateSize, 1413 FT_UShort* maxState_p, 1414 FT_UShort* maxEntry_p, 1415 GXV_Validator valid ) 1416 { 1417 FT_Bytes p = table; 1418 FT_Bytes limit = table + *length_p; 1419 FT_UShort clazz; 1420 FT_UShort entry; 1421 1422 FT_UNUSED( stateSize ); /* for the non-debugging case */ 1423 1424 1425 GXV_NAME_ENTER( "XStateArray" ); 1426 1427 GXV_TRACE(( "parse % 3d bytes by stateSize=% 3d maxClassID=% 3d\n", 1428 (int)(*length_p), stateSize, (int)(maxClassID) )); 1429 1430 /* 1431 * 2 states are predefined and must be described: 1432 * state 0 (start of text), 1 (start of line) 1433 */ 1434 GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 * 2 ); 1435 1436 *maxState_p = 0; 1437 *maxEntry_p = 0; 1438 1439 /* read if enough to read another state */ 1440 while ( p + ( ( 1 + maxClassID ) * 2 ) <= limit ) 1441 { 1442 (*maxState_p)++; 1443 for ( clazz = 0; clazz <= maxClassID; clazz++ ) 1444 { 1445 entry = FT_NEXT_USHORT( p ); 1446 *maxEntry_p = (FT_UShort)FT_MAX( *maxEntry_p, entry ); 1447 } 1448 } 1449 GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n", 1450 *maxState_p, *maxEntry_p )); 1451 1452 *length_p = p - table; 1453 1454 GXV_EXIT; 1455 } 1456 1457 1458 static void gxv_XEntryTable_validate(FT_Bytes table,FT_ULong * length_p,FT_UShort maxEntry,FT_ULong stateArray_length,FT_UShort maxClassID,FT_Bytes xstatetable_table,FT_Bytes xstatetable_limit,GXV_Validator valid)1459 gxv_XEntryTable_validate( FT_Bytes table, 1460 FT_ULong* length_p, 1461 FT_UShort maxEntry, 1462 FT_ULong stateArray_length, 1463 FT_UShort maxClassID, 1464 FT_Bytes xstatetable_table, 1465 FT_Bytes xstatetable_limit, 1466 GXV_Validator valid ) 1467 { 1468 FT_Bytes p = table; 1469 FT_Bytes limit = table + *length_p; 1470 FT_UShort entry; 1471 FT_UShort state; 1472 FT_Int entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( xstatetable ); 1473 1474 1475 GXV_NAME_ENTER( "XEntryTable" ); 1476 GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize )); 1477 1478 if ( ( p + ( maxEntry + 1 ) * entrySize ) > limit ) 1479 FT_INVALID_TOO_SHORT; 1480 1481 for (entry = 0; entry <= maxEntry ; entry++ ) 1482 { 1483 FT_UShort newState_idx; 1484 FT_UShort flags; 1485 GXV_XStateTable_GlyphOffsetDesc glyphOffset; 1486 1487 1488 GXV_LIMIT_CHECK( 2 + 2 ); 1489 newState_idx = FT_NEXT_USHORT( p ); 1490 flags = FT_NEXT_USHORT( p ); 1491 1492 if ( stateArray_length < (FT_ULong)( newState_idx * 2 ) ) 1493 { 1494 GXV_TRACE(( " newState index 0x%04x points out of stateArray\n", 1495 newState_idx )); 1496 GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); 1497 } 1498 1499 state = (FT_UShort)( newState_idx / ( 1 + maxClassID ) ); 1500 if ( 0 != ( newState_idx % ( 1 + maxClassID ) ) ) 1501 { 1502 FT_TRACE4(( "-> new state = %d (supposed)\n" 1503 "but newState index 0x%04x is not aligned to %d-classes\n", 1504 state, newState_idx, 1 + maxClassID )); 1505 GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); 1506 } 1507 1508 switch ( GXV_GLYPHOFFSET_FMT( xstatetable ) ) 1509 { 1510 case GXV_GLYPHOFFSET_NONE: 1511 glyphOffset.uc = 0; /* make compiler happy */ 1512 break; 1513 1514 case GXV_GLYPHOFFSET_UCHAR: 1515 glyphOffset.uc = FT_NEXT_BYTE( p ); 1516 break; 1517 1518 case GXV_GLYPHOFFSET_CHAR: 1519 glyphOffset.c = FT_NEXT_CHAR( p ); 1520 break; 1521 1522 case GXV_GLYPHOFFSET_USHORT: 1523 glyphOffset.u = FT_NEXT_USHORT( p ); 1524 break; 1525 1526 case GXV_GLYPHOFFSET_SHORT: 1527 glyphOffset.s = FT_NEXT_SHORT( p ); 1528 break; 1529 1530 case GXV_GLYPHOFFSET_ULONG: 1531 glyphOffset.ul = FT_NEXT_ULONG( p ); 1532 break; 1533 1534 case GXV_GLYPHOFFSET_LONG: 1535 glyphOffset.l = FT_NEXT_LONG( p ); 1536 break; 1537 1538 default: 1539 GXV_SET_ERR_IF_PARANOID( FT_INVALID_FORMAT ); 1540 goto Exit; 1541 } 1542 1543 if ( NULL != valid->xstatetable.entry_validate_func ) 1544 valid->xstatetable.entry_validate_func( state, 1545 flags, 1546 &glyphOffset, 1547 xstatetable_table, 1548 xstatetable_limit, 1549 valid ); 1550 } 1551 1552 Exit: 1553 *length_p = p - table; 1554 1555 GXV_EXIT; 1556 } 1557 1558 1559 FT_LOCAL_DEF( void ) gxv_XStateTable_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator valid)1560 gxv_XStateTable_validate( FT_Bytes table, 1561 FT_Bytes limit, 1562 GXV_Validator valid ) 1563 { 1564 /* StateHeader members */ 1565 FT_ULong classTable; /* offset to Class(Sub)Table */ 1566 FT_ULong stateArray; /* offset to StateArray */ 1567 FT_ULong entryTable; /* offset to EntryTable */ 1568 1569 FT_ULong classTable_length; 1570 FT_ULong stateArray_length; 1571 FT_ULong entryTable_length; 1572 FT_UShort maxState; 1573 FT_UShort maxEntry; 1574 1575 GXV_XStateTable_Subtable_Setup_Func setup_func; 1576 1577 FT_Bytes p = table; 1578 1579 1580 GXV_NAME_ENTER( "XStateTable" ); 1581 1582 GXV_TRACE(( "XStateTable header\n" )); 1583 1584 GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 ); 1585 valid->xstatetable.nClasses = FT_NEXT_ULONG( p ); 1586 classTable = FT_NEXT_ULONG( p ); 1587 stateArray = FT_NEXT_ULONG( p ); 1588 entryTable = FT_NEXT_ULONG( p ); 1589 1590 GXV_TRACE(( "nClasses =0x%08x\n", valid->xstatetable.nClasses )); 1591 GXV_TRACE(( "offset to classTable=0x%08x\n", classTable )); 1592 GXV_TRACE(( "offset to stateArray=0x%08x\n", stateArray )); 1593 GXV_TRACE(( "offset to entryTable=0x%08x\n", entryTable )); 1594 1595 if ( valid->xstatetable.nClasses > 0xFFFFU ) 1596 FT_INVALID_DATA; 1597 1598 GXV_TRACE(( "StateTable Subtables\n" )); 1599 1600 if ( valid->xstatetable.optdata_load_func != NULL ) 1601 valid->xstatetable.optdata_load_func( p, limit, valid ); 1602 1603 if ( valid->xstatetable.subtable_setup_func != NULL ) 1604 setup_func = valid->xstatetable.subtable_setup_func; 1605 else 1606 setup_func = gxv_XStateTable_subtable_setup; 1607 1608 setup_func( limit - table, 1609 classTable, 1610 stateArray, 1611 entryTable, 1612 &classTable_length, 1613 &stateArray_length, 1614 &entryTable_length, 1615 valid ); 1616 1617 if ( classTable != 0 ) 1618 { 1619 valid->xstatetable.maxClassID = 0; 1620 valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; 1621 valid->lookupval_func = gxv_XClassTable_lookupval_validate; 1622 valid->lookupfmt4_trans = gxv_XClassTable_lookupfmt4_transit; 1623 gxv_LookupTable_validate( table + classTable, 1624 table + classTable + classTable_length, 1625 valid ); 1626 #if 0 1627 if ( valid->subtable_length < classTable_length ) 1628 classTable_length = valid->subtable_length; 1629 #endif 1630 } 1631 else 1632 { 1633 /* XXX: check range? */ 1634 valid->xstatetable.maxClassID = 1635 (FT_UShort)( valid->xstatetable.nClasses - 1 ); 1636 } 1637 1638 if ( stateArray != 0 ) 1639 gxv_XStateArray_validate( table + stateArray, 1640 &stateArray_length, 1641 valid->xstatetable.maxClassID, 1642 valid->xstatetable.nClasses, 1643 &maxState, 1644 &maxEntry, 1645 valid ); 1646 else 1647 { 1648 #if 0 1649 maxState = 1; /* 0:start of text, 1:start of line are predefined */ 1650 #endif 1651 maxEntry = 0; 1652 } 1653 1654 if ( maxEntry > 0 && entryTable == 0 ) 1655 FT_INVALID_OFFSET; 1656 1657 if ( entryTable != 0 ) 1658 gxv_XEntryTable_validate( table + entryTable, 1659 &entryTable_length, 1660 maxEntry, 1661 stateArray_length, 1662 valid->xstatetable.maxClassID, 1663 table, 1664 limit, 1665 valid ); 1666 1667 GXV_EXIT; 1668 } 1669 1670 1671 /*************************************************************************/ 1672 /*************************************************************************/ 1673 /***** *****/ 1674 /***** Table overlapping *****/ 1675 /***** *****/ 1676 /*************************************************************************/ 1677 /*************************************************************************/ 1678 1679 static int gxv_compare_ranges(FT_Bytes table1_start,FT_ULong table1_length,FT_Bytes table2_start,FT_ULong table2_length)1680 gxv_compare_ranges( FT_Bytes table1_start, 1681 FT_ULong table1_length, 1682 FT_Bytes table2_start, 1683 FT_ULong table2_length ) 1684 { 1685 if ( table1_start == table2_start ) 1686 { 1687 if ( ( table1_length == 0 || table2_length == 0 ) ) 1688 goto Out; 1689 } 1690 else if ( table1_start < table2_start ) 1691 { 1692 if ( ( table1_start + table1_length ) <= table2_start ) 1693 goto Out; 1694 } 1695 else if ( table1_start > table2_start ) 1696 { 1697 if ( ( table1_start >= table2_start + table2_length ) ) 1698 goto Out; 1699 } 1700 return 1; 1701 1702 Out: 1703 return 0; 1704 } 1705 1706 1707 FT_LOCAL_DEF( void ) gxv_odtect_add_range(FT_Bytes start,FT_ULong length,const FT_String * name,GXV_odtect_Range odtect)1708 gxv_odtect_add_range( FT_Bytes start, 1709 FT_ULong length, 1710 const FT_String* name, 1711 GXV_odtect_Range odtect ) 1712 { 1713 odtect->range[odtect->nRanges].start = start; 1714 odtect->range[odtect->nRanges].length = length; 1715 odtect->range[odtect->nRanges].name = (FT_String*)name; 1716 odtect->nRanges++; 1717 } 1718 1719 1720 FT_LOCAL_DEF( void ) gxv_odtect_validate(GXV_odtect_Range odtect,GXV_Validator valid)1721 gxv_odtect_validate( GXV_odtect_Range odtect, 1722 GXV_Validator valid ) 1723 { 1724 FT_UInt i, j; 1725 1726 1727 GXV_NAME_ENTER( "check overlap among multi ranges" ); 1728 1729 for ( i = 0; i < odtect->nRanges; i++ ) 1730 for ( j = 0; j < i; j++ ) 1731 if ( 0 != gxv_compare_ranges( odtect->range[i].start, 1732 odtect->range[i].length, 1733 odtect->range[j].start, 1734 odtect->range[j].length ) ) 1735 { 1736 #ifdef FT_DEBUG_LEVEL_TRACE 1737 if ( odtect->range[i].name || odtect->range[j].name ) 1738 GXV_TRACE(( "found overlap between range %d and range %d\n", 1739 i, j )); 1740 else 1741 GXV_TRACE(( "found overlap between `%s' and `%s\'\n", 1742 odtect->range[i].name, 1743 odtect->range[j].name )); 1744 #endif 1745 FT_INVALID_OFFSET; 1746 } 1747 1748 GXV_EXIT; 1749 } 1750 1751 1752 /* END */ 1753