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 "gxvcommn.h"
00029
00030
00031
00032
00033
00034
00035
00036
00037 #undef FT_COMPONENT
00038 #define FT_COMPONENT trace_gxvcommon
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 static int
00050 gxv_compare_ushort_offset( FT_UShort* a,
00051 FT_UShort* b )
00052 {
00053 if ( *a < *b )
00054 return -1;
00055 else if ( *a > *b )
00056 return 1;
00057 else
00058 return 0;
00059 }
00060
00061
00062 FT_LOCAL_DEF( void )
00063 gxv_set_length_by_ushort_offset( FT_UShort* offset,
00064 FT_UShort** length,
00065 FT_UShort* buff,
00066 FT_UInt nmemb,
00067 FT_UShort limit,
00068 GXV_Validator valid )
00069 {
00070 FT_UInt i;
00071
00072
00073 for ( i = 0; i < nmemb; i++ )
00074 *(length[i]) = 0;
00075
00076 for ( i = 0; i < nmemb; i++ )
00077 buff[i] = offset[i];
00078 buff[nmemb] = limit;
00079
00080 ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_UShort ),
00081 ( int(*)(const void*, const void*) )gxv_compare_ushort_offset );
00082
00083 if ( buff[nmemb] > limit )
00084 FT_INVALID_OFFSET;
00085
00086 for ( i = 0; i < nmemb; i++ )
00087 {
00088 FT_UInt j;
00089
00090
00091 for ( j = 0; j < nmemb; j++ )
00092 if ( buff[j] == offset[i] )
00093 break;
00094
00095 if ( j == nmemb )
00096 FT_INVALID_OFFSET;
00097
00098 *(length[i]) = (FT_UShort)( buff[j + 1] - buff[j] );
00099
00100 if ( 0 != offset[i] && 0 == *(length[i]) )
00101 FT_INVALID_OFFSET;
00102 }
00103 }
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114 static int
00115 gxv_compare_ulong_offset( FT_ULong* a,
00116 FT_ULong* b )
00117 {
00118 if ( *a < *b )
00119 return -1;
00120 else if ( *a > *b )
00121 return 1;
00122 else
00123 return 0;
00124 }
00125
00126
00127 FT_LOCAL_DEF( void )
00128 gxv_set_length_by_ulong_offset( FT_ULong* offset,
00129 FT_ULong** length,
00130 FT_ULong* buff,
00131 FT_UInt nmemb,
00132 FT_ULong limit,
00133 GXV_Validator valid)
00134 {
00135 FT_UInt i;
00136
00137
00138 for ( i = 0; i < nmemb; i++ )
00139 *(length[i]) = 0;
00140
00141 for ( i = 0; i < nmemb; i++ )
00142 buff[i] = offset[i];
00143 buff[nmemb] = limit;
00144
00145 ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_ULong ),
00146 ( int(*)(const void*, const void*) )gxv_compare_ulong_offset );
00147
00148 if ( buff[nmemb] > limit )
00149 FT_INVALID_OFFSET;
00150
00151 for ( i = 0; i < nmemb; i++ )
00152 {
00153 FT_UInt j;
00154
00155
00156 for ( j = 0; j < nmemb; j++ )
00157 if ( buff[j] == offset[i] )
00158 break;
00159
00160 if ( j == nmemb )
00161 FT_INVALID_OFFSET;
00162
00163 *(length[i]) = buff[j + 1] - buff[j];
00164
00165 if ( 0 != offset[i] && 0 == *(length[i]) )
00166 FT_INVALID_OFFSET;
00167 }
00168 }
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 FT_LOCAL_DEF( void )
00181 gxv_array_getlimits_byte( FT_Bytes table,
00182 FT_Bytes limit,
00183 FT_Byte* min,
00184 FT_Byte* max,
00185 GXV_Validator valid )
00186 {
00187 FT_Bytes p = table;
00188
00189
00190 *min = 0xFF;
00191 *max = 0x00;
00192
00193 while ( p < limit )
00194 {
00195 FT_Byte val;
00196
00197
00198 GXV_LIMIT_CHECK( 1 );
00199 val = FT_NEXT_BYTE( p );
00200
00201 *min = (FT_Byte)FT_MIN( *min, val );
00202 *max = (FT_Byte)FT_MAX( *max, val );
00203 }
00204
00205 valid->subtable_length = p - table;
00206 }
00207
00208
00209 FT_LOCAL_DEF( void )
00210 gxv_array_getlimits_ushort( FT_Bytes table,
00211 FT_Bytes limit,
00212 FT_UShort* min,
00213 FT_UShort* max,
00214 GXV_Validator valid )
00215 {
00216 FT_Bytes p = table;
00217
00218
00219 *min = 0xFFFFU;
00220 *max = 0x0000;
00221
00222 while ( p < limit )
00223 {
00224 FT_UShort val;
00225
00226
00227 GXV_LIMIT_CHECK( 2 );
00228 val = FT_NEXT_USHORT( p );
00229
00230 *min = (FT_Byte)FT_MIN( *min, val );
00231 *max = (FT_Byte)FT_MAX( *max, val );
00232 }
00233
00234 valid->subtable_length = p - table;
00235 }
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246 typedef struct GXV_BinSrchHeader_
00247 {
00248 FT_UShort unitSize;
00249 FT_UShort nUnits;
00250 FT_UShort searchRange;
00251 FT_UShort entrySelector;
00252 FT_UShort rangeShift;
00253
00254 } GXV_BinSrchHeader;
00255
00256
00257 static void
00258 gxv_BinSrchHeader_check_consistency( GXV_BinSrchHeader* binSrchHeader,
00259 GXV_Validator valid )
00260 {
00261 FT_UShort searchRange;
00262 FT_UShort entrySelector;
00263 FT_UShort rangeShift;
00264
00265
00266 if ( binSrchHeader->unitSize == 0 )
00267 FT_INVALID_DATA;
00268
00269 if ( binSrchHeader->nUnits == 0 )
00270 {
00271 if ( binSrchHeader->searchRange == 0 &&
00272 binSrchHeader->entrySelector == 0 &&
00273 binSrchHeader->rangeShift == 0 )
00274 return;
00275 else
00276 FT_INVALID_DATA;
00277 }
00278
00279 for ( searchRange = 1, entrySelector = 1;
00280 ( searchRange * 2 ) <= binSrchHeader->nUnits &&
00281 searchRange < 0x8000U;
00282 searchRange *= 2, entrySelector++ )
00283 ;
00284
00285 entrySelector--;
00286 searchRange = (FT_UShort)( searchRange * binSrchHeader->unitSize );
00287 rangeShift = (FT_UShort)( binSrchHeader->nUnits * binSrchHeader->unitSize
00288 - searchRange );
00289
00290 if ( searchRange != binSrchHeader->searchRange ||
00291 entrySelector != binSrchHeader->entrySelector ||
00292 rangeShift != binSrchHeader->rangeShift )
00293 {
00294 GXV_TRACE(( "Inconsistency found in BinSrchHeader\n" ));
00295 GXV_TRACE(( "originally: unitSize=%d, nUnits=%d, "
00296 "searchRange=%d, entrySelector=%d, "
00297 "rangeShift=%d\n",
00298 binSrchHeader->unitSize, binSrchHeader->nUnits,
00299 binSrchHeader->searchRange, binSrchHeader->entrySelector,
00300 binSrchHeader->rangeShift ));
00301 GXV_TRACE(( "calculated: unitSize=%d, nUnits=%d, "
00302 "searchRange=%d, entrySelector=%d, "
00303 "rangeShift=%d\n",
00304 binSrchHeader->unitSize, binSrchHeader->nUnits,
00305 searchRange, entrySelector, rangeShift ));
00306
00307 if ( valid->root->level >= FT_VALIDATE_PARANOID )
00308 FT_INVALID_DATA;
00309 }
00310 }
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328 FT_LOCAL_DEF( void )
00329 gxv_BinSrchHeader_validate( FT_Bytes table,
00330 FT_Bytes limit,
00331 FT_UShort* unitSize_p,
00332 FT_UShort* nUnits_p,
00333 GXV_Validator valid )
00334 {
00335 FT_Bytes p = table;
00336 GXV_BinSrchHeader binSrchHeader;
00337
00338
00339 GXV_NAME_ENTER( "BinSrchHeader validate" );
00340
00341 if ( *unitSize_p == 0 )
00342 {
00343 GXV_LIMIT_CHECK( 2 );
00344 binSrchHeader.unitSize = FT_NEXT_USHORT( p );
00345 }
00346 else
00347 binSrchHeader.unitSize = *unitSize_p;
00348
00349 if ( *nUnits_p == 0 )
00350 {
00351 GXV_LIMIT_CHECK( 2 );
00352 binSrchHeader.nUnits = FT_NEXT_USHORT( p );
00353 }
00354 else
00355 binSrchHeader.nUnits = *nUnits_p;
00356
00357 GXV_LIMIT_CHECK( 2 + 2 + 2 );
00358 binSrchHeader.searchRange = FT_NEXT_USHORT( p );
00359 binSrchHeader.entrySelector = FT_NEXT_USHORT( p );
00360 binSrchHeader.rangeShift = FT_NEXT_USHORT( p );
00361 GXV_TRACE(( "nUnits %d\n", binSrchHeader.nUnits ));
00362
00363 gxv_BinSrchHeader_check_consistency( &binSrchHeader, valid );
00364
00365 if ( *unitSize_p == 0 )
00366 *unitSize_p = binSrchHeader.unitSize;
00367
00368 if ( *nUnits_p == 0 )
00369 *nUnits_p = binSrchHeader.nUnits;
00370
00371 valid->subtable_length = p - table;
00372 GXV_EXIT;
00373 }
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384 #define GXV_LOOKUP_VALUE_LOAD( P, SIGNSPEC ) \
00385 ( P += 2, gxv_lookup_value_load( P - 2, SIGNSPEC ) )
00386
00387 static GXV_LookupValueDesc
00388 gxv_lookup_value_load( FT_Bytes p,
00389 int signspec )
00390 {
00391 GXV_LookupValueDesc v;
00392
00393
00394 if ( signspec == GXV_LOOKUPVALUE_UNSIGNED )
00395 v.u = FT_NEXT_USHORT( p );
00396 else
00397 v.s = FT_NEXT_SHORT( p );
00398
00399 return v;
00400 }
00401
00402
00403 #define GXV_UNITSIZE_VALIDATE( FORMAT, UNITSIZE, NUNITS, CORRECTSIZE ) \
00404 FT_BEGIN_STMNT \
00405 if ( UNITSIZE != CORRECTSIZE ) \
00406 { \
00407 FT_ERROR(( "unitSize=%d differs from" \
00408 " expected unitSize=%d" \
00409 " in LookupTable %s\n", \
00410 UNITSIZE, CORRECTSIZE, FORMAT )); \
00411 if ( UNITSIZE != 0 && NUNITS != 0 ) \
00412 { \
00413 FT_ERROR(( " cannot validate anymore\n" )); \
00414 FT_INVALID_FORMAT; \
00415 } \
00416 else \
00417 FT_ERROR(( " forcibly continues\n" )); \
00418 } \
00419 FT_END_STMNT
00420
00421
00422
00423 static void
00424 gxv_LookupTable_fmt0_validate( FT_Bytes table,
00425 FT_Bytes limit,
00426 GXV_Validator valid )
00427 {
00428 FT_Bytes p = table;
00429 FT_UShort i;
00430
00431 GXV_LookupValueDesc value;
00432
00433
00434 GXV_NAME_ENTER( "LookupTable format 0" );
00435
00436 GXV_LIMIT_CHECK( 2 * valid->face->num_glyphs );
00437
00438 for ( i = 0; i < valid->face->num_glyphs; i++ )
00439 {
00440 GXV_LIMIT_CHECK( 2 );
00441 if ( p + 2 >= limit )
00442 {
00443 GXV_TRACE(( "too short, glyphs %d - %d are missing\n",
00444 i, valid->face->num_glyphs ));
00445 if ( valid->root->level >= FT_VALIDATE_PARANOID )
00446 FT_INVALID_GLYPH_ID;
00447 break;
00448 }
00449
00450 value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign );
00451 valid->lookupval_func( i, &value, valid );
00452 }
00453
00454 valid->subtable_length = p - table;
00455 GXV_EXIT;
00456 }
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475 static void
00476 gxv_LookupTable_fmt2_skip_endmarkers( FT_Bytes table,
00477 FT_UShort unitSize,
00478 GXV_Validator valid )
00479 {
00480 FT_Bytes p = table;
00481
00482
00483 while ( ( p + 4 ) < valid->root->limit )
00484 {
00485 if ( p[0] != 0xFF || p[1] != 0xFF ||
00486 p[2] != 0xFF || p[3] != 0xFF )
00487 break;
00488 p += unitSize;
00489 }
00490
00491 valid->subtable_length = p - table;
00492 }
00493
00494
00495 static void
00496 gxv_LookupTable_fmt2_validate( FT_Bytes table,
00497 FT_Bytes limit,
00498 GXV_Validator valid )
00499 {
00500 FT_Bytes p = table;
00501 FT_UShort gid;
00502
00503 FT_UShort unitSize;
00504 FT_UShort nUnits;
00505 FT_UShort unit;
00506 FT_UShort lastGlyph;
00507 FT_UShort firstGlyph;
00508 GXV_LookupValueDesc value;
00509
00510
00511 GXV_NAME_ENTER( "LookupTable format 2" );
00512
00513 unitSize = nUnits = 0;
00514 gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, valid );
00515 p += valid->subtable_length;
00516
00517 GXV_UNITSIZE_VALIDATE( "format2", unitSize, nUnits, 6 );
00518
00519 for ( unit = 0, gid = 0; unit < nUnits; unit++ )
00520 {
00521 GXV_LIMIT_CHECK( 2 + 2 + 2 );
00522 lastGlyph = FT_NEXT_USHORT( p );
00523 firstGlyph = FT_NEXT_USHORT( p );
00524 value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign );
00525
00526 gxv_glyphid_validate( firstGlyph, valid );
00527 gxv_glyphid_validate( lastGlyph, valid );
00528
00529 if ( lastGlyph < gid )
00530 {
00531 GXV_TRACE(( "reverse ordered segment specification:"
00532 " lastGlyph[%d]=%d < lastGlyph[%d]=%d\n",
00533 unit, lastGlyph, unit - 1 , gid ));
00534 if ( valid->root->level >= FT_VALIDATE_PARANOID )
00535 FT_INVALID_GLYPH_ID;
00536 }
00537
00538 if ( lastGlyph < firstGlyph )
00539 {
00540 GXV_TRACE(( "reverse ordered range specification at unit %d:",
00541 " lastGlyph %d < firstGlyph %d ",
00542 unit, lastGlyph, firstGlyph ));
00543 if ( valid->root->level >= FT_VALIDATE_PARANOID )
00544 FT_INVALID_GLYPH_ID;
00545
00546 if ( valid->root->level == FT_VALIDATE_TIGHT )
00547 continue;
00548
00549 FT_TRACE4(( "continuing with exchanged values\n" ));
00550 gid = firstGlyph;
00551 firstGlyph = lastGlyph;
00552 lastGlyph = gid;
00553 }
00554
00555 for ( gid = firstGlyph; gid <= lastGlyph; gid++ )
00556 valid->lookupval_func( gid, &value, valid );
00557 }
00558
00559 gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, valid );
00560 p += valid->subtable_length;
00561
00562 valid->subtable_length = p - table;
00563 GXV_EXIT;
00564 }
00565
00566
00567
00568 static void
00569 gxv_LookupTable_fmt4_validate( FT_Bytes table,
00570 FT_Bytes limit,
00571 GXV_Validator valid )
00572 {
00573 FT_Bytes p = table;
00574 FT_UShort unit;
00575 FT_UShort gid;
00576
00577 FT_UShort unitSize;
00578 FT_UShort nUnits;
00579 FT_UShort lastGlyph;
00580 FT_UShort firstGlyph;
00581 GXV_LookupValueDesc base_value;
00582 GXV_LookupValueDesc value;
00583
00584
00585 GXV_NAME_ENTER( "LookupTable format 4" );
00586
00587 unitSize = nUnits = 0;
00588 gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, valid );
00589 p += valid->subtable_length;
00590
00591 GXV_UNITSIZE_VALIDATE( "format4", unitSize, nUnits, 6 );
00592
00593 for ( unit = 0, gid = 0; unit < nUnits; unit++ )
00594 {
00595 GXV_LIMIT_CHECK( 2 + 2 );
00596 lastGlyph = FT_NEXT_USHORT( p );
00597 firstGlyph = FT_NEXT_USHORT( p );
00598
00599 gxv_glyphid_validate( firstGlyph, valid );
00600 gxv_glyphid_validate( lastGlyph, valid );
00601
00602 if ( lastGlyph < gid )
00603 {
00604 GXV_TRACE(( "reverse ordered segment specification:"
00605 " lastGlyph[%d]=%d < lastGlyph[%d]=%d\n",
00606 unit, lastGlyph, unit - 1 , gid ));
00607 if ( valid->root->level >= FT_VALIDATE_PARANOID )
00608 FT_INVALID_GLYPH_ID;
00609 }
00610
00611 if ( lastGlyph < firstGlyph )
00612 {
00613 GXV_TRACE(( "reverse ordered range specification at unit %d:",
00614 " lastGlyph %d < firstGlyph %d ",
00615 unit, lastGlyph, firstGlyph ));
00616 if ( valid->root->level >= FT_VALIDATE_PARANOID )
00617 FT_INVALID_GLYPH_ID;
00618
00619 if ( valid->root->level == FT_VALIDATE_TIGHT )
00620 continue;
00621
00622 FT_TRACE4(( "continuing with exchanged values\n" ));
00623 gid = firstGlyph;
00624 firstGlyph = lastGlyph;
00625 lastGlyph = gid;
00626 }
00627
00628 GXV_LIMIT_CHECK( 2 );
00629 base_value = GXV_LOOKUP_VALUE_LOAD( p, GXV_LOOKUPVALUE_UNSIGNED );
00630
00631 for ( gid = firstGlyph; gid <= lastGlyph; gid++ )
00632 {
00633 value = valid->lookupfmt4_trans( (FT_UShort)( gid - firstGlyph ),
00634 &base_value,
00635 limit,
00636 valid );
00637
00638 valid->lookupval_func( gid, &value, valid );
00639 }
00640 }
00641
00642 gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, valid );
00643 p += valid->subtable_length;
00644
00645 valid->subtable_length = p - table;
00646 GXV_EXIT;
00647 }
00648
00649
00650
00651 static void
00652 gxv_LookupTable_fmt6_skip_endmarkers( FT_Bytes table,
00653 FT_UShort unitSize,
00654 GXV_Validator valid )
00655 {
00656 FT_Bytes p = table;
00657
00658
00659 while ( p < valid->root->limit )
00660 {
00661 if ( p[0] != 0xFF || p[1] != 0xFF )
00662 break;
00663 p += unitSize;
00664 }
00665
00666 valid->subtable_length = p - table;
00667 }
00668
00669
00670 static void
00671 gxv_LookupTable_fmt6_validate( FT_Bytes table,
00672 FT_Bytes limit,
00673 GXV_Validator valid )
00674 {
00675 FT_Bytes p = table;
00676 FT_UShort unit;
00677 FT_UShort prev_glyph;
00678
00679 FT_UShort unitSize;
00680 FT_UShort nUnits;
00681 FT_UShort glyph;
00682 GXV_LookupValueDesc value;
00683
00684
00685 GXV_NAME_ENTER( "LookupTable format 6" );
00686
00687 unitSize = nUnits = 0;
00688 gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, valid );
00689 p += valid->subtable_length;
00690
00691 GXV_UNITSIZE_VALIDATE( "format6", unitSize, nUnits, 4 );
00692
00693 for ( unit = 0, prev_glyph = 0; unit < nUnits; unit++ )
00694 {
00695 GXV_LIMIT_CHECK( 2 + 2 );
00696 glyph = FT_NEXT_USHORT( p );
00697 value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign );
00698
00699 if ( gxv_glyphid_validate( glyph, valid ) )
00700 GXV_TRACE(( " endmarker found within defined range"
00701 " (entry %d < nUnits=%d)\n",
00702 unit, nUnits ));
00703
00704 if ( prev_glyph > glyph )
00705 {
00706 GXV_TRACE(( "current gid 0x%04x < previous gid 0x%04x\n",
00707 glyph, prev_glyph ));
00708 if ( valid->root->level >= FT_VALIDATE_PARANOID )
00709 FT_INVALID_GLYPH_ID;
00710 }
00711 prev_glyph = glyph;
00712
00713 valid->lookupval_func( glyph, &value, valid );
00714 }
00715
00716 gxv_LookupTable_fmt6_skip_endmarkers( p, unitSize, valid );
00717 p += valid->subtable_length;
00718
00719 valid->subtable_length = p - table;
00720 GXV_EXIT;
00721 }
00722
00723
00724
00725 static void
00726 gxv_LookupTable_fmt8_validate( FT_Bytes table,
00727 FT_Bytes limit,
00728 GXV_Validator valid )
00729 {
00730 FT_Bytes p = table;
00731 FT_UShort i;
00732
00733 GXV_LookupValueDesc value;
00734 FT_UShort firstGlyph;
00735 FT_UShort glyphCount;
00736
00737
00738 GXV_NAME_ENTER( "LookupTable format 8" );
00739
00740
00741 GXV_LIMIT_CHECK( 2 + 2 );
00742 firstGlyph = FT_NEXT_USHORT( p );
00743 glyphCount = FT_NEXT_USHORT( p );
00744
00745 gxv_glyphid_validate( firstGlyph, valid );
00746 gxv_glyphid_validate( (FT_UShort)( firstGlyph + glyphCount ), valid );
00747
00748
00749 for ( i = 0; i < glyphCount; i++ )
00750 {
00751 GXV_LIMIT_CHECK( 2 );
00752 value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign );
00753 valid->lookupval_func( (FT_UShort)( firstGlyph + i ), &value, valid );
00754 }
00755
00756 valid->subtable_length = p - table;
00757 GXV_EXIT;
00758 }
00759
00760
00761 FT_LOCAL_DEF( void )
00762 gxv_LookupTable_validate( FT_Bytes table,
00763 FT_Bytes limit,
00764 GXV_Validator valid )
00765 {
00766 FT_Bytes p = table;
00767 FT_UShort format;
00768
00769 GXV_Validate_Func fmt_funcs_table[] =
00770 {
00771 gxv_LookupTable_fmt0_validate,
00772 NULL,
00773 gxv_LookupTable_fmt2_validate,
00774 NULL,
00775 gxv_LookupTable_fmt4_validate,
00776 NULL,
00777 gxv_LookupTable_fmt6_validate,
00778 NULL,
00779 gxv_LookupTable_fmt8_validate,
00780 };
00781
00782 GXV_Validate_Func func;
00783
00784
00785 GXV_NAME_ENTER( "LookupTable" );
00786
00787
00788 valid->lookuptbl_head = table;
00789
00790
00791 GXV_LIMIT_CHECK( 2 );
00792 format = FT_NEXT_USHORT( p );
00793 GXV_TRACE(( " (format %d)\n", format ));
00794
00795 if ( format > 8 )
00796 FT_INVALID_FORMAT;
00797
00798 func = fmt_funcs_table[format];
00799 if ( func == NULL )
00800 FT_INVALID_FORMAT;
00801
00802 func( p, limit, valid );
00803 p += valid->subtable_length;
00804
00805 valid->subtable_length = p - table;
00806
00807 GXV_EXIT;
00808 }
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819 FT_LOCAL_DEF( FT_Int )
00820 gxv_glyphid_validate( FT_UShort gid,
00821 GXV_Validator valid )
00822 {
00823 FT_Face face;
00824
00825
00826 if ( gid == 0xFFFFU )
00827 {
00828 GXV_EXIT;
00829 return 1;
00830 }
00831
00832 face = valid->face;
00833 if ( face->num_glyphs < gid )
00834 {
00835 GXV_TRACE(( " gxv_glyphid_check() gid overflow: num_glyphs %d < %d\n",
00836 face->num_glyphs, gid ));
00837 if ( valid->root->level >= FT_VALIDATE_PARANOID )
00838 FT_INVALID_GLYPH_ID;
00839 }
00840
00841 return 0;
00842 }
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853 FT_LOCAL_DEF( void )
00854 gxv_ctlPoint_validate( FT_UShort gid,
00855 FT_Short ctl_point,
00856 GXV_Validator valid )
00857 {
00858 FT_Face face;
00859 FT_Error error;
00860
00861 FT_GlyphSlot glyph;
00862 FT_Outline outline;
00863 short n_points;
00864
00865
00866 face = valid->face;
00867
00868 error = FT_Load_Glyph( face,
00869 gid,
00870 FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM );
00871 if ( error )
00872 FT_INVALID_GLYPH_ID;
00873
00874 glyph = face->glyph;
00875 outline = glyph->outline;
00876 n_points = outline.n_points;
00877
00878
00879 if ( !( ctl_point < n_points ) )
00880 FT_INVALID_DATA;
00881 }
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892 FT_LOCAL_DEF( void )
00893 gxv_sfntName_validate( FT_UShort name_index,
00894 FT_UShort min_index,
00895 FT_UShort max_index,
00896 GXV_Validator valid )
00897 {
00898 FT_SfntName name;
00899 FT_UInt i;
00900 FT_UInt nnames;
00901
00902
00903 GXV_NAME_ENTER( "sfntName" );
00904
00905 if ( name_index < min_index || max_index < name_index )
00906 FT_INVALID_FORMAT;
00907
00908 nnames = FT_Get_Sfnt_Name_Count( valid->face );
00909 for ( i = 0; i < nnames; i++ )
00910 {
00911 if ( FT_Get_Sfnt_Name( valid->face, i, &name ) != FT_Err_Ok )
00912 continue ;
00913
00914 if ( name.name_id == name_index )
00915 goto Out;
00916 }
00917
00918 GXV_TRACE(( " nameIndex = %d (UNTITLED)\n", name_index ));
00919 FT_INVALID_DATA;
00920 goto Exit;
00921
00922 Out:
00923 FT_TRACE1(( " nameIndex = %d (", name_index ));
00924 GXV_TRACE_HEXDUMP_SFNTNAME( name );
00925 FT_TRACE1(( ")\n" ));
00926
00927 Exit:
00928 GXV_EXIT;
00929 }
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950 static void
00951 gxv_ClassTable_validate( FT_Bytes table,
00952 FT_UShort* length_p,
00953 FT_UShort stateSize,
00954 FT_Byte* maxClassID_p,
00955 GXV_Validator valid )
00956 {
00957 FT_Bytes p = table;
00958 FT_Bytes limit = table + *length_p;
00959 FT_UShort firstGlyph;
00960 FT_UShort nGlyphs;
00961
00962
00963 GXV_NAME_ENTER( "ClassTable" );
00964
00965 *maxClassID_p = 3;
00966
00967 GXV_LIMIT_CHECK( 2 + 2 );
00968 firstGlyph = FT_NEXT_USHORT( p );
00969 nGlyphs = FT_NEXT_USHORT( p );
00970
00971 GXV_TRACE(( " (firstGlyph = %d, nGlyphs = %d)\n", firstGlyph, nGlyphs ));
00972
00973 if ( !nGlyphs )
00974 goto Out;
00975
00976 gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs ), valid );
00977
00978 {
00979 FT_Byte nGlyphInClass[256];
00980 FT_Byte classID;
00981 FT_UShort i;
00982
00983
00984 ft_memset( nGlyphInClass, 0, 256 );
00985
00986
00987 for ( i = 0; i < nGlyphs; i++ )
00988 {
00989 GXV_LIMIT_CHECK( 1 );
00990 classID = FT_NEXT_BYTE( p );
00991 switch ( classID )
00992 {
00993
00994 case 0:
00995 case 2:
00996 case 3:
00997 FT_INVALID_DATA;
00998 break;
00999
01000 case 1:
01001 default:
01002 if ( classID >= stateSize )
01003 FT_INVALID_DATA;
01004
01005 nGlyphInClass[classID]++;
01006 break;
01007 }
01008 }
01009 *length_p = (FT_UShort)( p - table );
01010
01011
01012 for ( i = 0; i < stateSize; i++ )
01013 if ( ( 3 < i ) && ( nGlyphInClass[i] > 0 ) )
01014 *maxClassID_p = (FT_Byte)i;
01015 }
01016
01017 Out:
01018 GXV_TRACE(( "Declared stateSize=0x%02x, Used maxClassID=0x%02x\n",
01019 stateSize, *maxClassID_p ));
01020 GXV_EXIT;
01021 }
01022
01023
01024
01025
01026 static void
01027 gxv_StateArray_validate( FT_Bytes table,
01028 FT_UShort* length_p,
01029 FT_Byte maxClassID,
01030 FT_UShort stateSize,
01031 FT_Byte* maxState_p,
01032 FT_Byte* maxEntry_p,
01033 GXV_Validator valid )
01034 {
01035 FT_Bytes p = table;
01036 FT_Bytes limit = table + *length_p;
01037 FT_Byte clazz;
01038 FT_Byte entry;
01039
01040 FT_UNUSED( stateSize );
01041
01042
01043 GXV_NAME_ENTER( "StateArray" );
01044
01045 GXV_TRACE(( "parse %d bytes by stateSize=%d maxClassID=%d\n",
01046 (int)(*length_p), stateSize, (int)(maxClassID) ));
01047
01048
01049
01050
01051
01052 GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 );
01053
01054 *maxState_p = 0;
01055 *maxEntry_p = 0;
01056
01057
01058 while ( p + ( 1 + maxClassID ) <= limit )
01059 {
01060 (*maxState_p)++;
01061 for ( clazz = 0; clazz <= maxClassID; clazz++ )
01062 {
01063 entry = FT_NEXT_BYTE( p );
01064 *maxEntry_p = (FT_Byte)FT_MAX( *maxEntry_p, entry );
01065 }
01066 }
01067 GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n",
01068 *maxState_p, *maxEntry_p ));
01069
01070 *length_p = (FT_UShort)( p - table );
01071
01072 GXV_EXIT;
01073 }
01074
01075
01076
01077
01078 static void
01079 gxv_EntryTable_validate( FT_Bytes table,
01080 FT_UShort* length_p,
01081 FT_Byte maxEntry,
01082 FT_UShort stateArray,
01083 FT_UShort stateArray_length,
01084 FT_Byte maxClassID,
01085 FT_Bytes statetable_table,
01086 FT_Bytes statetable_limit,
01087 GXV_Validator valid )
01088 {
01089 FT_Bytes p = table;
01090 FT_Bytes limit = table + *length_p;
01091 FT_Byte entry;
01092 FT_Byte state;
01093 FT_Int entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( statetable );
01094
01095 GXV_XStateTable_GlyphOffsetDesc glyphOffset;
01096
01097
01098 GXV_NAME_ENTER( "EntryTable" );
01099
01100 GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize ));
01101
01102 if ( ( maxEntry + 1 ) * entrySize > *length_p )
01103 {
01104 if ( valid->root->level >= FT_VALIDATE_PARANOID )
01105 FT_INVALID_TOO_SHORT;
01106
01107
01108 maxEntry = (FT_Byte)( *length_p / entrySize - 1 );
01109 GXV_TRACE(( "too large maxEntry, shrinking to %d fit EntryTable length\n",
01110 maxEntry ));
01111 }
01112
01113 for ( entry = 0; entry <= maxEntry; entry++ )
01114 {
01115 FT_UShort newState;
01116 FT_UShort flags;
01117
01118
01119 GXV_LIMIT_CHECK( 2 + 2 );
01120 newState = FT_NEXT_USHORT( p );
01121 flags = FT_NEXT_USHORT( p );
01122
01123
01124 if ( newState < stateArray ||
01125 stateArray + stateArray_length < newState )
01126 {
01127 GXV_TRACE(( " newState offset 0x%04x is out of stateArray\n",
01128 newState ));
01129 if ( valid->root->level >= FT_VALIDATE_PARANOID )
01130 FT_INVALID_OFFSET;
01131 continue;
01132 }
01133
01134 if ( 0 != ( ( newState - stateArray ) % ( 1 + maxClassID ) ) )
01135 {
01136 GXV_TRACE(( " newState offset 0x%04x is not aligned to %d-classes\n",
01137 newState, 1 + maxClassID ));
01138 if ( valid->root->level >= FT_VALIDATE_PARANOID )
01139 FT_INVALID_OFFSET;
01140 continue;
01141 }
01142
01143 state = (FT_Byte)( ( newState - stateArray ) / ( 1 + maxClassID ) );
01144
01145 switch ( GXV_GLYPHOFFSET_FMT( statetable ) )
01146 {
01147 case GXV_GLYPHOFFSET_NONE:
01148 glyphOffset.uc = 0;
01149 break;
01150
01151 case GXV_GLYPHOFFSET_UCHAR:
01152 glyphOffset.uc = FT_NEXT_BYTE( p );
01153 break;
01154
01155 case GXV_GLYPHOFFSET_CHAR:
01156 glyphOffset.c = FT_NEXT_CHAR( p );
01157 break;
01158
01159 case GXV_GLYPHOFFSET_USHORT:
01160 glyphOffset.u = FT_NEXT_USHORT( p );
01161 break;
01162
01163 case GXV_GLYPHOFFSET_SHORT:
01164 glyphOffset.s = FT_NEXT_SHORT( p );
01165 break;
01166
01167 case GXV_GLYPHOFFSET_ULONG:
01168 glyphOffset.ul = FT_NEXT_ULONG( p );
01169 break;
01170
01171 case GXV_GLYPHOFFSET_LONG:
01172 glyphOffset.l = FT_NEXT_LONG( p );
01173 break;
01174
01175 default:
01176 if ( valid->root->level >= FT_VALIDATE_PARANOID )
01177 FT_INVALID_FORMAT;
01178 goto Exit;
01179 }
01180
01181 if ( NULL != valid->statetable.entry_validate_func )
01182 valid->statetable.entry_validate_func( state,
01183 flags,
01184 &glyphOffset,
01185 statetable_table,
01186 statetable_limit,
01187 valid );
01188 }
01189
01190 Exit:
01191 *length_p = (FT_UShort)( p - table );
01192
01193 GXV_EXIT;
01194 }
01195
01196
01197
01198
01199 FT_LOCAL_DEF( void )
01200 gxv_StateTable_subtable_setup( FT_UShort table_size,
01201 FT_UShort classTable,
01202 FT_UShort stateArray,
01203 FT_UShort entryTable,
01204 FT_UShort* classTable_length_p,
01205 FT_UShort* stateArray_length_p,
01206 FT_UShort* entryTable_length_p,
01207 GXV_Validator valid )
01208 {
01209 FT_UShort o[3];
01210 FT_UShort* l[3];
01211 FT_UShort buff[4];
01212
01213
01214 o[0] = classTable;
01215 o[1] = stateArray;
01216 o[2] = entryTable;
01217 l[0] = classTable_length_p;
01218 l[1] = stateArray_length_p;
01219 l[2] = entryTable_length_p;
01220
01221 gxv_set_length_by_ushort_offset( o, l, buff, 3, table_size, valid );
01222 }
01223
01224
01225 FT_LOCAL_DEF( void )
01226 gxv_StateTable_validate( FT_Bytes table,
01227 FT_Bytes limit,
01228 GXV_Validator valid )
01229 {
01230 FT_UShort stateSize;
01231 FT_UShort classTable;
01232 FT_UShort stateArray;
01233 FT_UShort entryTable;
01234
01235 FT_UShort classTable_length;
01236 FT_UShort stateArray_length;
01237 FT_UShort entryTable_length;
01238 FT_Byte maxClassID;
01239 FT_Byte maxState;
01240 FT_Byte maxEntry;
01241
01242 GXV_StateTable_Subtable_Setup_Func setup_func;
01243
01244 FT_Bytes p = table;
01245
01246
01247 GXV_NAME_ENTER( "StateTable" );
01248
01249 GXV_TRACE(( "StateTable header\n" ));
01250
01251 GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
01252 stateSize = FT_NEXT_USHORT( p );
01253 classTable = FT_NEXT_USHORT( p );
01254 stateArray = FT_NEXT_USHORT( p );
01255 entryTable = FT_NEXT_USHORT( p );
01256
01257 GXV_TRACE(( "stateSize=0x%04x\n", stateSize ));
01258 GXV_TRACE(( "offset to classTable=0x%04x\n", classTable ));
01259 GXV_TRACE(( "offset to stateArray=0x%04x\n", stateArray ));
01260 GXV_TRACE(( "offset to entryTable=0x%04x\n", entryTable ));
01261
01262 if ( stateSize > 0xFF )
01263 FT_INVALID_DATA;
01264
01265 if ( valid->statetable.optdata_load_func != NULL )
01266 valid->statetable.optdata_load_func( p, limit, valid );
01267
01268 if ( valid->statetable.subtable_setup_func != NULL)
01269 setup_func = valid->statetable.subtable_setup_func;
01270 else
01271 setup_func = gxv_StateTable_subtable_setup;
01272
01273 setup_func( (FT_UShort)( limit - table ),
01274 classTable,
01275 stateArray,
01276 entryTable,
01277 &classTable_length,
01278 &stateArray_length,
01279 &entryTable_length,
01280 valid );
01281
01282 GXV_TRACE(( "StateTable Subtables\n" ));
01283
01284 if ( classTable != 0 )
01285 gxv_ClassTable_validate( table + classTable,
01286 &classTable_length,
01287 stateSize,
01288 &maxClassID,
01289 valid );
01290 else
01291 maxClassID = (FT_Byte)( stateSize - 1 );
01292
01293 if ( stateArray != 0 )
01294 gxv_StateArray_validate( table + stateArray,
01295 &stateArray_length,
01296 maxClassID,
01297 stateSize,
01298 &maxState,
01299 &maxEntry,
01300 valid );
01301 else
01302 {
01303 maxState = 1;
01304 maxEntry = 0;
01305 }
01306
01307 if ( maxEntry > 0 && entryTable == 0 )
01308 FT_INVALID_OFFSET;
01309
01310 if ( entryTable != 0 )
01311 gxv_EntryTable_validate( table + entryTable,
01312 &entryTable_length,
01313 maxEntry,
01314 stateArray,
01315 stateArray_length,
01316 maxClassID,
01317 table,
01318 limit,
01319 valid );
01320
01321 GXV_EXIT;
01322 }
01323
01324
01325
01326
01327 FT_LOCAL_DEF( void )
01328 gxv_XStateTable_subtable_setup( FT_ULong table_size,
01329 FT_ULong classTable,
01330 FT_ULong stateArray,
01331 FT_ULong entryTable,
01332 FT_ULong* classTable_length_p,
01333 FT_ULong* stateArray_length_p,
01334 FT_ULong* entryTable_length_p,
01335 GXV_Validator valid )
01336 {
01337 FT_ULong o[3];
01338 FT_ULong* l[3];
01339 FT_ULong buff[4];
01340
01341
01342 o[0] = classTable;
01343 o[1] = stateArray;
01344 o[2] = entryTable;
01345 l[0] = classTable_length_p;
01346 l[1] = stateArray_length_p;
01347 l[2] = entryTable_length_p;
01348
01349 gxv_set_length_by_ulong_offset( o, l, buff, 4, table_size, valid );
01350 }
01351
01352
01353 static void
01354 gxv_XClassTable_lookupval_validate( FT_UShort glyph,
01355 GXV_LookupValueCPtr value_p,
01356 GXV_Validator valid )
01357 {
01358 FT_UNUSED( glyph );
01359
01360 if ( value_p->u >= valid->xstatetable.nClasses )
01361 FT_INVALID_DATA;
01362 if ( value_p->u > valid->xstatetable.maxClassID )
01363 valid->xstatetable.maxClassID = value_p->u;
01364 }
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393 static GXV_LookupValueDesc
01394 gxv_XClassTable_lookupfmt4_transit( FT_UShort relative_gindex,
01395 GXV_LookupValueCPtr base_value_p,
01396 FT_Bytes lookuptbl_limit,
01397 GXV_Validator valid )
01398 {
01399 FT_Bytes p;
01400 FT_Bytes limit;
01401 FT_UShort offset;
01402 GXV_LookupValueDesc value;
01403
01404
01405 offset = (FT_UShort)( base_value_p->u +
01406 relative_gindex * sizeof ( FT_UShort ) );
01407
01408 p = valid->lookuptbl_head + offset;
01409 limit = lookuptbl_limit;
01410
01411 GXV_LIMIT_CHECK ( 2 );
01412 value.u = FT_NEXT_USHORT( p );
01413
01414 return value;
01415 }
01416
01417
01418 static void
01419 gxv_XStateArray_validate( FT_Bytes table,
01420 FT_ULong* length_p,
01421 FT_UShort maxClassID,
01422 FT_ULong stateSize,
01423 FT_UShort* maxState_p,
01424 FT_UShort* maxEntry_p,
01425 GXV_Validator valid )
01426 {
01427 FT_Bytes p = table;
01428 FT_Bytes limit = table + *length_p;
01429 FT_UShort clazz;
01430 FT_UShort entry;
01431
01432 FT_UNUSED( stateSize );
01433
01434
01435 GXV_NAME_ENTER( "XStateArray" );
01436
01437 GXV_TRACE(( "parse % 3d bytes by stateSize=% 3d maxClassID=% 3d\n",
01438 (int)(*length_p), stateSize, (int)(maxClassID) ));
01439
01440
01441
01442
01443
01444 GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 * 2 );
01445
01446 *maxState_p = 0;
01447 *maxEntry_p = 0;
01448
01449
01450 while ( p + ( ( 1 + maxClassID ) * 2 ) <= limit )
01451 {
01452 (*maxState_p)++;
01453 for ( clazz = 0; clazz <= maxClassID; clazz++ )
01454 {
01455 entry = FT_NEXT_USHORT( p );
01456 *maxEntry_p = (FT_UShort)FT_MAX( *maxEntry_p, entry );
01457 }
01458 }
01459 GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n",
01460 *maxState_p, *maxEntry_p ));
01461
01462 *length_p = p - table;
01463
01464 GXV_EXIT;
01465 }
01466
01467
01468 static void
01469 gxv_XEntryTable_validate( FT_Bytes table,
01470 FT_ULong* length_p,
01471 FT_UShort maxEntry,
01472 FT_ULong stateArray_length,
01473 FT_UShort maxClassID,
01474 FT_Bytes xstatetable_table,
01475 FT_Bytes xstatetable_limit,
01476 GXV_Validator valid )
01477 {
01478 FT_Bytes p = table;
01479 FT_Bytes limit = table + *length_p;
01480 FT_UShort entry;
01481 FT_UShort state;
01482 FT_Int entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( xstatetable );
01483
01484
01485 GXV_NAME_ENTER( "XEntryTable" );
01486 GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize ));
01487
01488 if ( ( p + ( maxEntry + 1 ) * entrySize ) > limit )
01489 FT_INVALID_TOO_SHORT;
01490
01491 for (entry = 0; entry <= maxEntry ; entry++ )
01492 {
01493 FT_UShort newState_idx;
01494 FT_UShort flags;
01495 GXV_XStateTable_GlyphOffsetDesc glyphOffset;
01496
01497
01498 GXV_LIMIT_CHECK( 2 + 2 );
01499 newState_idx = FT_NEXT_USHORT( p );
01500 flags = FT_NEXT_USHORT( p );
01501
01502 if ( stateArray_length < (FT_ULong)( newState_idx * 2 ) )
01503 {
01504 GXV_TRACE(( " newState index 0x%04x points out of stateArray\n",
01505 newState_idx ));
01506 if ( valid->root->level >= FT_VALIDATE_PARANOID )
01507 FT_INVALID_OFFSET;
01508 }
01509
01510 state = (FT_UShort)( newState_idx / ( 1 + maxClassID ) );
01511 if ( 0 != ( newState_idx % ( 1 + maxClassID ) ) )
01512 {
01513 FT_TRACE4(( "-> new state = %d (supposed)\n"
01514 "but newState index 0x%04x is not aligned to %d-classes\n",
01515 state, newState_idx, 1 + maxClassID ));
01516 if ( valid->root->level >= FT_VALIDATE_PARANOID )
01517 FT_INVALID_OFFSET;
01518 }
01519
01520 switch ( GXV_GLYPHOFFSET_FMT( xstatetable ) )
01521 {
01522 case GXV_GLYPHOFFSET_NONE:
01523 glyphOffset.uc = 0;
01524 break;
01525
01526 case GXV_GLYPHOFFSET_UCHAR:
01527 glyphOffset.uc = FT_NEXT_BYTE( p );
01528 break;
01529
01530 case GXV_GLYPHOFFSET_CHAR:
01531 glyphOffset.c = FT_NEXT_CHAR( p );
01532 break;
01533
01534 case GXV_GLYPHOFFSET_USHORT:
01535 glyphOffset.u = FT_NEXT_USHORT( p );
01536 break;
01537
01538 case GXV_GLYPHOFFSET_SHORT:
01539 glyphOffset.s = FT_NEXT_SHORT( p );
01540 break;
01541
01542 case GXV_GLYPHOFFSET_ULONG:
01543 glyphOffset.ul = FT_NEXT_ULONG( p );
01544 break;
01545
01546 case GXV_GLYPHOFFSET_LONG:
01547 glyphOffset.l = FT_NEXT_LONG( p );
01548 break;
01549
01550 default:
01551 if ( valid->root->level >= FT_VALIDATE_PARANOID )
01552 FT_INVALID_FORMAT;
01553 goto Exit;
01554 }
01555
01556 if ( NULL != valid->xstatetable.entry_validate_func )
01557 valid->xstatetable.entry_validate_func( state,
01558 flags,
01559 &glyphOffset,
01560 xstatetable_table,
01561 xstatetable_limit,
01562 valid );
01563 }
01564
01565 Exit:
01566 *length_p = p - table;
01567
01568 GXV_EXIT;
01569 }
01570
01571
01572 FT_LOCAL_DEF( void )
01573 gxv_XStateTable_validate( FT_Bytes table,
01574 FT_Bytes limit,
01575 GXV_Validator valid )
01576 {
01577
01578 FT_ULong classTable;
01579 FT_ULong stateArray;
01580 FT_ULong entryTable;
01581
01582 FT_ULong classTable_length;
01583 FT_ULong stateArray_length;
01584 FT_ULong entryTable_length;
01585 FT_UShort maxState;
01586 FT_UShort maxEntry;
01587
01588 GXV_XStateTable_Subtable_Setup_Func setup_func;
01589
01590 FT_Bytes p = table;
01591
01592
01593 GXV_NAME_ENTER( "XStateTable" );
01594
01595 GXV_TRACE(( "XStateTable header\n" ));
01596
01597 GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 );
01598 valid->xstatetable.nClasses = FT_NEXT_ULONG( p );
01599 classTable = FT_NEXT_ULONG( p );
01600 stateArray = FT_NEXT_ULONG( p );
01601 entryTable = FT_NEXT_ULONG( p );
01602
01603 GXV_TRACE(( "nClasses =0x%08x\n", valid->xstatetable.nClasses ));
01604 GXV_TRACE(( "offset to classTable=0x%08x\n", classTable ));
01605 GXV_TRACE(( "offset to stateArray=0x%08x\n", stateArray ));
01606 GXV_TRACE(( "offset to entryTable=0x%08x\n", entryTable ));
01607
01608 if ( valid->xstatetable.nClasses > 0xFFFFU )
01609 FT_INVALID_DATA;
01610
01611 GXV_TRACE(( "StateTable Subtables\n" ));
01612
01613 if ( valid->xstatetable.optdata_load_func != NULL )
01614 valid->xstatetable.optdata_load_func( p, limit, valid );
01615
01616 if ( valid->xstatetable.subtable_setup_func != NULL )
01617 setup_func = valid->xstatetable.subtable_setup_func;
01618 else
01619 setup_func = gxv_XStateTable_subtable_setup;
01620
01621 setup_func( limit - table,
01622 classTable,
01623 stateArray,
01624 entryTable,
01625 &classTable_length,
01626 &stateArray_length,
01627 &entryTable_length,
01628 valid );
01629
01630 if ( classTable != 0 )
01631 {
01632 valid->xstatetable.maxClassID = 0;
01633 valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED;
01634 valid->lookupval_func = gxv_XClassTable_lookupval_validate;
01635 valid->lookupfmt4_trans = gxv_XClassTable_lookupfmt4_transit;
01636 gxv_LookupTable_validate( table + classTable,
01637 table + classTable + classTable_length,
01638 valid );
01639 if ( valid->subtable_length < classTable_length )
01640 classTable_length = valid->subtable_length;
01641 }
01642 else
01643 {
01644
01645 valid->xstatetable.maxClassID =
01646 (FT_UShort)( valid->xstatetable.nClasses - 1 );
01647 }
01648
01649 if ( stateArray != 0 )
01650 gxv_XStateArray_validate( table + stateArray,
01651 &stateArray_length,
01652 valid->xstatetable.maxClassID,
01653 valid->xstatetable.nClasses,
01654 &maxState,
01655 &maxEntry,
01656 valid );
01657 else
01658 {
01659 maxState = 1;
01660 maxEntry = 0;
01661 }
01662
01663 if ( maxEntry > 0 && entryTable == 0 )
01664 FT_INVALID_OFFSET;
01665
01666 if ( entryTable != 0 )
01667 gxv_XEntryTable_validate( table + entryTable,
01668 &entryTable_length,
01669 maxEntry,
01670 stateArray_length,
01671 valid->xstatetable.maxClassID,
01672 table,
01673 limit,
01674 valid );
01675
01676 GXV_EXIT;
01677 }
01678
01679
01680
01681
01682
01683
01684
01685
01686
01687
01688 static int
01689 gxv_compare_ranges( FT_Bytes table1_start,
01690 FT_ULong table1_length,
01691 FT_Bytes table2_start,
01692 FT_ULong table2_length )
01693 {
01694 if ( table1_start == table2_start )
01695 {
01696 if ( ( table1_length == 0 || table2_length == 0 ) )
01697 goto Out;
01698 }
01699 else if ( table1_start < table2_start )
01700 {
01701 if ( ( table1_start + table1_length ) <= table2_start )
01702 goto Out;
01703 }
01704 else if ( table1_start > table2_start )
01705 {
01706 if ( ( table1_start >= table2_start + table2_length ) )
01707 goto Out;
01708 }
01709 return 1;
01710
01711 Out:
01712 return 0;
01713 }
01714
01715
01716 FT_LOCAL_DEF( void )
01717 gxv_odtect_add_range( FT_Bytes start,
01718 FT_ULong length,
01719 const FT_String* name,
01720 GXV_odtect_Range odtect )
01721 {
01722 odtect->range[ odtect->nRanges ].start = start;
01723 odtect->range[ odtect->nRanges ].length = length;
01724 odtect->range[ odtect->nRanges ].name = (FT_String*)name;
01725 odtect->nRanges++;
01726 }
01727
01728
01729 FT_LOCAL_DEF( void )
01730 gxv_odtect_validate( GXV_odtect_Range odtect,
01731 GXV_Validator valid )
01732 {
01733 FT_UInt i, j;
01734
01735
01736 GXV_NAME_ENTER( "check overlap among multi ranges" );
01737
01738 for ( i = 0; i < odtect->nRanges; i++ )
01739 for ( j = 0; j < i; j++ )
01740 if ( 0 != gxv_compare_ranges( odtect->range[i].start,
01741 odtect->range[i].length,
01742 odtect->range[j].start,
01743 odtect->range[j].length ) )
01744 {
01745 if ( odtect->range[i].name || odtect->range[j].name )
01746 GXV_TRACE(( "found overlap between range %d and range %d\n",
01747 i, j ));
01748 else
01749 GXV_TRACE(( "found overlap between `%s' and `%s\'\n",
01750 odtect->range[i].name,
01751 odtect->range[j].name ));
01752 FT_INVALID_OFFSET;
01753 }
01754
01755 GXV_EXIT;
01756 }
01757
01758
01759