1 /**************************************************************************** 2 * 3 * gxvjust.c 4 * 5 * TrueTypeGX/AAT just table validation (body). 6 * 7 * Copyright 2005-2018 by 8 * suzuki toshiya, Masatake YAMATO, Red Hat K.K., 9 * David Turner, Robert Wilhelm, and Werner Lemberg. 10 * 11 * This file is part of the FreeType project, and may only be used, 12 * modified, and distributed under the terms of the FreeType project 13 * license, LICENSE.TXT. By continuing to use, modify, or distribute 14 * this file you indicate that you have read the license and 15 * understand and accept it fully. 16 * 17 */ 18 19 /**************************************************************************** 20 * 21 * gxvalid is derived from both gxlayout module and otvalid module. 22 * Development of gxlayout is supported by the Information-technology 23 * Promotion Agency(IPA), Japan. 24 * 25 */ 26 27 28 #include "gxvalid.h" 29 #include "gxvcommn.h" 30 31 #include FT_SFNT_NAMES_H 32 33 34 /************************************************************************** 35 * 36 * The macro FT_COMPONENT is used in trace mode. It is an implicit 37 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log 38 * messages during execution. 39 */ 40 #undef FT_COMPONENT 41 #define FT_COMPONENT trace_gxvjust 42 43 /* 44 * referred `just' table format specification: 45 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6just.html 46 * last updated 2000. 47 * ---------------------------------------------- 48 * [JUST HEADER]: GXV_JUST_HEADER_SIZE 49 * version (fixed: 32bit) = 0x00010000 50 * format (uint16: 16bit) = 0 is only defined (2000) 51 * horizOffset (uint16: 16bit) 52 * vertOffset (uint16: 16bit) 53 * ---------------------------------------------- 54 */ 55 56 typedef struct GXV_just_DataRec_ 57 { 58 FT_UShort wdc_offset_max; 59 FT_UShort wdc_offset_min; 60 FT_UShort pc_offset_max; 61 FT_UShort pc_offset_min; 62 63 } GXV_just_DataRec, *GXV_just_Data; 64 65 66 #define GXV_JUST_DATA( a ) GXV_TABLE_DATA( just, a ) 67 68 69 /* GX just table does not define their subset of GID */ 70 static void gxv_just_check_max_gid(FT_UShort gid,const FT_String * msg_tag,GXV_Validator gxvalid)71 gxv_just_check_max_gid( FT_UShort gid, 72 const FT_String* msg_tag, 73 GXV_Validator gxvalid ) 74 { 75 if ( gid < gxvalid->face->num_glyphs ) 76 return; 77 78 GXV_TRACE(( "just table includes too large %s" 79 " GID=%d > %d (in maxp)\n", 80 msg_tag, gid, gxvalid->face->num_glyphs )); 81 GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); 82 } 83 84 85 static void gxv_just_wdp_entry_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)86 gxv_just_wdp_entry_validate( FT_Bytes table, 87 FT_Bytes limit, 88 GXV_Validator gxvalid ) 89 { 90 FT_Bytes p = table; 91 FT_ULong justClass; 92 #ifdef GXV_LOAD_UNUSED_VARS 93 FT_Fixed beforeGrowLimit; 94 FT_Fixed beforeShrinkGrowLimit; 95 FT_Fixed afterGrowLimit; 96 FT_Fixed afterShrinkGrowLimit; 97 FT_UShort growFlags; 98 FT_UShort shrinkFlags; 99 #endif 100 101 102 GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 + 4 + 2 + 2 ); 103 justClass = FT_NEXT_ULONG( p ); 104 #ifndef GXV_LOAD_UNUSED_VARS 105 p += 4 + 4 + 4 + 4 + 2 + 2; 106 #else 107 beforeGrowLimit = FT_NEXT_ULONG( p ); 108 beforeShrinkGrowLimit = FT_NEXT_ULONG( p ); 109 afterGrowLimit = FT_NEXT_ULONG( p ); 110 afterShrinkGrowLimit = FT_NEXT_ULONG( p ); 111 growFlags = FT_NEXT_USHORT( p ); 112 shrinkFlags = FT_NEXT_USHORT( p ); 113 #endif 114 115 /* According to Apple spec, only 7bits in justClass is used */ 116 if ( ( justClass & 0xFFFFFF80UL ) != 0 ) 117 { 118 GXV_TRACE(( "just table includes non-zero value" 119 " in unused justClass higher bits" 120 " of WidthDeltaPair" )); 121 GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); 122 } 123 124 gxvalid->subtable_length = (FT_ULong)( p - table ); 125 } 126 127 128 static void gxv_just_wdc_entry_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)129 gxv_just_wdc_entry_validate( FT_Bytes table, 130 FT_Bytes limit, 131 GXV_Validator gxvalid ) 132 { 133 FT_Bytes p = table; 134 FT_ULong count, i; 135 136 137 GXV_LIMIT_CHECK( 4 ); 138 count = FT_NEXT_ULONG( p ); 139 for ( i = 0; i < count; i++ ) 140 { 141 GXV_TRACE(( "validating wdc pair %d/%d\n", i + 1, count )); 142 gxv_just_wdp_entry_validate( p, limit, gxvalid ); 143 p += gxvalid->subtable_length; 144 } 145 146 gxvalid->subtable_length = (FT_ULong)( p - table ); 147 } 148 149 150 static void gxv_just_widthDeltaClusters_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)151 gxv_just_widthDeltaClusters_validate( FT_Bytes table, 152 FT_Bytes limit, 153 GXV_Validator gxvalid ) 154 { 155 FT_Bytes p = table; 156 FT_Bytes wdc_end = table + GXV_JUST_DATA( wdc_offset_max ); 157 FT_UInt i; 158 159 160 GXV_NAME_ENTER( "just justDeltaClusters" ); 161 162 if ( limit <= wdc_end ) 163 FT_INVALID_OFFSET; 164 165 for ( i = 0; p <= wdc_end; i++ ) 166 { 167 gxv_just_wdc_entry_validate( p, limit, gxvalid ); 168 p += gxvalid->subtable_length; 169 } 170 171 gxvalid->subtable_length = (FT_ULong)( p - table ); 172 173 GXV_EXIT; 174 } 175 176 177 static void gxv_just_actSubrecord_type0_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)178 gxv_just_actSubrecord_type0_validate( FT_Bytes table, 179 FT_Bytes limit, 180 GXV_Validator gxvalid ) 181 { 182 FT_Bytes p = table; 183 184 FT_Fixed lowerLimit; 185 FT_Fixed upperLimit; 186 #ifdef GXV_LOAD_UNUSED_VARS 187 FT_UShort order; 188 #endif 189 FT_UShort decomposedCount; 190 191 FT_UInt i; 192 193 194 GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 ); 195 lowerLimit = FT_NEXT_LONG( p ); 196 upperLimit = FT_NEXT_LONG( p ); 197 #ifdef GXV_LOAD_UNUSED_VARS 198 order = FT_NEXT_USHORT( p ); 199 #else 200 p += 2; 201 #endif 202 decomposedCount = FT_NEXT_USHORT( p ); 203 204 if ( lowerLimit >= upperLimit ) 205 { 206 GXV_TRACE(( "just table includes invalid range spec:" 207 " lowerLimit(%d) > upperLimit(%d)\n" )); 208 GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); 209 } 210 211 for ( i = 0; i < decomposedCount; i++ ) 212 { 213 FT_UShort glyphs; 214 215 216 GXV_LIMIT_CHECK( 2 ); 217 glyphs = FT_NEXT_USHORT( p ); 218 gxv_just_check_max_gid( glyphs, "type0:glyphs", gxvalid ); 219 } 220 221 gxvalid->subtable_length = (FT_ULong)( p - table ); 222 } 223 224 225 static void gxv_just_actSubrecord_type1_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)226 gxv_just_actSubrecord_type1_validate( FT_Bytes table, 227 FT_Bytes limit, 228 GXV_Validator gxvalid ) 229 { 230 FT_Bytes p = table; 231 FT_UShort addGlyph; 232 233 234 GXV_LIMIT_CHECK( 2 ); 235 addGlyph = FT_NEXT_USHORT( p ); 236 237 gxv_just_check_max_gid( addGlyph, "type1:addGlyph", gxvalid ); 238 239 gxvalid->subtable_length = (FT_ULong)( p - table ); 240 } 241 242 243 static void gxv_just_actSubrecord_type2_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)244 gxv_just_actSubrecord_type2_validate( FT_Bytes table, 245 FT_Bytes limit, 246 GXV_Validator gxvalid ) 247 { 248 FT_Bytes p = table; 249 #ifdef GXV_LOAD_UNUSED_VARS 250 FT_Fixed substThreshhold; /* Apple misspelled "Threshhold" */ 251 #endif 252 FT_UShort addGlyph; 253 FT_UShort substGlyph; 254 255 256 GXV_LIMIT_CHECK( 4 + 2 + 2 ); 257 #ifdef GXV_LOAD_UNUSED_VARS 258 substThreshhold = FT_NEXT_ULONG( p ); 259 #else 260 p += 4; 261 #endif 262 addGlyph = FT_NEXT_USHORT( p ); 263 substGlyph = FT_NEXT_USHORT( p ); 264 265 if ( addGlyph != 0xFFFF ) 266 gxv_just_check_max_gid( addGlyph, "type2:addGlyph", gxvalid ); 267 268 gxv_just_check_max_gid( substGlyph, "type2:substGlyph", gxvalid ); 269 270 gxvalid->subtable_length = (FT_ULong)( p - table ); 271 } 272 273 274 static void gxv_just_actSubrecord_type4_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)275 gxv_just_actSubrecord_type4_validate( FT_Bytes table, 276 FT_Bytes limit, 277 GXV_Validator gxvalid ) 278 { 279 FT_Bytes p = table; 280 FT_ULong variantsAxis; 281 FT_Fixed minimumLimit; 282 FT_Fixed noStretchValue; 283 FT_Fixed maximumLimit; 284 285 286 GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 ); 287 variantsAxis = FT_NEXT_ULONG( p ); 288 minimumLimit = FT_NEXT_LONG( p ); 289 noStretchValue = FT_NEXT_LONG( p ); 290 maximumLimit = FT_NEXT_LONG( p ); 291 292 gxvalid->subtable_length = (FT_ULong)( p - table ); 293 294 if ( variantsAxis != 0x64756374L ) /* 'duct' */ 295 GXV_TRACE(( "variantsAxis 0x%08x is non default value", 296 variantsAxis )); 297 298 if ( minimumLimit > noStretchValue ) 299 GXV_TRACE(( "type4:minimumLimit 0x%08x > noStretchValue 0x%08x\n", 300 minimumLimit, noStretchValue )); 301 else if ( noStretchValue > maximumLimit ) 302 GXV_TRACE(( "type4:noStretchValue 0x%08x > maximumLimit 0x%08x\n", 303 noStretchValue, maximumLimit )); 304 else if ( !IS_PARANOID_VALIDATION ) 305 return; 306 307 FT_INVALID_DATA; 308 } 309 310 311 static void gxv_just_actSubrecord_type5_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)312 gxv_just_actSubrecord_type5_validate( FT_Bytes table, 313 FT_Bytes limit, 314 GXV_Validator gxvalid ) 315 { 316 FT_Bytes p = table; 317 FT_UShort flags; 318 FT_UShort glyph; 319 320 321 GXV_LIMIT_CHECK( 2 + 2 ); 322 flags = FT_NEXT_USHORT( p ); 323 glyph = FT_NEXT_USHORT( p ); 324 325 if ( flags ) 326 GXV_TRACE(( "type5: nonzero value 0x%04x in unused flags\n", 327 flags )); 328 gxv_just_check_max_gid( glyph, "type5:glyph", gxvalid ); 329 330 gxvalid->subtable_length = (FT_ULong)( p - table ); 331 } 332 333 334 /* parse single actSubrecord */ 335 static void gxv_just_actSubrecord_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)336 gxv_just_actSubrecord_validate( FT_Bytes table, 337 FT_Bytes limit, 338 GXV_Validator gxvalid ) 339 { 340 FT_Bytes p = table; 341 FT_UShort actionClass; 342 FT_UShort actionType; 343 FT_ULong actionLength; 344 345 346 GXV_NAME_ENTER( "just actSubrecord" ); 347 348 GXV_LIMIT_CHECK( 2 + 2 + 4 ); 349 actionClass = FT_NEXT_USHORT( p ); 350 actionType = FT_NEXT_USHORT( p ); 351 actionLength = FT_NEXT_ULONG( p ); 352 353 /* actionClass is related with justClass using 7bit only */ 354 if ( ( actionClass & 0xFF80 ) != 0 ) 355 GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); 356 357 if ( actionType == 0 ) 358 gxv_just_actSubrecord_type0_validate( p, limit, gxvalid ); 359 else if ( actionType == 1 ) 360 gxv_just_actSubrecord_type1_validate( p, limit, gxvalid ); 361 else if ( actionType == 2 ) 362 gxv_just_actSubrecord_type2_validate( p, limit, gxvalid ); 363 else if ( actionType == 3 ) 364 ; /* Stretch glyph action: no actionData */ 365 else if ( actionType == 4 ) 366 gxv_just_actSubrecord_type4_validate( p, limit, gxvalid ); 367 else if ( actionType == 5 ) 368 gxv_just_actSubrecord_type5_validate( p, limit, gxvalid ); 369 else 370 FT_INVALID_DATA; 371 372 gxvalid->subtable_length = actionLength; 373 374 GXV_EXIT; 375 } 376 377 378 static void gxv_just_pcActionRecord_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)379 gxv_just_pcActionRecord_validate( FT_Bytes table, 380 FT_Bytes limit, 381 GXV_Validator gxvalid ) 382 { 383 FT_Bytes p = table; 384 FT_ULong actionCount; 385 FT_ULong i; 386 387 388 GXV_LIMIT_CHECK( 4 ); 389 actionCount = FT_NEXT_ULONG( p ); 390 GXV_TRACE(( "actionCount = %d\n", actionCount )); 391 392 for ( i = 0; i < actionCount; i++ ) 393 { 394 gxv_just_actSubrecord_validate( p, limit, gxvalid ); 395 p += gxvalid->subtable_length; 396 } 397 398 gxvalid->subtable_length = (FT_ULong)( p - table ); 399 400 GXV_EXIT; 401 } 402 403 404 static void gxv_just_pcTable_LookupValue_entry_validate(FT_UShort glyph,GXV_LookupValueCPtr value_p,GXV_Validator gxvalid)405 gxv_just_pcTable_LookupValue_entry_validate( FT_UShort glyph, 406 GXV_LookupValueCPtr value_p, 407 GXV_Validator gxvalid ) 408 { 409 FT_UNUSED( glyph ); 410 411 if ( value_p->u > GXV_JUST_DATA( pc_offset_max ) ) 412 GXV_JUST_DATA( pc_offset_max ) = value_p->u; 413 if ( value_p->u < GXV_JUST_DATA( pc_offset_max ) ) 414 GXV_JUST_DATA( pc_offset_min ) = value_p->u; 415 } 416 417 418 static void gxv_just_pcLookupTable_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)419 gxv_just_pcLookupTable_validate( FT_Bytes table, 420 FT_Bytes limit, 421 GXV_Validator gxvalid ) 422 { 423 FT_Bytes p = table; 424 425 426 GXV_NAME_ENTER( "just pcLookupTable" ); 427 GXV_JUST_DATA( pc_offset_max ) = 0x0000; 428 GXV_JUST_DATA( pc_offset_min ) = 0xFFFFU; 429 430 gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; 431 gxvalid->lookupval_func = gxv_just_pcTable_LookupValue_entry_validate; 432 433 gxv_LookupTable_validate( p, limit, gxvalid ); 434 435 /* subtable_length is set by gxv_LookupTable_validate() */ 436 437 GXV_EXIT; 438 } 439 440 441 static void gxv_just_postcompTable_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)442 gxv_just_postcompTable_validate( FT_Bytes table, 443 FT_Bytes limit, 444 GXV_Validator gxvalid ) 445 { 446 FT_Bytes p = table; 447 448 449 GXV_NAME_ENTER( "just postcompTable" ); 450 451 gxv_just_pcLookupTable_validate( p, limit, gxvalid ); 452 p += gxvalid->subtable_length; 453 454 gxv_just_pcActionRecord_validate( p, limit, gxvalid ); 455 p += gxvalid->subtable_length; 456 457 gxvalid->subtable_length = (FT_ULong)( p - table ); 458 459 GXV_EXIT; 460 } 461 462 463 static void gxv_just_classTable_entry_validate(FT_Byte state,FT_UShort flags,GXV_StateTable_GlyphOffsetCPtr glyphOffset_p,FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)464 gxv_just_classTable_entry_validate( 465 FT_Byte state, 466 FT_UShort flags, 467 GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, 468 FT_Bytes table, 469 FT_Bytes limit, 470 GXV_Validator gxvalid ) 471 { 472 #ifdef GXV_LOAD_UNUSED_VARS 473 /* TODO: validate markClass & currentClass */ 474 FT_UShort setMark; 475 FT_UShort dontAdvance; 476 FT_UShort markClass; 477 FT_UShort currentClass; 478 #endif 479 480 FT_UNUSED( state ); 481 FT_UNUSED( glyphOffset_p ); 482 FT_UNUSED( table ); 483 FT_UNUSED( limit ); 484 FT_UNUSED( gxvalid ); 485 486 #ifndef GXV_LOAD_UNUSED_VARS 487 FT_UNUSED( flags ); 488 #else 489 setMark = (FT_UShort)( ( flags >> 15 ) & 1 ); 490 dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); 491 markClass = (FT_UShort)( ( flags >> 7 ) & 0x7F ); 492 currentClass = (FT_UShort)( flags & 0x7F ); 493 #endif 494 } 495 496 497 static void gxv_just_justClassTable_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)498 gxv_just_justClassTable_validate ( FT_Bytes table, 499 FT_Bytes limit, 500 GXV_Validator gxvalid ) 501 { 502 FT_Bytes p = table; 503 FT_UShort length; 504 FT_UShort coverage; 505 FT_ULong subFeatureFlags; 506 507 508 GXV_NAME_ENTER( "just justClassTable" ); 509 510 GXV_LIMIT_CHECK( 2 + 2 + 4 ); 511 length = FT_NEXT_USHORT( p ); 512 coverage = FT_NEXT_USHORT( p ); 513 subFeatureFlags = FT_NEXT_ULONG( p ); 514 515 GXV_TRACE(( " justClassTable: coverage = 0x%04x (%s) ", coverage )); 516 if ( ( coverage & 0x4000 ) == 0 ) 517 GXV_TRACE(( "ascending\n" )); 518 else 519 GXV_TRACE(( "descending\n" )); 520 521 if ( subFeatureFlags ) 522 GXV_TRACE(( " justClassTable: nonzero value (0x%08x)" 523 " in unused subFeatureFlags\n", subFeatureFlags )); 524 525 gxvalid->statetable.optdata = NULL; 526 gxvalid->statetable.optdata_load_func = NULL; 527 gxvalid->statetable.subtable_setup_func = NULL; 528 gxvalid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE; 529 gxvalid->statetable.entry_validate_func = 530 gxv_just_classTable_entry_validate; 531 532 gxv_StateTable_validate( p, table + length, gxvalid ); 533 534 /* subtable_length is set by gxv_LookupTable_validate() */ 535 536 GXV_EXIT; 537 } 538 539 540 static void gxv_just_wdcTable_LookupValue_validate(FT_UShort glyph,GXV_LookupValueCPtr value_p,GXV_Validator gxvalid)541 gxv_just_wdcTable_LookupValue_validate( FT_UShort glyph, 542 GXV_LookupValueCPtr value_p, 543 GXV_Validator gxvalid ) 544 { 545 FT_UNUSED( glyph ); 546 547 if ( value_p->u > GXV_JUST_DATA( wdc_offset_max ) ) 548 GXV_JUST_DATA( wdc_offset_max ) = value_p->u; 549 if ( value_p->u < GXV_JUST_DATA( wdc_offset_min ) ) 550 GXV_JUST_DATA( wdc_offset_min ) = value_p->u; 551 } 552 553 554 static void gxv_just_justData_lookuptable_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)555 gxv_just_justData_lookuptable_validate( FT_Bytes table, 556 FT_Bytes limit, 557 GXV_Validator gxvalid ) 558 { 559 FT_Bytes p = table; 560 561 562 GXV_JUST_DATA( wdc_offset_max ) = 0x0000; 563 GXV_JUST_DATA( wdc_offset_min ) = 0xFFFFU; 564 565 gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; 566 gxvalid->lookupval_func = gxv_just_wdcTable_LookupValue_validate; 567 568 gxv_LookupTable_validate( p, limit, gxvalid ); 569 570 /* subtable_length is set by gxv_LookupTable_validate() */ 571 572 GXV_EXIT; 573 } 574 575 576 /* 577 * gxv_just_justData_validate() parses and validates horizData, vertData. 578 */ 579 static void gxv_just_justData_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)580 gxv_just_justData_validate( FT_Bytes table, 581 FT_Bytes limit, 582 GXV_Validator gxvalid ) 583 { 584 /* 585 * following 3 offsets are measured from the start of `just' 586 * (which table points to), not justData 587 */ 588 FT_UShort justClassTableOffset; 589 FT_UShort wdcTableOffset; 590 FT_UShort pcTableOffset; 591 FT_Bytes p = table; 592 593 GXV_ODTECT( 4, odtect ); 594 595 596 GXV_NAME_ENTER( "just justData" ); 597 598 GXV_ODTECT_INIT( odtect ); 599 GXV_LIMIT_CHECK( 2 + 2 + 2 ); 600 justClassTableOffset = FT_NEXT_USHORT( p ); 601 wdcTableOffset = FT_NEXT_USHORT( p ); 602 pcTableOffset = FT_NEXT_USHORT( p ); 603 604 GXV_TRACE(( " (justClassTableOffset = 0x%04x)\n", justClassTableOffset )); 605 GXV_TRACE(( " (wdcTableOffset = 0x%04x)\n", wdcTableOffset )); 606 GXV_TRACE(( " (pcTableOffset = 0x%04x)\n", pcTableOffset )); 607 608 gxv_just_justData_lookuptable_validate( p, limit, gxvalid ); 609 gxv_odtect_add_range( p, gxvalid->subtable_length, 610 "just_LookupTable", odtect ); 611 612 if ( wdcTableOffset ) 613 { 614 gxv_just_widthDeltaClusters_validate( 615 gxvalid->root->base + wdcTableOffset, limit, gxvalid ); 616 gxv_odtect_add_range( gxvalid->root->base + wdcTableOffset, 617 gxvalid->subtable_length, "just_wdcTable", odtect ); 618 } 619 620 if ( pcTableOffset ) 621 { 622 gxv_just_postcompTable_validate( gxvalid->root->base + pcTableOffset, 623 limit, gxvalid ); 624 gxv_odtect_add_range( gxvalid->root->base + pcTableOffset, 625 gxvalid->subtable_length, "just_pcTable", odtect ); 626 } 627 628 if ( justClassTableOffset ) 629 { 630 gxv_just_justClassTable_validate( 631 gxvalid->root->base + justClassTableOffset, limit, gxvalid ); 632 gxv_odtect_add_range( gxvalid->root->base + justClassTableOffset, 633 gxvalid->subtable_length, "just_justClassTable", 634 odtect ); 635 } 636 637 gxv_odtect_validate( odtect, gxvalid ); 638 639 GXV_EXIT; 640 } 641 642 643 FT_LOCAL_DEF( void ) gxv_just_validate(FT_Bytes table,FT_Face face,FT_Validator ftvalid)644 gxv_just_validate( FT_Bytes table, 645 FT_Face face, 646 FT_Validator ftvalid ) 647 { 648 FT_Bytes p = table; 649 FT_Bytes limit = 0; 650 651 GXV_ValidatorRec gxvalidrec; 652 GXV_Validator gxvalid = &gxvalidrec; 653 GXV_just_DataRec justrec; 654 GXV_just_Data just = &justrec; 655 656 FT_ULong version; 657 FT_UShort format; 658 FT_UShort horizOffset; 659 FT_UShort vertOffset; 660 661 GXV_ODTECT( 3, odtect ); 662 663 664 GXV_ODTECT_INIT( odtect ); 665 666 gxvalid->root = ftvalid; 667 gxvalid->table_data = just; 668 gxvalid->face = face; 669 670 FT_TRACE3(( "validating `just' table\n" )); 671 GXV_INIT; 672 673 limit = gxvalid->root->limit; 674 675 GXV_LIMIT_CHECK( 4 + 2 + 2 + 2 ); 676 version = FT_NEXT_ULONG( p ); 677 format = FT_NEXT_USHORT( p ); 678 horizOffset = FT_NEXT_USHORT( p ); 679 vertOffset = FT_NEXT_USHORT( p ); 680 gxv_odtect_add_range( table, (FT_ULong)( p - table ), 681 "just header", odtect ); 682 683 684 /* Version 1.0 (always:2000) */ 685 GXV_TRACE(( " (version = 0x%08x)\n", version )); 686 if ( version != 0x00010000UL ) 687 FT_INVALID_FORMAT; 688 689 /* format 0 (always:2000) */ 690 GXV_TRACE(( " (format = 0x%04x)\n", format )); 691 if ( format != 0x0000 ) 692 FT_INVALID_FORMAT; 693 694 GXV_TRACE(( " (horizOffset = %d)\n", horizOffset )); 695 GXV_TRACE(( " (vertOffset = %d)\n", vertOffset )); 696 697 698 /* validate justData */ 699 if ( 0 < horizOffset ) 700 { 701 gxv_just_justData_validate( table + horizOffset, limit, gxvalid ); 702 gxv_odtect_add_range( table + horizOffset, gxvalid->subtable_length, 703 "horizJustData", odtect ); 704 } 705 706 if ( 0 < vertOffset ) 707 { 708 gxv_just_justData_validate( table + vertOffset, limit, gxvalid ); 709 gxv_odtect_add_range( table + vertOffset, gxvalid->subtable_length, 710 "vertJustData", odtect ); 711 } 712 713 gxv_odtect_validate( odtect, gxvalid ); 714 715 FT_TRACE4(( "\n" )); 716 } 717 718 719 /* END */ 720