• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  *
3  * gxvmorx2.c
4  *
5  *   TrueTypeGX/AAT morx table validation
6  *   body for type2 (Ligature Substitution) subtable.
7  *
8  * Copyright (C) 2005-2019 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_type2_StateOptRec_
43   {
44     FT_ULong  ligActionTable;
45     FT_ULong  componentTable;
46     FT_ULong  ligatureTable;
47     FT_ULong  ligActionTable_length;
48     FT_ULong  componentTable_length;
49     FT_ULong  ligatureTable_length;
50 
51   }  GXV_morx_subtable_type2_StateOptRec,
52     *GXV_morx_subtable_type2_StateOptRecData;
53 
54 
55 #define GXV_MORX_SUBTABLE_TYPE2_HEADER_SIZE \
56           ( GXV_XSTATETABLE_HEADER_SIZE + 4 + 4 + 4 )
57 
58 
59   static void
gxv_morx_subtable_type2_opttable_load(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)60   gxv_morx_subtable_type2_opttable_load( FT_Bytes       table,
61                                          FT_Bytes       limit,
62                                          GXV_Validator  gxvalid )
63   {
64     FT_Bytes  p = table;
65 
66     GXV_morx_subtable_type2_StateOptRecData  optdata =
67       (GXV_morx_subtable_type2_StateOptRecData)gxvalid->xstatetable.optdata;
68 
69 
70     GXV_LIMIT_CHECK( 4 + 4 + 4 );
71     optdata->ligActionTable = FT_NEXT_ULONG( p );
72     optdata->componentTable = FT_NEXT_ULONG( p );
73     optdata->ligatureTable  = FT_NEXT_ULONG( p );
74 
75     GXV_TRACE(( "offset to ligActionTable=0x%08x\n",
76                 optdata->ligActionTable ));
77     GXV_TRACE(( "offset to componentTable=0x%08x\n",
78                 optdata->componentTable ));
79     GXV_TRACE(( "offset to ligatureTable=0x%08x\n",
80                 optdata->ligatureTable ));
81   }
82 
83 
84   static void
gxv_morx_subtable_type2_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)85   gxv_morx_subtable_type2_subtable_setup( FT_ULong       table_size,
86                                           FT_ULong       classTable,
87                                           FT_ULong       stateArray,
88                                           FT_ULong       entryTable,
89                                           FT_ULong*      classTable_length_p,
90                                           FT_ULong*      stateArray_length_p,
91                                           FT_ULong*      entryTable_length_p,
92                                           GXV_Validator  gxvalid )
93   {
94     FT_ULong   o[6];
95     FT_ULong*  l[6];
96     FT_ULong   buff[7];
97 
98     GXV_morx_subtable_type2_StateOptRecData  optdata =
99       (GXV_morx_subtable_type2_StateOptRecData)gxvalid->xstatetable.optdata;
100 
101 
102     GXV_NAME_ENTER( "subtable boundaries setup" );
103 
104     o[0] = classTable;
105     o[1] = stateArray;
106     o[2] = entryTable;
107     o[3] = optdata->ligActionTable;
108     o[4] = optdata->componentTable;
109     o[5] = optdata->ligatureTable;
110     l[0] = classTable_length_p;
111     l[1] = stateArray_length_p;
112     l[2] = entryTable_length_p;
113     l[3] = &(optdata->ligActionTable_length);
114     l[4] = &(optdata->componentTable_length);
115     l[5] = &(optdata->ligatureTable_length);
116 
117     gxv_set_length_by_ulong_offset( o, l, buff, 6, table_size, gxvalid );
118 
119     GXV_TRACE(( "classTable: offset=0x%08x length=0x%08x\n",
120                 classTable, *classTable_length_p ));
121     GXV_TRACE(( "stateArray: offset=0x%08x length=0x%08x\n",
122                 stateArray, *stateArray_length_p ));
123     GXV_TRACE(( "entryTable: offset=0x%08x length=0x%08x\n",
124                 entryTable, *entryTable_length_p ));
125     GXV_TRACE(( "ligActionTable: offset=0x%08x length=0x%08x\n",
126                 optdata->ligActionTable,
127                 optdata->ligActionTable_length ));
128     GXV_TRACE(( "componentTable: offset=0x%08x length=0x%08x\n",
129                 optdata->componentTable,
130                 optdata->componentTable_length ));
131     GXV_TRACE(( "ligatureTable:  offset=0x%08x length=0x%08x\n",
132                 optdata->ligatureTable,
133                 optdata->ligatureTable_length ));
134 
135     GXV_EXIT;
136   }
137 
138 
139 #define GXV_MORX_LIGACTION_ENTRY_SIZE  4
140 
141 
142   static void
gxv_morx_subtable_type2_ligActionIndex_validate(FT_Bytes table,FT_UShort ligActionIndex,GXV_Validator gxvalid)143   gxv_morx_subtable_type2_ligActionIndex_validate(
144     FT_Bytes       table,
145     FT_UShort      ligActionIndex,
146     GXV_Validator  gxvalid )
147   {
148     /* access ligActionTable */
149     GXV_morx_subtable_type2_StateOptRecData optdata =
150       (GXV_morx_subtable_type2_StateOptRecData)gxvalid->xstatetable.optdata;
151 
152     FT_Bytes lat_base  = table + optdata->ligActionTable;
153     FT_Bytes p         = lat_base +
154                          ligActionIndex * GXV_MORX_LIGACTION_ENTRY_SIZE;
155     FT_Bytes lat_limit = lat_base + optdata->ligActionTable;
156 
157 
158     if ( p < lat_base )
159     {
160       GXV_TRACE(( "p < lat_base (%d byte rewind)\n", lat_base - p ));
161       FT_INVALID_OFFSET;
162     }
163     else if ( lat_limit < p )
164     {
165       GXV_TRACE(( "lat_limit < p (%d byte overrun)\n", p - lat_limit ));
166       FT_INVALID_OFFSET;
167     }
168 
169     {
170       /* validate entry in ligActionTable */
171       FT_ULong   lig_action;
172 #ifdef GXV_LOAD_UNUSED_VARS
173       FT_UShort  last;
174       FT_UShort  store;
175 #endif
176       FT_ULong   offset;
177       FT_Long    gid_limit;
178 
179 
180       lig_action = FT_NEXT_ULONG( p );
181 #ifdef GXV_LOAD_UNUSED_VARS
182       last       = (FT_UShort)( ( lig_action >> 31 ) & 1 );
183       store      = (FT_UShort)( ( lig_action >> 30 ) & 1 );
184 #endif
185 
186       offset = lig_action & 0x3FFFFFFFUL;
187 
188       /* this offset is 30-bit signed value to add to GID */
189       /* it is different from the location offset in mort */
190       if ( ( offset & 0x3FFF0000UL ) == 0x3FFF0000UL )
191       { /* negative offset */
192         gid_limit = gxvalid->face->num_glyphs -
193                     (FT_Long)( offset & 0x0000FFFFUL );
194         if ( gid_limit > 0 )
195           return;
196 
197         GXV_TRACE(( "ligature action table includes"
198                     " too negative offset moving all GID"
199                     " below defined range: 0x%04x\n",
200                     offset & 0xFFFFU ));
201         GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
202       }
203       else if ( ( offset & 0x3FFF0000UL ) == 0x00000000UL )
204       { /* positive offset */
205         if ( (FT_Long)offset < gxvalid->face->num_glyphs )
206           return;
207 
208         GXV_TRACE(( "ligature action table includes"
209                     " too large offset moving all GID"
210                     " over defined range: 0x%04x\n",
211                     offset & 0xFFFFU ));
212         GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
213       }
214 
215       GXV_TRACE(( "ligature action table includes"
216                   " invalid offset to add to 16-bit GID:"
217                   " 0x%08x\n", offset ));
218       GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
219     }
220   }
221 
222 
223   static void
gxv_morx_subtable_type2_entry_validate(FT_UShort state,FT_UShort flags,GXV_StateTable_GlyphOffsetCPtr glyphOffset_p,FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)224   gxv_morx_subtable_type2_entry_validate(
225     FT_UShort                       state,
226     FT_UShort                       flags,
227     GXV_StateTable_GlyphOffsetCPtr  glyphOffset_p,
228     FT_Bytes                        table,
229     FT_Bytes                        limit,
230     GXV_Validator                   gxvalid )
231   {
232 #ifdef GXV_LOAD_UNUSED_VARS
233     FT_UShort  setComponent;
234     FT_UShort  dontAdvance;
235     FT_UShort  performAction;
236 #endif
237     FT_UShort  reserved;
238     FT_UShort  ligActionIndex;
239 
240     FT_UNUSED( state );
241     FT_UNUSED( limit );
242 
243 
244 #ifdef GXV_LOAD_UNUSED_VARS
245     setComponent   = (FT_UShort)( ( flags >> 15 ) & 1 );
246     dontAdvance    = (FT_UShort)( ( flags >> 14 ) & 1 );
247     performAction  = (FT_UShort)( ( flags >> 13 ) & 1 );
248 #endif
249 
250     reserved       = (FT_UShort)( flags & 0x1FFF );
251     ligActionIndex = glyphOffset_p->u;
252 
253     if ( reserved > 0 )
254       GXV_TRACE(( "  reserved 14bit is non-zero\n" ));
255 
256     if ( 0 < ligActionIndex )
257       gxv_morx_subtable_type2_ligActionIndex_validate(
258         table, ligActionIndex, gxvalid );
259   }
260 
261 
262   static void
gxv_morx_subtable_type2_ligatureTable_validate(FT_Bytes table,GXV_Validator gxvalid)263   gxv_morx_subtable_type2_ligatureTable_validate( FT_Bytes       table,
264                                                   GXV_Validator  gxvalid )
265   {
266     GXV_morx_subtable_type2_StateOptRecData  optdata =
267       (GXV_morx_subtable_type2_StateOptRecData)gxvalid->xstatetable.optdata;
268 
269     FT_Bytes p     = table + optdata->ligatureTable;
270     FT_Bytes limit = table + optdata->ligatureTable
271                            + optdata->ligatureTable_length;
272 
273 
274     GXV_NAME_ENTER( "morx chain subtable type2 - substitutionTable" );
275 
276     if ( 0 != optdata->ligatureTable )
277     {
278       /* Apple does not give specification of ligatureTable format */
279       while ( p < limit )
280       {
281         FT_UShort  lig_gid;
282 
283 
284         GXV_LIMIT_CHECK( 2 );
285         lig_gid = FT_NEXT_USHORT( p );
286         if ( lig_gid < gxvalid->face->num_glyphs )
287           GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID );
288       }
289     }
290 
291     GXV_EXIT;
292   }
293 
294 
295   FT_LOCAL_DEF( void )
gxv_morx_subtable_type2_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)296   gxv_morx_subtable_type2_validate( FT_Bytes       table,
297                                     FT_Bytes       limit,
298                                     GXV_Validator  gxvalid )
299   {
300     FT_Bytes  p = table;
301 
302     GXV_morx_subtable_type2_StateOptRec  lig_rec;
303 
304 
305     GXV_NAME_ENTER( "morx chain subtable type2 (Ligature Substitution)" );
306 
307     GXV_LIMIT_CHECK( GXV_MORX_SUBTABLE_TYPE2_HEADER_SIZE );
308 
309     gxvalid->xstatetable.optdata =
310       &lig_rec;
311     gxvalid->xstatetable.optdata_load_func =
312       gxv_morx_subtable_type2_opttable_load;
313     gxvalid->xstatetable.subtable_setup_func =
314       gxv_morx_subtable_type2_subtable_setup;
315     gxvalid->xstatetable.entry_glyphoffset_fmt =
316       GXV_GLYPHOFFSET_USHORT;
317     gxvalid->xstatetable.entry_validate_func =
318       gxv_morx_subtable_type2_entry_validate;
319 
320     gxv_XStateTable_validate( p, limit, gxvalid );
321 
322 #if 0
323     p += gxvalid->subtable_length;
324 #endif
325     gxv_morx_subtable_type2_ligatureTable_validate( table, gxvalid );
326 
327     GXV_EXIT;
328   }
329 
330 
331 /* END */
332