1/****************************************************************************
2 *
3 * gxvmort1.c
4 *
5 * TrueTypeGX/AAT mort 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 "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_type1_StateOptRec_
43 {
44 FT_UShort substitutionTable;
45 FT_UShort substitutionTable_length;
46
47 } GXV_mort_subtable_type1_StateOptRec,
48 *GXV_mort_subtable_type1_StateOptRecData;
49
50#define GXV_MORT_SUBTABLE_TYPE1_HEADER_SIZE \
51 ( GXV_STATETABLE_HEADER_SIZE + 2 )
52
53
54 static void
55 gxv_mort_subtable_type1_substitutionTable_load( FT_Bytes table,
56 FT_Bytes limit,
57 GXV_Validator gxvalid )
58 {
59 FT_Bytes p = table;
60
61 GXV_mort_subtable_type1_StateOptRecData optdata =
62 (GXV_mort_subtable_type1_StateOptRecData)gxvalid->statetable.optdata;
63
64
65 GXV_LIMIT_CHECK( 2 );
66 optdata->substitutionTable = FT_NEXT_USHORT( p );
67 }
68
69
70 static void
71 gxv_mort_subtable_type1_subtable_setup( FT_UShort table_size,
72 FT_UShort classTable,
73 FT_UShort stateArray,
74 FT_UShort entryTable,
75 FT_UShort* classTable_length_p,
76 FT_UShort* stateArray_length_p,
77 FT_UShort* entryTable_length_p,
78 GXV_Validator gxvalid )
79 {
80 FT_UShort o[4];
81 FT_UShort *l[4];
82 FT_UShort buff[5];
83
84 GXV_mort_subtable_type1_StateOptRecData optdata =
85 (GXV_mort_subtable_type1_StateOptRecData)gxvalid->statetable.optdata;
86
87
88 o[0] = classTable;
89 o[1] = stateArray;
90 o[2] = entryTable;
91 o[3] = optdata->substitutionTable;
92 l[0] = classTable_length_p;
93 l[1] = stateArray_length_p;
94 l[2] = entryTable_length_p;
95 l[3] = &( optdata->substitutionTable_length );
96
97 gxv_set_length_by_ushort_offset( o, l, buff, 4, table_size, gxvalid );
98 }
99
100
101 static void
102 gxv_mort_subtable_type1_offset_to_subst_validate(
103 FT_Short wordOffset,
104 const FT_String* tag,
105 FT_Byte state,
106 GXV_Validator gxvalid )
107 {
108 FT_UShort substTable;
109 FT_UShort substTable_limit;
110
111 FT_UNUSED( tag );
112 FT_UNUSED( state );
113
114
115 substTable =
116 ((GXV_mort_subtable_type1_StateOptRec *)
117 (gxvalid->statetable.optdata))->substitutionTable;
118 substTable_limit =
119 (FT_UShort)( substTable +
120 ((GXV_mort_subtable_type1_StateOptRec *)
121 (gxvalid->statetable.optdata))->substitutionTable_length );
122
123 gxvalid->min_gid = (FT_UShort)( ( substTable - wordOffset * 2 ) / 2 );
124 gxvalid->max_gid = (FT_UShort)( ( substTable_limit - wordOffset * 2 ) / 2 );
125 gxvalid->max_gid = (FT_UShort)( FT_MAX( gxvalid->max_gid,
126 gxvalid->face->num_glyphs ) );
127
128 /* XXX: check range? */
129
130 /* TODO: min_gid & max_gid comparison with ClassTable contents */
131 }
132
133
134 static void
135 gxv_mort_subtable_type1_entry_validate(
136 FT_Byte state,
137 FT_UShort flags,
138 GXV_StateTable_GlyphOffsetCPtr glyphOffset_p,
139 FT_Bytes table,
140 FT_Bytes limit,
141 GXV_Validator gxvalid )
142 {
143#ifdef GXV_LOAD_UNUSED_VARS
144 FT_UShort setMark;
145 FT_UShort dontAdvance;
146#endif
147 FT_UShort reserved;
148 FT_Short markOffset;
149 FT_Short currentOffset;
150
151 FT_UNUSED( table );
152 FT_UNUSED( limit );
153
154
155#ifdef GXV_LOAD_UNUSED_VARS
156 setMark = (FT_UShort)( flags >> 15 );
157 dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 );
158#endif
159 reserved = (FT_UShort)( flags & 0x3FFF );
160
161 markOffset = (FT_Short)( glyphOffset_p->ul >> 16 );
162 currentOffset = (FT_Short)( glyphOffset_p->ul );
163
164 if ( 0 < reserved )
165 {
166 GXV_TRACE(( " non-zero bits found in reserved range\n" ));
167 GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA );
168 }
169
170 gxv_mort_subtable_type1_offset_to_subst_validate( markOffset,
171 "markOffset",
172 state,
173 gxvalid );
174
175 gxv_mort_subtable_type1_offset_to_subst_validate( currentOffset,
176 "currentOffset",
177 state,
178 gxvalid );
179 }
180
181
182 static void
183 gxv_mort_subtable_type1_substTable_validate( FT_Bytes table,
184 FT_Bytes limit,
185 GXV_Validator gxvalid )
186 {
187 FT_Bytes p = table;
188 FT_UShort num_gids = (FT_UShort)(
189 ((GXV_mort_subtable_type1_StateOptRec *)
190 (gxvalid->statetable.optdata))->substitutionTable_length / 2 );
191 FT_UShort i;
192
193
194 GXV_NAME_ENTER( "validating contents of substitutionTable" );
195 for ( i = 0; i < num_gids; i++ )
196 {
197 FT_UShort dst_gid;
198
199
200 GXV_LIMIT_CHECK( 2 );
201 dst_gid = FT_NEXT_USHORT( p );
202
203 if ( dst_gid >= 0xFFFFU )
204 continue;
205
206 if ( dst_gid < gxvalid->min_gid || gxvalid->max_gid < dst_gid )
207 {
208 GXV_TRACE(( "substTable include a strange gid[%d]=%d >"
209 " out of define range (%d..%d)\n",
210 i, dst_gid, gxvalid->min_gid, gxvalid->max_gid ));
211 GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID );
212 }
213 }
214
215 GXV_EXIT;
216 }
217
218
219 /*
220 * subtable for Contextual glyph substitution is a modified StateTable.
221 * In addition to classTable, stateArray, and entryTable, the field
222 * `substitutionTable' is added.
223 */
224 FT_LOCAL_DEF( void )
225 gxv_mort_subtable_type1_validate( FT_Bytes table,
226 FT_Bytes limit,
227 GXV_Validator gxvalid )
228 {
229 FT_Bytes p = table;
230
231 GXV_mort_subtable_type1_StateOptRec st_rec;
232
233
234 GXV_NAME_ENTER( "mort chain subtable type1 (Contextual Glyph Subst)" );
235
236 GXV_LIMIT_CHECK( GXV_MORT_SUBTABLE_TYPE1_HEADER_SIZE );
237
238 gxvalid->statetable.optdata =
239 &st_rec;
240 gxvalid->statetable.optdata_load_func =
241 gxv_mort_subtable_type1_substitutionTable_load;
242 gxvalid->statetable.subtable_setup_func =
243 gxv_mort_subtable_type1_subtable_setup;
244 gxvalid->statetable.entry_glyphoffset_fmt =
245 GXV_GLYPHOFFSET_ULONG;
246 gxvalid->statetable.entry_validate_func =
247
248 gxv_mort_subtable_type1_entry_validate;
249 gxv_StateTable_validate( p, limit, gxvalid );
250
251 gxv_mort_subtable_type1_substTable_validate(
252 table + st_rec.substitutionTable,
253 table + st_rec.substitutionTable + st_rec.substitutionTable_length,
254 gxvalid );
255
256 GXV_EXIT;
257 }
258
259
260/* END */
261