1/****************************************************************************
2 *
3 * gxvmorx1.c
4 *
5 * TrueTypeGX/AAT morx table validation
6 * body for type1 (Contextual Substitution) subtable.
7 *
8 * Copyright (C) 2005-2023 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
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
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
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
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
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
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 )
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