1 /**************************************************************************** 2 * 3 * gxvprop.c 4 * 5 * TrueTypeGX/AAT prop table validation (body). 6 * 7 * Copyright (C) 2004-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 32 /************************************************************************** 33 * 34 * The macro FT_COMPONENT is used in trace mode. It is an implicit 35 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log 36 * messages during execution. 37 */ 38 #undef FT_COMPONENT 39 #define FT_COMPONENT gxvprop 40 41 42 /*************************************************************************/ 43 /*************************************************************************/ 44 /***** *****/ 45 /***** Data and Types *****/ 46 /***** *****/ 47 /*************************************************************************/ 48 /*************************************************************************/ 49 50 #define GXV_PROP_HEADER_SIZE ( 4 + 2 + 2 ) 51 #define GXV_PROP_SIZE_MIN GXV_PROP_HEADER_SIZE 52 53 typedef struct GXV_prop_DataRec_ 54 { 55 FT_Fixed version; 56 57 } GXV_prop_DataRec, *GXV_prop_Data; 58 59 #define GXV_PROP_DATA( field ) GXV_TABLE_DATA( prop, field ) 60 61 #define GXV_PROP_FLOATER 0x8000U 62 #define GXV_PROP_USE_COMPLEMENTARY_BRACKET 0x1000U 63 #define GXV_PROP_COMPLEMENTARY_BRACKET_OFFSET 0x0F00U 64 #define GXV_PROP_ATTACHING_TO_RIGHT 0x0080U 65 #define GXV_PROP_RESERVED 0x0060U 66 #define GXV_PROP_DIRECTIONALITY_CLASS 0x001FU 67 68 69 /*************************************************************************/ 70 /*************************************************************************/ 71 /***** *****/ 72 /***** UTILITY FUNCTIONS *****/ 73 /***** *****/ 74 /*************************************************************************/ 75 /*************************************************************************/ 76 77 static void gxv_prop_zero_advance_validate(FT_UShort gid,GXV_Validator gxvalid)78 gxv_prop_zero_advance_validate( FT_UShort gid, 79 GXV_Validator gxvalid ) 80 { 81 FT_Face face; 82 FT_Error error; 83 FT_GlyphSlot glyph; 84 85 86 GXV_NAME_ENTER( "zero advance" ); 87 88 face = gxvalid->face; 89 90 error = FT_Load_Glyph( face, 91 gid, 92 FT_LOAD_IGNORE_TRANSFORM ); 93 if ( error ) 94 FT_INVALID_GLYPH_ID; 95 96 glyph = face->glyph; 97 98 if ( glyph->advance.x != (FT_Pos)0 || 99 glyph->advance.y != (FT_Pos)0 ) 100 { 101 GXV_TRACE(( " found non-zero advance in zero-advance glyph\n" )); 102 FT_INVALID_DATA; 103 } 104 105 GXV_EXIT; 106 } 107 108 109 /* Pass 0 as GLYPH to check the default property */ 110 static void gxv_prop_property_validate(FT_UShort property,FT_UShort glyph,GXV_Validator gxvalid)111 gxv_prop_property_validate( FT_UShort property, 112 FT_UShort glyph, 113 GXV_Validator gxvalid ) 114 { 115 if ( glyph != 0 && ( property & GXV_PROP_FLOATER ) ) 116 gxv_prop_zero_advance_validate( glyph, gxvalid ); 117 118 if ( property & GXV_PROP_USE_COMPLEMENTARY_BRACKET ) 119 { 120 FT_UShort offset; 121 char complement; 122 123 124 offset = (FT_UShort)( property & GXV_PROP_COMPLEMENTARY_BRACKET_OFFSET ); 125 if ( offset == 0 ) 126 { 127 GXV_TRACE(( " found zero offset to property\n" )); 128 FT_INVALID_OFFSET; 129 } 130 131 complement = (char)( offset >> 8 ); 132 if ( complement & 0x08 ) 133 { 134 /* Top bit is set: negative */ 135 136 /* Calculate the absolute offset */ 137 complement = (char)( ( complement & 0x07 ) + 1 ); 138 139 /* The gid for complement must be greater than 0 */ 140 if ( glyph <= complement ) 141 { 142 GXV_TRACE(( " found non-positive glyph complement\n" )); 143 FT_INVALID_DATA; 144 } 145 } 146 else 147 { 148 /* The gid for complement must be the face. */ 149 gxv_glyphid_validate( (FT_UShort)( glyph + complement ), gxvalid ); 150 } 151 } 152 else 153 { 154 if ( property & GXV_PROP_COMPLEMENTARY_BRACKET_OFFSET ) 155 GXV_TRACE(( "glyph %d cannot have complementary bracketing\n", 156 glyph )); 157 } 158 159 /* this is introduced in version 2.0 */ 160 if ( property & GXV_PROP_ATTACHING_TO_RIGHT ) 161 { 162 if ( GXV_PROP_DATA( version ) == 0x00010000UL ) 163 { 164 GXV_TRACE(( " found older version (1.0) in new version table\n" )); 165 FT_INVALID_DATA; 166 } 167 } 168 169 if ( property & GXV_PROP_RESERVED ) 170 { 171 GXV_TRACE(( " found non-zero bits in reserved bits\n" )); 172 FT_INVALID_DATA; 173 } 174 175 if ( ( property & GXV_PROP_DIRECTIONALITY_CLASS ) > 11 ) 176 { 177 /* TODO: Too restricted. Use the validation level. */ 178 if ( GXV_PROP_DATA( version ) == 0x00010000UL || 179 GXV_PROP_DATA( version ) == 0x00020000UL ) 180 { 181 GXV_TRACE(( " found too old version in directionality class\n" )); 182 FT_INVALID_DATA; 183 } 184 } 185 } 186 187 188 static void gxv_prop_LookupValue_validate(FT_UShort glyph,GXV_LookupValueCPtr value_p,GXV_Validator gxvalid)189 gxv_prop_LookupValue_validate( FT_UShort glyph, 190 GXV_LookupValueCPtr value_p, 191 GXV_Validator gxvalid ) 192 { 193 gxv_prop_property_validate( value_p->u, glyph, gxvalid ); 194 } 195 196 197 /* 198 +===============+ --------+ 199 | lookup header | | 200 +===============+ | 201 | BinSrchHeader | | 202 +===============+ | 203 | lastGlyph[0] | | 204 +---------------+ | 205 | firstGlyph[0] | | head of lookup table 206 +---------------+ | + 207 | offset[0] | -> | offset [byte] 208 +===============+ | + 209 | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] 210 +---------------+ | 211 | firstGlyph[1] | | 212 +---------------+ | 213 | offset[1] | | 214 +===============+ | 215 | 216 ... | 217 | 218 16bit value array | 219 +===============+ | 220 | value | <-------+ 221 ... 222 */ 223 224 static GXV_LookupValueDesc gxv_prop_LookupFmt4_transit(FT_UShort relative_gindex,GXV_LookupValueCPtr base_value_p,FT_Bytes lookuptbl_limit,GXV_Validator gxvalid)225 gxv_prop_LookupFmt4_transit( FT_UShort relative_gindex, 226 GXV_LookupValueCPtr base_value_p, 227 FT_Bytes lookuptbl_limit, 228 GXV_Validator gxvalid ) 229 { 230 FT_Bytes p; 231 FT_Bytes limit; 232 FT_UShort offset; 233 GXV_LookupValueDesc value; 234 235 /* XXX: check range? */ 236 offset = (FT_UShort)( base_value_p->u + 237 relative_gindex * sizeof ( FT_UShort ) ); 238 p = gxvalid->lookuptbl_head + offset; 239 limit = lookuptbl_limit; 240 241 GXV_LIMIT_CHECK ( 2 ); 242 value.u = FT_NEXT_USHORT( p ); 243 244 return value; 245 } 246 247 248 /*************************************************************************/ 249 /*************************************************************************/ 250 /***** *****/ 251 /***** prop TABLE *****/ 252 /***** *****/ 253 /*************************************************************************/ 254 /*************************************************************************/ 255 256 FT_LOCAL_DEF( void ) gxv_prop_validate(FT_Bytes table,FT_Face face,FT_Validator ftvalid)257 gxv_prop_validate( FT_Bytes table, 258 FT_Face face, 259 FT_Validator ftvalid ) 260 { 261 FT_Bytes p = table; 262 FT_Bytes limit = 0; 263 GXV_ValidatorRec gxvalidrec; 264 GXV_Validator gxvalid = &gxvalidrec; 265 266 GXV_prop_DataRec proprec; 267 GXV_prop_Data prop = &proprec; 268 269 FT_Fixed version; 270 FT_UShort format; 271 FT_UShort defaultProp; 272 273 274 gxvalid->root = ftvalid; 275 gxvalid->table_data = prop; 276 gxvalid->face = face; 277 278 FT_TRACE3(( "validating `prop' table\n" )); 279 GXV_INIT; 280 281 GXV_LIMIT_CHECK( 4 + 2 + 2 ); 282 version = FT_NEXT_LONG( p ); 283 format = FT_NEXT_USHORT( p ); 284 defaultProp = FT_NEXT_USHORT( p ); 285 286 GXV_TRACE(( " version 0x%08lx\n", version )); 287 GXV_TRACE(( " format 0x%04x\n", format )); 288 GXV_TRACE(( " defaultProp 0x%04x\n", defaultProp )); 289 290 /* only versions 1.0, 2.0, 3.0 are defined (1996) */ 291 if ( version != 0x00010000UL && 292 version != 0x00020000UL && 293 version != 0x00030000UL ) 294 { 295 GXV_TRACE(( " found unknown version\n" )); 296 FT_INVALID_FORMAT; 297 } 298 299 300 /* only formats 0x0000, 0x0001 are defined (1996) */ 301 if ( format > 1 ) 302 { 303 GXV_TRACE(( " found unknown format\n" )); 304 FT_INVALID_FORMAT; 305 } 306 307 gxv_prop_property_validate( defaultProp, 0, gxvalid ); 308 309 if ( format == 0 ) 310 { 311 FT_TRACE3(( "(format 0, no per-glyph properties, " 312 "remaining %ld bytes are skipped)", limit - p )); 313 goto Exit; 314 } 315 316 /* format == 1 */ 317 GXV_PROP_DATA( version ) = version; 318 319 gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; 320 gxvalid->lookupval_func = gxv_prop_LookupValue_validate; 321 gxvalid->lookupfmt4_trans = gxv_prop_LookupFmt4_transit; 322 323 gxv_LookupTable_validate( p, limit, gxvalid ); 324 325 Exit: 326 FT_TRACE4(( "\n" )); 327 } 328 329 330 /* END */ 331