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