00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "gxvmort.h"
00028 #include "gxvfeat.h"
00029
00030
00031
00032
00033
00034
00035
00036
00037 #undef FT_COMPONENT
00038 #define FT_COMPONENT trace_gxvmort
00039
00040
00041 static void
00042 gxv_mort_feature_validate( GXV_mort_feature f,
00043 GXV_Validator valid )
00044 {
00045 if ( f->featureType >= gxv_feat_registry_length )
00046 {
00047 GXV_TRACE(( "featureType %d is out of registered range, "
00048 "setting %d is unchecked\n",
00049 f->featureType, f->featureSetting ));
00050 if ( valid->root->level >= FT_VALIDATE_PARANOID )
00051 FT_INVALID_DATA;
00052 }
00053 else if ( !gxv_feat_registry[f->featureType].existence )
00054 {
00055 GXV_TRACE(( "featureType %d is within registered area "
00056 "but undefined, setting %d is unchecked\n",
00057 f->featureType, f->featureSetting ));
00058 if ( valid->root->level >= FT_VALIDATE_PARANOID )
00059 FT_INVALID_DATA;
00060 }
00061 else
00062 {
00063 FT_Byte nSettings_max;
00064
00065
00066
00067 nSettings_max = gxv_feat_registry[f->featureType].nSettings;
00068 if ( gxv_feat_registry[f->featureType].exclusive )
00069 nSettings_max = (FT_Byte)( 2 * nSettings_max );
00070
00071 GXV_TRACE(( "featureType %d is registered", f->featureType ));
00072 GXV_TRACE(( "setting %d", f->featureSetting ));
00073
00074 if ( f->featureSetting > nSettings_max )
00075 {
00076 GXV_TRACE(( "out of defined range %d", nSettings_max ));
00077 if ( valid->root->level >= FT_VALIDATE_PARANOID )
00078 FT_INVALID_DATA;
00079 }
00080 GXV_TRACE(( "\n" ));
00081 }
00082
00083
00084 }
00085
00086
00087
00088
00089
00090
00091 FT_LOCAL_DEF( void )
00092 gxv_mort_featurearray_validate( FT_Bytes table,
00093 FT_Bytes limit,
00094 FT_ULong nFeatureFlags,
00095 GXV_Validator valid )
00096 {
00097 FT_Bytes p = table;
00098 FT_ULong i;
00099
00100 GXV_mort_featureRec f = GXV_MORT_FEATURE_OFF;
00101
00102
00103 GXV_NAME_ENTER( "mort feature list" );
00104 for ( i = 0; i < nFeatureFlags; i++ )
00105 {
00106 GXV_LIMIT_CHECK( 2 + 2 + 4 + 4 );
00107 f.featureType = FT_NEXT_USHORT( p );
00108 f.featureSetting = FT_NEXT_USHORT( p );
00109 f.enableFlags = FT_NEXT_ULONG( p );
00110 f.disableFlags = FT_NEXT_ULONG( p );
00111
00112 gxv_mort_feature_validate( &f, valid );
00113 }
00114
00115 if ( !IS_GXV_MORT_FEATURE_OFF( f ) )
00116 FT_INVALID_DATA;
00117
00118 valid->subtable_length = p - table;
00119 GXV_EXIT;
00120 }
00121
00122
00123 FT_LOCAL_DEF( void )
00124 gxv_mort_coverage_validate( FT_UShort coverage,
00125 GXV_Validator valid )
00126 {
00127 FT_UNUSED( valid );
00128
00129 if ( coverage & 0x8000U )
00130 GXV_TRACE(( " this subtable is for vertical text only\n" ));
00131 else
00132 GXV_TRACE(( " this subtable is for horizontal text only\n" ));
00133
00134 if ( coverage & 0x4000 )
00135 GXV_TRACE(( " this subtable is applied to glyph array "
00136 "in descending order\n" ));
00137 else
00138 GXV_TRACE(( " this subtable is applied to glyph array "
00139 "in ascending order\n" ));
00140
00141 if ( coverage & 0x2000 )
00142 GXV_TRACE(( " this subtable is forcibly applied to "
00143 "vertical/horizontal text\n" ));
00144
00145 if ( coverage & 0x1FF8 )
00146 GXV_TRACE(( " coverage has non-zero bits in reserved area\n" ));
00147 }
00148
00149
00150 static void
00151 gxv_mort_subtables_validate( FT_Bytes table,
00152 FT_Bytes limit,
00153 FT_UShort nSubtables,
00154 GXV_Validator valid )
00155 {
00156 FT_Bytes p = table;
00157
00158 GXV_Validate_Func fmt_funcs_table[] =
00159 {
00160 gxv_mort_subtable_type0_validate,
00161 gxv_mort_subtable_type1_validate,
00162 gxv_mort_subtable_type2_validate,
00163 NULL,
00164 gxv_mort_subtable_type4_validate,
00165 gxv_mort_subtable_type5_validate,
00166
00167 };
00168
00169 GXV_Validate_Func func;
00170 FT_UShort i;
00171
00172
00173 GXV_NAME_ENTER( "subtables in a chain" );
00174
00175 for ( i = 0; i < nSubtables; i++ )
00176 {
00177 FT_UShort length;
00178 FT_UShort coverage;
00179 FT_ULong subFeatureFlags;
00180 FT_UInt type;
00181 FT_UInt rest;
00182
00183
00184 GXV_LIMIT_CHECK( 2 + 2 + 4 );
00185 length = FT_NEXT_USHORT( p );
00186 coverage = FT_NEXT_USHORT( p );
00187 subFeatureFlags = FT_NEXT_ULONG( p );
00188
00189 GXV_TRACE(( "validating chain subtable %d/%d (%d bytes)\n",
00190 i + 1, nSubtables, length ));
00191 type = coverage & 0x0007;
00192 rest = length - ( 2 + 2 + 4 );
00193
00194 GXV_LIMIT_CHECK( rest );
00195 gxv_mort_coverage_validate( coverage, valid );
00196
00197 if ( type > 5 )
00198 FT_INVALID_FORMAT;
00199
00200 func = fmt_funcs_table[type];
00201 if ( func == NULL )
00202 GXV_TRACE(( "morx type %d is reserved\n", type ));
00203
00204 func( p, p + rest, valid );
00205
00206 p += rest;
00207 }
00208
00209 valid->subtable_length = p - table;
00210
00211 GXV_EXIT;
00212 }
00213
00214
00215 static void
00216 gxv_mort_chain_validate( FT_Bytes table,
00217 FT_Bytes limit,
00218 GXV_Validator valid )
00219 {
00220 FT_Bytes p = table;
00221 FT_ULong defaultFlags;
00222 FT_ULong chainLength;
00223 FT_UShort nFeatureFlags;
00224 FT_UShort nSubtables;
00225
00226
00227 GXV_NAME_ENTER( "mort chain header" );
00228
00229 GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 );
00230 defaultFlags = FT_NEXT_ULONG( p );
00231 chainLength = FT_NEXT_ULONG( p );
00232 nFeatureFlags = FT_NEXT_USHORT( p );
00233 nSubtables = FT_NEXT_USHORT( p );
00234
00235 gxv_mort_featurearray_validate( p, table + chainLength,
00236 nFeatureFlags, valid );
00237 p += valid->subtable_length;
00238 gxv_mort_subtables_validate( p, table + chainLength, nSubtables, valid );
00239 valid->subtable_length = chainLength;
00240
00241 GXV_EXIT;
00242 }
00243
00244
00245 FT_LOCAL_DEF( void )
00246 gxv_mort_validate( FT_Bytes table,
00247 FT_Face face,
00248 FT_Validator ftvalid )
00249 {
00250 GXV_ValidatorRec validrec;
00251 GXV_Validator valid = &validrec;
00252 FT_Bytes p = table;
00253 FT_Bytes limit = 0;
00254 FT_ULong version;
00255 FT_ULong nChains;
00256 FT_ULong i;
00257
00258
00259 valid->root = ftvalid;
00260 valid->face = face;
00261 limit = valid->root->limit;
00262
00263 FT_TRACE3(( "validating `mort' table\n" ));
00264 GXV_INIT;
00265
00266 GXV_LIMIT_CHECK( 4 + 4 );
00267 version = FT_NEXT_ULONG( p );
00268 nChains = FT_NEXT_ULONG( p );
00269
00270 if (version != 0x00010000UL)
00271 FT_INVALID_FORMAT;
00272
00273 for ( i = 0; i < nChains; i++ )
00274 {
00275 GXV_TRACE(( "validating chain %d/%d\n", i + 1, nChains ));
00276 GXV_32BIT_ALIGNMENT_VALIDATE( p - table );
00277 gxv_mort_chain_validate( p, limit, valid );
00278 p += valid->subtable_length;
00279 }
00280
00281 FT_TRACE4(( "\n" ));
00282 }
00283
00284
00285