00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "gxvalid.h"
00029 #include "gxvcommn.h"
00030
00031 #include FT_SFNT_NAMES_H
00032 #include FT_SERVICE_GX_VALIDATE_H
00033
00034
00035
00036
00037
00038
00039
00040
00041 #undef FT_COMPONENT
00042 #define FT_COMPONENT trace_gxvkern
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 typedef enum GXV_kern_Version_
00054 {
00055 KERN_VERSION_CLASSIC = 0x0000,
00056 KERN_VERSION_NEW = 0x0001
00057
00058 } GXV_kern_Version;
00059
00060
00061 typedef enum GXV_kern_Dialect_
00062 {
00063 KERN_DIALECT_UNKNOWN = 0,
00064 KERN_DIALECT_MS = FT_VALIDATE_MS,
00065 KERN_DIALECT_APPLE = FT_VALIDATE_APPLE,
00066 KERN_DIALECT_ANY = FT_VALIDATE_CKERN
00067
00068 } GXV_kern_Dialect;
00069
00070
00071 typedef struct GXV_kern_DataRec_
00072 {
00073 GXV_kern_Version version;
00074 void *subtable_data;
00075 GXV_kern_Dialect dialect_request;
00076
00077 } GXV_kern_DataRec, *GXV_kern_Data;
00078
00079
00080 #define GXV_KERN_DATA( field ) GXV_TABLE_DATA( kern, field )
00081
00082 #define KERN_IS_CLASSIC( valid ) \
00083 ( KERN_VERSION_CLASSIC == GXV_KERN_DATA( version ) )
00084 #define KERN_IS_NEW( valid ) \
00085 ( KERN_VERSION_NEW == GXV_KERN_DATA( version ) )
00086
00087 #define KERN_DIALECT( valid ) \
00088 GXV_KERN_DATA( dialect_request )
00089 #define KERN_ALLOWS_MS( valid ) \
00090 ( KERN_DIALECT( valid ) & KERN_DIALECT_MS )
00091 #define KERN_ALLOWS_APPLE( valid ) \
00092 ( KERN_DIALECT( valid ) & KERN_DIALECT_APPLE )
00093
00094 #define GXV_KERN_HEADER_SIZE ( KERN_IS_NEW( valid ) ? 8 : 4 )
00095 #define GXV_KERN_SUBTABLE_HEADER_SIZE ( KERN_IS_NEW( valid ) ? 8 : 6 )
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109 static void
00110 gxv_kern_subtable_fmt0_pairs_validate( FT_Bytes table,
00111 FT_Bytes limit,
00112 FT_UShort nPairs,
00113 GXV_Validator valid )
00114 {
00115 FT_Bytes p = table;
00116 FT_UShort i;
00117
00118 FT_UShort last_gid_left = 0;
00119 FT_UShort last_gid_right = 0;
00120
00121 FT_UNUSED( limit );
00122
00123
00124 GXV_NAME_ENTER( "kern format 0 pairs" );
00125
00126 for ( i = 0; i < nPairs; i++ )
00127 {
00128 FT_UShort gid_left;
00129 FT_UShort gid_right;
00130 FT_Short kernValue;
00131
00132
00133
00134 gid_left = FT_NEXT_USHORT( p );
00135 gxv_glyphid_validate( gid_left, valid );
00136
00137
00138 gid_right = FT_NEXT_USHORT( p );
00139 gxv_glyphid_validate( gid_right, valid );
00140
00141
00142 GXV_TRACE(( "left gid = %u, right gid = %u\n", gid_left, gid_right ));
00143 if ( gid_left == last_gid_left )
00144 {
00145 if ( last_gid_right < gid_right )
00146 last_gid_right = gid_right;
00147 else
00148 FT_INVALID_DATA;
00149 }
00150 else if ( last_gid_left < gid_left )
00151 {
00152 last_gid_left = gid_left;
00153 last_gid_right = gid_right;
00154 }
00155 else
00156 FT_INVALID_DATA;
00157
00158
00159 kernValue = FT_NEXT_SHORT( p );
00160 }
00161
00162 GXV_EXIT;
00163 }
00164
00165 static void
00166 gxv_kern_subtable_fmt0_validate( FT_Bytes table,
00167 FT_Bytes limit,
00168 GXV_Validator valid )
00169 {
00170 FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE;
00171
00172 FT_UShort nPairs;
00173 FT_UShort unitSize;
00174
00175
00176 GXV_NAME_ENTER( "kern subtable format 0" );
00177
00178 unitSize = 2 + 2 + 2;
00179 nPairs = 0;
00180
00181
00182 GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
00183 gxv_BinSrchHeader_validate( p, limit, &unitSize, &nPairs, valid );
00184 p += 2 + 2 + 2 + 2;
00185
00186 gxv_kern_subtable_fmt0_pairs_validate( p, limit, nPairs, valid );
00187
00188 GXV_EXIT;
00189 }
00190
00191
00192
00193
00194
00195 typedef struct GXV_kern_fmt1_StateOptRec_
00196 {
00197 FT_UShort valueTable;
00198 FT_UShort valueTable_length;
00199
00200 } GXV_kern_fmt1_StateOptRec, *GXV_kern_fmt1_StateOptRecData;
00201
00202
00203 static void
00204 gxv_kern_subtable_fmt1_valueTable_load( FT_Bytes table,
00205 FT_Bytes limit,
00206 GXV_Validator valid )
00207 {
00208 FT_Bytes p = table;
00209 GXV_kern_fmt1_StateOptRecData optdata =
00210 (GXV_kern_fmt1_StateOptRecData)valid->statetable.optdata;
00211
00212
00213 GXV_LIMIT_CHECK( 2 );
00214 optdata->valueTable = FT_NEXT_USHORT( p );
00215 }
00216
00217
00218
00219
00220
00221 static void
00222 gxv_kern_subtable_fmt1_subtable_setup( FT_UShort table_size,
00223 FT_UShort classTable,
00224 FT_UShort stateArray,
00225 FT_UShort entryTable,
00226 FT_UShort* classTable_length_p,
00227 FT_UShort* stateArray_length_p,
00228 FT_UShort* entryTable_length_p,
00229 GXV_Validator valid )
00230 {
00231 FT_UShort o[4];
00232 FT_UShort *l[4];
00233 FT_UShort buff[5];
00234
00235 GXV_kern_fmt1_StateOptRecData optdata =
00236 (GXV_kern_fmt1_StateOptRecData)valid->statetable.optdata;
00237
00238
00239 o[0] = classTable;
00240 o[1] = stateArray;
00241 o[2] = entryTable;
00242 o[3] = optdata->valueTable;
00243 l[0] = classTable_length_p;
00244 l[1] = stateArray_length_p;
00245 l[2] = entryTable_length_p;
00246 l[3] = &(optdata->valueTable_length);
00247
00248 gxv_set_length_by_ushort_offset( o, l, buff, 4, table_size, valid );
00249 }
00250
00251
00252
00253
00254
00255 static void
00256 gxv_kern_subtable_fmt1_entry_validate(
00257 FT_Byte state,
00258 FT_UShort flags,
00259 GXV_StateTable_GlyphOffsetCPtr glyphOffset_p,
00260 FT_Bytes table,
00261 FT_Bytes limit,
00262 GXV_Validator valid )
00263 {
00264 FT_UShort push;
00265 FT_UShort dontAdvance;
00266 FT_UShort valueOffset;
00267 FT_UShort kernAction;
00268 FT_UShort kernValue;
00269
00270 FT_UNUSED( state );
00271 FT_UNUSED( glyphOffset_p );
00272
00273
00274 push = (FT_UShort)( ( flags >> 15 ) & 1 );
00275 dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 );
00276 valueOffset = (FT_UShort)( flags & 0x3FFF );
00277
00278 {
00279 GXV_kern_fmt1_StateOptRecData vt_rec =
00280 (GXV_kern_fmt1_StateOptRecData)valid->statetable.optdata;
00281 FT_Bytes p;
00282
00283
00284 if ( valueOffset < vt_rec->valueTable )
00285 FT_INVALID_OFFSET;
00286
00287 p = table + valueOffset;
00288 limit = table + vt_rec->valueTable + vt_rec->valueTable_length;
00289
00290 GXV_LIMIT_CHECK( 2 + 2 );
00291 kernAction = FT_NEXT_USHORT( p );
00292 kernValue = FT_NEXT_USHORT( p );
00293 }
00294 }
00295
00296
00297 static void
00298 gxv_kern_subtable_fmt1_validate( FT_Bytes table,
00299 FT_Bytes limit,
00300 GXV_Validator valid )
00301 {
00302 FT_Bytes p = table;
00303 GXV_kern_fmt1_StateOptRec vt_rec;
00304
00305
00306 GXV_NAME_ENTER( "kern subtable format 1" );
00307
00308 valid->statetable.optdata =
00309 &vt_rec;
00310 valid->statetable.optdata_load_func =
00311 gxv_kern_subtable_fmt1_valueTable_load;
00312 valid->statetable.subtable_setup_func =
00313 gxv_kern_subtable_fmt1_subtable_setup;
00314 valid->statetable.entry_glyphoffset_fmt =
00315 GXV_GLYPHOFFSET_NONE;
00316 valid->statetable.entry_validate_func =
00317 gxv_kern_subtable_fmt1_entry_validate;
00318
00319 gxv_StateTable_validate( p, limit, valid );
00320
00321 GXV_EXIT;
00322 }
00323
00324
00325
00326
00327 typedef enum GXV_kern_ClassSpec_
00328 {
00329 GXV_KERN_CLS_L = 0,
00330 GXV_KERN_CLS_R
00331
00332 } GXV_kern_ClassSpec;
00333
00334
00335
00336
00337
00338
00339 typedef struct GXV_kern_subtable_fmt2_DataRec_
00340 {
00341 FT_UShort rowWidth;
00342 FT_UShort array;
00343 FT_UShort offset_min[2];
00344 FT_UShort offset_max[2];
00345 const FT_String* class_tag[2];
00346 GXV_odtect_Range odtect;
00347
00348 } GXV_kern_subtable_fmt2_DataRec, *GXV_kern_subtable_fmt2_Data;
00349
00350
00351 #define GXV_KERN_FMT2_DATA( field ) \
00352 ( ( (GXV_kern_subtable_fmt2_DataRec *) \
00353 ( GXV_KERN_DATA( subtable_data ) ) )->field )
00354
00355
00356
00357
00358 static void
00359 gxv_kern_subtable_fmt2_clstbl_validate( FT_Bytes table,
00360 FT_Bytes limit,
00361 GXV_kern_ClassSpec spec,
00362 GXV_Validator valid )
00363 {
00364 const FT_String* tag = GXV_KERN_FMT2_DATA( class_tag[spec] );
00365 GXV_odtect_Range odtect = GXV_KERN_FMT2_DATA( odtect );
00366
00367 FT_Bytes p = table;
00368 FT_UShort firstGlyph;
00369 FT_UShort nGlyphs;
00370
00371
00372 GXV_NAME_ENTER( "kern format 2 classTable" );
00373
00374 GXV_LIMIT_CHECK( 2 + 2 );
00375 firstGlyph = FT_NEXT_USHORT( p );
00376 nGlyphs = FT_NEXT_USHORT( p );
00377 GXV_TRACE(( " %s firstGlyph=%d, nGlyphs=%d\n",
00378 tag, firstGlyph, nGlyphs ));
00379
00380 gxv_glyphid_validate( firstGlyph, valid );
00381 gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs - 1 ), valid );
00382
00383 gxv_array_getlimits_ushort( p, p + ( 2 * nGlyphs ),
00384 &( GXV_KERN_FMT2_DATA( offset_min[spec] ) ),
00385 &( GXV_KERN_FMT2_DATA( offset_max[spec] ) ),
00386 valid );
00387
00388 gxv_odtect_add_range( table, 2 * nGlyphs, tag, odtect );
00389
00390 GXV_EXIT;
00391 }
00392
00393
00394 static void
00395 gxv_kern_subtable_fmt2_validate( FT_Bytes table,
00396 FT_Bytes limit,
00397 GXV_Validator valid )
00398 {
00399 GXV_ODTECT( 3, odtect );
00400 GXV_kern_subtable_fmt2_DataRec fmt2_rec =
00401 { 0, 0, { 0, 0 }, { 0, 0 }, { "leftClass", "rightClass" }, NULL };
00402
00403 FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE;
00404 FT_UShort leftOffsetTable;
00405 FT_UShort rightOffsetTable;
00406
00407
00408 GXV_NAME_ENTER( "kern subtable format 2" );
00409
00410 GXV_ODTECT_INIT( odtect );
00411 fmt2_rec.odtect = odtect;
00412 GXV_KERN_DATA( subtable_data ) = &fmt2_rec;
00413
00414 GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
00415 GXV_KERN_FMT2_DATA( rowWidth ) = FT_NEXT_USHORT( p );
00416 leftOffsetTable = FT_NEXT_USHORT( p );
00417 rightOffsetTable = FT_NEXT_USHORT( p );
00418 GXV_KERN_FMT2_DATA( array ) = FT_NEXT_USHORT( p );
00419
00420 GXV_TRACE(( "rowWidth = %d\n", GXV_KERN_FMT2_DATA( rowWidth ) ));
00421
00422
00423 GXV_LIMIT_CHECK( leftOffsetTable );
00424 GXV_LIMIT_CHECK( rightOffsetTable );
00425 GXV_LIMIT_CHECK( GXV_KERN_FMT2_DATA( array ) );
00426
00427 gxv_kern_subtable_fmt2_clstbl_validate( table + leftOffsetTable, limit,
00428 GXV_KERN_CLS_L, valid );
00429
00430 gxv_kern_subtable_fmt2_clstbl_validate( table + rightOffsetTable, limit,
00431 GXV_KERN_CLS_R, valid );
00432
00433 if ( GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_L] ) +
00434 GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_R] )
00435 < GXV_KERN_FMT2_DATA( array ) )
00436 FT_INVALID_OFFSET;
00437
00438 gxv_odtect_add_range( table + GXV_KERN_FMT2_DATA( array ),
00439 GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_L] )
00440 + GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_R] )
00441 - GXV_KERN_FMT2_DATA( array ),
00442 "array", odtect );
00443
00444 gxv_odtect_validate( odtect, valid );
00445
00446 GXV_EXIT;
00447 }
00448
00449
00450
00451
00452 static void
00453 gxv_kern_subtable_fmt3_validate( FT_Bytes table,
00454 FT_Bytes limit,
00455 GXV_Validator valid )
00456 {
00457 FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE;
00458 FT_UShort glyphCount;
00459 FT_Byte kernValueCount;
00460 FT_Byte leftClassCount;
00461 FT_Byte rightClassCount;
00462 FT_Byte flags;
00463
00464
00465 GXV_NAME_ENTER( "kern subtable format 3" );
00466
00467 GXV_LIMIT_CHECK( 2 + 1 + 1 + 1 + 1 );
00468 glyphCount = FT_NEXT_USHORT( p );
00469 kernValueCount = FT_NEXT_BYTE( p );
00470 leftClassCount = FT_NEXT_BYTE( p );
00471 rightClassCount = FT_NEXT_BYTE( p );
00472 flags = FT_NEXT_BYTE( p );
00473
00474 if ( valid->face->num_glyphs != glyphCount )
00475 {
00476 GXV_TRACE(( "maxGID=%d, but glyphCount=%d\n",
00477 valid->face->num_glyphs, glyphCount ));
00478 if ( valid->root->level >= FT_VALIDATE_PARANOID )
00479 FT_INVALID_GLYPH_ID;
00480 }
00481
00482
00483
00484
00485 GXV_LIMIT_CHECK( 2 * kernValueCount );
00486 p += 2 * kernValueCount;
00487
00488
00489
00490
00491 {
00492 FT_Byte min, max;
00493
00494
00495 GXV_LIMIT_CHECK( glyphCount );
00496 gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, valid );
00497 p += valid->subtable_length;
00498
00499 if ( leftClassCount < max )
00500 FT_INVALID_DATA;
00501 }
00502
00503
00504
00505
00506 {
00507 FT_Byte min, max;
00508
00509
00510 GXV_LIMIT_CHECK( glyphCount );
00511 gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, valid );
00512 p += valid->subtable_length;
00513
00514 if ( rightClassCount < max )
00515 FT_INVALID_DATA;
00516 }
00517
00518
00519
00520
00521 {
00522 FT_UShort i, j;
00523
00524
00525 for ( i = 0; i < leftClassCount; i++ )
00526 {
00527 for ( j = 0; j < rightClassCount; j++ )
00528 {
00529 GXV_LIMIT_CHECK( 1 );
00530 if ( kernValueCount < FT_NEXT_BYTE( p ) )
00531 FT_INVALID_OFFSET;
00532 }
00533 }
00534 }
00535
00536 valid->subtable_length = p - table;
00537
00538 GXV_EXIT;
00539 }
00540
00541
00542 static FT_Bool
00543 gxv_kern_coverage_new_apple_validate( FT_UShort coverage,
00544 FT_UShort* format,
00545 GXV_Validator valid )
00546 {
00547
00548 FT_Bool kernVertical;
00549 FT_Bool kernCrossStream;
00550 FT_Bool kernVariation;
00551
00552 FT_UNUSED( valid );
00553
00554
00555
00556 if ( coverage & 0x1FFC )
00557 return 0;
00558
00559 kernVertical = FT_BOOL( ( coverage >> 15 ) & 1 );
00560 kernCrossStream = FT_BOOL( ( coverage >> 14 ) & 1 );
00561 kernVariation = FT_BOOL( ( coverage >> 13 ) & 1 );
00562
00563 *format = (FT_UShort)( coverage & 0x0003 );
00564
00565 GXV_TRACE(( "new Apple-dialect: "
00566 "horizontal=%d, cross-stream=%d, variation=%d, format=%d\n",
00567 !kernVertical, kernCrossStream, kernVariation, *format ));
00568
00569 GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" ));
00570
00571 return 1;
00572 }
00573
00574
00575 static FT_Bool
00576 gxv_kern_coverage_classic_apple_validate( FT_UShort coverage,
00577 FT_UShort* format,
00578 GXV_Validator valid )
00579 {
00580
00581 FT_Bool horizontal;
00582 FT_Bool cross_stream;
00583
00584
00585
00586 if ( !( coverage & 0xFD00 ) && KERN_ALLOWS_MS( valid ) )
00587 return 0;
00588
00589
00590 if ( coverage & 0x02FC )
00591 return 0;
00592
00593 horizontal = FT_BOOL( ( coverage >> 15 ) & 1 );
00594 cross_stream = FT_BOOL( ( coverage >> 13 ) & 1 );
00595
00596 *format = (FT_UShort)( coverage & 0x0003 );
00597
00598 GXV_TRACE(( "classic Apple-dialect: "
00599 "horizontal=%d, cross-stream=%d, format=%d\n",
00600 horizontal, cross_stream, *format ));
00601
00602
00603 if ( *format == 1 )
00604 return 0;
00605
00606 GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" ));
00607
00608 return 1;
00609 }
00610
00611
00612 static FT_Bool
00613 gxv_kern_coverage_classic_microsoft_validate( FT_UShort coverage,
00614 FT_UShort* format,
00615 GXV_Validator valid )
00616 {
00617
00618 FT_Bool horizontal;
00619 FT_Bool minimum;
00620 FT_Bool cross_stream;
00621 FT_Bool override;
00622
00623 FT_UNUSED( valid );
00624
00625
00626
00627 if ( coverage & 0xFDF0 )
00628 return 0;
00629
00630 horizontal = FT_BOOL( coverage & 1 );
00631 minimum = FT_BOOL( ( coverage >> 1 ) & 1 );
00632 cross_stream = FT_BOOL( ( coverage >> 2 ) & 1 );
00633 override = FT_BOOL( ( coverage >> 3 ) & 1 );
00634
00635 *format = (FT_UShort)( ( coverage >> 8 ) & 0x0003 );
00636
00637 GXV_TRACE(( "classic Microsoft-dialect: "
00638 "horizontal=%d, minimum=%d, cross-stream=%d, "
00639 "override=%d, format=%d\n",
00640 horizontal, minimum, cross_stream, override, *format ));
00641
00642 if ( *format == 2 )
00643 GXV_TRACE((
00644 "kerning values in Microsoft format 2 subtable are ignored\n" ));
00645
00646 return 1;
00647 }
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658 static GXV_kern_Dialect
00659 gxv_kern_coverage_validate( FT_UShort coverage,
00660 FT_UShort* format,
00661 GXV_Validator valid )
00662 {
00663 GXV_kern_Dialect result = KERN_DIALECT_UNKNOWN;
00664
00665
00666 GXV_NAME_ENTER( "validating coverage" );
00667
00668 GXV_TRACE(( "interprete coverage 0x%04x by Apple style\n", coverage ));
00669
00670 if ( KERN_IS_NEW( valid ) )
00671 {
00672 if ( gxv_kern_coverage_new_apple_validate( coverage,
00673 format,
00674 valid ) )
00675 {
00676 result = KERN_DIALECT_APPLE;
00677 goto Exit;
00678 }
00679 }
00680
00681 if ( KERN_IS_CLASSIC( valid ) && KERN_ALLOWS_APPLE( valid ) )
00682 {
00683 if ( gxv_kern_coverage_classic_apple_validate( coverage,
00684 format,
00685 valid ) )
00686 {
00687 result = KERN_DIALECT_APPLE;
00688 goto Exit;
00689 }
00690 }
00691
00692 if ( KERN_IS_CLASSIC( valid ) && KERN_ALLOWS_MS( valid ) )
00693 {
00694 if ( gxv_kern_coverage_classic_microsoft_validate( coverage,
00695 format,
00696 valid ) )
00697 {
00698 result = KERN_DIALECT_MS;
00699 goto Exit;
00700 }
00701 }
00702
00703 GXV_TRACE(( "cannot interprete coverage, broken kern subtable\n" ));
00704
00705 Exit:
00706 GXV_EXIT;
00707 return result;
00708 }
00709
00710
00711 static void
00712 gxv_kern_subtable_validate( FT_Bytes table,
00713 FT_Bytes limit,
00714 GXV_Validator valid )
00715 {
00716 FT_Bytes p = table;
00717 FT_UShort version = 0;
00718 FT_ULong length;
00719 FT_UShort coverage;
00720 FT_UShort tupleIndex = 0;
00721 FT_UShort u16[2];
00722 FT_UShort format = 255;
00723
00724
00725 GXV_NAME_ENTER( "kern subtable" );
00726
00727 GXV_LIMIT_CHECK( 2 + 2 + 2 );
00728 u16[0] = FT_NEXT_USHORT( p );
00729 u16[1] = FT_NEXT_USHORT( p );
00730 coverage = FT_NEXT_USHORT( p );
00731
00732 switch ( gxv_kern_coverage_validate( coverage, &format, valid ) )
00733 {
00734 case KERN_DIALECT_MS:
00735 version = u16[0];
00736 length = u16[1];
00737 tupleIndex = 0;
00738 GXV_TRACE(( "Subtable version = %d\n", version ));
00739 GXV_TRACE(( "Subtable length = %d\n", length ));
00740 break;
00741
00742 case KERN_DIALECT_APPLE:
00743 version = 0;
00744 length = ( u16[0] << 16 ) + u16[1];
00745 tupleIndex = 0;
00746 GXV_TRACE(( "Subtable length = %d\n", length ));
00747
00748 if ( KERN_IS_NEW( valid ) )
00749 {
00750 GXV_LIMIT_CHECK( 2 );
00751 tupleIndex = FT_NEXT_USHORT( p );
00752 GXV_TRACE(( "Subtable tupleIndex = %d\n", tupleIndex ));
00753 }
00754 break;
00755
00756 default:
00757 length = u16[1];
00758 GXV_TRACE(( "cannot detect subtable dialect, "
00759 "just skip %d byte\n", length ));
00760 goto Exit;
00761 }
00762
00763
00764 if ( format == 0 )
00765 gxv_kern_subtable_fmt0_validate( table, table + length, valid );
00766 else if ( format == 1 )
00767 gxv_kern_subtable_fmt1_validate( table, table + length, valid );
00768 else if ( format == 2 )
00769 gxv_kern_subtable_fmt2_validate( table, table + length, valid );
00770 else if ( format == 3 )
00771 gxv_kern_subtable_fmt3_validate( table, table + length, valid );
00772 else
00773 FT_INVALID_DATA;
00774
00775 Exit:
00776 valid->subtable_length = length;
00777 GXV_EXIT;
00778 }
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789 static void
00790 gxv_kern_validate_generic( FT_Bytes table,
00791 FT_Face face,
00792 FT_Bool classic_only,
00793 GXV_kern_Dialect dialect_request,
00794 FT_Validator ftvalid )
00795 {
00796 GXV_ValidatorRec validrec;
00797 GXV_Validator valid = &validrec;
00798
00799 GXV_kern_DataRec kernrec;
00800 GXV_kern_Data kern = &kernrec;
00801
00802 FT_Bytes p = table;
00803 FT_Bytes limit = 0;
00804
00805 FT_ULong nTables = 0;
00806 FT_UInt i;
00807
00808
00809 valid->root = ftvalid;
00810 valid->table_data = kern;
00811 valid->face = face;
00812
00813 FT_TRACE3(( "validating `kern' table\n" ));
00814 GXV_INIT;
00815 KERN_DIALECT( valid ) = dialect_request;
00816
00817 GXV_LIMIT_CHECK( 2 );
00818 GXV_KERN_DATA( version ) = (GXV_kern_Version)FT_NEXT_USHORT( p );
00819 GXV_TRACE(( "version 0x%04x (higher 16bit)\n",
00820 GXV_KERN_DATA( version ) ));
00821
00822 if ( 0x0001 < GXV_KERN_DATA( version ) )
00823 FT_INVALID_FORMAT;
00824 else if ( KERN_IS_CLASSIC( valid ) )
00825 {
00826 GXV_LIMIT_CHECK( 2 );
00827 nTables = FT_NEXT_USHORT( p );
00828 }
00829 else if ( KERN_IS_NEW( valid ) )
00830 {
00831 if ( classic_only )
00832 FT_INVALID_FORMAT;
00833
00834 if ( 0x0000 != FT_NEXT_USHORT( p ) )
00835 FT_INVALID_FORMAT;
00836
00837 GXV_LIMIT_CHECK( 4 );
00838 nTables = FT_NEXT_ULONG( p );
00839 }
00840
00841 for ( i = 0; i < nTables; i++ )
00842 {
00843 GXV_TRACE(( "validating subtable %d/%d\n", i, nTables ));
00844
00845 gxv_kern_subtable_validate( p, 0, valid );
00846 p += valid->subtable_length;
00847 }
00848
00849 FT_TRACE4(( "\n" ));
00850 }
00851
00852
00853 FT_LOCAL_DEF( void )
00854 gxv_kern_validate( FT_Bytes table,
00855 FT_Face face,
00856 FT_Validator ftvalid )
00857 {
00858 gxv_kern_validate_generic( table, face, 0, KERN_DIALECT_ANY, ftvalid );
00859 }
00860
00861
00862 FT_LOCAL_DEF( void )
00863 gxv_kern_validate_classic( FT_Bytes table,
00864 FT_Face face,
00865 FT_Int dialect_flags,
00866 FT_Validator ftvalid )
00867 {
00868 GXV_kern_Dialect dialect_request;
00869
00870
00871 dialect_request = (GXV_kern_Dialect)dialect_flags;
00872 gxv_kern_validate_generic( table, face, 1, dialect_request, ftvalid );
00873 }
00874
00875
00876