1/***************************************************************************/ 2/* */ 3/* gxvkern.c */ 4/* */ 5/* TrueTypeGX/AAT kern table validation (body). */ 6/* */ 7/* Copyright 2004-2018 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 "gxvalid.h" 29#include "gxvcommn.h" 30 31#include FT_SFNT_NAMES_H 32#include FT_SERVICE_GX_VALIDATE_H 33 34 35 /*************************************************************************/ 36 /* */ 37 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 38 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 39 /* messages during execution. */ 40 /* */ 41#undef FT_COMPONENT 42#define FT_COMPONENT trace_gxvkern 43 44 45 /*************************************************************************/ 46 /*************************************************************************/ 47 /***** *****/ 48 /***** Data and Types *****/ 49 /***** *****/ 50 /*************************************************************************/ 51 /*************************************************************************/ 52 53 typedef enum GXV_kern_Version_ 54 { 55 KERN_VERSION_CLASSIC = 0x0000, 56 KERN_VERSION_NEW = 0x0001 57 58 } GXV_kern_Version; 59 60 61 typedef enum GXV_kern_Dialect_ 62 { 63 KERN_DIALECT_UNKNOWN = 0, 64 KERN_DIALECT_MS = FT_VALIDATE_MS, 65 KERN_DIALECT_APPLE = FT_VALIDATE_APPLE, 66 KERN_DIALECT_ANY = FT_VALIDATE_CKERN 67 68 } GXV_kern_Dialect; 69 70 71 typedef struct GXV_kern_DataRec_ 72 { 73 GXV_kern_Version version; 74 void *subtable_data; 75 GXV_kern_Dialect dialect_request; 76 77 } GXV_kern_DataRec, *GXV_kern_Data; 78 79 80#define GXV_KERN_DATA( field ) GXV_TABLE_DATA( kern, field ) 81 82#define KERN_IS_CLASSIC( gxvalid ) \ 83 ( KERN_VERSION_CLASSIC == GXV_KERN_DATA( version ) ) 84#define KERN_IS_NEW( gxvalid ) \ 85 ( KERN_VERSION_NEW == GXV_KERN_DATA( version ) ) 86 87#define KERN_DIALECT( gxvalid ) \ 88 GXV_KERN_DATA( dialect_request ) 89#define KERN_ALLOWS_MS( gxvalid ) \ 90 ( KERN_DIALECT( gxvalid ) & KERN_DIALECT_MS ) 91#define KERN_ALLOWS_APPLE( gxvalid ) \ 92 ( KERN_DIALECT( gxvalid ) & KERN_DIALECT_APPLE ) 93 94#define GXV_KERN_HEADER_SIZE ( KERN_IS_NEW( gxvalid ) ? 8 : 4 ) 95#define GXV_KERN_SUBTABLE_HEADER_SIZE ( KERN_IS_NEW( gxvalid ) ? 8 : 6 ) 96 97 98 /*************************************************************************/ 99 /*************************************************************************/ 100 /***** *****/ 101 /***** SUBTABLE VALIDATORS *****/ 102 /***** *****/ 103 /*************************************************************************/ 104 /*************************************************************************/ 105 106 107 /* ============================= format 0 ============================== */ 108 109 static void 110 gxv_kern_subtable_fmt0_pairs_validate( FT_Bytes table, 111 FT_Bytes limit, 112 FT_UShort nPairs, 113 GXV_Validator gxvalid ) 114 { 115 FT_Bytes p = table; 116 FT_UShort i; 117 118 FT_UShort last_gid_left = 0; 119 FT_UShort last_gid_right = 0; 120 121 FT_UNUSED( limit ); 122 123 124 GXV_NAME_ENTER( "kern format 0 pairs" ); 125 126 for ( i = 0; i < nPairs; i++ ) 127 { 128 FT_UShort gid_left; 129 FT_UShort gid_right; 130#ifdef GXV_LOAD_UNUSED_VARS 131 FT_Short kernValue; 132#endif 133 134 135 /* left */ 136 gid_left = FT_NEXT_USHORT( p ); 137 gxv_glyphid_validate( gid_left, gxvalid ); 138 139 /* right */ 140 gid_right = FT_NEXT_USHORT( p ); 141 gxv_glyphid_validate( gid_right, gxvalid ); 142 143 /* Pairs of left and right GIDs must be unique and sorted. */ 144 GXV_TRACE(( "left gid = %u, right gid = %u\n", gid_left, gid_right )); 145 if ( gid_left == last_gid_left ) 146 { 147 if ( last_gid_right < gid_right ) 148 last_gid_right = gid_right; 149 else 150 FT_INVALID_DATA; 151 } 152 else if ( last_gid_left < gid_left ) 153 { 154 last_gid_left = gid_left; 155 last_gid_right = gid_right; 156 } 157 else 158 FT_INVALID_DATA; 159 160 /* skip the kern value */ 161#ifdef GXV_LOAD_UNUSED_VARS 162 kernValue = FT_NEXT_SHORT( p ); 163#else 164 p += 2; 165#endif 166 } 167 168 GXV_EXIT; 169 } 170 171 static void 172 gxv_kern_subtable_fmt0_validate( FT_Bytes table, 173 FT_Bytes limit, 174 GXV_Validator gxvalid ) 175 { 176 FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE; 177 178 FT_UShort nPairs; 179 FT_UShort unitSize; 180 181 182 GXV_NAME_ENTER( "kern subtable format 0" ); 183 184 unitSize = 2 + 2 + 2; 185 nPairs = 0; 186 187 /* nPairs, searchRange, entrySelector, rangeShift */ 188 GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 ); 189 gxv_BinSrchHeader_validate( p, limit, &unitSize, &nPairs, gxvalid ); 190 p += 2 + 2 + 2 + 2; 191 192 gxv_kern_subtable_fmt0_pairs_validate( p, limit, nPairs, gxvalid ); 193 194 GXV_EXIT; 195 } 196 197 198 /* ============================= format 1 ============================== */ 199 200 201 typedef struct GXV_kern_fmt1_StateOptRec_ 202 { 203 FT_UShort valueTable; 204 FT_UShort valueTable_length; 205 206 } GXV_kern_fmt1_StateOptRec, *GXV_kern_fmt1_StateOptRecData; 207 208 209 static void 210 gxv_kern_subtable_fmt1_valueTable_load( FT_Bytes table, 211 FT_Bytes limit, 212 GXV_Validator gxvalid ) 213 { 214 FT_Bytes p = table; 215 GXV_kern_fmt1_StateOptRecData optdata = 216 (GXV_kern_fmt1_StateOptRecData)gxvalid->statetable.optdata; 217 218 219 GXV_LIMIT_CHECK( 2 ); 220 optdata->valueTable = FT_NEXT_USHORT( p ); 221 } 222 223 224 /* 225 * passed tables_size covers whole StateTable, including kern fmt1 header 226 */ 227 static void 228 gxv_kern_subtable_fmt1_subtable_setup( FT_UShort table_size, 229 FT_UShort classTable, 230 FT_UShort stateArray, 231 FT_UShort entryTable, 232 FT_UShort* classTable_length_p, 233 FT_UShort* stateArray_length_p, 234 FT_UShort* entryTable_length_p, 235 GXV_Validator gxvalid ) 236 { 237 FT_UShort o[4]; 238 FT_UShort *l[4]; 239 FT_UShort buff[5]; 240 241 GXV_kern_fmt1_StateOptRecData optdata = 242 (GXV_kern_fmt1_StateOptRecData)gxvalid->statetable.optdata; 243 244 245 o[0] = classTable; 246 o[1] = stateArray; 247 o[2] = entryTable; 248 o[3] = optdata->valueTable; 249 l[0] = classTable_length_p; 250 l[1] = stateArray_length_p; 251 l[2] = entryTable_length_p; 252 l[3] = &(optdata->valueTable_length); 253 254 gxv_set_length_by_ushort_offset( o, l, buff, 4, table_size, gxvalid ); 255 } 256 257 258 /* 259 * passed table & limit are of whole StateTable, not including subtables 260 */ 261 static void 262 gxv_kern_subtable_fmt1_entry_validate( 263 FT_Byte state, 264 FT_UShort flags, 265 GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, 266 FT_Bytes table, 267 FT_Bytes limit, 268 GXV_Validator gxvalid ) 269 { 270#ifdef GXV_LOAD_UNUSED_VARS 271 FT_UShort push; 272 FT_UShort dontAdvance; 273#endif 274 FT_UShort valueOffset; 275#ifdef GXV_LOAD_UNUSED_VARS 276 FT_UShort kernAction; 277 FT_UShort kernValue; 278#endif 279 280 FT_UNUSED( state ); 281 FT_UNUSED( glyphOffset_p ); 282 283 284#ifdef GXV_LOAD_UNUSED_VARS 285 push = (FT_UShort)( ( flags >> 15 ) & 1 ); 286 dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); 287#endif 288 valueOffset = (FT_UShort)( flags & 0x3FFF ); 289 290 { 291 GXV_kern_fmt1_StateOptRecData vt_rec = 292 (GXV_kern_fmt1_StateOptRecData)gxvalid->statetable.optdata; 293 FT_Bytes p; 294 295 296 if ( valueOffset < vt_rec->valueTable ) 297 FT_INVALID_OFFSET; 298 299 p = table + valueOffset; 300 limit = table + vt_rec->valueTable + vt_rec->valueTable_length; 301 302 GXV_LIMIT_CHECK( 2 + 2 ); 303#ifdef GXV_LOAD_UNUSED_VARS 304 kernAction = FT_NEXT_USHORT( p ); 305 kernValue = FT_NEXT_USHORT( p ); 306#endif 307 } 308 } 309 310 311 static void 312 gxv_kern_subtable_fmt1_validate( FT_Bytes table, 313 FT_Bytes limit, 314 GXV_Validator gxvalid ) 315 { 316 FT_Bytes p = table; 317 GXV_kern_fmt1_StateOptRec vt_rec; 318 319 320 GXV_NAME_ENTER( "kern subtable format 1" ); 321 322 gxvalid->statetable.optdata = 323 &vt_rec; 324 gxvalid->statetable.optdata_load_func = 325 gxv_kern_subtable_fmt1_valueTable_load; 326 gxvalid->statetable.subtable_setup_func = 327 gxv_kern_subtable_fmt1_subtable_setup; 328 gxvalid->statetable.entry_glyphoffset_fmt = 329 GXV_GLYPHOFFSET_NONE; 330 gxvalid->statetable.entry_validate_func = 331 gxv_kern_subtable_fmt1_entry_validate; 332 333 gxv_StateTable_validate( p, limit, gxvalid ); 334 335 GXV_EXIT; 336 } 337 338 339 /* ================ Data for Class-Based Subtables 2, 3 ================ */ 340 341 typedef enum GXV_kern_ClassSpec_ 342 { 343 GXV_KERN_CLS_L = 0, 344 GXV_KERN_CLS_R 345 346 } GXV_kern_ClassSpec; 347 348 349 /* ============================= format 2 ============================== */ 350 351 /* ---------------------- format 2 specific data ----------------------- */ 352 353 typedef struct GXV_kern_subtable_fmt2_DataRec_ 354 { 355 FT_UShort rowWidth; 356 FT_UShort array; 357 FT_UShort offset_min[2]; 358 FT_UShort offset_max[2]; 359 const FT_String* class_tag[2]; 360 GXV_odtect_Range odtect; 361 362 } GXV_kern_subtable_fmt2_DataRec, *GXV_kern_subtable_fmt2_Data; 363 364 365#define GXV_KERN_FMT2_DATA( field ) \ 366 ( ( (GXV_kern_subtable_fmt2_DataRec *) \ 367 ( GXV_KERN_DATA( subtable_data ) ) )->field ) 368 369 370 /* -------------------------- utility functions ----------------------- */ 371 372 static void 373 gxv_kern_subtable_fmt2_clstbl_validate( FT_Bytes table, 374 FT_Bytes limit, 375 GXV_kern_ClassSpec spec, 376 GXV_Validator gxvalid ) 377 { 378 const FT_String* tag = GXV_KERN_FMT2_DATA( class_tag[spec] ); 379 GXV_odtect_Range odtect = GXV_KERN_FMT2_DATA( odtect ); 380 381 FT_Bytes p = table; 382 FT_UShort firstGlyph; 383 FT_UShort nGlyphs; 384 385 386 GXV_NAME_ENTER( "kern format 2 classTable" ); 387 388 GXV_LIMIT_CHECK( 2 + 2 ); 389 firstGlyph = FT_NEXT_USHORT( p ); 390 nGlyphs = FT_NEXT_USHORT( p ); 391 GXV_TRACE(( " %s firstGlyph=%d, nGlyphs=%d\n", 392 tag, firstGlyph, nGlyphs )); 393 394 gxv_glyphid_validate( firstGlyph, gxvalid ); 395 gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs - 1 ), gxvalid ); 396 397 gxv_array_getlimits_ushort( p, p + ( 2 * nGlyphs ), 398 &( GXV_KERN_FMT2_DATA( offset_min[spec] ) ), 399 &( GXV_KERN_FMT2_DATA( offset_max[spec] ) ), 400 gxvalid ); 401 402 gxv_odtect_add_range( table, 2 * nGlyphs, tag, odtect ); 403 404 GXV_EXIT; 405 } 406 407 408 static void 409 gxv_kern_subtable_fmt2_validate( FT_Bytes table, 410 FT_Bytes limit, 411 GXV_Validator gxvalid ) 412 { 413 GXV_ODTECT( 3, odtect ); 414 GXV_kern_subtable_fmt2_DataRec fmt2_rec = 415 { 0, 0, { 0, 0 }, { 0, 0 }, { "leftClass", "rightClass" }, NULL }; 416 417 FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE; 418 FT_UShort leftOffsetTable; 419 FT_UShort rightOffsetTable; 420 421 422 GXV_NAME_ENTER( "kern subtable format 2" ); 423 424 GXV_ODTECT_INIT( odtect ); 425 fmt2_rec.odtect = odtect; 426 GXV_KERN_DATA( subtable_data ) = &fmt2_rec; 427 428 GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 ); 429 GXV_KERN_FMT2_DATA( rowWidth ) = FT_NEXT_USHORT( p ); 430 leftOffsetTable = FT_NEXT_USHORT( p ); 431 rightOffsetTable = FT_NEXT_USHORT( p ); 432 GXV_KERN_FMT2_DATA( array ) = FT_NEXT_USHORT( p ); 433 434 GXV_TRACE(( "rowWidth = %d\n", GXV_KERN_FMT2_DATA( rowWidth ) )); 435 436 437 GXV_LIMIT_CHECK( leftOffsetTable ); 438 GXV_LIMIT_CHECK( rightOffsetTable ); 439 GXV_LIMIT_CHECK( GXV_KERN_FMT2_DATA( array ) ); 440 441 gxv_kern_subtable_fmt2_clstbl_validate( table + leftOffsetTable, limit, 442 GXV_KERN_CLS_L, gxvalid ); 443 444 gxv_kern_subtable_fmt2_clstbl_validate( table + rightOffsetTable, limit, 445 GXV_KERN_CLS_R, gxvalid ); 446 447 if ( GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_L] ) + 448 GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_R] ) 449 < GXV_KERN_FMT2_DATA( array ) ) 450 FT_INVALID_OFFSET; 451 452 gxv_odtect_add_range( table + GXV_KERN_FMT2_DATA( array ), 453 GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_L] ) 454 + GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_R] ) 455 - GXV_KERN_FMT2_DATA( array ), 456 "array", odtect ); 457 458 gxv_odtect_validate( odtect, gxvalid ); 459 460 GXV_EXIT; 461 } 462 463 464 /* ============================= format 3 ============================== */ 465 466 static void 467 gxv_kern_subtable_fmt3_validate( FT_Bytes table, 468 FT_Bytes limit, 469 GXV_Validator gxvalid ) 470 { 471 FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE; 472 FT_UShort glyphCount; 473 FT_Byte kernValueCount; 474 FT_Byte leftClassCount; 475 FT_Byte rightClassCount; 476 FT_Byte flags; 477 478 479 GXV_NAME_ENTER( "kern subtable format 3" ); 480 481 GXV_LIMIT_CHECK( 2 + 1 + 1 + 1 + 1 ); 482 glyphCount = FT_NEXT_USHORT( p ); 483 kernValueCount = FT_NEXT_BYTE( p ); 484 leftClassCount = FT_NEXT_BYTE( p ); 485 rightClassCount = FT_NEXT_BYTE( p ); 486 flags = FT_NEXT_BYTE( p ); 487 488 if ( gxvalid->face->num_glyphs != glyphCount ) 489 { 490 GXV_TRACE(( "maxGID=%d, but glyphCount=%d\n", 491 gxvalid->face->num_glyphs, glyphCount )); 492 GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); 493 } 494 495 if ( flags != 0 ) 496 GXV_TRACE(( "kern subtable fmt3 has nonzero value" 497 " (%d) in unused flag\n", flags )); 498 /* 499 * just skip kernValue[kernValueCount] 500 */ 501 GXV_LIMIT_CHECK( 2 * kernValueCount ); 502 p += 2 * kernValueCount; 503 504 /* 505 * check leftClass[gid] < leftClassCount 506 */ 507 { 508 FT_Byte min, max; 509 510 511 GXV_LIMIT_CHECK( glyphCount ); 512 gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, gxvalid ); 513 p += gxvalid->subtable_length; 514 515 if ( leftClassCount < max ) 516 FT_INVALID_DATA; 517 } 518 519 /* 520 * check rightClass[gid] < rightClassCount 521 */ 522 { 523 FT_Byte min, max; 524 525 526 GXV_LIMIT_CHECK( glyphCount ); 527 gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, gxvalid ); 528 p += gxvalid->subtable_length; 529 530 if ( rightClassCount < max ) 531 FT_INVALID_DATA; 532 } 533 534 /* 535 * check kernIndex[i, j] < kernValueCount 536 */ 537 { 538 FT_UShort i, j; 539 540 541 for ( i = 0; i < leftClassCount; i++ ) 542 { 543 for ( j = 0; j < rightClassCount; j++ ) 544 { 545 GXV_LIMIT_CHECK( 1 ); 546 if ( kernValueCount < FT_NEXT_BYTE( p ) ) 547 FT_INVALID_OFFSET; 548 } 549 } 550 } 551 552 gxvalid->subtable_length = (FT_ULong)( p - table ); 553 554 GXV_EXIT; 555 } 556 557 558 static FT_Bool 559 gxv_kern_coverage_new_apple_validate( FT_UShort coverage, 560 FT_UShort* format, 561 GXV_Validator gxvalid ) 562 { 563 /* new Apple-dialect */ 564#ifdef GXV_LOAD_TRACE_VARS 565 FT_Bool kernVertical; 566 FT_Bool kernCrossStream; 567 FT_Bool kernVariation; 568#endif 569 570 FT_UNUSED( gxvalid ); 571 572 573 /* reserved bits = 0 */ 574 if ( coverage & 0x1FFC ) 575 return FALSE; 576 577#ifdef GXV_LOAD_TRACE_VARS 578 kernVertical = FT_BOOL( ( coverage >> 15 ) & 1 ); 579 kernCrossStream = FT_BOOL( ( coverage >> 14 ) & 1 ); 580 kernVariation = FT_BOOL( ( coverage >> 13 ) & 1 ); 581#endif 582 583 *format = (FT_UShort)( coverage & 0x0003 ); 584 585 GXV_TRACE(( "new Apple-dialect: " 586 "horizontal=%d, cross-stream=%d, variation=%d, format=%d\n", 587 !kernVertical, kernCrossStream, kernVariation, *format )); 588 589 GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" )); 590 591 return TRUE; 592 } 593 594 595 static FT_Bool 596 gxv_kern_coverage_classic_apple_validate( FT_UShort coverage, 597 FT_UShort* format, 598 GXV_Validator gxvalid ) 599 { 600 /* classic Apple-dialect */ 601#ifdef GXV_LOAD_TRACE_VARS 602 FT_Bool horizontal; 603 FT_Bool cross_stream; 604#endif 605 606 607 /* check expected flags, but don't check if MS-dialect is impossible */ 608 if ( !( coverage & 0xFD00 ) && KERN_ALLOWS_MS( gxvalid ) ) 609 return FALSE; 610 611 /* reserved bits = 0 */ 612 if ( coverage & 0x02FC ) 613 return FALSE; 614 615#ifdef GXV_LOAD_TRACE_VARS 616 horizontal = FT_BOOL( ( coverage >> 15 ) & 1 ); 617 cross_stream = FT_BOOL( ( coverage >> 13 ) & 1 ); 618#endif 619 620 *format = (FT_UShort)( coverage & 0x0003 ); 621 622 GXV_TRACE(( "classic Apple-dialect: " 623 "horizontal=%d, cross-stream=%d, format=%d\n", 624 horizontal, cross_stream, *format )); 625 626 /* format 1 requires GX State Machine, too new for classic */ 627 if ( *format == 1 ) 628 return FALSE; 629 630 GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" )); 631 632 return TRUE; 633 } 634 635 636 static FT_Bool 637 gxv_kern_coverage_classic_microsoft_validate( FT_UShort coverage, 638 FT_UShort* format, 639 GXV_Validator gxvalid ) 640 { 641 /* classic Microsoft-dialect */ 642#ifdef GXV_LOAD_TRACE_VARS 643 FT_Bool horizontal; 644 FT_Bool minimum; 645 FT_Bool cross_stream; 646 FT_Bool override; 647#endif 648 649 FT_UNUSED( gxvalid ); 650 651 652 /* reserved bits = 0 */ 653 if ( coverage & 0xFDF0 ) 654 return FALSE; 655 656#ifdef GXV_LOAD_TRACE_VARS 657 horizontal = FT_BOOL( coverage & 1 ); 658 minimum = FT_BOOL( ( coverage >> 1 ) & 1 ); 659 cross_stream = FT_BOOL( ( coverage >> 2 ) & 1 ); 660 override = FT_BOOL( ( coverage >> 3 ) & 1 ); 661#endif 662 663 *format = (FT_UShort)( ( coverage >> 8 ) & 0x0003 ); 664 665 GXV_TRACE(( "classic Microsoft-dialect: " 666 "horizontal=%d, minimum=%d, cross-stream=%d, " 667 "override=%d, format=%d\n", 668 horizontal, minimum, cross_stream, override, *format )); 669 670 if ( *format == 2 ) 671 GXV_TRACE(( 672 "kerning values in Microsoft format 2 subtable are ignored\n" )); 673 674 return TRUE; 675 } 676 677 678 /*************************************************************************/ 679 /*************************************************************************/ 680 /***** *****/ 681 /***** MAIN *****/ 682 /***** *****/ 683 /*************************************************************************/ 684 /*************************************************************************/ 685 686 static GXV_kern_Dialect 687 gxv_kern_coverage_validate( FT_UShort coverage, 688 FT_UShort* format, 689 GXV_Validator gxvalid ) 690 { 691 GXV_kern_Dialect result = KERN_DIALECT_UNKNOWN; 692 693 694 GXV_NAME_ENTER( "validating coverage" ); 695 696 GXV_TRACE(( "interpret coverage 0x%04x by Apple style\n", coverage )); 697 698 if ( KERN_IS_NEW( gxvalid ) ) 699 { 700 if ( gxv_kern_coverage_new_apple_validate( coverage, 701 format, 702 gxvalid ) ) 703 { 704 result = KERN_DIALECT_APPLE; 705 goto Exit; 706 } 707 } 708 709 if ( KERN_IS_CLASSIC( gxvalid ) && KERN_ALLOWS_APPLE( gxvalid ) ) 710 { 711 if ( gxv_kern_coverage_classic_apple_validate( coverage, 712 format, 713 gxvalid ) ) 714 { 715 result = KERN_DIALECT_APPLE; 716 goto Exit; 717 } 718 } 719 720 if ( KERN_IS_CLASSIC( gxvalid ) && KERN_ALLOWS_MS( gxvalid ) ) 721 { 722 if ( gxv_kern_coverage_classic_microsoft_validate( coverage, 723 format, 724 gxvalid ) ) 725 { 726 result = KERN_DIALECT_MS; 727 goto Exit; 728 } 729 } 730 731 GXV_TRACE(( "cannot interpret coverage, broken kern subtable\n" )); 732 733 Exit: 734 GXV_EXIT; 735 return result; 736 } 737 738 739 static void 740 gxv_kern_subtable_validate( FT_Bytes table, 741 FT_Bytes limit, 742 GXV_Validator gxvalid ) 743 { 744 FT_Bytes p = table; 745#ifdef GXV_LOAD_TRACE_VARS 746 FT_UShort version = 0; /* MS only: subtable version, unused */ 747#endif 748 FT_ULong length; /* MS: 16bit, Apple: 32bit*/ 749 FT_UShort coverage; 750#ifdef GXV_LOAD_TRACE_VARS 751 FT_UShort tupleIndex = 0; /* Apple only */ 752#endif 753 FT_UShort u16[2]; 754 FT_UShort format = 255; /* subtable format */ 755 756 757 GXV_NAME_ENTER( "kern subtable" ); 758 759 GXV_LIMIT_CHECK( 2 + 2 + 2 ); 760 u16[0] = FT_NEXT_USHORT( p ); /* Apple: length_hi MS: version */ 761 u16[1] = FT_NEXT_USHORT( p ); /* Apple: length_lo MS: length */ 762 coverage = FT_NEXT_USHORT( p ); 763 764 switch ( gxv_kern_coverage_validate( coverage, &format, gxvalid ) ) 765 { 766 case KERN_DIALECT_MS: 767#ifdef GXV_LOAD_TRACE_VARS 768 version = u16[0]; 769#endif 770 length = u16[1]; 771#ifdef GXV_LOAD_TRACE_VARS 772 tupleIndex = 0; 773#endif 774 GXV_TRACE(( "Subtable version = %d\n", version )); 775 GXV_TRACE(( "Subtable length = %d\n", length )); 776 break; 777 778 case KERN_DIALECT_APPLE: 779#ifdef GXV_LOAD_TRACE_VARS 780 version = 0; 781#endif 782 length = ( (FT_ULong)u16[0] << 16 ) + u16[1]; 783#ifdef GXV_LOAD_TRACE_VARS 784 tupleIndex = 0; 785#endif 786 GXV_TRACE(( "Subtable length = %d\n", length )); 787 788 if ( KERN_IS_NEW( gxvalid ) ) 789 { 790 GXV_LIMIT_CHECK( 2 ); 791#ifdef GXV_LOAD_TRACE_VARS 792 tupleIndex = FT_NEXT_USHORT( p ); 793#else 794 p += 2; 795#endif 796 GXV_TRACE(( "Subtable tupleIndex = %d\n", tupleIndex )); 797 } 798 break; 799 800 default: 801 length = u16[1]; 802 GXV_TRACE(( "cannot detect subtable dialect, " 803 "just skip %d byte\n", length )); 804 goto Exit; 805 } 806 807 /* formats 1, 2, 3 require the position of the start of this subtable */ 808 if ( format == 0 ) 809 gxv_kern_subtable_fmt0_validate( table, table + length, gxvalid ); 810 else if ( format == 1 ) 811 gxv_kern_subtable_fmt1_validate( table, table + length, gxvalid ); 812 else if ( format == 2 ) 813 gxv_kern_subtable_fmt2_validate( table, table + length, gxvalid ); 814 else if ( format == 3 ) 815 gxv_kern_subtable_fmt3_validate( table, table + length, gxvalid ); 816 else 817 FT_INVALID_DATA; 818 819 Exit: 820 gxvalid->subtable_length = length; 821 GXV_EXIT; 822 } 823 824 825 /*************************************************************************/ 826 /*************************************************************************/ 827 /***** *****/ 828 /***** kern TABLE *****/ 829 /***** *****/ 830 /*************************************************************************/ 831 /*************************************************************************/ 832 833 static void 834 gxv_kern_validate_generic( FT_Bytes table, 835 FT_Face face, 836 FT_Bool classic_only, 837 GXV_kern_Dialect dialect_request, 838 FT_Validator ftvalid ) 839 { 840 GXV_ValidatorRec gxvalidrec; 841 GXV_Validator gxvalid = &gxvalidrec; 842 843 GXV_kern_DataRec kernrec; 844 GXV_kern_Data kern = &kernrec; 845 846 FT_Bytes p = table; 847 FT_Bytes limit = 0; 848 849 FT_ULong nTables = 0; 850 FT_UInt i; 851 852 853 gxvalid->root = ftvalid; 854 gxvalid->table_data = kern; 855 gxvalid->face = face; 856 857 FT_TRACE3(( "validating `kern' table\n" )); 858 GXV_INIT; 859 KERN_DIALECT( gxvalid ) = dialect_request; 860 861 GXV_LIMIT_CHECK( 2 ); 862 GXV_KERN_DATA( version ) = (GXV_kern_Version)FT_NEXT_USHORT( p ); 863 GXV_TRACE(( "version 0x%04x (higher 16bit)\n", 864 GXV_KERN_DATA( version ) )); 865 866 if ( 0x0001 < GXV_KERN_DATA( version ) ) 867 FT_INVALID_FORMAT; 868 else if ( KERN_IS_CLASSIC( gxvalid ) ) 869 { 870 GXV_LIMIT_CHECK( 2 ); 871 nTables = FT_NEXT_USHORT( p ); 872 } 873 else if ( KERN_IS_NEW( gxvalid ) ) 874 { 875 if ( classic_only ) 876 FT_INVALID_FORMAT; 877 878 if ( 0x0000 != FT_NEXT_USHORT( p ) ) 879 FT_INVALID_FORMAT; 880 881 GXV_LIMIT_CHECK( 4 ); 882 nTables = FT_NEXT_ULONG( p ); 883 } 884 885 for ( i = 0; i < nTables; i++ ) 886 { 887 GXV_TRACE(( "validating subtable %d/%d\n", i, nTables )); 888 /* p should be 32bit-aligned? */ 889 gxv_kern_subtable_validate( p, 0, gxvalid ); 890 p += gxvalid->subtable_length; 891 } 892 893 FT_TRACE4(( "\n" )); 894 } 895 896 897 FT_LOCAL_DEF( void ) 898 gxv_kern_validate( FT_Bytes table, 899 FT_Face face, 900 FT_Validator ftvalid ) 901 { 902 gxv_kern_validate_generic( table, face, 0, KERN_DIALECT_ANY, ftvalid ); 903 } 904 905 906 FT_LOCAL_DEF( void ) 907 gxv_kern_validate_classic( FT_Bytes table, 908 FT_Face face, 909 FT_Int dialect_flags, 910 FT_Validator ftvalid ) 911 { 912 GXV_kern_Dialect dialect_request; 913 914 915 dialect_request = (GXV_kern_Dialect)dialect_flags; 916 gxv_kern_validate_generic( table, face, 1, dialect_request, ftvalid ); 917 } 918 919 920/* END */ 921