1 | /**************************************************************************** |
2 | * |
3 | * gxvfeat.c |
4 | * |
5 | * TrueTypeGX/AAT feat table validation (body). |
6 | * |
7 | * Copyright (C) 2004-2023 by |
8 | * suzuki toshiya, Masatake YAMATO, Red Hat K.K., |
9 | * David Turner, Robert Wilhelm, and Werner Lemberg. |
10 | * |
11 | * This file is part of the FreeType project, and may only be used, |
12 | * modified, and distributed under the terms of the FreeType project |
13 | * license, LICENSE.TXT. By continuing to use, modify, or distribute |
14 | * this file you indicate that you have read the license and |
15 | * understand and accept it fully. |
16 | * |
17 | */ |
18 | |
19 | /**************************************************************************** |
20 | * |
21 | * gxvalid is derived from both gxlayout module and otvalid module. |
22 | * Development of gxlayout is supported by the Information-technology |
23 | * Promotion Agency(IPA), Japan. |
24 | * |
25 | */ |
26 | |
27 | |
28 | #include "gxvalid.h" |
29 | #include "gxvcommn.h" |
30 | #include "gxvfeat.h" |
31 | |
32 | |
33 | /************************************************************************** |
34 | * |
35 | * The macro FT_COMPONENT is used in trace mode. It is an implicit |
36 | * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log |
37 | * messages during execution. |
38 | */ |
39 | #undef FT_COMPONENT |
40 | #define FT_COMPONENT gxvfeat |
41 | |
42 | |
43 | /*************************************************************************/ |
44 | /*************************************************************************/ |
45 | /***** *****/ |
46 | /***** Data and Types *****/ |
47 | /***** *****/ |
48 | /*************************************************************************/ |
49 | /*************************************************************************/ |
50 | |
51 | typedef struct GXV_feat_DataRec_ |
52 | { |
53 | FT_UInt reserved_size; |
54 | FT_UShort feature; |
55 | FT_UShort setting; |
56 | |
57 | } GXV_feat_DataRec, *GXV_feat_Data; |
58 | |
59 | |
60 | #define GXV_FEAT_DATA( field ) GXV_TABLE_DATA( feat, field ) |
61 | |
62 | |
63 | typedef enum GXV_FeatureFlagsMask_ |
64 | { |
65 | GXV_FEAT_MASK_EXCLUSIVE_SETTINGS = 0x8000U, |
66 | GXV_FEAT_MASK_DYNAMIC_DEFAULT = 0x4000, |
67 | GXV_FEAT_MASK_UNUSED = 0x3F00, |
68 | GXV_FEAT_MASK_DEFAULT_SETTING = 0x00FF |
69 | |
70 | } GXV_FeatureFlagsMask; |
71 | |
72 | |
73 | /*************************************************************************/ |
74 | /*************************************************************************/ |
75 | /***** *****/ |
76 | /***** UTILITY FUNCTIONS *****/ |
77 | /***** *****/ |
78 | /*************************************************************************/ |
79 | /*************************************************************************/ |
80 | |
81 | static void |
82 | gxv_feat_registry_validate( FT_UShort feature, |
83 | FT_UShort nSettings, |
84 | FT_Bool exclusive, |
85 | GXV_Validator gxvalid ) |
86 | { |
87 | GXV_NAME_ENTER( "feature in registry" ); |
88 | |
89 | GXV_TRACE(( " (feature = %u)\n" , feature )); |
90 | |
91 | if ( feature >= gxv_feat_registry_length ) |
92 | { |
93 | GXV_TRACE(( "feature number %d is out of range %lu\n" , |
94 | feature, gxv_feat_registry_length )); |
95 | GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); |
96 | goto Exit; |
97 | } |
98 | |
99 | if ( gxv_feat_registry[feature].existence == 0 ) |
100 | { |
101 | GXV_TRACE(( "feature number %d is in defined range but doesn't exist\n" , |
102 | feature )); |
103 | GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); |
104 | goto Exit; |
105 | } |
106 | |
107 | if ( gxv_feat_registry[feature].apple_reserved ) |
108 | { |
109 | /* Don't use here. Apple is reserved. */ |
110 | GXV_TRACE(( "feature number %d is reserved by Apple\n" , feature )); |
111 | if ( gxvalid->root->level >= FT_VALIDATE_TIGHT ) |
112 | FT_INVALID_DATA; |
113 | } |
114 | |
115 | if ( nSettings != gxv_feat_registry[feature].nSettings ) |
116 | { |
117 | GXV_TRACE(( "feature %d: nSettings %d != defined nSettings %d\n" , |
118 | feature, nSettings, |
119 | gxv_feat_registry[feature].nSettings )); |
120 | if ( gxvalid->root->level >= FT_VALIDATE_TIGHT ) |
121 | FT_INVALID_DATA; |
122 | } |
123 | |
124 | if ( exclusive != gxv_feat_registry[feature].exclusive ) |
125 | { |
126 | GXV_TRACE(( "exclusive flag %d differs from predefined value\n" , |
127 | exclusive )); |
128 | if ( gxvalid->root->level >= FT_VALIDATE_TIGHT ) |
129 | FT_INVALID_DATA; |
130 | } |
131 | |
132 | Exit: |
133 | GXV_EXIT; |
134 | } |
135 | |
136 | |
137 | static void |
138 | gxv_feat_name_index_validate( FT_Bytes table, |
139 | FT_Bytes limit, |
140 | GXV_Validator gxvalid ) |
141 | { |
142 | FT_Bytes p = table; |
143 | |
144 | FT_Short nameIndex; |
145 | |
146 | |
147 | GXV_NAME_ENTER( "nameIndex" ); |
148 | |
149 | GXV_LIMIT_CHECK( 2 ); |
150 | nameIndex = FT_NEXT_SHORT ( p ); |
151 | GXV_TRACE(( " (nameIndex = %d)\n" , nameIndex )); |
152 | |
153 | gxv_sfntName_validate( (FT_UShort)nameIndex, |
154 | 255, |
155 | 32768U, |
156 | gxvalid ); |
157 | |
158 | GXV_EXIT; |
159 | } |
160 | |
161 | |
162 | static void |
163 | gxv_feat_setting_validate( FT_Bytes table, |
164 | FT_Bytes limit, |
165 | FT_Bool exclusive, |
166 | GXV_Validator gxvalid ) |
167 | { |
168 | FT_Bytes p = table; |
169 | FT_UShort setting; |
170 | |
171 | |
172 | GXV_NAME_ENTER( "setting" ); |
173 | |
174 | GXV_LIMIT_CHECK( 2 ); |
175 | |
176 | setting = FT_NEXT_USHORT( p ); |
177 | |
178 | /* If we have exclusive setting, the setting should be odd. */ |
179 | if ( exclusive && ( setting & 1 ) == 0 ) |
180 | FT_INVALID_DATA; |
181 | |
182 | gxv_feat_name_index_validate( p, limit, gxvalid ); |
183 | |
184 | GXV_FEAT_DATA( setting ) = setting; |
185 | |
186 | GXV_EXIT; |
187 | } |
188 | |
189 | |
190 | static void |
191 | gxv_feat_name_validate( FT_Bytes table, |
192 | FT_Bytes limit, |
193 | GXV_Validator gxvalid ) |
194 | { |
195 | FT_Bytes p = table; |
196 | FT_UInt reserved_size = GXV_FEAT_DATA( reserved_size ); |
197 | |
198 | FT_UShort feature; |
199 | FT_UShort nSettings; |
200 | FT_ULong settingTable; |
201 | FT_UShort featureFlags; |
202 | |
203 | FT_Bool exclusive; |
204 | FT_Int last_setting; |
205 | FT_UInt i; |
206 | |
207 | |
208 | GXV_NAME_ENTER( "name" ); |
209 | |
210 | /* feature + nSettings + settingTable + featureFlags */ |
211 | GXV_LIMIT_CHECK( 2 + 2 + 4 + 2 ); |
212 | |
213 | feature = FT_NEXT_USHORT( p ); |
214 | GXV_FEAT_DATA( feature ) = feature; |
215 | |
216 | nSettings = FT_NEXT_USHORT( p ); |
217 | settingTable = FT_NEXT_ULONG ( p ); |
218 | featureFlags = FT_NEXT_USHORT( p ); |
219 | |
220 | if ( settingTable < reserved_size ) |
221 | FT_INVALID_OFFSET; |
222 | |
223 | if ( ( featureFlags & GXV_FEAT_MASK_UNUSED ) == 0 ) |
224 | GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); |
225 | |
226 | exclusive = FT_BOOL( featureFlags & GXV_FEAT_MASK_EXCLUSIVE_SETTINGS ); |
227 | if ( exclusive ) |
228 | { |
229 | FT_Byte dynamic_default; |
230 | |
231 | |
232 | if ( featureFlags & GXV_FEAT_MASK_DYNAMIC_DEFAULT ) |
233 | dynamic_default = (FT_Byte)( featureFlags & |
234 | GXV_FEAT_MASK_DEFAULT_SETTING ); |
235 | else |
236 | dynamic_default = 0; |
237 | |
238 | /* If exclusive, check whether default setting is in the range. */ |
239 | if ( !( dynamic_default < nSettings ) ) |
240 | FT_INVALID_FORMAT; |
241 | } |
242 | |
243 | gxv_feat_registry_validate( feature, nSettings, exclusive, gxvalid ); |
244 | |
245 | gxv_feat_name_index_validate( p, limit, gxvalid ); |
246 | |
247 | p = gxvalid->root->base + settingTable; |
248 | for ( last_setting = -1, i = 0; i < nSettings; i++ ) |
249 | { |
250 | gxv_feat_setting_validate( p, limit, exclusive, gxvalid ); |
251 | |
252 | if ( (FT_Int)GXV_FEAT_DATA( setting ) <= last_setting ) |
253 | GXV_SET_ERR_IF_PARANOID( FT_INVALID_FORMAT ); |
254 | |
255 | last_setting = (FT_Int)GXV_FEAT_DATA( setting ); |
256 | /* setting + nameIndex */ |
257 | p += ( 2 + 2 ); |
258 | } |
259 | |
260 | GXV_EXIT; |
261 | } |
262 | |
263 | |
264 | /*************************************************************************/ |
265 | /*************************************************************************/ |
266 | /***** *****/ |
267 | /***** feat TABLE *****/ |
268 | /***** *****/ |
269 | /*************************************************************************/ |
270 | /*************************************************************************/ |
271 | |
272 | FT_LOCAL_DEF( void ) |
273 | gxv_feat_validate( FT_Bytes table, |
274 | FT_Face face, |
275 | FT_Validator ftvalid ) |
276 | { |
277 | GXV_ValidatorRec gxvalidrec; |
278 | GXV_Validator gxvalid = &gxvalidrec; |
279 | |
280 | GXV_feat_DataRec featrec; |
281 | GXV_feat_Data feat = &featrec; |
282 | |
283 | FT_Bytes p = table; |
284 | FT_Bytes limit = 0; |
285 | |
286 | FT_UInt featureNameCount; |
287 | |
288 | FT_UInt i; |
289 | FT_Int last_feature; |
290 | |
291 | |
292 | gxvalid->root = ftvalid; |
293 | gxvalid->table_data = feat; |
294 | gxvalid->face = face; |
295 | |
296 | FT_TRACE3(( "validating `feat' table\n" )); |
297 | GXV_INIT; |
298 | |
299 | feat->reserved_size = 0; |
300 | |
301 | /* version + featureNameCount + none_0 + none_1 */ |
302 | GXV_LIMIT_CHECK( 4 + 2 + 2 + 4 ); |
303 | feat->reserved_size += 4 + 2 + 2 + 4; |
304 | |
305 | if ( FT_NEXT_ULONG( p ) != 0x00010000UL ) /* Version */ |
306 | FT_INVALID_FORMAT; |
307 | |
308 | featureNameCount = FT_NEXT_USHORT( p ); |
309 | GXV_TRACE(( " (featureNameCount = %d)\n" , featureNameCount )); |
310 | |
311 | if ( !( IS_PARANOID_VALIDATION ) ) |
312 | p += 6; /* skip (none) and (none) */ |
313 | else |
314 | { |
315 | if ( FT_NEXT_USHORT( p ) != 0 ) |
316 | FT_INVALID_DATA; |
317 | |
318 | if ( FT_NEXT_ULONG( p ) != 0 ) |
319 | FT_INVALID_DATA; |
320 | } |
321 | |
322 | feat->reserved_size += featureNameCount * ( 2 + 2 + 4 + 2 + 2 ); |
323 | |
324 | for ( last_feature = -1, i = 0; i < featureNameCount; i++ ) |
325 | { |
326 | gxv_feat_name_validate( p, limit, gxvalid ); |
327 | |
328 | if ( (FT_Int)GXV_FEAT_DATA( feature ) <= last_feature ) |
329 | GXV_SET_ERR_IF_PARANOID( FT_INVALID_FORMAT ); |
330 | |
331 | last_feature = GXV_FEAT_DATA( feature ); |
332 | p += 2 + 2 + 4 + 2 + 2; |
333 | } |
334 | |
335 | FT_TRACE4(( "\n" )); |
336 | } |
337 | |
338 | |
339 | /* END */ |
340 | |