1 /**************************************************************************** 2 * 3 * gxvcommn.c 4 * 5 * TrueTypeGX/AAT common tables validation (body). 6 * 7 * Copyright (C) 2004-2020 by 8 * 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 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 gxvalid)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 gxvalid ) 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 gxvalid)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 gxvalid) 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 gxvalid)181 gxv_array_getlimits_byte( FT_Bytes table, 182 FT_Bytes limit, 183 FT_Byte* min, 184 FT_Byte* max, 185 GXV_Validator gxvalid ) 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 gxvalid->subtable_length = (FT_ULong)( 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 gxvalid)210 gxv_array_getlimits_ushort( FT_Bytes table, 211 FT_Bytes limit, 212 FT_UShort* min, 213 FT_UShort* max, 214 GXV_Validator gxvalid ) 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 gxvalid->subtable_length = (FT_ULong)( 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 gxvalid)258 gxv_BinSrchHeader_check_consistency( GXV_BinSrchHeader* binSrchHeader, 259 GXV_Validator gxvalid ) 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 gxvalid)328 gxv_BinSrchHeader_validate( FT_Bytes table, 329 FT_Bytes limit, 330 FT_UShort* unitSize_p, 331 FT_UShort* nUnits_p, 332 GXV_Validator gxvalid ) 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, gxvalid ); 363 364 if ( *unitSize_p == 0 ) 365 *unitSize_p = binSrchHeader.unitSize; 366 367 if ( *nUnits_p == 0 ) 368 *nUnits_p = binSrchHeader.nUnits; 369 370 gxvalid->subtable_length = (FT_ULong)( 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,GXV_LookupValue_SignSpec signspec)387 gxv_lookup_value_load( FT_Bytes p, 388 GXV_LookupValue_SignSpec 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 gxvalid)423 gxv_LookupTable_fmt0_validate( FT_Bytes table, 424 FT_Bytes limit, 425 GXV_Validator gxvalid ) 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 * gxvalid->face->num_glyphs ); 436 437 for ( i = 0; i < gxvalid->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, gxvalid->face->num_glyphs )); 444 GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); 445 break; 446 } 447 448 value = GXV_LOOKUP_VALUE_LOAD( p, gxvalid->lookupval_sign ); 449 gxvalid->lookupval_func( i, &value, gxvalid ); 450 } 451 452 gxvalid->subtable_length = (FT_ULong)( p - table ); 453 GXV_EXIT; 454 } 455 456 457 /* ================= Segment Single Format 2 Lookup 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 gxvalid)474 gxv_LookupTable_fmt2_skip_endmarkers( FT_Bytes table, 475 FT_UShort unitSize, 476 GXV_Validator gxvalid ) 477 { 478 FT_Bytes p = table; 479 480 481 while ( ( p + 4 ) < gxvalid->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 gxvalid->subtable_length = (FT_ULong)( p - table ); 490 } 491 492 493 static void gxv_LookupTable_fmt2_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)494 gxv_LookupTable_fmt2_validate( FT_Bytes table, 495 FT_Bytes limit, 496 GXV_Validator gxvalid ) 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, gxvalid ); 513 p += gxvalid->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, gxvalid->lookupval_sign ); 523 524 gxv_glyphid_validate( firstGlyph, gxvalid ); 525 gxv_glyphid_validate( lastGlyph, gxvalid ); 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 ( gxvalid->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 gxvalid->lookupval_func( gid, &value, gxvalid ); 553 } 554 555 gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, gxvalid ); 556 p += gxvalid->subtable_length; 557 558 gxvalid->subtable_length = (FT_ULong)( 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 gxvalid)565 gxv_LookupTable_fmt4_validate( FT_Bytes table, 566 FT_Bytes limit, 567 GXV_Validator gxvalid ) 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, gxvalid ); 585 p += gxvalid->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, gxvalid ); 596 gxv_glyphid_validate( lastGlyph, gxvalid ); 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 ( gxvalid->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 = gxvalid->lookupfmt4_trans( (FT_UShort)( gid - firstGlyph ), 628 &base_value, 629 limit, 630 gxvalid ); 631 632 gxvalid->lookupval_func( gid, &value, gxvalid ); 633 } 634 } 635 636 gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, gxvalid ); 637 p += gxvalid->subtable_length; 638 639 gxvalid->subtable_length = (FT_ULong)( 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 gxvalid)646 gxv_LookupTable_fmt6_skip_endmarkers( FT_Bytes table, 647 FT_UShort unitSize, 648 GXV_Validator gxvalid ) 649 { 650 FT_Bytes p = table; 651 652 653 while ( p < gxvalid->root->limit ) 654 { 655 if ( p[0] != 0xFF || p[1] != 0xFF ) 656 break; 657 p += unitSize; 658 } 659 660 gxvalid->subtable_length = (FT_ULong)( p - table ); 661 } 662 663 664 static void gxv_LookupTable_fmt6_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)665 gxv_LookupTable_fmt6_validate( FT_Bytes table, 666 FT_Bytes limit, 667 GXV_Validator gxvalid ) 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, gxvalid ); 683 p += gxvalid->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, gxvalid->lookupval_sign ); 692 693 if ( gxv_glyphid_validate( glyph, gxvalid ) ) 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 gxvalid->lookupval_func( glyph, &value, gxvalid ); 707 } 708 709 gxv_LookupTable_fmt6_skip_endmarkers( p, unitSize, gxvalid ); 710 p += gxvalid->subtable_length; 711 712 gxvalid->subtable_length = (FT_ULong)( 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 gxvalid)719 gxv_LookupTable_fmt8_validate( FT_Bytes table, 720 FT_Bytes limit, 721 GXV_Validator gxvalid ) 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, gxvalid ); 739 gxv_glyphid_validate( (FT_UShort)( firstGlyph + glyphCount ), gxvalid ); 740 741 /* valueArray */ 742 for ( i = 0; i < glyphCount; i++ ) 743 { 744 GXV_LIMIT_CHECK( 2 ); 745 value = GXV_LOOKUP_VALUE_LOAD( p, gxvalid->lookupval_sign ); 746 gxvalid->lookupval_func( (FT_UShort)( firstGlyph + i ), &value, gxvalid ); 747 } 748 749 gxvalid->subtable_length = (FT_ULong)( p - table ); 750 GXV_EXIT; 751 } 752 753 754 FT_LOCAL_DEF( void ) gxv_LookupTable_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)755 gxv_LookupTable_validate( FT_Bytes table, 756 FT_Bytes limit, 757 GXV_Validator gxvalid ) 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 gxvalid->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 ) 793 FT_INVALID_FORMAT; 794 795 func( p, limit, gxvalid ); 796 p += gxvalid->subtable_length; 797 798 gxvalid->subtable_length = (FT_ULong)( 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 gxvalid)813 gxv_glyphid_validate( FT_UShort gid, 814 GXV_Validator gxvalid ) 815 { 816 FT_Face face; 817 818 819 if ( gid == 0xFFFFU ) 820 { 821 GXV_EXIT; 822 return 1; 823 } 824 825 face = gxvalid->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_UShort ctl_point,GXV_Validator gxvalid)846 gxv_ctlPoint_validate( FT_UShort gid, 847 FT_UShort ctl_point, 848 GXV_Validator gxvalid ) 849 { 850 FT_Face face; 851 FT_Error error; 852 853 FT_GlyphSlot glyph; 854 FT_Outline outline; 855 FT_UShort n_points; 856 857 858 face = gxvalid->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 = (FT_UShort)outline.n_points; 869 870 if ( !( ctl_point < n_points ) ) 871 FT_INVALID_DATA; 872 } 873 874 875 /*************************************************************************/ 876 /*************************************************************************/ 877 /***** *****/ 878 /***** SFNT NAME *****/ 879 /***** *****/ 880 /*************************************************************************/ 881 /*************************************************************************/ 882 883 FT_LOCAL_DEF( void ) gxv_sfntName_validate(FT_UShort name_index,FT_UShort min_index,FT_UShort max_index,GXV_Validator gxvalid)884 gxv_sfntName_validate( FT_UShort name_index, 885 FT_UShort min_index, 886 FT_UShort max_index, 887 GXV_Validator gxvalid ) 888 { 889 FT_SfntName name; 890 FT_UInt i; 891 FT_UInt nnames; 892 893 894 GXV_NAME_ENTER( "sfntName" ); 895 896 if ( name_index < min_index || max_index < name_index ) 897 FT_INVALID_FORMAT; 898 899 nnames = FT_Get_Sfnt_Name_Count( gxvalid->face ); 900 for ( i = 0; i < nnames; i++ ) 901 { 902 if ( FT_Get_Sfnt_Name( gxvalid->face, i, &name ) != FT_Err_Ok ) 903 continue; 904 905 if ( name.name_id == name_index ) 906 goto Out; 907 } 908 909 GXV_TRACE(( " nameIndex = %d (UNTITLED)\n", name_index )); 910 FT_INVALID_DATA; 911 goto Exit; /* make compiler happy */ 912 913 Out: 914 FT_TRACE1(( " nameIndex = %d (", name_index )); 915 GXV_TRACE_HEXDUMP_SFNTNAME( name ); 916 FT_TRACE1(( ")\n" )); 917 918 Exit: 919 GXV_EXIT; 920 } 921 922 923 /*************************************************************************/ 924 /*************************************************************************/ 925 /***** *****/ 926 /***** STATE TABLE *****/ 927 /***** *****/ 928 /*************************************************************************/ 929 /*************************************************************************/ 930 931 /* -------------------------- Class Table --------------------------- */ 932 933 /* 934 * highestClass specifies how many classes are defined in this 935 * Class Subtable. Apple spec does not mention whether undefined 936 * holes in the class (e.g.: 0-3 are predefined, 4 is unused, 5 is used) 937 * are permitted. At present, holes in a defined class are not checked. 938 * -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp> 939 */ 940 941 static void gxv_ClassTable_validate(FT_Bytes table,FT_UShort * length_p,FT_UShort stateSize,FT_Byte * maxClassID_p,GXV_Validator gxvalid)942 gxv_ClassTable_validate( FT_Bytes table, 943 FT_UShort* length_p, 944 FT_UShort stateSize, 945 FT_Byte* maxClassID_p, 946 GXV_Validator gxvalid ) 947 { 948 FT_Bytes p = table; 949 FT_Bytes limit = table + *length_p; 950 FT_UShort firstGlyph; 951 FT_UShort nGlyphs; 952 953 954 GXV_NAME_ENTER( "ClassTable" ); 955 956 *maxClassID_p = 3; /* Classes 0, 2, and 3 are predefined */ 957 958 GXV_LIMIT_CHECK( 2 + 2 ); 959 firstGlyph = FT_NEXT_USHORT( p ); 960 nGlyphs = FT_NEXT_USHORT( p ); 961 962 GXV_TRACE(( " (firstGlyph = %d, nGlyphs = %d)\n", firstGlyph, nGlyphs )); 963 964 if ( !nGlyphs ) 965 goto Out; 966 967 gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs ), gxvalid ); 968 969 { 970 FT_Byte nGlyphInClass[256]; 971 FT_Byte classID; 972 FT_UShort i; 973 974 975 FT_MEM_ZERO( nGlyphInClass, 256 ); 976 977 978 for ( i = 0; i < nGlyphs; i++ ) 979 { 980 GXV_LIMIT_CHECK( 1 ); 981 classID = FT_NEXT_BYTE( p ); 982 switch ( classID ) 983 { 984 /* following classes should not appear in class array */ 985 case 0: /* end of text */ 986 case 2: /* out of bounds */ 987 case 3: /* end of line */ 988 FT_INVALID_DATA; 989 break; 990 991 case 1: /* out of bounds */ 992 default: /* user-defined: 4 - ( stateSize - 1 ) */ 993 if ( classID >= stateSize ) 994 FT_INVALID_DATA; /* assign glyph to undefined state */ 995 996 nGlyphInClass[classID]++; 997 break; 998 } 999 } 1000 *length_p = (FT_UShort)( p - table ); 1001 1002 /* scan max ClassID in use */ 1003 for ( i = 0; i < stateSize; i++ ) 1004 if ( ( 3 < i ) && ( nGlyphInClass[i] > 0 ) ) 1005 *maxClassID_p = (FT_Byte)i; /* XXX: Check Range? */ 1006 } 1007 1008 Out: 1009 GXV_TRACE(( "Declared stateSize=0x%02x, Used maxClassID=0x%02x\n", 1010 stateSize, *maxClassID_p )); 1011 GXV_EXIT; 1012 } 1013 1014 1015 /* --------------------------- State Array ----------------------------- */ 1016 1017 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 gxvalid)1018 gxv_StateArray_validate( FT_Bytes table, 1019 FT_UShort* length_p, 1020 FT_Byte maxClassID, 1021 FT_UShort stateSize, 1022 FT_Byte* maxState_p, 1023 FT_Byte* maxEntry_p, 1024 GXV_Validator gxvalid ) 1025 { 1026 FT_Bytes p = table; 1027 FT_Bytes limit = table + *length_p; 1028 FT_Byte clazz; 1029 FT_Byte entry; 1030 1031 FT_UNUSED( stateSize ); /* for the non-debugging case */ 1032 1033 1034 GXV_NAME_ENTER( "StateArray" ); 1035 1036 GXV_TRACE(( "parse %d bytes by stateSize=%d maxClassID=%d\n", 1037 (int)(*length_p), stateSize, (int)(maxClassID) )); 1038 1039 /* 1040 * 2 states are predefined and must be described in StateArray: 1041 * state 0 (start of text), 1 (start of line) 1042 */ 1043 GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 ); 1044 1045 *maxState_p = 0; 1046 *maxEntry_p = 0; 1047 1048 /* read if enough to read another state */ 1049 while ( p + ( 1 + maxClassID ) <= limit ) 1050 { 1051 (*maxState_p)++; 1052 for ( clazz = 0; clazz <= maxClassID; clazz++ ) 1053 { 1054 entry = FT_NEXT_BYTE( p ); 1055 *maxEntry_p = (FT_Byte)FT_MAX( *maxEntry_p, entry ); 1056 } 1057 } 1058 GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n", 1059 *maxState_p, *maxEntry_p )); 1060 1061 *length_p = (FT_UShort)( p - table ); 1062 1063 GXV_EXIT; 1064 } 1065 1066 1067 /* --------------------------- Entry Table ----------------------------- */ 1068 1069 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 gxvalid)1070 gxv_EntryTable_validate( FT_Bytes table, 1071 FT_UShort* length_p, 1072 FT_Byte maxEntry, 1073 FT_UShort stateArray, 1074 FT_UShort stateArray_length, 1075 FT_Byte maxClassID, 1076 FT_Bytes statetable_table, 1077 FT_Bytes statetable_limit, 1078 GXV_Validator gxvalid ) 1079 { 1080 FT_Bytes p = table; 1081 FT_Bytes limit = table + *length_p; 1082 FT_Byte entry; 1083 FT_Byte state; 1084 FT_Int entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( statetable ); 1085 1086 GXV_XStateTable_GlyphOffsetDesc glyphOffset; 1087 1088 1089 GXV_NAME_ENTER( "EntryTable" ); 1090 1091 GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize )); 1092 1093 if ( ( maxEntry + 1 ) * entrySize > *length_p ) 1094 { 1095 GXV_SET_ERR_IF_PARANOID( FT_INVALID_TOO_SHORT ); 1096 1097 /* ftxvalidator and FontValidator both warn and continue */ 1098 maxEntry = (FT_Byte)( *length_p / entrySize - 1 ); 1099 GXV_TRACE(( "too large maxEntry, shrinking to %d fit EntryTable length\n", 1100 maxEntry )); 1101 } 1102 1103 for ( entry = 0; entry <= maxEntry; entry++ ) 1104 { 1105 FT_UShort newState; 1106 FT_UShort flags; 1107 1108 1109 GXV_LIMIT_CHECK( 2 + 2 ); 1110 newState = FT_NEXT_USHORT( p ); 1111 flags = FT_NEXT_USHORT( p ); 1112 1113 1114 if ( newState < stateArray || 1115 stateArray + stateArray_length < newState ) 1116 { 1117 GXV_TRACE(( " newState offset 0x%04x is out of stateArray\n", 1118 newState )); 1119 GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); 1120 continue; 1121 } 1122 1123 if ( 0 != ( ( newState - stateArray ) % ( 1 + maxClassID ) ) ) 1124 { 1125 GXV_TRACE(( " newState offset 0x%04x is not aligned to %d-classes\n", 1126 newState, 1 + maxClassID )); 1127 GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); 1128 continue; 1129 } 1130 1131 state = (FT_Byte)( ( newState - stateArray ) / ( 1 + maxClassID ) ); 1132 1133 switch ( GXV_GLYPHOFFSET_FMT( statetable ) ) 1134 { 1135 case GXV_GLYPHOFFSET_NONE: 1136 glyphOffset.uc = 0; /* make compiler happy */ 1137 break; 1138 1139 case GXV_GLYPHOFFSET_UCHAR: 1140 glyphOffset.uc = FT_NEXT_BYTE( p ); 1141 break; 1142 1143 case GXV_GLYPHOFFSET_CHAR: 1144 glyphOffset.c = FT_NEXT_CHAR( p ); 1145 break; 1146 1147 case GXV_GLYPHOFFSET_USHORT: 1148 glyphOffset.u = FT_NEXT_USHORT( p ); 1149 break; 1150 1151 case GXV_GLYPHOFFSET_SHORT: 1152 glyphOffset.s = FT_NEXT_SHORT( p ); 1153 break; 1154 1155 case GXV_GLYPHOFFSET_ULONG: 1156 glyphOffset.ul = FT_NEXT_ULONG( p ); 1157 break; 1158 1159 case GXV_GLYPHOFFSET_LONG: 1160 glyphOffset.l = FT_NEXT_LONG( p ); 1161 break; 1162 } 1163 1164 if ( gxvalid->statetable.entry_validate_func ) 1165 gxvalid->statetable.entry_validate_func( state, 1166 flags, 1167 &glyphOffset, 1168 statetable_table, 1169 statetable_limit, 1170 gxvalid ); 1171 } 1172 1173 *length_p = (FT_UShort)( p - table ); 1174 1175 GXV_EXIT; 1176 } 1177 1178 1179 /* =========================== State Table ============================= */ 1180 1181 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 gxvalid)1182 gxv_StateTable_subtable_setup( FT_UShort table_size, 1183 FT_UShort classTable, 1184 FT_UShort stateArray, 1185 FT_UShort entryTable, 1186 FT_UShort* classTable_length_p, 1187 FT_UShort* stateArray_length_p, 1188 FT_UShort* entryTable_length_p, 1189 GXV_Validator gxvalid ) 1190 { 1191 FT_UShort o[3]; 1192 FT_UShort* l[3]; 1193 FT_UShort buff[4]; 1194 1195 1196 o[0] = classTable; 1197 o[1] = stateArray; 1198 o[2] = entryTable; 1199 l[0] = classTable_length_p; 1200 l[1] = stateArray_length_p; 1201 l[2] = entryTable_length_p; 1202 1203 gxv_set_length_by_ushort_offset( o, l, buff, 3, table_size, gxvalid ); 1204 } 1205 1206 1207 FT_LOCAL_DEF( void ) gxv_StateTable_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)1208 gxv_StateTable_validate( FT_Bytes table, 1209 FT_Bytes limit, 1210 GXV_Validator gxvalid ) 1211 { 1212 FT_UShort stateSize; 1213 FT_UShort classTable; /* offset to Class(Sub)Table */ 1214 FT_UShort stateArray; /* offset to StateArray */ 1215 FT_UShort entryTable; /* offset to EntryTable */ 1216 1217 FT_UShort classTable_length; 1218 FT_UShort stateArray_length; 1219 FT_UShort entryTable_length; 1220 FT_Byte maxClassID; 1221 FT_Byte maxState; 1222 FT_Byte maxEntry; 1223 1224 GXV_StateTable_Subtable_Setup_Func setup_func; 1225 1226 FT_Bytes p = table; 1227 1228 1229 GXV_NAME_ENTER( "StateTable" ); 1230 1231 GXV_TRACE(( "StateTable header\n" )); 1232 1233 GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 ); 1234 stateSize = FT_NEXT_USHORT( p ); 1235 classTable = FT_NEXT_USHORT( p ); 1236 stateArray = FT_NEXT_USHORT( p ); 1237 entryTable = FT_NEXT_USHORT( p ); 1238 1239 GXV_TRACE(( "stateSize=0x%04x\n", stateSize )); 1240 GXV_TRACE(( "offset to classTable=0x%04x\n", classTable )); 1241 GXV_TRACE(( "offset to stateArray=0x%04x\n", stateArray )); 1242 GXV_TRACE(( "offset to entryTable=0x%04x\n", entryTable )); 1243 1244 if ( stateSize > 0xFF ) 1245 FT_INVALID_DATA; 1246 1247 if ( gxvalid->statetable.optdata_load_func ) 1248 gxvalid->statetable.optdata_load_func( p, limit, gxvalid ); 1249 1250 if ( gxvalid->statetable.subtable_setup_func ) 1251 setup_func = gxvalid->statetable.subtable_setup_func; 1252 else 1253 setup_func = gxv_StateTable_subtable_setup; 1254 1255 setup_func( (FT_UShort)( limit - table ), 1256 classTable, 1257 stateArray, 1258 entryTable, 1259 &classTable_length, 1260 &stateArray_length, 1261 &entryTable_length, 1262 gxvalid ); 1263 1264 GXV_TRACE(( "StateTable Subtables\n" )); 1265 1266 if ( classTable != 0 ) 1267 gxv_ClassTable_validate( table + classTable, 1268 &classTable_length, 1269 stateSize, 1270 &maxClassID, 1271 gxvalid ); 1272 else 1273 maxClassID = (FT_Byte)( stateSize - 1 ); 1274 1275 if ( stateArray != 0 ) 1276 gxv_StateArray_validate( table + stateArray, 1277 &stateArray_length, 1278 maxClassID, 1279 stateSize, 1280 &maxState, 1281 &maxEntry, 1282 gxvalid ); 1283 else 1284 { 1285 #if 0 1286 maxState = 1; /* 0:start of text, 1:start of line are predefined */ 1287 #endif 1288 maxEntry = 0; 1289 } 1290 1291 if ( maxEntry > 0 && entryTable == 0 ) 1292 FT_INVALID_OFFSET; 1293 1294 if ( entryTable != 0 ) 1295 gxv_EntryTable_validate( table + entryTable, 1296 &entryTable_length, 1297 maxEntry, 1298 stateArray, 1299 stateArray_length, 1300 maxClassID, 1301 table, 1302 limit, 1303 gxvalid ); 1304 1305 GXV_EXIT; 1306 } 1307 1308 1309 /* ================= eXtended State Table (for morx) =================== */ 1310 1311 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 gxvalid)1312 gxv_XStateTable_subtable_setup( FT_ULong table_size, 1313 FT_ULong classTable, 1314 FT_ULong stateArray, 1315 FT_ULong entryTable, 1316 FT_ULong* classTable_length_p, 1317 FT_ULong* stateArray_length_p, 1318 FT_ULong* entryTable_length_p, 1319 GXV_Validator gxvalid ) 1320 { 1321 FT_ULong o[3]; 1322 FT_ULong* l[3]; 1323 FT_ULong buff[4]; 1324 1325 1326 o[0] = classTable; 1327 o[1] = stateArray; 1328 o[2] = entryTable; 1329 l[0] = classTable_length_p; 1330 l[1] = stateArray_length_p; 1331 l[2] = entryTable_length_p; 1332 1333 gxv_set_length_by_ulong_offset( o, l, buff, 3, table_size, gxvalid ); 1334 } 1335 1336 1337 static void gxv_XClassTable_lookupval_validate(FT_UShort glyph,GXV_LookupValueCPtr value_p,GXV_Validator gxvalid)1338 gxv_XClassTable_lookupval_validate( FT_UShort glyph, 1339 GXV_LookupValueCPtr value_p, 1340 GXV_Validator gxvalid ) 1341 { 1342 FT_UNUSED( glyph ); 1343 1344 if ( value_p->u >= gxvalid->xstatetable.nClasses ) 1345 FT_INVALID_DATA; 1346 if ( value_p->u > gxvalid->xstatetable.maxClassID ) 1347 gxvalid->xstatetable.maxClassID = value_p->u; 1348 } 1349 1350 1351 /* 1352 +===============+ --------+ 1353 | lookup header | | 1354 +===============+ | 1355 | BinSrchHeader | | 1356 +===============+ | 1357 | lastGlyph[0] | | 1358 +---------------+ | 1359 | firstGlyph[0] | | head of lookup table 1360 +---------------+ | + 1361 | offset[0] | -> | offset [byte] 1362 +===============+ | + 1363 | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] 1364 +---------------+ | 1365 | firstGlyph[1] | | 1366 +---------------+ | 1367 | offset[1] | | 1368 +===============+ | 1369 | 1370 .... | 1371 | 1372 16bit value array | 1373 +===============+ | 1374 | value | <-------+ 1375 .... 1376 */ 1377 static GXV_LookupValueDesc gxv_XClassTable_lookupfmt4_transit(FT_UShort relative_gindex,GXV_LookupValueCPtr base_value_p,FT_Bytes lookuptbl_limit,GXV_Validator gxvalid)1378 gxv_XClassTable_lookupfmt4_transit( FT_UShort relative_gindex, 1379 GXV_LookupValueCPtr base_value_p, 1380 FT_Bytes lookuptbl_limit, 1381 GXV_Validator gxvalid ) 1382 { 1383 FT_Bytes p; 1384 FT_Bytes limit; 1385 FT_UShort offset; 1386 GXV_LookupValueDesc value; 1387 1388 /* XXX: check range? */ 1389 offset = (FT_UShort)( base_value_p->u + 1390 relative_gindex * sizeof ( FT_UShort ) ); 1391 1392 p = gxvalid->lookuptbl_head + offset; 1393 limit = lookuptbl_limit; 1394 1395 GXV_LIMIT_CHECK ( 2 ); 1396 value.u = FT_NEXT_USHORT( p ); 1397 1398 return value; 1399 } 1400 1401 1402 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 gxvalid)1403 gxv_XStateArray_validate( FT_Bytes table, 1404 FT_ULong* length_p, 1405 FT_UShort maxClassID, 1406 FT_ULong stateSize, 1407 FT_UShort* maxState_p, 1408 FT_UShort* maxEntry_p, 1409 GXV_Validator gxvalid ) 1410 { 1411 FT_Bytes p = table; 1412 FT_Bytes limit = table + *length_p; 1413 FT_UShort clazz; 1414 FT_UShort entry; 1415 1416 FT_UNUSED( stateSize ); /* for the non-debugging case */ 1417 1418 1419 GXV_NAME_ENTER( "XStateArray" ); 1420 1421 GXV_TRACE(( "parse % 3d bytes by stateSize=% 3d maxClassID=% 3d\n", 1422 (int)(*length_p), stateSize, (int)(maxClassID) )); 1423 1424 /* 1425 * 2 states are predefined and must be described: 1426 * state 0 (start of text), 1 (start of line) 1427 */ 1428 GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 * 2 ); 1429 1430 *maxState_p = 0; 1431 *maxEntry_p = 0; 1432 1433 /* read if enough to read another state */ 1434 while ( p + ( ( 1 + maxClassID ) * 2 ) <= limit ) 1435 { 1436 (*maxState_p)++; 1437 for ( clazz = 0; clazz <= maxClassID; clazz++ ) 1438 { 1439 entry = FT_NEXT_USHORT( p ); 1440 *maxEntry_p = (FT_UShort)FT_MAX( *maxEntry_p, entry ); 1441 } 1442 } 1443 GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n", 1444 *maxState_p, *maxEntry_p )); 1445 1446 *length_p = (FT_ULong)( p - table ); 1447 1448 GXV_EXIT; 1449 } 1450 1451 1452 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 gxvalid)1453 gxv_XEntryTable_validate( FT_Bytes table, 1454 FT_ULong* length_p, 1455 FT_UShort maxEntry, 1456 FT_ULong stateArray_length, 1457 FT_UShort maxClassID, 1458 FT_Bytes xstatetable_table, 1459 FT_Bytes xstatetable_limit, 1460 GXV_Validator gxvalid ) 1461 { 1462 FT_Bytes p = table; 1463 FT_Bytes limit = table + *length_p; 1464 FT_UShort entry; 1465 FT_UShort state; 1466 FT_Int entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( xstatetable ); 1467 1468 1469 GXV_NAME_ENTER( "XEntryTable" ); 1470 GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize )); 1471 1472 if ( ( p + ( maxEntry + 1 ) * entrySize ) > limit ) 1473 FT_INVALID_TOO_SHORT; 1474 1475 for (entry = 0; entry <= maxEntry; entry++ ) 1476 { 1477 FT_UShort newState_idx; 1478 FT_UShort flags; 1479 GXV_XStateTable_GlyphOffsetDesc glyphOffset; 1480 1481 1482 GXV_LIMIT_CHECK( 2 + 2 ); 1483 newState_idx = FT_NEXT_USHORT( p ); 1484 flags = FT_NEXT_USHORT( p ); 1485 1486 if ( stateArray_length < (FT_ULong)( newState_idx * 2 ) ) 1487 { 1488 GXV_TRACE(( " newState index 0x%04x points out of stateArray\n", 1489 newState_idx )); 1490 GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); 1491 } 1492 1493 state = (FT_UShort)( newState_idx / ( 1 + maxClassID ) ); 1494 if ( 0 != ( newState_idx % ( 1 + maxClassID ) ) ) 1495 { 1496 FT_TRACE4(( "-> new state = %d (supposed)\n" 1497 "but newState index 0x%04x is not aligned to %d-classes\n", 1498 state, newState_idx, 1 + maxClassID )); 1499 GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); 1500 } 1501 1502 switch ( GXV_GLYPHOFFSET_FMT( xstatetable ) ) 1503 { 1504 case GXV_GLYPHOFFSET_NONE: 1505 glyphOffset.uc = 0; /* make compiler happy */ 1506 break; 1507 1508 case GXV_GLYPHOFFSET_UCHAR: 1509 glyphOffset.uc = FT_NEXT_BYTE( p ); 1510 break; 1511 1512 case GXV_GLYPHOFFSET_CHAR: 1513 glyphOffset.c = FT_NEXT_CHAR( p ); 1514 break; 1515 1516 case GXV_GLYPHOFFSET_USHORT: 1517 glyphOffset.u = FT_NEXT_USHORT( p ); 1518 break; 1519 1520 case GXV_GLYPHOFFSET_SHORT: 1521 glyphOffset.s = FT_NEXT_SHORT( p ); 1522 break; 1523 1524 case GXV_GLYPHOFFSET_ULONG: 1525 glyphOffset.ul = FT_NEXT_ULONG( p ); 1526 break; 1527 1528 case GXV_GLYPHOFFSET_LONG: 1529 glyphOffset.l = FT_NEXT_LONG( p ); 1530 break; 1531 1532 default: 1533 GXV_SET_ERR_IF_PARANOID( FT_INVALID_FORMAT ); 1534 goto Exit; 1535 } 1536 1537 if ( gxvalid->xstatetable.entry_validate_func ) 1538 gxvalid->xstatetable.entry_validate_func( state, 1539 flags, 1540 &glyphOffset, 1541 xstatetable_table, 1542 xstatetable_limit, 1543 gxvalid ); 1544 } 1545 1546 Exit: 1547 *length_p = (FT_ULong)( p - table ); 1548 1549 GXV_EXIT; 1550 } 1551 1552 1553 FT_LOCAL_DEF( void ) gxv_XStateTable_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)1554 gxv_XStateTable_validate( FT_Bytes table, 1555 FT_Bytes limit, 1556 GXV_Validator gxvalid ) 1557 { 1558 /* StateHeader members */ 1559 FT_ULong classTable; /* offset to Class(Sub)Table */ 1560 FT_ULong stateArray; /* offset to StateArray */ 1561 FT_ULong entryTable; /* offset to EntryTable */ 1562 1563 FT_ULong classTable_length; 1564 FT_ULong stateArray_length; 1565 FT_ULong entryTable_length; 1566 FT_UShort maxState; 1567 FT_UShort maxEntry; 1568 1569 GXV_XStateTable_Subtable_Setup_Func setup_func; 1570 1571 FT_Bytes p = table; 1572 1573 1574 GXV_NAME_ENTER( "XStateTable" ); 1575 1576 GXV_TRACE(( "XStateTable header\n" )); 1577 1578 GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 ); 1579 gxvalid->xstatetable.nClasses = FT_NEXT_ULONG( p ); 1580 classTable = FT_NEXT_ULONG( p ); 1581 stateArray = FT_NEXT_ULONG( p ); 1582 entryTable = FT_NEXT_ULONG( p ); 1583 1584 GXV_TRACE(( "nClasses =0x%08x\n", gxvalid->xstatetable.nClasses )); 1585 GXV_TRACE(( "offset to classTable=0x%08x\n", classTable )); 1586 GXV_TRACE(( "offset to stateArray=0x%08x\n", stateArray )); 1587 GXV_TRACE(( "offset to entryTable=0x%08x\n", entryTable )); 1588 1589 if ( gxvalid->xstatetable.nClasses > 0xFFFFU ) 1590 FT_INVALID_DATA; 1591 1592 GXV_TRACE(( "StateTable Subtables\n" )); 1593 1594 if ( gxvalid->xstatetable.optdata_load_func ) 1595 gxvalid->xstatetable.optdata_load_func( p, limit, gxvalid ); 1596 1597 if ( gxvalid->xstatetable.subtable_setup_func ) 1598 setup_func = gxvalid->xstatetable.subtable_setup_func; 1599 else 1600 setup_func = gxv_XStateTable_subtable_setup; 1601 1602 setup_func( (FT_ULong)( limit - table ), 1603 classTable, 1604 stateArray, 1605 entryTable, 1606 &classTable_length, 1607 &stateArray_length, 1608 &entryTable_length, 1609 gxvalid ); 1610 1611 if ( classTable != 0 ) 1612 { 1613 gxvalid->xstatetable.maxClassID = 0; 1614 gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; 1615 gxvalid->lookupval_func = gxv_XClassTable_lookupval_validate; 1616 gxvalid->lookupfmt4_trans = gxv_XClassTable_lookupfmt4_transit; 1617 gxv_LookupTable_validate( table + classTable, 1618 table + classTable + classTable_length, 1619 gxvalid ); 1620 #if 0 1621 if ( gxvalid->subtable_length < classTable_length ) 1622 classTable_length = gxvalid->subtable_length; 1623 #endif 1624 } 1625 else 1626 { 1627 /* XXX: check range? */ 1628 gxvalid->xstatetable.maxClassID = 1629 (FT_UShort)( gxvalid->xstatetable.nClasses - 1 ); 1630 } 1631 1632 if ( stateArray != 0 ) 1633 gxv_XStateArray_validate( table + stateArray, 1634 &stateArray_length, 1635 gxvalid->xstatetable.maxClassID, 1636 gxvalid->xstatetable.nClasses, 1637 &maxState, 1638 &maxEntry, 1639 gxvalid ); 1640 else 1641 { 1642 #if 0 1643 maxState = 1; /* 0:start of text, 1:start of line are predefined */ 1644 #endif 1645 maxEntry = 0; 1646 } 1647 1648 if ( maxEntry > 0 && entryTable == 0 ) 1649 FT_INVALID_OFFSET; 1650 1651 if ( entryTable != 0 ) 1652 gxv_XEntryTable_validate( table + entryTable, 1653 &entryTable_length, 1654 maxEntry, 1655 stateArray_length, 1656 gxvalid->xstatetable.maxClassID, 1657 table, 1658 limit, 1659 gxvalid ); 1660 1661 GXV_EXIT; 1662 } 1663 1664 1665 /*************************************************************************/ 1666 /*************************************************************************/ 1667 /***** *****/ 1668 /***** Table overlapping *****/ 1669 /***** *****/ 1670 /*************************************************************************/ 1671 /*************************************************************************/ 1672 1673 static int gxv_compare_ranges(FT_Bytes table1_start,FT_ULong table1_length,FT_Bytes table2_start,FT_ULong table2_length)1674 gxv_compare_ranges( FT_Bytes table1_start, 1675 FT_ULong table1_length, 1676 FT_Bytes table2_start, 1677 FT_ULong table2_length ) 1678 { 1679 if ( table1_start == table2_start ) 1680 { 1681 if ( ( table1_length == 0 || table2_length == 0 ) ) 1682 goto Out; 1683 } 1684 else if ( table1_start < table2_start ) 1685 { 1686 if ( ( table1_start + table1_length ) <= table2_start ) 1687 goto Out; 1688 } 1689 else if ( table1_start > table2_start ) 1690 { 1691 if ( ( table1_start >= table2_start + table2_length ) ) 1692 goto Out; 1693 } 1694 return 1; 1695 1696 Out: 1697 return 0; 1698 } 1699 1700 1701 FT_LOCAL_DEF( void ) gxv_odtect_add_range(FT_Bytes start,FT_ULong length,const FT_String * name,GXV_odtect_Range odtect)1702 gxv_odtect_add_range( FT_Bytes start, 1703 FT_ULong length, 1704 const FT_String* name, 1705 GXV_odtect_Range odtect ) 1706 { 1707 odtect->range[odtect->nRanges].start = start; 1708 odtect->range[odtect->nRanges].length = length; 1709 odtect->range[odtect->nRanges].name = (FT_String*)name; 1710 odtect->nRanges++; 1711 } 1712 1713 1714 FT_LOCAL_DEF( void ) gxv_odtect_validate(GXV_odtect_Range odtect,GXV_Validator gxvalid)1715 gxv_odtect_validate( GXV_odtect_Range odtect, 1716 GXV_Validator gxvalid ) 1717 { 1718 FT_UInt i, j; 1719 1720 1721 GXV_NAME_ENTER( "check overlap among multi ranges" ); 1722 1723 for ( i = 0; i < odtect->nRanges; i++ ) 1724 for ( j = 0; j < i; j++ ) 1725 if ( 0 != gxv_compare_ranges( odtect->range[i].start, 1726 odtect->range[i].length, 1727 odtect->range[j].start, 1728 odtect->range[j].length ) ) 1729 { 1730 #ifdef FT_DEBUG_LEVEL_TRACE 1731 if ( odtect->range[i].name || odtect->range[j].name ) 1732 GXV_TRACE(( "found overlap between range %d and range %d\n", 1733 i, j )); 1734 else 1735 GXV_TRACE(( "found overlap between `%s' and `%s\'\n", 1736 odtect->range[i].name, 1737 odtect->range[j].name )); 1738 #endif 1739 FT_INVALID_OFFSET; 1740 } 1741 1742 GXV_EXIT; 1743 } 1744 1745 1746 /* END */ 1747