1 /***************************************************************************/
2 /*                                                                         */
3 /*  gxvmort.c                                                              */
4 /*                                                                         */
5 /*    TrueTypeGX/AAT mort table validation (body).                         */
6 /*                                                                         */
7 /*  Copyright 2005, 2013 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 "gxvmort.h"
28 #include "gxvfeat.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_gxvmort
39 
40 
41   static void
gxv_mort_feature_validate(GXV_mort_feature f,GXV_Validator valid)42   gxv_mort_feature_validate( GXV_mort_feature  f,
43                              GXV_Validator     valid )
44   {
45     if ( f->featureType >= gxv_feat_registry_length )
46     {
47       GXV_TRACE(( "featureType %d is out of registered range, "
48                   "setting %d is unchecked\n",
49                   f->featureType, f->featureSetting ));
50       GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA );
51     }
52     else if ( !gxv_feat_registry[f->featureType].existence )
53     {
54       GXV_TRACE(( "featureType %d is within registered area "
55                   "but undefined, setting %d is unchecked\n",
56                   f->featureType, f->featureSetting ));
57       GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA );
58     }
59     else
60     {
61       FT_Byte  nSettings_max;
62 
63 
64       /* nSettings in gxvfeat.c is halved for exclusive on/off settings */
65       nSettings_max = gxv_feat_registry[f->featureType].nSettings;
66       if ( gxv_feat_registry[f->featureType].exclusive )
67         nSettings_max = (FT_Byte)( 2 * nSettings_max );
68 
69       GXV_TRACE(( "featureType %d is registered", f->featureType ));
70       GXV_TRACE(( "setting %d", f->featureSetting ));
71 
72       if ( f->featureSetting > nSettings_max )
73       {
74         GXV_TRACE(( "out of defined range %d", nSettings_max ));
75         GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA );
76       }
77       GXV_TRACE(( "\n" ));
78     }
79 
80     /* TODO: enableFlags must be unique value in specified chain?  */
81   }
82 
83 
84   /*
85    * nFeatureFlags is typed to FT_ULong to accept that in
86    * mort (typed FT_UShort) and morx (typed FT_ULong).
87    */
88   FT_LOCAL_DEF( void )
gxv_mort_featurearray_validate(FT_Bytes table,FT_Bytes limit,FT_ULong nFeatureFlags,GXV_Validator valid)89   gxv_mort_featurearray_validate( FT_Bytes       table,
90                                   FT_Bytes       limit,
91                                   FT_ULong       nFeatureFlags,
92                                   GXV_Validator  valid )
93   {
94     FT_Bytes  p = table;
95     FT_ULong  i;
96 
97     GXV_mort_featureRec  f = GXV_MORT_FEATURE_OFF;
98 
99 
100     GXV_NAME_ENTER( "mort feature list" );
101     for ( i = 0; i < nFeatureFlags; i++ )
102     {
103       GXV_LIMIT_CHECK( 2 + 2 + 4 + 4 );
104       f.featureType    = FT_NEXT_USHORT( p );
105       f.featureSetting = FT_NEXT_USHORT( p );
106       f.enableFlags    = FT_NEXT_ULONG( p );
107       f.disableFlags   = FT_NEXT_ULONG( p );
108 
109       gxv_mort_feature_validate( &f, valid );
110     }
111 
112     if ( !IS_GXV_MORT_FEATURE_OFF( f ) )
113       FT_INVALID_DATA;
114 
115     valid->subtable_length = p - table;
116     GXV_EXIT;
117   }
118 
119 
120   FT_LOCAL_DEF( void )
gxv_mort_coverage_validate(FT_UShort coverage,GXV_Validator valid)121   gxv_mort_coverage_validate( FT_UShort      coverage,
122                               GXV_Validator  valid )
123   {
124     FT_UNUSED( valid );
125 
126 #ifdef FT_DEBUG_LEVEL_TRACE
127     if ( coverage & 0x8000U )
128       GXV_TRACE(( " this subtable is for vertical text only\n" ));
129     else
130       GXV_TRACE(( " this subtable is for horizontal text only\n" ));
131 
132     if ( coverage & 0x4000 )
133       GXV_TRACE(( " this subtable is applied to glyph array "
134                   "in descending order\n" ));
135     else
136       GXV_TRACE(( " this subtable is applied to glyph array "
137                   "in ascending order\n" ));
138 
139     if ( coverage & 0x2000 )
140       GXV_TRACE(( " this subtable is forcibly applied to "
141                   "vertical/horizontal text\n" ));
142 
143     if ( coverage & 0x1FF8 )
144       GXV_TRACE(( " coverage has non-zero bits in reserved area\n" ));
145 #endif
146   }
147 
148 
149   static void
gxv_mort_subtables_validate(FT_Bytes table,FT_Bytes limit,FT_UShort nSubtables,GXV_Validator valid)150   gxv_mort_subtables_validate( FT_Bytes       table,
151                                FT_Bytes       limit,
152                                FT_UShort      nSubtables,
153                                GXV_Validator  valid )
154   {
155     FT_Bytes  p = table;
156 
157     GXV_Validate_Func fmt_funcs_table[] =
158     {
159       gxv_mort_subtable_type0_validate, /* 0 */
160       gxv_mort_subtable_type1_validate, /* 1 */
161       gxv_mort_subtable_type2_validate, /* 2 */
162       NULL,                             /* 3 */
163       gxv_mort_subtable_type4_validate, /* 4 */
164       gxv_mort_subtable_type5_validate, /* 5 */
165 
166     };
167 
168     FT_UShort  i;
169 
170 
171     GXV_NAME_ENTER( "subtables in a chain" );
172 
173     for ( i = 0; i < nSubtables; i++ )
174     {
175       GXV_Validate_Func  func;
176 
177       FT_UShort  length;
178       FT_UShort  coverage;
179 #ifdef GXV_LOAD_UNUSED_VARS
180       FT_ULong   subFeatureFlags;
181 #endif
182       FT_UInt    type;
183       FT_UInt    rest;
184 
185 
186       GXV_LIMIT_CHECK( 2 + 2 + 4 );
187       length          = FT_NEXT_USHORT( p );
188       coverage        = FT_NEXT_USHORT( p );
189 #ifdef GXV_LOAD_UNUSED_VARS
190       subFeatureFlags = FT_NEXT_ULONG( p );
191 #else
192       p += 4;
193 #endif
194 
195       GXV_TRACE(( "validating chain subtable %d/%d (%d bytes)\n",
196                   i + 1, nSubtables, length ));
197       type = coverage & 0x0007;
198       rest = length - ( 2 + 2 + 4 );
199 
200       GXV_LIMIT_CHECK( rest );
201       gxv_mort_coverage_validate( coverage, valid );
202 
203       if ( type > 5 )
204         FT_INVALID_FORMAT;
205 
206       func = fmt_funcs_table[type];
207       if ( func == NULL )
208         GXV_TRACE(( "morx type %d is reserved\n", type ));
209 
210       func( p, p + rest, valid );
211 
212       p += rest;
213       /* TODO: validate subFeatureFlags */
214     }
215 
216     valid->subtable_length = p - table;
217 
218     GXV_EXIT;
219   }
220 
221 
222   static void
gxv_mort_chain_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator valid)223   gxv_mort_chain_validate( FT_Bytes       table,
224                            FT_Bytes       limit,
225                            GXV_Validator  valid )
226   {
227     FT_Bytes   p = table;
228 #ifdef GXV_LOAD_UNUSED_VARS
229     FT_ULong   defaultFlags;
230 #endif
231     FT_ULong   chainLength;
232     FT_UShort  nFeatureFlags;
233     FT_UShort  nSubtables;
234 
235 
236     GXV_NAME_ENTER( "mort chain header" );
237 
238     GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 );
239 #ifdef GXV_LOAD_UNUSED_VARS
240     defaultFlags  = FT_NEXT_ULONG( p );
241 #else
242     p += 4;
243 #endif
244     chainLength   = FT_NEXT_ULONG( p );
245     nFeatureFlags = FT_NEXT_USHORT( p );
246     nSubtables    = FT_NEXT_USHORT( p );
247 
248     gxv_mort_featurearray_validate( p, table + chainLength,
249                                     nFeatureFlags, valid );
250     p += valid->subtable_length;
251     gxv_mort_subtables_validate( p, table + chainLength, nSubtables, valid );
252     valid->subtable_length = chainLength;
253 
254     /* TODO: validate defaultFlags */
255     GXV_EXIT;
256   }
257 
258 
259   FT_LOCAL_DEF( void )
gxv_mort_validate(FT_Bytes table,FT_Face face,FT_Validator ftvalid)260   gxv_mort_validate( FT_Bytes      table,
261                      FT_Face       face,
262                      FT_Validator  ftvalid )
263   {
264     GXV_ValidatorRec  validrec;
265     GXV_Validator     valid = &validrec;
266     FT_Bytes          p     = table;
267     FT_Bytes          limit = 0;
268     FT_ULong          version;
269     FT_ULong          nChains;
270     FT_ULong          i;
271 
272 
273     valid->root = ftvalid;
274     valid->face = face;
275     limit       = valid->root->limit;
276 
277     FT_TRACE3(( "validating `mort' table\n" ));
278     GXV_INIT;
279 
280     GXV_LIMIT_CHECK( 4 + 4 );
281     version = FT_NEXT_ULONG( p );
282     nChains = FT_NEXT_ULONG( p );
283 
284     if (version != 0x00010000UL)
285       FT_INVALID_FORMAT;
286 
287     for ( i = 0; i < nChains; i++ )
288     {
289       GXV_TRACE(( "validating chain %d/%d\n", i + 1, nChains ));
290       GXV_32BIT_ALIGNMENT_VALIDATE( p - table );
291       gxv_mort_chain_validate( p, limit, valid );
292       p += valid->subtable_length;
293     }
294 
295     FT_TRACE4(( "\n" ));
296   }
297 
298 
299 /* END */
300