Imported Upstream version 2.10.4
[platform/upstream/freetype2.git] / src / gxvalid / gxvmorx2.c
1 /****************************************************************************
2  *
3  * gxvmorx2.c
4  *
5  *   TrueTypeGX/AAT morx table validation
6  *   body for type2 (Ligature 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_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
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
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
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
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
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 )
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 */