|
1 /***************************************************************************/ |
|
2 /* */ |
|
3 /* gxvfeat.c */ |
|
4 /* */ |
|
5 /* TrueTypeGX/AAT feat table validation (body). */ |
|
6 /* */ |
|
7 /* Copyright 2004, 2005, 2008 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 trace_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 valid ) |
|
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 %d\n", |
|
94 feature, gxv_feat_registry_length )); |
|
95 if ( valid->root->level == FT_VALIDATE_PARANOID ) |
|
96 FT_INVALID_DATA; |
|
97 goto Exit; |
|
98 } |
|
99 |
|
100 if ( gxv_feat_registry[feature].existence == 0 ) |
|
101 { |
|
102 GXV_TRACE(( "feature number %d is in defined range but doesn't exist\n", |
|
103 feature )); |
|
104 if ( valid->root->level == FT_VALIDATE_PARANOID ) |
|
105 FT_INVALID_DATA; |
|
106 goto Exit; |
|
107 } |
|
108 |
|
109 if ( gxv_feat_registry[feature].apple_reserved ) |
|
110 { |
|
111 /* Don't use here. Apple is reserved. */ |
|
112 GXV_TRACE(( "feature number %d is reserved by Apple\n", feature )); |
|
113 if ( valid->root->level >= FT_VALIDATE_TIGHT ) |
|
114 FT_INVALID_DATA; |
|
115 } |
|
116 |
|
117 if ( nSettings != gxv_feat_registry[feature].nSettings ) |
|
118 { |
|
119 GXV_TRACE(( "feature %d: nSettings %d != defined nSettings %d\n", |
|
120 feature, nSettings, |
|
121 gxv_feat_registry[feature].nSettings )); |
|
122 if ( valid->root->level >= FT_VALIDATE_TIGHT ) |
|
123 FT_INVALID_DATA; |
|
124 } |
|
125 |
|
126 if ( exclusive != gxv_feat_registry[feature].exclusive ) |
|
127 { |
|
128 GXV_TRACE(( "exclusive flag %d differs from predefined value\n", |
|
129 exclusive )); |
|
130 if ( valid->root->level >= FT_VALIDATE_TIGHT ) |
|
131 FT_INVALID_DATA; |
|
132 } |
|
133 |
|
134 Exit: |
|
135 GXV_EXIT; |
|
136 } |
|
137 |
|
138 |
|
139 static void |
|
140 gxv_feat_name_index_validate( FT_Bytes table, |
|
141 FT_Bytes limit, |
|
142 GXV_Validator valid ) |
|
143 { |
|
144 FT_Bytes p = table; |
|
145 |
|
146 FT_Short nameIndex; |
|
147 |
|
148 |
|
149 GXV_NAME_ENTER( "nameIndex" ); |
|
150 |
|
151 GXV_LIMIT_CHECK( 2 ); |
|
152 nameIndex = FT_NEXT_SHORT ( p ); |
|
153 GXV_TRACE(( " (nameIndex = %d)\n", nameIndex )); |
|
154 |
|
155 gxv_sfntName_validate( (FT_UShort)nameIndex, |
|
156 255, |
|
157 32768U, |
|
158 valid ); |
|
159 |
|
160 GXV_EXIT; |
|
161 } |
|
162 |
|
163 |
|
164 static void |
|
165 gxv_feat_setting_validate( FT_Bytes table, |
|
166 FT_Bytes limit, |
|
167 FT_Bool exclusive, |
|
168 GXV_Validator valid ) |
|
169 { |
|
170 FT_Bytes p = table; |
|
171 FT_UShort setting; |
|
172 |
|
173 |
|
174 GXV_NAME_ENTER( "setting" ); |
|
175 |
|
176 GXV_LIMIT_CHECK( 2 ); |
|
177 |
|
178 setting = FT_NEXT_USHORT( p ); |
|
179 |
|
180 /* If we have exclusive setting, the setting should be odd. */ |
|
181 if ( exclusive && ( setting % 2 ) == 0 ) |
|
182 FT_INVALID_DATA; |
|
183 |
|
184 gxv_feat_name_index_validate( p, limit, valid ); |
|
185 |
|
186 GXV_FEAT_DATA( setting ) = setting; |
|
187 |
|
188 GXV_EXIT; |
|
189 } |
|
190 |
|
191 |
|
192 static void |
|
193 gxv_feat_name_validate( FT_Bytes table, |
|
194 FT_Bytes limit, |
|
195 GXV_Validator valid ) |
|
196 { |
|
197 FT_Bytes p = table; |
|
198 FT_UInt reserved_size = GXV_FEAT_DATA( reserved_size ); |
|
199 |
|
200 FT_UShort feature; |
|
201 FT_UShort nSettings; |
|
202 FT_ULong settingTable; |
|
203 FT_UShort featureFlags; |
|
204 |
|
205 FT_Bool exclusive; |
|
206 FT_Int last_setting; |
|
207 FT_UInt i; |
|
208 |
|
209 |
|
210 GXV_NAME_ENTER( "name" ); |
|
211 |
|
212 /* feature + nSettings + settingTable + featureFlags */ |
|
213 GXV_LIMIT_CHECK( 2 + 2 + 4 + 2 ); |
|
214 |
|
215 feature = FT_NEXT_USHORT( p ); |
|
216 GXV_FEAT_DATA( feature ) = feature; |
|
217 |
|
218 nSettings = FT_NEXT_USHORT( p ); |
|
219 settingTable = FT_NEXT_ULONG ( p ); |
|
220 featureFlags = FT_NEXT_USHORT( p ); |
|
221 |
|
222 if ( settingTable < reserved_size ) |
|
223 FT_INVALID_OFFSET; |
|
224 |
|
225 if ( valid->root->level == FT_VALIDATE_PARANOID && |
|
226 ( featureFlags & GXV_FEAT_MASK_UNUSED ) == 0 ) |
|
227 FT_INVALID_DATA; |
|
228 |
|
229 exclusive = FT_BOOL( featureFlags & GXV_FEAT_MASK_EXCLUSIVE_SETTINGS ); |
|
230 if ( exclusive ) |
|
231 { |
|
232 FT_Byte dynamic_default; |
|
233 |
|
234 |
|
235 if ( featureFlags & GXV_FEAT_MASK_DYNAMIC_DEFAULT ) |
|
236 dynamic_default = (FT_Byte)( featureFlags & |
|
237 GXV_FEAT_MASK_DEFAULT_SETTING ); |
|
238 else |
|
239 dynamic_default = 0; |
|
240 |
|
241 /* If exclusive, check whether default setting is in the range. */ |
|
242 if ( !( dynamic_default < nSettings ) ) |
|
243 FT_INVALID_FORMAT; |
|
244 } |
|
245 |
|
246 gxv_feat_registry_validate( feature, nSettings, exclusive, valid ); |
|
247 |
|
248 gxv_feat_name_index_validate( p, limit, valid ); |
|
249 |
|
250 p = valid->root->base + settingTable; |
|
251 for ( last_setting = -1, i = 0; i < nSettings; i++ ) |
|
252 { |
|
253 gxv_feat_setting_validate( p, limit, exclusive, valid ); |
|
254 |
|
255 if ( valid->root->level == FT_VALIDATE_PARANOID && |
|
256 (FT_Int)GXV_FEAT_DATA( setting ) <= last_setting ) |
|
257 FT_INVALID_FORMAT; |
|
258 |
|
259 last_setting = (FT_Int)GXV_FEAT_DATA( setting ); |
|
260 /* setting + nameIndex */ |
|
261 p += ( 2 + 2 ); |
|
262 } |
|
263 |
|
264 GXV_EXIT; |
|
265 } |
|
266 |
|
267 |
|
268 /*************************************************************************/ |
|
269 /*************************************************************************/ |
|
270 /***** *****/ |
|
271 /***** feat TABLE *****/ |
|
272 /***** *****/ |
|
273 /*************************************************************************/ |
|
274 /*************************************************************************/ |
|
275 |
|
276 FT_LOCAL_DEF( void ) |
|
277 gxv_feat_validate( FT_Bytes table, |
|
278 FT_Face face, |
|
279 FT_Validator ftvalid ) |
|
280 { |
|
281 GXV_ValidatorRec validrec; |
|
282 GXV_Validator valid = &validrec; |
|
283 |
|
284 GXV_feat_DataRec featrec; |
|
285 GXV_feat_Data feat = &featrec; |
|
286 |
|
287 FT_Bytes p = table; |
|
288 FT_Bytes limit = 0; |
|
289 |
|
290 FT_UInt featureNameCount; |
|
291 |
|
292 FT_UInt i; |
|
293 FT_Int last_feature; |
|
294 |
|
295 |
|
296 valid->root = ftvalid; |
|
297 valid->table_data = feat; |
|
298 valid->face = face; |
|
299 |
|
300 FT_TRACE3(( "validating `feat' table\n" )); |
|
301 GXV_INIT; |
|
302 |
|
303 feat->reserved_size = 0; |
|
304 |
|
305 /* version + featureNameCount + none_0 + none_1 */ |
|
306 GXV_LIMIT_CHECK( 4 + 2 + 2 + 4 ); |
|
307 feat->reserved_size += 4 + 2 + 2 + 4; |
|
308 |
|
309 if ( FT_NEXT_ULONG( p ) != 0x00010000UL ) /* Version */ |
|
310 FT_INVALID_FORMAT; |
|
311 |
|
312 featureNameCount = FT_NEXT_USHORT( p ); |
|
313 GXV_TRACE(( " (featureNameCount = %d)\n", featureNameCount )); |
|
314 |
|
315 if ( valid->root->level != FT_VALIDATE_PARANOID ) |
|
316 p += 6; /* skip (none) and (none) */ |
|
317 else |
|
318 { |
|
319 if ( FT_NEXT_USHORT( p ) != 0 ) |
|
320 FT_INVALID_DATA; |
|
321 |
|
322 if ( FT_NEXT_ULONG( p ) != 0 ) |
|
323 FT_INVALID_DATA; |
|
324 } |
|
325 |
|
326 feat->reserved_size += featureNameCount * ( 2 + 2 + 4 + 2 + 2 ); |
|
327 |
|
328 for ( last_feature = -1, i = 0; i < featureNameCount; i++ ) |
|
329 { |
|
330 gxv_feat_name_validate( p, limit, valid ); |
|
331 |
|
332 if ( valid->root->level == FT_VALIDATE_PARANOID && |
|
333 (FT_Int)GXV_FEAT_DATA( feature ) <= last_feature ) |
|
334 FT_INVALID_FORMAT; |
|
335 |
|
336 last_feature = GXV_FEAT_DATA( feature ); |
|
337 p += 2 + 2 + 4 + 2 + 2; |
|
338 } |
|
339 |
|
340 FT_TRACE4(( "\n" )); |
|
341 } |
|
342 |
|
343 |
|
344 /* END */ |