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