• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  *
3  * gxvmort.c
4  *
5  *   TrueTypeGX/AAT mort table validation (body).
6  *
7  * Copyright (C) 2005-2020 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  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     FT_UNUSED( coverage );
127 
128 #ifdef FT_DEBUG_LEVEL_TRACE
129     if ( coverage & 0x8000U )
130       GXV_TRACE(( " this subtable is for vertical text only\n" ));
131     else
132       GXV_TRACE(( " this subtable is for horizontal text only\n" ));
133 
134     if ( coverage & 0x4000 )
135       GXV_TRACE(( " this subtable is applied to glyph array "
136                   "in descending order\n" ));
137     else
138       GXV_TRACE(( " this subtable is applied to glyph array "
139                   "in ascending order\n" ));
140 
141     if ( coverage & 0x2000 )
142       GXV_TRACE(( " this subtable is forcibly applied to "
143                   "vertical/horizontal text\n" ));
144 
145     if ( coverage & 0x1FF8 )
146       GXV_TRACE(( " coverage has non-zero bits in reserved area\n" ));
147 #endif
148   }
149 
150 
151   static void
gxv_mort_subtables_validate(FT_Bytes table,FT_Bytes limit,FT_UShort nSubtables,GXV_Validator gxvalid)152   gxv_mort_subtables_validate( FT_Bytes       table,
153                                FT_Bytes       limit,
154                                FT_UShort      nSubtables,
155                                GXV_Validator  gxvalid )
156   {
157     FT_Bytes  p = table;
158 
159     GXV_Validate_Func fmt_funcs_table[] =
160     {
161       gxv_mort_subtable_type0_validate, /* 0 */
162       gxv_mort_subtable_type1_validate, /* 1 */
163       gxv_mort_subtable_type2_validate, /* 2 */
164       NULL,                             /* 3 */
165       gxv_mort_subtable_type4_validate, /* 4 */
166       gxv_mort_subtable_type5_validate, /* 5 */
167 
168     };
169 
170     FT_UShort  i;
171 
172 
173     GXV_NAME_ENTER( "subtables in a chain" );
174 
175     for ( i = 0; i < nSubtables; i++ )
176     {
177       GXV_Validate_Func  func;
178 
179       FT_UShort  length;
180       FT_UShort  coverage;
181 #ifdef GXV_LOAD_UNUSED_VARS
182       FT_ULong   subFeatureFlags;
183 #endif
184       FT_UInt    type;
185       FT_UInt    rest;
186 
187 
188       GXV_LIMIT_CHECK( 2 + 2 + 4 );
189       length          = FT_NEXT_USHORT( p );
190       coverage        = FT_NEXT_USHORT( p );
191 #ifdef GXV_LOAD_UNUSED_VARS
192       subFeatureFlags = FT_NEXT_ULONG( p );
193 #else
194       p += 4;
195 #endif
196 
197       GXV_TRACE(( "validating chain subtable %d/%d (%d bytes)\n",
198                   i + 1, nSubtables, length ));
199       type = coverage & 0x0007;
200       rest = length - ( 2 + 2 + 4 );
201 
202       GXV_LIMIT_CHECK( rest );
203       gxv_mort_coverage_validate( coverage, gxvalid );
204 
205       if ( type > 5 )
206         FT_INVALID_FORMAT;
207 
208       func = fmt_funcs_table[type];
209       if ( !func )
210         GXV_TRACE(( "morx type %d is reserved\n", type ));
211 
212       func( p, p + rest, gxvalid );
213 
214       p += rest;
215       /* TODO: validate subFeatureFlags */
216     }
217 
218     gxvalid->subtable_length = (FT_ULong)( p - table );
219 
220     GXV_EXIT;
221   }
222 
223 
224   static void
gxv_mort_chain_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)225   gxv_mort_chain_validate( FT_Bytes       table,
226                            FT_Bytes       limit,
227                            GXV_Validator  gxvalid )
228   {
229     FT_Bytes   p = table;
230 #ifdef GXV_LOAD_UNUSED_VARS
231     FT_ULong   defaultFlags;
232 #endif
233     FT_ULong   chainLength;
234     FT_UShort  nFeatureFlags;
235     FT_UShort  nSubtables;
236 
237 
238     GXV_NAME_ENTER( "mort chain header" );
239 
240     GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 );
241 #ifdef GXV_LOAD_UNUSED_VARS
242     defaultFlags  = FT_NEXT_ULONG( p );
243 #else
244     p += 4;
245 #endif
246     chainLength   = FT_NEXT_ULONG( p );
247     nFeatureFlags = FT_NEXT_USHORT( p );
248     nSubtables    = FT_NEXT_USHORT( p );
249 
250     gxv_mort_featurearray_validate( p, table + chainLength,
251                                     nFeatureFlags, gxvalid );
252     p += gxvalid->subtable_length;
253     gxv_mort_subtables_validate( p, table + chainLength, nSubtables, gxvalid );
254     gxvalid->subtable_length = chainLength;
255 
256     /* TODO: validate defaultFlags */
257     GXV_EXIT;
258   }
259 
260 
261   FT_LOCAL_DEF( void )
gxv_mort_validate(FT_Bytes table,FT_Face face,FT_Validator ftvalid)262   gxv_mort_validate( FT_Bytes      table,
263                      FT_Face       face,
264                      FT_Validator  ftvalid )
265   {
266     GXV_ValidatorRec  gxvalidrec;
267     GXV_Validator     gxvalid = &gxvalidrec;
268     FT_Bytes          p     = table;
269     FT_Bytes          limit = 0;
270     FT_ULong          version;
271     FT_ULong          nChains;
272     FT_ULong          i;
273 
274 
275     gxvalid->root = ftvalid;
276     gxvalid->face = face;
277     limit         = gxvalid->root->limit;
278 
279     FT_TRACE3(( "validating `mort' table\n" ));
280     GXV_INIT;
281 
282     GXV_LIMIT_CHECK( 4 + 4 );
283     version = FT_NEXT_ULONG( p );
284     nChains = FT_NEXT_ULONG( p );
285 
286     if (version != 0x00010000UL)
287       FT_INVALID_FORMAT;
288 
289     for ( i = 0; i < nChains; i++ )
290     {
291       GXV_TRACE(( "validating chain %d/%d\n", i + 1, nChains ));
292       GXV_32BIT_ALIGNMENT_VALIDATE( p - table );
293       gxv_mort_chain_validate( p, limit, gxvalid );
294       p += gxvalid->subtable_length;
295     }
296 
297     FT_TRACE4(( "\n" ));
298   }
299 
300 
301 /* END */
302