1 /****************************************************************************
2  *
3  * gxvmort2.c
4  *
5  *   TrueTypeGX/AAT mort 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 "gxvmort.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   typedef struct  GXV_mort_subtable_type2_StateOptRec_
43   {
44     FT_UShort  ligActionTable;
45     FT_UShort  componentTable;
46     FT_UShort  ligatureTable;
47     FT_UShort  ligActionTable_length;
48     FT_UShort  componentTable_length;
49     FT_UShort  ligatureTable_length;
50 
51   }  GXV_mort_subtable_type2_StateOptRec,
52     *GXV_mort_subtable_type2_StateOptRecData;
53 
54 #define GXV_MORT_SUBTABLE_TYPE2_HEADER_SIZE \
55           ( GXV_STATETABLE_HEADER_SIZE + 2 + 2 + 2 )
56 
57 
58   static void
gxv_mort_subtable_type2_opttable_load(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)59   gxv_mort_subtable_type2_opttable_load( FT_Bytes       table,
60                                          FT_Bytes       limit,
61                                          GXV_Validator  gxvalid )
62   {
63     FT_Bytes  p = table;
64     GXV_mort_subtable_type2_StateOptRecData  optdata =
65       (GXV_mort_subtable_type2_StateOptRecData)gxvalid->statetable.optdata;
66 
67 
68     GXV_LIMIT_CHECK( 2 + 2 + 2 );
69     optdata->ligActionTable = FT_NEXT_USHORT( p );
70     optdata->componentTable = FT_NEXT_USHORT( p );
71     optdata->ligatureTable  = FT_NEXT_USHORT( p );
72 
73     GXV_TRACE(( "offset to ligActionTable=0x%04x\n",
74                 optdata->ligActionTable ));
75     GXV_TRACE(( "offset to componentTable=0x%04x\n",
76                 optdata->componentTable ));
77     GXV_TRACE(( "offset to ligatureTable=0x%04x\n",
78                 optdata->ligatureTable ));
79   }
80 
81 
82   static void
gxv_mort_subtable_type2_subtable_setup(FT_UShort table_size,FT_UShort classTable,FT_UShort stateArray,FT_UShort entryTable,FT_UShort * classTable_length_p,FT_UShort * stateArray_length_p,FT_UShort * entryTable_length_p,GXV_Validator gxvalid)83   gxv_mort_subtable_type2_subtable_setup( FT_UShort      table_size,
84                                           FT_UShort      classTable,
85                                           FT_UShort      stateArray,
86                                           FT_UShort      entryTable,
87                                           FT_UShort      *classTable_length_p,
88                                           FT_UShort      *stateArray_length_p,
89                                           FT_UShort      *entryTable_length_p,
90                                           GXV_Validator  gxvalid )
91   {
92     FT_UShort  o[6];
93     FT_UShort  *l[6];
94     FT_UShort  buff[7];
95 
96     GXV_mort_subtable_type2_StateOptRecData  optdata =
97       (GXV_mort_subtable_type2_StateOptRecData)gxvalid->statetable.optdata;
98 
99 
100     GXV_NAME_ENTER( "subtable boundaries setup" );
101 
102     o[0] = classTable;
103     o[1] = stateArray;
104     o[2] = entryTable;
105     o[3] = optdata->ligActionTable;
106     o[4] = optdata->componentTable;
107     o[5] = optdata->ligatureTable;
108     l[0] = classTable_length_p;
109     l[1] = stateArray_length_p;
110     l[2] = entryTable_length_p;
111     l[3] = &(optdata->ligActionTable_length);
112     l[4] = &(optdata->componentTable_length);
113     l[5] = &(optdata->ligatureTable_length);
114 
115     gxv_set_length_by_ushort_offset( o, l, buff, 6, table_size, gxvalid );
116 
117     GXV_TRACE(( "classTable: offset=0x%04x length=0x%04x\n",
118                 classTable, *classTable_length_p ));
119     GXV_TRACE(( "stateArray: offset=0x%04x length=0x%04x\n",
120                 stateArray, *stateArray_length_p ));
121     GXV_TRACE(( "entryTable: offset=0x%04x length=0x%04x\n",
122                 entryTable, *entryTable_length_p ));
123     GXV_TRACE(( "ligActionTable: offset=0x%04x length=0x%04x\n",
124                 optdata->ligActionTable,
125                 optdata->ligActionTable_length ));
126     GXV_TRACE(( "componentTable: offset=0x%04x length=0x%04x\n",
127                 optdata->componentTable,
128                 optdata->componentTable_length ));
129     GXV_TRACE(( "ligatureTable:  offset=0x%04x length=0x%04x\n",
130                 optdata->ligatureTable,
131                 optdata->ligatureTable_length ));
132 
133     GXV_EXIT;
134   }
135 
136 
137   static void
gxv_mort_subtable_type2_ligActionOffset_validate(FT_Bytes table,FT_UShort ligActionOffset,GXV_Validator gxvalid)138   gxv_mort_subtable_type2_ligActionOffset_validate(
139     FT_Bytes       table,
140     FT_UShort      ligActionOffset,
141     GXV_Validator  gxvalid )
142   {
143     /* access ligActionTable */
144     GXV_mort_subtable_type2_StateOptRecData  optdata =
145       (GXV_mort_subtable_type2_StateOptRecData)gxvalid->statetable.optdata;
146 
147     FT_Bytes lat_base  = table + optdata->ligActionTable;
148     FT_Bytes p         = table + ligActionOffset;
149     FT_Bytes lat_limit = lat_base + optdata->ligActionTable;
150 
151 
152     GXV_32BIT_ALIGNMENT_VALIDATE( ligActionOffset );
153     if ( p < lat_base )
154     {
155       GXV_TRACE(( "too short offset 0x%04x: p < lat_base (%d byte rewind)\n",
156                   ligActionOffset, lat_base - p ));
157 
158       /* FontValidator, ftxvalidator, ftxdumperfuser warn but continue */
159       GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
160     }
161     else if ( lat_limit < p )
162     {
163       GXV_TRACE(( "too large offset 0x%04x: lat_limit < p (%d byte overrun)\n",
164                   ligActionOffset, p - lat_limit ));
165 
166       /* FontValidator, ftxvalidator, ftxdumperfuser warn but continue */
167       GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
168     }
169     else
170     {
171       /* validate entry in ligActionTable */
172       FT_ULong   lig_action;
173 #ifdef GXV_LOAD_UNUSED_VARS
174       FT_UShort  last;
175       FT_UShort  store;
176 #endif
177       FT_ULong   offset;
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       /* Apple spec defines this offset as a word offset */
187       offset = lig_action & 0x3FFFFFFFUL;
188       if ( offset * 2 < optdata->ligatureTable )
189       {
190         GXV_TRACE(( "too short offset 0x%08x:"
191                     " 2 x offset < ligatureTable (%d byte rewind)\n",
192                      offset, optdata->ligatureTable - offset * 2 ));
193 
194         GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
195       } else if ( offset * 2 >
196                   optdata->ligatureTable + optdata->ligatureTable_length )
197       {
198         GXV_TRACE(( "too long offset 0x%08x:"
199                     " 2 x offset > ligatureTable + ligatureTable_length"
200                     " (%d byte overrun)\n",
201                      offset,
202                      optdata->ligatureTable + optdata->ligatureTable_length
203                      - offset * 2 ));
204 
205         GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
206       }
207     }
208   }
209 
210 
211   static void
gxv_mort_subtable_type2_entry_validate(FT_Byte state,FT_UShort flags,GXV_StateTable_GlyphOffsetCPtr glyphOffset_p,FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)212   gxv_mort_subtable_type2_entry_validate(
213     FT_Byte                         state,
214     FT_UShort                       flags,
215     GXV_StateTable_GlyphOffsetCPtr  glyphOffset_p,
216     FT_Bytes                        table,
217     FT_Bytes                        limit,
218     GXV_Validator                   gxvalid )
219   {
220 #ifdef GXV_LOAD_UNUSED_VARS
221     FT_UShort setComponent;
222     FT_UShort dontAdvance;
223 #endif
224     FT_UShort offset;
225 
226     FT_UNUSED( state );
227     FT_UNUSED( glyphOffset_p );
228     FT_UNUSED( limit );
229 
230 
231 #ifdef GXV_LOAD_UNUSED_VARS
232     setComponent = (FT_UShort)( ( flags >> 15 ) & 1 );
233     dontAdvance  = (FT_UShort)( ( flags >> 14 ) & 1 );
234 #endif
235 
236     offset = (FT_UShort)( flags & 0x3FFFU );
237 
238     if ( 0 < offset )
239       gxv_mort_subtable_type2_ligActionOffset_validate( table, offset,
240                                                         gxvalid );
241   }
242 
243 
244   static void
gxv_mort_subtable_type2_ligatureTable_validate(FT_Bytes table,GXV_Validator gxvalid)245   gxv_mort_subtable_type2_ligatureTable_validate( FT_Bytes       table,
246                                                   GXV_Validator  gxvalid )
247   {
248     GXV_mort_subtable_type2_StateOptRecData  optdata =
249       (GXV_mort_subtable_type2_StateOptRecData)gxvalid->statetable.optdata;
250 
251     FT_Bytes p     = table + optdata->ligatureTable;
252     FT_Bytes limit = table + optdata->ligatureTable
253                            + optdata->ligatureTable_length;
254 
255 
256     GXV_NAME_ENTER( "mort chain subtable type2 - substitutionTable" );
257     if ( 0 != optdata->ligatureTable )
258     {
259       /* Apple does not give specification of ligatureTable format */
260       while ( p < limit )
261       {
262         FT_UShort  lig_gid;
263 
264 
265         GXV_LIMIT_CHECK( 2 );
266         lig_gid = FT_NEXT_USHORT( p );
267 
268         if ( gxvalid->face->num_glyphs < lig_gid )
269           GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID );
270       }
271     }
272     GXV_EXIT;
273   }
274 
275 
276   FT_LOCAL_DEF( void )
gxv_mort_subtable_type2_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)277   gxv_mort_subtable_type2_validate( FT_Bytes       table,
278                                     FT_Bytes       limit,
279                                     GXV_Validator  gxvalid )
280   {
281     FT_Bytes  p = table;
282 
283     GXV_mort_subtable_type2_StateOptRec  lig_rec;
284 
285 
286     GXV_NAME_ENTER( "mort chain subtable type2 (Ligature Substitution)" );
287 
288     GXV_LIMIT_CHECK( GXV_MORT_SUBTABLE_TYPE2_HEADER_SIZE );
289 
290     gxvalid->statetable.optdata =
291       &lig_rec;
292     gxvalid->statetable.optdata_load_func =
293       gxv_mort_subtable_type2_opttable_load;
294     gxvalid->statetable.subtable_setup_func =
295       gxv_mort_subtable_type2_subtable_setup;
296     gxvalid->statetable.entry_glyphoffset_fmt =
297       GXV_GLYPHOFFSET_NONE;
298     gxvalid->statetable.entry_validate_func =
299       gxv_mort_subtable_type2_entry_validate;
300 
301     gxv_StateTable_validate( p, limit, gxvalid );
302 
303     p += gxvalid->subtable_length;
304     gxv_mort_subtable_type2_ligatureTable_validate( table, gxvalid );
305 
306     gxvalid->subtable_length = (FT_ULong)( p - table );
307 
308     GXV_EXIT;
309   }
310 
311 
312 /* END */
313