1 /***************************************************************************/ 2 /* */ 3 /* gxvkern.c */ 4 /* */ 5 /* TrueTypeGX/AAT kern table validation (body). */ 6 /* */ 7 /* Copyright 2004, 2005, 2006, 2007 */ 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 "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( valid ) \ 83 ( KERN_VERSION_CLASSIC == GXV_KERN_DATA( version ) ) 84 #define KERN_IS_NEW( valid ) \ 85 ( KERN_VERSION_NEW == GXV_KERN_DATA( version ) ) 86 87 #define KERN_DIALECT( valid ) \ 88 GXV_KERN_DATA( dialect_request ) 89 #define KERN_ALLOWS_MS( valid ) \ 90 ( KERN_DIALECT( valid ) & KERN_DIALECT_MS ) 91 #define KERN_ALLOWS_APPLE( valid ) \ 92 ( KERN_DIALECT( valid ) & KERN_DIALECT_APPLE ) 93 94 #define GXV_KERN_HEADER_SIZE ( KERN_IS_NEW( valid ) ? 8 : 4 ) 95 #define GXV_KERN_SUBTABLE_HEADER_SIZE ( KERN_IS_NEW( valid ) ? 8 : 6 ) 96 97 98 /*************************************************************************/ 99 /*************************************************************************/ 100 /***** *****/ 101 /***** SUBTABLE VALIDATORS *****/ 102 /***** *****/ 103 /*************************************************************************/ 104 /*************************************************************************/ 105 106 107 /* ============================= format 0 ============================== */ 108 109 static void gxv_kern_subtable_fmt0_pairs_validate(FT_Bytes table,FT_Bytes limit,FT_UShort nPairs,GXV_Validator valid)110 gxv_kern_subtable_fmt0_pairs_validate( FT_Bytes table, 111 FT_Bytes limit, 112 FT_UShort nPairs, 113 GXV_Validator valid ) 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, valid ); 138 139 /* right */ 140 gid_right = FT_NEXT_USHORT( p ); 141 gxv_glyphid_validate( gid_right, valid ); 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 gxv_kern_subtable_fmt0_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator valid)172 gxv_kern_subtable_fmt0_validate( FT_Bytes table, 173 FT_Bytes limit, 174 GXV_Validator valid ) 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, valid ); 190 p += 2 + 2 + 2 + 2; 191 192 gxv_kern_subtable_fmt0_pairs_validate( p, limit, nPairs, valid ); 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 gxv_kern_subtable_fmt1_valueTable_load(FT_Bytes table,FT_Bytes limit,GXV_Validator valid)210 gxv_kern_subtable_fmt1_valueTable_load( FT_Bytes table, 211 FT_Bytes limit, 212 GXV_Validator valid ) 213 { 214 FT_Bytes p = table; 215 GXV_kern_fmt1_StateOptRecData optdata = 216 (GXV_kern_fmt1_StateOptRecData)valid->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 gxv_kern_subtable_fmt1_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)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 valid ) 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)valid->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, valid ); 255 } 256 257 258 /* 259 * passed table & limit are of whole StateTable, not including subtables 260 */ 261 static void gxv_kern_subtable_fmt1_entry_validate(FT_Byte state,FT_UShort flags,GXV_StateTable_GlyphOffsetCPtr glyphOffset_p,FT_Bytes table,FT_Bytes limit,GXV_Validator valid)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 valid ) 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)valid->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 #else 307 p += 4; 308 #endif 309 } 310 } 311 312 313 static void gxv_kern_subtable_fmt1_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator valid)314 gxv_kern_subtable_fmt1_validate( FT_Bytes table, 315 FT_Bytes limit, 316 GXV_Validator valid ) 317 { 318 FT_Bytes p = table; 319 GXV_kern_fmt1_StateOptRec vt_rec; 320 321 322 GXV_NAME_ENTER( "kern subtable format 1" ); 323 324 valid->statetable.optdata = 325 &vt_rec; 326 valid->statetable.optdata_load_func = 327 gxv_kern_subtable_fmt1_valueTable_load; 328 valid->statetable.subtable_setup_func = 329 gxv_kern_subtable_fmt1_subtable_setup; 330 valid->statetable.entry_glyphoffset_fmt = 331 GXV_GLYPHOFFSET_NONE; 332 valid->statetable.entry_validate_func = 333 gxv_kern_subtable_fmt1_entry_validate; 334 335 gxv_StateTable_validate( p, limit, valid ); 336 337 GXV_EXIT; 338 } 339 340 341 /* ================ Data for Class-Based Subtables 2, 3 ================ */ 342 343 typedef enum GXV_kern_ClassSpec_ 344 { 345 GXV_KERN_CLS_L = 0, 346 GXV_KERN_CLS_R 347 348 } GXV_kern_ClassSpec; 349 350 351 /* ============================= format 2 ============================== */ 352 353 /* ---------------------- format 2 specific data ----------------------- */ 354 355 typedef struct GXV_kern_subtable_fmt2_DataRec_ 356 { 357 FT_UShort rowWidth; 358 FT_UShort array; 359 FT_UShort offset_min[2]; 360 FT_UShort offset_max[2]; 361 const FT_String* class_tag[2]; 362 GXV_odtect_Range odtect; 363 364 } GXV_kern_subtable_fmt2_DataRec, *GXV_kern_subtable_fmt2_Data; 365 366 367 #define GXV_KERN_FMT2_DATA( field ) \ 368 ( ( (GXV_kern_subtable_fmt2_DataRec *) \ 369 ( GXV_KERN_DATA( subtable_data ) ) )->field ) 370 371 372 /* -------------------------- utility functions ----------------------- */ 373 374 static void gxv_kern_subtable_fmt2_clstbl_validate(FT_Bytes table,FT_Bytes limit,GXV_kern_ClassSpec spec,GXV_Validator valid)375 gxv_kern_subtable_fmt2_clstbl_validate( FT_Bytes table, 376 FT_Bytes limit, 377 GXV_kern_ClassSpec spec, 378 GXV_Validator valid ) 379 { 380 const FT_String* tag = GXV_KERN_FMT2_DATA( class_tag[spec] ); 381 GXV_odtect_Range odtect = GXV_KERN_FMT2_DATA( odtect ); 382 383 FT_Bytes p = table; 384 FT_UShort firstGlyph; 385 FT_UShort nGlyphs; 386 387 388 GXV_NAME_ENTER( "kern format 2 classTable" ); 389 390 GXV_LIMIT_CHECK( 2 + 2 ); 391 firstGlyph = FT_NEXT_USHORT( p ); 392 nGlyphs = FT_NEXT_USHORT( p ); 393 GXV_TRACE(( " %s firstGlyph=%d, nGlyphs=%d\n", 394 tag, firstGlyph, nGlyphs )); 395 396 gxv_glyphid_validate( firstGlyph, valid ); 397 gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs - 1 ), valid ); 398 399 gxv_array_getlimits_ushort( p, p + ( 2 * nGlyphs ), 400 &( GXV_KERN_FMT2_DATA( offset_min[spec] ) ), 401 &( GXV_KERN_FMT2_DATA( offset_max[spec] ) ), 402 valid ); 403 404 gxv_odtect_add_range( table, 2 * nGlyphs, tag, odtect ); 405 406 GXV_EXIT; 407 } 408 409 410 static void gxv_kern_subtable_fmt2_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator valid)411 gxv_kern_subtable_fmt2_validate( FT_Bytes table, 412 FT_Bytes limit, 413 GXV_Validator valid ) 414 { 415 GXV_ODTECT( 3, odtect ); 416 GXV_kern_subtable_fmt2_DataRec fmt2_rec = 417 { 0, 0, { 0, 0 }, { 0, 0 }, { "leftClass", "rightClass" }, NULL }; 418 419 FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE; 420 FT_UShort leftOffsetTable; 421 FT_UShort rightOffsetTable; 422 423 424 GXV_NAME_ENTER( "kern subtable format 2" ); 425 426 GXV_ODTECT_INIT( odtect ); 427 fmt2_rec.odtect = odtect; 428 GXV_KERN_DATA( subtable_data ) = &fmt2_rec; 429 430 GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 ); 431 GXV_KERN_FMT2_DATA( rowWidth ) = FT_NEXT_USHORT( p ); 432 leftOffsetTable = FT_NEXT_USHORT( p ); 433 rightOffsetTable = FT_NEXT_USHORT( p ); 434 GXV_KERN_FMT2_DATA( array ) = FT_NEXT_USHORT( p ); 435 436 GXV_TRACE(( "rowWidth = %d\n", GXV_KERN_FMT2_DATA( rowWidth ) )); 437 438 439 GXV_LIMIT_CHECK( leftOffsetTable ); 440 GXV_LIMIT_CHECK( rightOffsetTable ); 441 GXV_LIMIT_CHECK( GXV_KERN_FMT2_DATA( array ) ); 442 443 gxv_kern_subtable_fmt2_clstbl_validate( table + leftOffsetTable, limit, 444 GXV_KERN_CLS_L, valid ); 445 446 gxv_kern_subtable_fmt2_clstbl_validate( table + rightOffsetTable, limit, 447 GXV_KERN_CLS_R, valid ); 448 449 if ( GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_L] ) + 450 GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_R] ) 451 < GXV_KERN_FMT2_DATA( array ) ) 452 FT_INVALID_OFFSET; 453 454 gxv_odtect_add_range( table + GXV_KERN_FMT2_DATA( array ), 455 GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_L] ) 456 + GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_R] ) 457 - GXV_KERN_FMT2_DATA( array ), 458 "array", odtect ); 459 460 gxv_odtect_validate( odtect, valid ); 461 462 GXV_EXIT; 463 } 464 465 466 /* ============================= format 3 ============================== */ 467 468 static void gxv_kern_subtable_fmt3_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator valid)469 gxv_kern_subtable_fmt3_validate( FT_Bytes table, 470 FT_Bytes limit, 471 GXV_Validator valid ) 472 { 473 FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE; 474 FT_UShort glyphCount; 475 FT_Byte kernValueCount; 476 FT_Byte leftClassCount; 477 FT_Byte rightClassCount; 478 FT_Byte flags; 479 480 481 GXV_NAME_ENTER( "kern subtable format 3" ); 482 483 GXV_LIMIT_CHECK( 2 + 1 + 1 + 1 + 1 ); 484 glyphCount = FT_NEXT_USHORT( p ); 485 kernValueCount = FT_NEXT_BYTE( p ); 486 leftClassCount = FT_NEXT_BYTE( p ); 487 rightClassCount = FT_NEXT_BYTE( p ); 488 flags = FT_NEXT_BYTE( p ); 489 490 if ( valid->face->num_glyphs != glyphCount ) 491 { 492 GXV_TRACE(( "maxGID=%d, but glyphCount=%d\n", 493 valid->face->num_glyphs, glyphCount )); 494 GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); 495 } 496 497 if ( flags != 0 ) 498 GXV_TRACE(( "kern subtable fmt3 has nonzero value" 499 " (%d) in unused flag\n", flags )); 500 /* 501 * just skip kernValue[kernValueCount] 502 */ 503 GXV_LIMIT_CHECK( 2 * kernValueCount ); 504 p += 2 * kernValueCount; 505 506 /* 507 * check leftClass[gid] < leftClassCount 508 */ 509 { 510 FT_Byte min, max; 511 512 513 GXV_LIMIT_CHECK( glyphCount ); 514 gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, valid ); 515 p += valid->subtable_length; 516 517 if ( leftClassCount < max ) 518 FT_INVALID_DATA; 519 } 520 521 /* 522 * check rightClass[gid] < rightClassCount 523 */ 524 { 525 FT_Byte min, max; 526 527 528 GXV_LIMIT_CHECK( glyphCount ); 529 gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, valid ); 530 p += valid->subtable_length; 531 532 if ( rightClassCount < max ) 533 FT_INVALID_DATA; 534 } 535 536 /* 537 * check kernIndex[i, j] < kernValueCount 538 */ 539 { 540 FT_UShort i, j; 541 542 543 for ( i = 0; i < leftClassCount; i++ ) 544 { 545 for ( j = 0; j < rightClassCount; j++ ) 546 { 547 GXV_LIMIT_CHECK( 1 ); 548 if ( kernValueCount < FT_NEXT_BYTE( p ) ) 549 FT_INVALID_OFFSET; 550 } 551 } 552 } 553 554 valid->subtable_length = p - table; 555 556 GXV_EXIT; 557 } 558 559 560 static FT_Bool gxv_kern_coverage_new_apple_validate(FT_UShort coverage,FT_UShort * format,GXV_Validator valid)561 gxv_kern_coverage_new_apple_validate( FT_UShort coverage, 562 FT_UShort* format, 563 GXV_Validator valid ) 564 { 565 /* new Apple-dialect */ 566 #ifdef GXV_LOAD_TRACE_VARS 567 FT_Bool kernVertical; 568 FT_Bool kernCrossStream; 569 FT_Bool kernVariation; 570 #endif 571 572 FT_UNUSED( valid ); 573 574 575 /* reserved bits = 0 */ 576 if ( coverage & 0x1FFC ) 577 return FALSE; 578 579 #ifdef GXV_LOAD_TRACE_VARS 580 kernVertical = FT_BOOL( ( coverage >> 15 ) & 1 ); 581 kernCrossStream = FT_BOOL( ( coverage >> 14 ) & 1 ); 582 kernVariation = FT_BOOL( ( coverage >> 13 ) & 1 ); 583 #endif 584 585 *format = (FT_UShort)( coverage & 0x0003 ); 586 587 GXV_TRACE(( "new Apple-dialect: " 588 "horizontal=%d, cross-stream=%d, variation=%d, format=%d\n", 589 !kernVertical, kernCrossStream, kernVariation, *format )); 590 591 GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" )); 592 593 return TRUE; 594 } 595 596 597 static FT_Bool gxv_kern_coverage_classic_apple_validate(FT_UShort coverage,FT_UShort * format,GXV_Validator valid)598 gxv_kern_coverage_classic_apple_validate( FT_UShort coverage, 599 FT_UShort* format, 600 GXV_Validator valid ) 601 { 602 /* classic Apple-dialect */ 603 #ifdef GXV_LOAD_TRACE_VARS 604 FT_Bool horizontal; 605 FT_Bool cross_stream; 606 #endif 607 608 609 /* check expected flags, but don't check if MS-dialect is impossible */ 610 if ( !( coverage & 0xFD00 ) && KERN_ALLOWS_MS( valid ) ) 611 return FALSE; 612 613 /* reserved bits = 0 */ 614 if ( coverage & 0x02FC ) 615 return FALSE; 616 617 #ifdef GXV_LOAD_TRACE_VARS 618 horizontal = FT_BOOL( ( coverage >> 15 ) & 1 ); 619 cross_stream = FT_BOOL( ( coverage >> 13 ) & 1 ); 620 #endif 621 622 *format = (FT_UShort)( coverage & 0x0003 ); 623 624 GXV_TRACE(( "classic Apple-dialect: " 625 "horizontal=%d, cross-stream=%d, format=%d\n", 626 horizontal, cross_stream, *format )); 627 628 /* format 1 requires GX State Machine, too new for classic */ 629 if ( *format == 1 ) 630 return FALSE; 631 632 GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" )); 633 634 return TRUE; 635 } 636 637 638 static FT_Bool gxv_kern_coverage_classic_microsoft_validate(FT_UShort coverage,FT_UShort * format,GXV_Validator valid)639 gxv_kern_coverage_classic_microsoft_validate( FT_UShort coverage, 640 FT_UShort* format, 641 GXV_Validator valid ) 642 { 643 /* classic Microsoft-dialect */ 644 #ifdef GXV_LOAD_TRACE_VARS 645 FT_Bool horizontal; 646 FT_Bool minimum; 647 FT_Bool cross_stream; 648 FT_Bool override; 649 #endif 650 651 FT_UNUSED( valid ); 652 653 654 /* reserved bits = 0 */ 655 if ( coverage & 0xFDF0 ) 656 return FALSE; 657 658 #ifdef GXV_LOAD_TRACE_VARS 659 horizontal = FT_BOOL( coverage & 1 ); 660 minimum = FT_BOOL( ( coverage >> 1 ) & 1 ); 661 cross_stream = FT_BOOL( ( coverage >> 2 ) & 1 ); 662 override = FT_BOOL( ( coverage >> 3 ) & 1 ); 663 #endif 664 665 *format = (FT_UShort)( ( coverage >> 8 ) & 0x0003 ); 666 667 GXV_TRACE(( "classic Microsoft-dialect: " 668 "horizontal=%d, minimum=%d, cross-stream=%d, " 669 "override=%d, format=%d\n", 670 horizontal, minimum, cross_stream, override, *format )); 671 672 if ( *format == 2 ) 673 GXV_TRACE(( 674 "kerning values in Microsoft format 2 subtable are ignored\n" )); 675 676 return TRUE; 677 } 678 679 680 /*************************************************************************/ 681 /*************************************************************************/ 682 /***** *****/ 683 /***** MAIN *****/ 684 /***** *****/ 685 /*************************************************************************/ 686 /*************************************************************************/ 687 688 static GXV_kern_Dialect gxv_kern_coverage_validate(FT_UShort coverage,FT_UShort * format,GXV_Validator valid)689 gxv_kern_coverage_validate( FT_UShort coverage, 690 FT_UShort* format, 691 GXV_Validator valid ) 692 { 693 GXV_kern_Dialect result = KERN_DIALECT_UNKNOWN; 694 695 696 GXV_NAME_ENTER( "validating coverage" ); 697 698 GXV_TRACE(( "interprete coverage 0x%04x by Apple style\n", coverage )); 699 700 if ( KERN_IS_NEW( valid ) ) 701 { 702 if ( gxv_kern_coverage_new_apple_validate( coverage, 703 format, 704 valid ) ) 705 { 706 result = KERN_DIALECT_APPLE; 707 goto Exit; 708 } 709 } 710 711 if ( KERN_IS_CLASSIC( valid ) && KERN_ALLOWS_APPLE( valid ) ) 712 { 713 if ( gxv_kern_coverage_classic_apple_validate( coverage, 714 format, 715 valid ) ) 716 { 717 result = KERN_DIALECT_APPLE; 718 goto Exit; 719 } 720 } 721 722 if ( KERN_IS_CLASSIC( valid ) && KERN_ALLOWS_MS( valid ) ) 723 { 724 if ( gxv_kern_coverage_classic_microsoft_validate( coverage, 725 format, 726 valid ) ) 727 { 728 result = KERN_DIALECT_MS; 729 goto Exit; 730 } 731 } 732 733 GXV_TRACE(( "cannot interprete coverage, broken kern subtable\n" )); 734 735 Exit: 736 GXV_EXIT; 737 return result; 738 } 739 740 741 static void gxv_kern_subtable_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator valid)742 gxv_kern_subtable_validate( FT_Bytes table, 743 FT_Bytes limit, 744 GXV_Validator valid ) 745 { 746 FT_Bytes p = table; 747 #ifdef GXV_LOAD_TRACE_VARS 748 FT_UShort version = 0; /* MS only: subtable version, unused */ 749 #endif 750 FT_ULong length; /* MS: 16bit, Apple: 32bit*/ 751 FT_UShort coverage; 752 #ifdef GXV_LOAD_TRACE_VARS 753 FT_UShort tupleIndex = 0; /* Apple only */ 754 #endif 755 FT_UShort u16[2]; 756 FT_UShort format = 255; /* subtable format */ 757 758 759 GXV_NAME_ENTER( "kern subtable" ); 760 761 GXV_LIMIT_CHECK( 2 + 2 + 2 ); 762 u16[0] = FT_NEXT_USHORT( p ); /* Apple: length_hi MS: version */ 763 u16[1] = FT_NEXT_USHORT( p ); /* Apple: length_lo MS: length */ 764 coverage = FT_NEXT_USHORT( p ); 765 766 switch ( gxv_kern_coverage_validate( coverage, &format, valid ) ) 767 { 768 case KERN_DIALECT_MS: 769 #ifdef GXV_LOAD_TRACE_VARS 770 version = u16[0]; 771 #endif 772 length = u16[1]; 773 #ifdef GXV_LOAD_TRACE_VARS 774 tupleIndex = 0; 775 #endif 776 GXV_TRACE(( "Subtable version = %d\n", version )); 777 GXV_TRACE(( "Subtable length = %d\n", length )); 778 break; 779 780 case KERN_DIALECT_APPLE: 781 #ifdef GXV_LOAD_TRACE_VARS 782 version = 0; 783 #endif 784 length = ( u16[0] << 16 ) + u16[1]; 785 #ifdef GXV_LOAD_TRACE_VARS 786 tupleIndex = 0; 787 #endif 788 GXV_TRACE(( "Subtable length = %d\n", length )); 789 790 if ( KERN_IS_NEW( valid ) ) 791 { 792 GXV_LIMIT_CHECK( 2 ); 793 #ifdef GXV_LOAD_TRACE_VARS 794 tupleIndex = FT_NEXT_USHORT( p ); 795 #else 796 p += 2; 797 #endif 798 GXV_TRACE(( "Subtable tupleIndex = %d\n", tupleIndex )); 799 } 800 break; 801 802 default: 803 length = u16[1]; 804 GXV_TRACE(( "cannot detect subtable dialect, " 805 "just skip %d byte\n", length )); 806 goto Exit; 807 } 808 809 /* formats 1, 2, 3 require the position of the start of this subtable */ 810 if ( format == 0 ) 811 gxv_kern_subtable_fmt0_validate( table, table + length, valid ); 812 else if ( format == 1 ) 813 gxv_kern_subtable_fmt1_validate( table, table + length, valid ); 814 else if ( format == 2 ) 815 gxv_kern_subtable_fmt2_validate( table, table + length, valid ); 816 else if ( format == 3 ) 817 gxv_kern_subtable_fmt3_validate( table, table + length, valid ); 818 else 819 FT_INVALID_DATA; 820 821 Exit: 822 valid->subtable_length = length; 823 GXV_EXIT; 824 } 825 826 827 /*************************************************************************/ 828 /*************************************************************************/ 829 /***** *****/ 830 /***** kern TABLE *****/ 831 /***** *****/ 832 /*************************************************************************/ 833 /*************************************************************************/ 834 835 static void gxv_kern_validate_generic(FT_Bytes table,FT_Face face,FT_Bool classic_only,GXV_kern_Dialect dialect_request,FT_Validator ftvalid)836 gxv_kern_validate_generic( FT_Bytes table, 837 FT_Face face, 838 FT_Bool classic_only, 839 GXV_kern_Dialect dialect_request, 840 FT_Validator ftvalid ) 841 { 842 GXV_ValidatorRec validrec; 843 GXV_Validator valid = &validrec; 844 845 GXV_kern_DataRec kernrec; 846 GXV_kern_Data kern = &kernrec; 847 848 FT_Bytes p = table; 849 FT_Bytes limit = 0; 850 851 FT_ULong nTables = 0; 852 FT_UInt i; 853 854 855 valid->root = ftvalid; 856 valid->table_data = kern; 857 valid->face = face; 858 859 FT_TRACE3(( "validating `kern' table\n" )); 860 GXV_INIT; 861 KERN_DIALECT( valid ) = dialect_request; 862 863 GXV_LIMIT_CHECK( 2 ); 864 GXV_KERN_DATA( version ) = (GXV_kern_Version)FT_NEXT_USHORT( p ); 865 GXV_TRACE(( "version 0x%04x (higher 16bit)\n", 866 GXV_KERN_DATA( version ) )); 867 868 if ( 0x0001 < GXV_KERN_DATA( version ) ) 869 FT_INVALID_FORMAT; 870 else if ( KERN_IS_CLASSIC( valid ) ) 871 { 872 GXV_LIMIT_CHECK( 2 ); 873 nTables = FT_NEXT_USHORT( p ); 874 } 875 else if ( KERN_IS_NEW( valid ) ) 876 { 877 if ( classic_only ) 878 FT_INVALID_FORMAT; 879 880 if ( 0x0000 != FT_NEXT_USHORT( p ) ) 881 FT_INVALID_FORMAT; 882 883 GXV_LIMIT_CHECK( 4 ); 884 nTables = FT_NEXT_ULONG( p ); 885 } 886 887 for ( i = 0; i < nTables; i++ ) 888 { 889 GXV_TRACE(( "validating subtable %d/%d\n", i, nTables )); 890 /* p should be 32bit-aligned? */ 891 gxv_kern_subtable_validate( p, 0, valid ); 892 p += valid->subtable_length; 893 } 894 895 FT_TRACE4(( "\n" )); 896 } 897 898 899 FT_LOCAL_DEF( void ) gxv_kern_validate(FT_Bytes table,FT_Face face,FT_Validator ftvalid)900 gxv_kern_validate( FT_Bytes table, 901 FT_Face face, 902 FT_Validator ftvalid ) 903 { 904 gxv_kern_validate_generic( table, face, 0, KERN_DIALECT_ANY, ftvalid ); 905 } 906 907 908 FT_LOCAL_DEF( void ) gxv_kern_validate_classic(FT_Bytes table,FT_Face face,FT_Int dialect_flags,FT_Validator ftvalid)909 gxv_kern_validate_classic( FT_Bytes table, 910 FT_Face face, 911 FT_Int dialect_flags, 912 FT_Validator ftvalid ) 913 { 914 GXV_kern_Dialect dialect_request; 915 916 917 dialect_request = (GXV_kern_Dialect)dialect_flags; 918 gxv_kern_validate_generic( table, face, 1, dialect_request, ftvalid ); 919 } 920 921 922 /* END */ 923