1 /**************************************************************************** 2 * 3 * gxvmorx1.c 4 * 5 * TrueTypeGX/AAT morx table validation 6 * body for type1 (Contextual Substitution) subtable. 7 * 8 * Copyright (C) 2005-2020 by 9 * suzuki toshiya, Masatake YAMATO, Red Hat K.K., 10 * David Turner, Robert Wilhelm, and Werner Lemberg. 11 * 12 * This file is part of the FreeType project, and may only be used, 13 * modified, and distributed under the terms of the FreeType project 14 * license, LICENSE.TXT. By continuing to use, modify, or distribute 15 * this file you indicate that you have read the license and 16 * understand and accept it fully. 17 * 18 */ 19 20 /**************************************************************************** 21 * 22 * gxvalid is derived from both gxlayout module and otvalid module. 23 * Development of gxlayout is supported by the Information-technology 24 * Promotion Agency(IPA), Japan. 25 * 26 */ 27 28 29 #include "gxvmorx.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 gxvmorx 40 41 42 typedef struct GXV_morx_subtable_type1_StateOptRec_ 43 { 44 FT_ULong substitutionTable; 45 FT_ULong substitutionTable_length; 46 FT_UShort substitutionTable_num_lookupTables; 47 48 } GXV_morx_subtable_type1_StateOptRec, 49 *GXV_morx_subtable_type1_StateOptRecData; 50 51 52 #define GXV_MORX_SUBTABLE_TYPE1_HEADER_SIZE \ 53 ( GXV_STATETABLE_HEADER_SIZE + 2 ) 54 55 56 static void gxv_morx_subtable_type1_substitutionTable_load(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)57 gxv_morx_subtable_type1_substitutionTable_load( FT_Bytes table, 58 FT_Bytes limit, 59 GXV_Validator gxvalid ) 60 { 61 FT_Bytes p = table; 62 63 GXV_morx_subtable_type1_StateOptRecData optdata = 64 (GXV_morx_subtable_type1_StateOptRecData)gxvalid->xstatetable.optdata; 65 66 67 GXV_LIMIT_CHECK( 2 ); 68 optdata->substitutionTable = FT_NEXT_USHORT( p ); 69 } 70 71 72 static void gxv_morx_subtable_type1_subtable_setup(FT_ULong table_size,FT_ULong classTable,FT_ULong stateArray,FT_ULong entryTable,FT_ULong * classTable_length_p,FT_ULong * stateArray_length_p,FT_ULong * entryTable_length_p,GXV_Validator gxvalid)73 gxv_morx_subtable_type1_subtable_setup( FT_ULong table_size, 74 FT_ULong classTable, 75 FT_ULong stateArray, 76 FT_ULong entryTable, 77 FT_ULong* classTable_length_p, 78 FT_ULong* stateArray_length_p, 79 FT_ULong* entryTable_length_p, 80 GXV_Validator gxvalid ) 81 { 82 FT_ULong o[4]; 83 FT_ULong *l[4]; 84 FT_ULong buff[5]; 85 86 GXV_morx_subtable_type1_StateOptRecData optdata = 87 (GXV_morx_subtable_type1_StateOptRecData)gxvalid->xstatetable.optdata; 88 89 90 o[0] = classTable; 91 o[1] = stateArray; 92 o[2] = entryTable; 93 o[3] = optdata->substitutionTable; 94 l[0] = classTable_length_p; 95 l[1] = stateArray_length_p; 96 l[2] = entryTable_length_p; 97 l[3] = &(optdata->substitutionTable_length); 98 99 gxv_set_length_by_ulong_offset( o, l, buff, 4, table_size, gxvalid ); 100 } 101 102 103 static void gxv_morx_subtable_type1_entry_validate(FT_UShort state,FT_UShort flags,GXV_StateTable_GlyphOffsetCPtr glyphOffset_p,FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)104 gxv_morx_subtable_type1_entry_validate( 105 FT_UShort state, 106 FT_UShort flags, 107 GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, 108 FT_Bytes table, 109 FT_Bytes limit, 110 GXV_Validator gxvalid ) 111 { 112 #ifdef GXV_LOAD_TRACE_VARS 113 FT_UShort setMark; 114 FT_UShort dontAdvance; 115 #endif 116 FT_UShort reserved; 117 FT_Short markIndex; 118 FT_Short currentIndex; 119 120 GXV_morx_subtable_type1_StateOptRecData optdata = 121 (GXV_morx_subtable_type1_StateOptRecData)gxvalid->xstatetable.optdata; 122 123 FT_UNUSED( state ); 124 FT_UNUSED( table ); 125 FT_UNUSED( limit ); 126 127 128 #ifdef GXV_LOAD_TRACE_VARS 129 setMark = (FT_UShort)( ( flags >> 15 ) & 1 ); 130 dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); 131 #endif 132 133 reserved = (FT_UShort)( flags & 0x3FFF ); 134 135 markIndex = (FT_Short)( glyphOffset_p->ul >> 16 ); 136 currentIndex = (FT_Short)( glyphOffset_p->ul ); 137 138 GXV_TRACE(( " setMark=%01d dontAdvance=%01d\n", 139 setMark, dontAdvance )); 140 141 if ( 0 < reserved ) 142 { 143 GXV_TRACE(( " non-zero bits found in reserved range\n" )); 144 GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); 145 } 146 147 GXV_TRACE(( "markIndex = %d, currentIndex = %d\n", 148 markIndex, currentIndex )); 149 150 if ( optdata->substitutionTable_num_lookupTables < markIndex + 1 ) 151 optdata->substitutionTable_num_lookupTables = 152 (FT_UShort)( markIndex + 1 ); 153 154 if ( optdata->substitutionTable_num_lookupTables < currentIndex + 1 ) 155 optdata->substitutionTable_num_lookupTables = 156 (FT_UShort)( currentIndex + 1 ); 157 } 158 159 160 static void gxv_morx_subtable_type1_LookupValue_validate(FT_UShort glyph,GXV_LookupValueCPtr value_p,GXV_Validator gxvalid)161 gxv_morx_subtable_type1_LookupValue_validate( FT_UShort glyph, 162 GXV_LookupValueCPtr value_p, 163 GXV_Validator gxvalid ) 164 { 165 FT_UNUSED( glyph ); /* for the non-debugging case */ 166 167 GXV_TRACE(( "morx subtable type1 subst.: %d -> %d\n", glyph, value_p->u )); 168 169 if ( value_p->u > gxvalid->face->num_glyphs ) 170 FT_INVALID_GLYPH_ID; 171 } 172 173 174 static GXV_LookupValueDesc gxv_morx_subtable_type1_LookupFmt4_transit(FT_UShort relative_gindex,GXV_LookupValueCPtr base_value_p,FT_Bytes lookuptbl_limit,GXV_Validator gxvalid)175 gxv_morx_subtable_type1_LookupFmt4_transit( 176 FT_UShort relative_gindex, 177 GXV_LookupValueCPtr base_value_p, 178 FT_Bytes lookuptbl_limit, 179 GXV_Validator gxvalid ) 180 { 181 FT_Bytes p; 182 FT_Bytes limit; 183 FT_UShort offset; 184 GXV_LookupValueDesc value; 185 186 /* XXX: check range? */ 187 offset = (FT_UShort)( base_value_p->u + 188 relative_gindex * sizeof ( FT_UShort ) ); 189 190 p = gxvalid->lookuptbl_head + offset; 191 limit = lookuptbl_limit; 192 193 GXV_LIMIT_CHECK ( 2 ); 194 value.u = FT_NEXT_USHORT( p ); 195 196 return value; 197 } 198 199 200 /* 201 * TODO: length should be limit? 202 **/ 203 static void gxv_morx_subtable_type1_substitutionTable_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)204 gxv_morx_subtable_type1_substitutionTable_validate( FT_Bytes table, 205 FT_Bytes limit, 206 GXV_Validator gxvalid ) 207 { 208 FT_Bytes p = table; 209 FT_UShort i; 210 211 GXV_morx_subtable_type1_StateOptRecData optdata = 212 (GXV_morx_subtable_type1_StateOptRecData)gxvalid->xstatetable.optdata; 213 214 215 /* TODO: calculate offset/length for each lookupTables */ 216 gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; 217 gxvalid->lookupval_func = gxv_morx_subtable_type1_LookupValue_validate; 218 gxvalid->lookupfmt4_trans = gxv_morx_subtable_type1_LookupFmt4_transit; 219 220 for ( i = 0; i < optdata->substitutionTable_num_lookupTables; i++ ) 221 { 222 FT_ULong offset; 223 224 225 GXV_LIMIT_CHECK( 4 ); 226 offset = FT_NEXT_ULONG( p ); 227 228 gxv_LookupTable_validate( table + offset, limit, gxvalid ); 229 } 230 231 /* TODO: overlapping of lookupTables in substitutionTable */ 232 } 233 234 235 /* 236 * subtable for Contextual glyph substitution is a modified StateTable. 237 * In addition to classTable, stateArray, entryTable, the field 238 * `substitutionTable' is added. 239 */ 240 FT_LOCAL_DEF( void ) gxv_morx_subtable_type1_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)241 gxv_morx_subtable_type1_validate( FT_Bytes table, 242 FT_Bytes limit, 243 GXV_Validator gxvalid ) 244 { 245 FT_Bytes p = table; 246 247 GXV_morx_subtable_type1_StateOptRec st_rec; 248 249 250 GXV_NAME_ENTER( "morx chain subtable type1 (Contextual Glyph Subst)" ); 251 252 GXV_LIMIT_CHECK( GXV_MORX_SUBTABLE_TYPE1_HEADER_SIZE ); 253 254 st_rec.substitutionTable_num_lookupTables = 0; 255 256 gxvalid->xstatetable.optdata = 257 &st_rec; 258 gxvalid->xstatetable.optdata_load_func = 259 gxv_morx_subtable_type1_substitutionTable_load; 260 gxvalid->xstatetable.subtable_setup_func = 261 gxv_morx_subtable_type1_subtable_setup; 262 gxvalid->xstatetable.entry_glyphoffset_fmt = 263 GXV_GLYPHOFFSET_ULONG; 264 gxvalid->xstatetable.entry_validate_func = 265 gxv_morx_subtable_type1_entry_validate; 266 267 gxv_XStateTable_validate( p, limit, gxvalid ); 268 269 gxv_morx_subtable_type1_substitutionTable_validate( 270 table + st_rec.substitutionTable, 271 table + st_rec.substitutionTable + st_rec.substitutionTable_length, 272 gxvalid ); 273 274 GXV_EXIT; 275 } 276 277 278 /* END */ 279