Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygengxvcommn.c
Go to the documentation of this file.
00001 /***************************************************************************/ 00002 /* */ 00003 /* gxvcommn.c */ 00004 /* */ 00005 /* TrueTypeGX/AAT common tables validation (body). */ 00006 /* */ 00007 /* Copyright 2004, 2005, 2009, 2010 */ 00008 /* by suzuki toshiya, Masatake YAMATO, Red Hat K.K., */ 00009 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 00010 /* */ 00011 /* This file is part of the FreeType project, and may only be used, */ 00012 /* modified, and distributed under the terms of the FreeType project */ 00013 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 00014 /* this file you indicate that you have read the license and */ 00015 /* understand and accept it fully. */ 00016 /* */ 00017 /***************************************************************************/ 00018 00019 /***************************************************************************/ 00020 /* */ 00021 /* gxvalid is derived from both gxlayout module and otvalid module. */ 00022 /* Development of gxlayout is supported by the Information-technology */ 00023 /* Promotion Agency(IPA), Japan. */ 00024 /* */ 00025 /***************************************************************************/ 00026 00027 00028 #include "gxvcommn.h" 00029 00030 00031 /*************************************************************************/ 00032 /* */ 00033 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 00034 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 00035 /* messages during execution. */ 00036 /* */ 00037 #undef FT_COMPONENT 00038 #define FT_COMPONENT trace_gxvcommon 00039 00040 00041 /*************************************************************************/ 00042 /*************************************************************************/ 00043 /***** *****/ 00044 /***** 16bit offset sorter *****/ 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 /***** 32bit offset sorter *****/ 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 /***** scan value array and get min & max *****/ 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 /***** BINSEARCHHEADER *****/ 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 * parser & validator of BinSrchHeader 00315 * which is used in LookupTable format 2, 4, 6. 00316 * 00317 * Essential parameters (unitSize, nUnits) are returned by 00318 * given pointer, others (searchRange, entrySelector, rangeShift) 00319 * can be calculated by essential parameters, so they are just 00320 * validated and discarded. 00321 * 00322 * However, wrong values in searchRange, entrySelector, rangeShift 00323 * won't cause fatal errors, because these parameters might be 00324 * only used in old m68k font driver in MacOS. 00325 * -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp> 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 /***** LOOKUP TABLE *****/ 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 /* ================= Simple Array Format 0 Lookup Table ================ */ 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 ) /* some fonts have too-short fmt0 array */ 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 /* ================= Segment Single Format 2 Loolup Table ============== */ 00460 /* 00461 * Apple spec says: 00462 * 00463 * To guarantee that a binary search terminates, you must include one or 00464 * more special `end of search table' values at the end of the data to 00465 * be searched. The number of termination values that need to be 00466 * included is table-specific. The value that indicates binary search 00467 * termination is 0xFFFF. 00468 * 00469 * The problem is that nUnits does not include this end-marker. It's 00470 * quite difficult to discriminate whether the following 0xFFFF comes from 00471 * the end-marker or some next data. 00472 * 00473 * -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp> 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 || /* lastGlyph */ 00486 p[2] != 0xFF || p[3] != 0xFF ) /* firstGlyph */ 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; /* ftxvalidator silently skips such an entry */ 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 /* ================= Segment Array Format 4 Lookup Table =============== */ 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; /* ftxvalidator silently skips such an entry */ 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 /* ================= Segment Table Format 6 Lookup Table =============== */ 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 /* ================= Trimmed Array Format 8 Lookup Table =============== */ 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 /* firstGlyph + glyphCount */ 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 /* valueArray */ 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, /* 0 */ 00772 NULL, /* 1 */ 00773 gxv_LookupTable_fmt2_validate, /* 2 */ 00774 NULL, /* 3 */ 00775 gxv_LookupTable_fmt4_validate, /* 4 */ 00776 NULL, /* 5 */ 00777 gxv_LookupTable_fmt6_validate, /* 6 */ 00778 NULL, /* 7 */ 00779 gxv_LookupTable_fmt8_validate, /* 8 */ 00780 }; 00781 00782 GXV_Validate_Func func; 00783 00784 00785 GXV_NAME_ENTER( "LookupTable" ); 00786 00787 /* lookuptbl_head may be used in fmt4 transit function. */ 00788 valid->lookuptbl_head = table; 00789 00790 /* format */ 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 /***** Glyph ID *****/ 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 /***** CONTROL POINT *****/ 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 /***** SFNT NAME *****/ 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 ) != GXV_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; /* make compiler happy */ 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 /***** STATE TABLE *****/ 00936 /***** *****/ 00937 /*************************************************************************/ 00938 /*************************************************************************/ 00939 00940 /* -------------------------- Class Table --------------------------- */ 00941 00942 /* 00943 * highestClass specifies how many classes are defined in this 00944 * Class Subtable. Apple spec does not mention whether undefined 00945 * holes in the class (e.g.: 0-3 are predefined, 4 is unused, 5 is used) 00946 * are permitted. At present, holes in a defined class are not checked. 00947 * -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp> 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; /* Classes 0, 2, and 3 are predefined */ 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 /* following classes should not appear in class array */ 00994 case 0: /* end of text */ 00995 case 2: /* out of bounds */ 00996 case 3: /* end of line */ 00997 FT_INVALID_DATA; 00998 break; 00999 01000 case 1: /* out of bounds */ 01001 default: /* user-defined: 4 - ( stateSize - 1 ) */ 01002 if ( classID >= stateSize ) 01003 FT_INVALID_DATA; /* assign glyph to undefined state */ 01004 01005 nGlyphInClass[classID]++; 01006 break; 01007 } 01008 } 01009 *length_p = (FT_UShort)( p - table ); 01010 01011 /* scan max ClassID in use */ 01012 for ( i = 0; i < stateSize; i++ ) 01013 if ( ( 3 < i ) && ( nGlyphInClass[i] > 0 ) ) 01014 *maxClassID_p = (FT_Byte)i; /* XXX: Check Range? */ 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 /* --------------------------- State Array ----------------------------- */ 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 ); /* for the non-debugging case */ 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 * 2 states are predefined and must be described in StateArray: 01050 * state 0 (start of text), 1 (start of line) 01051 */ 01052 GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 ); 01053 01054 *maxState_p = 0; 01055 *maxEntry_p = 0; 01056 01057 /* read if enough to read another state */ 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 /* --------------------------- Entry Table ----------------------------- */ 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 /* ftxvalidator and FontValidator both warn and continue */ 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; /* make compiler happy */ 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 /* =========================== State Table ============================= */ 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; /* offset to Class(Sub)Table */ 01232 FT_UShort stateArray; /* offset to StateArray */ 01233 FT_UShort entryTable; /* offset to 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; /* 0:start of text, 1:start of line are predefined */ 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 /* ================= eXtended State Table (for morx) =================== */ 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 | lookup header | | 01370 +===============+ | 01371 | BinSrchHeader | | 01372 +===============+ | 01373 | lastGlyph[0] | | 01374 +---------------+ | 01375 | firstGlyph[0] | | head of lookup table 01376 +---------------+ | + 01377 | offset[0] | -> | offset [byte] 01378 +===============+ | + 01379 | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] 01380 +---------------+ | 01381 | firstGlyph[1] | | 01382 +---------------+ | 01383 | offset[1] | | 01384 +===============+ | 01385 | 01386 .... | 01387 | 01388 16bit value array | 01389 +===============+ | 01390 | value | <-------+ 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 /* XXX: check range? */ 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 ); /* for the non-debugging case */ 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 * 2 states are predefined and must be described: 01442 * state 0 (start of text), 1 (start of line) 01443 */ 01444 GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 * 2 ); 01445 01446 *maxState_p = 0; 01447 *maxEntry_p = 0; 01448 01449 /* read if enough to read another state */ 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; /* make compiler happy */ 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 /* StateHeader members */ 01578 FT_ULong classTable; /* offset to Class(Sub)Table */ 01579 FT_ULong stateArray; /* offset to StateArray */ 01580 FT_ULong entryTable; /* offset to 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 /* XXX: check range? */ 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; /* 0:start of text, 1:start of line are predefined */ 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 /***** Table overlapping *****/ 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 /* END */ Generated on Tue May 22 2012 04:37:51 for ReactOS by
1.7.6.1
|