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