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