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