1 | /***************************************************************************/ |
---|
2 | /* */ |
---|
3 | /* gxvcommn.c */ |
---|
4 | /* */ |
---|
5 | /* TrueTypeGX/AAT common tables validation (body). */ |
---|
6 | /* */ |
---|
7 | /* Copyright 2004, 2005 by suzuki toshiya, Masatake YAMATO, Red Hat K.K., */ |
---|
8 | /* David Turner, Robert Wilhelm, and Werner Lemberg. */ |
---|
9 | /* */ |
---|
10 | /* This file is part of the FreeType project, and may only be used, */ |
---|
11 | /* modified, and distributed under the terms of the FreeType project */ |
---|
12 | /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ |
---|
13 | /* this file you indicate that you have read the license and */ |
---|
14 | /* understand and accept it fully. */ |
---|
15 | /* */ |
---|
16 | /***************************************************************************/ |
---|
17 | |
---|
18 | /***************************************************************************/ |
---|
19 | /* */ |
---|
20 | /* gxvalid is derived from both gxlayout module and otvalid module. */ |
---|
21 | /* Development of gxlayout is supported by the Information-technology */ |
---|
22 | /* Promotion Agency(IPA), Japan. */ |
---|
23 | /* */ |
---|
24 | /***************************************************************************/ |
---|
25 | |
---|
26 | |
---|
27 | #include "gxvcommn.h" |
---|
28 | |
---|
29 | |
---|
30 | /*************************************************************************/ |
---|
31 | /* */ |
---|
32 | /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ |
---|
33 | /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ |
---|
34 | /* messages during execution. */ |
---|
35 | /* */ |
---|
36 | #undef FT_COMPONENT |
---|
37 | #define FT_COMPONENT trace_gxvcommon |
---|
38 | |
---|
39 | |
---|
40 | /*************************************************************************/ |
---|
41 | /*************************************************************************/ |
---|
42 | /***** *****/ |
---|
43 | /***** 16bit offset sorter *****/ |
---|
44 | /***** *****/ |
---|
45 | /*************************************************************************/ |
---|
46 | /*************************************************************************/ |
---|
47 | |
---|
48 | static int |
---|
49 | gxv_compare_ushort_offset( FT_UShort* a, |
---|
50 | FT_UShort* b ) |
---|
51 | { |
---|
52 | if ( *a < *b ) |
---|
53 | return -1; |
---|
54 | else if ( *a > *b ) |
---|
55 | return 1; |
---|
56 | else |
---|
57 | return 0; |
---|
58 | } |
---|
59 | |
---|
60 | |
---|
61 | FT_LOCAL_DEF( void ) |
---|
62 | gxv_set_length_by_ushort_offset( FT_UShort* offset, |
---|
63 | FT_UShort** length, |
---|
64 | FT_UShort* buff, |
---|
65 | FT_UInt nmemb, |
---|
66 | FT_UShort limit, |
---|
67 | GXV_Validator valid ) |
---|
68 | { |
---|
69 | FT_UInt i; |
---|
70 | |
---|
71 | |
---|
72 | for ( i = 0; i < nmemb; i++ ) |
---|
73 | *(length[i]) = 0; |
---|
74 | |
---|
75 | for ( i = 0; i < nmemb; i++ ) |
---|
76 | buff[i] = offset[i]; |
---|
77 | buff[nmemb] = limit; |
---|
78 | |
---|
79 | ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_UShort ), |
---|
80 | ( int(*)(const void*, const void*) )gxv_compare_ushort_offset ); |
---|
81 | |
---|
82 | if ( buff[nmemb] > limit ) |
---|
83 | FT_INVALID_OFFSET; |
---|
84 | |
---|
85 | for ( i = 0; i < nmemb; i++ ) |
---|
86 | { |
---|
87 | FT_UInt j; |
---|
88 | |
---|
89 | |
---|
90 | for ( j = 0; j < nmemb; j++ ) |
---|
91 | if ( buff[j] == offset[i] ) |
---|
92 | break; |
---|
93 | |
---|
94 | if ( j == nmemb ) |
---|
95 | FT_INVALID_OFFSET; |
---|
96 | |
---|
97 | *(length[i]) = (FT_UShort)( buff[j + 1] - buff[j] ); |
---|
98 | |
---|
99 | if ( 0 != offset[i] && 0 == *(length[i]) ) |
---|
100 | FT_INVALID_OFFSET; |
---|
101 | } |
---|
102 | } |
---|
103 | |
---|
104 | |
---|
105 | /*************************************************************************/ |
---|
106 | /*************************************************************************/ |
---|
107 | /***** *****/ |
---|
108 | /***** 32bit offset sorter *****/ |
---|
109 | /***** *****/ |
---|
110 | /*************************************************************************/ |
---|
111 | /*************************************************************************/ |
---|
112 | |
---|
113 | static int |
---|
114 | gxv_compare_ulong_offset( FT_ULong* a, |
---|
115 | FT_ULong* b ) |
---|
116 | { |
---|
117 | if ( *a < *b ) |
---|
118 | return -1; |
---|
119 | else if ( *a > *b ) |
---|
120 | return 1; |
---|
121 | else |
---|
122 | return 0; |
---|
123 | } |
---|
124 | |
---|
125 | |
---|
126 | FT_LOCAL_DEF( void ) |
---|
127 | gxv_set_length_by_ulong_offset( FT_ULong* offset, |
---|
128 | FT_ULong** length, |
---|
129 | FT_ULong* buff, |
---|
130 | FT_UInt nmemb, |
---|
131 | FT_ULong limit, |
---|
132 | GXV_Validator valid) |
---|
133 | { |
---|
134 | FT_UInt i; |
---|
135 | |
---|
136 | |
---|
137 | for ( i = 0; i < nmemb; i++ ) |
---|
138 | *(length[i]) = 0; |
---|
139 | |
---|
140 | for ( i = 0; i < nmemb; i++ ) |
---|
141 | buff[i] = offset[i]; |
---|
142 | buff[nmemb] = limit; |
---|
143 | |
---|
144 | ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_ULong ), |
---|
145 | ( int(*)(const void*, const void*) )gxv_compare_ulong_offset ); |
---|
146 | |
---|
147 | if ( buff[nmemb] > limit ) |
---|
148 | FT_INVALID_OFFSET; |
---|
149 | |
---|
150 | for ( i = 0; i < nmemb; i++ ) |
---|
151 | { |
---|
152 | FT_UInt j; |
---|
153 | |
---|
154 | |
---|
155 | for ( j = 0; j < nmemb; j++ ) |
---|
156 | if ( buff[j] == offset[i] ) |
---|
157 | break; |
---|
158 | |
---|
159 | if ( j == nmemb ) |
---|
160 | FT_INVALID_OFFSET; |
---|
161 | |
---|
162 | *(length[i]) = buff[j + 1] - buff[j]; |
---|
163 | |
---|
164 | if ( 0 != offset[i] && 0 == *(length[i]) ) |
---|
165 | FT_INVALID_OFFSET; |
---|
166 | } |
---|
167 | } |
---|
168 | |
---|
169 | |
---|
170 | /*************************************************************************/ |
---|
171 | /*************************************************************************/ |
---|
172 | /***** *****/ |
---|
173 | /***** scan value array and get min & max *****/ |
---|
174 | /***** *****/ |
---|
175 | /*************************************************************************/ |
---|
176 | /*************************************************************************/ |
---|
177 | |
---|
178 | |
---|
179 | FT_LOCAL_DEF( void ) |
---|
180 | gxv_array_getlimits_byte( FT_Bytes table, |
---|
181 | FT_Bytes limit, |
---|
182 | FT_Byte* min, |
---|
183 | FT_Byte* max, |
---|
184 | GXV_Validator valid ) |
---|
185 | { |
---|
186 | FT_Bytes p = table; |
---|
187 | |
---|
188 | |
---|
189 | *min = 0xFF; |
---|
190 | *max = 0x00; |
---|
191 | |
---|
192 | while ( p < limit ) |
---|
193 | { |
---|
194 | FT_Byte val; |
---|
195 | |
---|
196 | |
---|
197 | GXV_LIMIT_CHECK( 1 ); |
---|
198 | val = FT_NEXT_BYTE( p ); |
---|
199 | |
---|
200 | *min = (FT_Byte)FT_MIN( *min, val ); |
---|
201 | *max = (FT_Byte)FT_MAX( *max, val ); |
---|
202 | } |
---|
203 | |
---|
204 | valid->subtable_length = p - table; |
---|
205 | } |
---|
206 | |
---|
207 | |
---|
208 | FT_LOCAL_DEF( void ) |
---|
209 | gxv_array_getlimits_ushort( FT_Bytes table, |
---|
210 | FT_Bytes limit, |
---|
211 | FT_UShort* min, |
---|
212 | FT_UShort* max, |
---|
213 | GXV_Validator valid ) |
---|
214 | { |
---|
215 | FT_Bytes p = table; |
---|
216 | |
---|
217 | |
---|
218 | *min = 0xFFFFU; |
---|
219 | *max = 0x0000; |
---|
220 | |
---|
221 | while ( p < limit ) |
---|
222 | { |
---|
223 | FT_UShort val; |
---|
224 | |
---|
225 | |
---|
226 | GXV_LIMIT_CHECK( 2 ); |
---|
227 | val = FT_NEXT_USHORT( p ); |
---|
228 | |
---|
229 | *min = (FT_Byte)FT_MIN( *min, val ); |
---|
230 | *max = (FT_Byte)FT_MAX( *max, val ); |
---|
231 | } |
---|
232 | |
---|
233 | valid->subtable_length = p - table; |
---|
234 | } |
---|
235 | |
---|
236 | |
---|
237 | /*************************************************************************/ |
---|
238 | /*************************************************************************/ |
---|
239 | /***** *****/ |
---|
240 | /***** BINSEARCHHEADER *****/ |
---|
241 | /***** *****/ |
---|
242 | /*************************************************************************/ |
---|
243 | /*************************************************************************/ |
---|
244 | |
---|
245 | typedef struct GXV_BinSrchHeader_ |
---|
246 | { |
---|
247 | FT_UShort unitSize; |
---|
248 | FT_UShort nUnits; |
---|
249 | FT_UShort searchRange; |
---|
250 | FT_UShort entrySelector; |
---|
251 | FT_UShort rangeShift; |
---|
252 | |
---|
253 | } GXV_BinSrchHeader; |
---|
254 | |
---|
255 | |
---|
256 | static void |
---|
257 | gxv_BinSrchHeader_check_consistency( GXV_BinSrchHeader* binSrchHeader, |
---|
258 | GXV_Validator valid ) |
---|
259 | { |
---|
260 | FT_UShort searchRange; |
---|
261 | FT_UShort entrySelector; |
---|
262 | FT_UShort rangeShift; |
---|
263 | |
---|
264 | |
---|
265 | if ( binSrchHeader->unitSize == 0 ) |
---|
266 | FT_INVALID_DATA; |
---|
267 | |
---|
268 | if ( binSrchHeader->nUnits == 0 ) |
---|
269 | { |
---|
270 | if ( binSrchHeader->searchRange == 0 && |
---|
271 | binSrchHeader->entrySelector == 0 && |
---|
272 | binSrchHeader->rangeShift == 0 ) |
---|
273 | return; |
---|
274 | else |
---|
275 | FT_INVALID_DATA; |
---|
276 | } |
---|
277 | |
---|
278 | for ( searchRange = 1, entrySelector = 1; |
---|
279 | ( searchRange * 2 ) <= binSrchHeader->nUnits && |
---|
280 | searchRange < 0x8000U; |
---|
281 | searchRange *= 2, entrySelector++ ) |
---|
282 | ; |
---|
283 | |
---|
284 | entrySelector--; |
---|
285 | searchRange = (FT_UShort)( searchRange * binSrchHeader->unitSize ); |
---|
286 | rangeShift = (FT_UShort)( binSrchHeader->nUnits * binSrchHeader->unitSize |
---|
287 | - searchRange ); |
---|
288 | |
---|
289 | if ( searchRange != binSrchHeader->searchRange || |
---|
290 | entrySelector != binSrchHeader->entrySelector || |
---|
291 | rangeShift != binSrchHeader->rangeShift ) |
---|
292 | { |
---|
293 | GXV_TRACE(( "Inconsistency found in BinSrchHeader\n" )); |
---|
294 | GXV_TRACE(( "originally: unitSize=%d, nUnits=%d, " |
---|
295 | "searchRange=%d, entrySelector=%d, " |
---|
296 | "rangeShift=%d\n", |
---|
297 | binSrchHeader->unitSize, binSrchHeader->nUnits, |
---|
298 | binSrchHeader->searchRange, binSrchHeader->entrySelector, |
---|
299 | binSrchHeader->rangeShift )); |
---|
300 | GXV_TRACE(( "calculated: unitSize=%d, nUnits=%d, " |
---|
301 | "searchRange=%d, entrySelector=%d, " |
---|
302 | "rangeShift=%d\n", |
---|
303 | binSrchHeader->unitSize, binSrchHeader->nUnits, |
---|
304 | searchRange, entrySelector, rangeShift )); |
---|
305 | |
---|
306 | if ( valid->root->level >= FT_VALIDATE_PARANOID ) |
---|
307 | FT_INVALID_DATA; |
---|
308 | } |
---|
309 | } |
---|
310 | |
---|
311 | |
---|
312 | /* |
---|
313 | * parser & validator of BinSrchHeader |
---|
314 | * which is used in LookupTable format 2, 4, 6. |
---|
315 | * |
---|
316 | * Essential parameters (unitSize, nUnits) are returned by |
---|
317 | * given pointer, others (searchRange, entrySelector, rangeShift) |
---|
318 | * can be calculated by essential parameters, so they are just |
---|
319 | * validated and discarded. |
---|
320 | * |
---|
321 | * However, wrong values in searchRange, entrySelector, rangeShift |
---|
322 | * won't cause fatal errors, because these parameters might be |
---|
323 | * only used in old m68k font driver in MacOS. |
---|
324 | * -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp> |
---|
325 | */ |
---|
326 | |
---|
327 | FT_LOCAL_DEF( void ) |
---|
328 | gxv_BinSrchHeader_validate( FT_Bytes table, |
---|
329 | FT_Bytes limit, |
---|
330 | FT_UShort* unitSize_p, |
---|
331 | FT_UShort* nUnits_p, |
---|
332 | GXV_Validator valid ) |
---|
333 | { |
---|
334 | FT_Bytes p = table; |
---|
335 | GXV_BinSrchHeader binSrchHeader; |
---|
336 | |
---|
337 | |
---|
338 | GXV_NAME_ENTER( "BinSrchHeader validate" ); |
---|
339 | |
---|
340 | if ( *unitSize_p == 0 ) |
---|
341 | { |
---|
342 | GXV_LIMIT_CHECK( 2 ); |
---|
343 | binSrchHeader.unitSize = FT_NEXT_USHORT( p ); |
---|
344 | } |
---|
345 | else |
---|
346 | binSrchHeader.unitSize = *unitSize_p; |
---|
347 | |
---|
348 | if ( *nUnits_p == 0 ) |
---|
349 | { |
---|
350 | GXV_LIMIT_CHECK( 2 ); |
---|
351 | binSrchHeader.nUnits = FT_NEXT_USHORT( p ); |
---|
352 | } |
---|
353 | else |
---|
354 | binSrchHeader.nUnits = *nUnits_p; |
---|
355 | |
---|
356 | GXV_LIMIT_CHECK( 2 + 2 + 2 ); |
---|
357 | binSrchHeader.searchRange = FT_NEXT_USHORT( p ); |
---|
358 | binSrchHeader.entrySelector = FT_NEXT_USHORT( p ); |
---|
359 | binSrchHeader.rangeShift = FT_NEXT_USHORT( p ); |
---|
360 | GXV_TRACE(( "nUnits %d\n", binSrchHeader.nUnits )); |
---|
361 | |
---|
362 | gxv_BinSrchHeader_check_consistency( &binSrchHeader, valid ); |
---|
363 | |
---|
364 | if ( *unitSize_p == 0 ) |
---|
365 | *unitSize_p = binSrchHeader.unitSize; |
---|
366 | |
---|
367 | if ( *nUnits_p == 0 ) |
---|
368 | *nUnits_p = binSrchHeader.nUnits; |
---|
369 | |
---|
370 | valid->subtable_length = p - table; |
---|
371 | GXV_EXIT; |
---|
372 | } |
---|
373 | |
---|
374 | |
---|
375 | /*************************************************************************/ |
---|
376 | /*************************************************************************/ |
---|
377 | /***** *****/ |
---|
378 | /***** LOOKUP TABLE *****/ |
---|
379 | /***** *****/ |
---|
380 | /*************************************************************************/ |
---|
381 | /*************************************************************************/ |
---|
382 | |
---|
383 | #define GXV_LOOKUP_VALUE_LOAD( P, SIGNSPEC ) \ |
---|
384 | ( P += 2, gxv_lookup_value_load( P - 2, SIGNSPEC ) ) |
---|
385 | |
---|
386 | static GXV_LookupValueDesc |
---|
387 | gxv_lookup_value_load( FT_Bytes p, |
---|
388 | int signspec ) |
---|
389 | { |
---|
390 | GXV_LookupValueDesc v; |
---|
391 | |
---|
392 | |
---|
393 | if ( signspec == GXV_LOOKUPVALUE_UNSIGNED ) |
---|
394 | v.u = FT_NEXT_USHORT( p ); |
---|
395 | else |
---|
396 | v.s = FT_NEXT_SHORT( p ); |
---|
397 | |
---|
398 | return v; |
---|
399 | } |
---|
400 | |
---|
401 | |
---|
402 | #define GXV_UNITSIZE_VALIDATE( FORMAT, UNITSIZE, NUNITS, CORRECTSIZE ) \ |
---|
403 | FT_BEGIN_STMNT \ |
---|
404 | if ( UNITSIZE != CORRECTSIZE ) \ |
---|
405 | { \ |
---|
406 | FT_ERROR(( "unitSize=%d differs from" \ |
---|
407 | "expected unitSize=%d" \ |
---|
408 | "in LookupTable %s", \ |
---|
409 | UNITSIZE, CORRECTSIZE, FORMAT )); \ |
---|
410 | if ( UNITSIZE != 0 && NUNITS != 0 ) \ |
---|
411 | { \ |
---|
412 | FT_ERROR(( " cannot validate anymore\n" )); \ |
---|
413 | FT_INVALID_FORMAT; \ |
---|
414 | } \ |
---|
415 | else \ |
---|
416 | FT_ERROR(( " forcibly continues\n" )); \ |
---|
417 | } \ |
---|
418 | FT_END_STMNT |
---|
419 | |
---|
420 | |
---|
421 | /* ================= Simple Array Format 0 Lookup Table ================ */ |
---|
422 | static void |
---|
423 | gxv_LookupTable_fmt0_validate( FT_Bytes table, |
---|
424 | FT_Bytes limit, |
---|
425 | GXV_Validator valid ) |
---|
426 | { |
---|
427 | FT_Bytes p = table; |
---|
428 | FT_UShort i; |
---|
429 | |
---|
430 | GXV_LookupValueDesc value; |
---|
431 | |
---|
432 | |
---|
433 | GXV_NAME_ENTER( "LookupTable format 0" ); |
---|
434 | |
---|
435 | GXV_LIMIT_CHECK( 2 * valid->face->num_glyphs ); |
---|
436 | |
---|
437 | for ( i = 0; i < valid->face->num_glyphs; i++ ) |
---|
438 | { |
---|
439 | GXV_LIMIT_CHECK( 2 ); |
---|
440 | if ( p + 2 >= limit ) /* some fonts have too-short fmt0 array */ |
---|
441 | { |
---|
442 | GXV_TRACE(( "too short, glyphs %d - %d are missing\n", |
---|
443 | i, valid->face->num_glyphs )); |
---|
444 | if ( valid->root->level >= FT_VALIDATE_PARANOID ) |
---|
445 | FT_INVALID_GLYPH_ID; |
---|
446 | break; |
---|
447 | } |
---|
448 | |
---|
449 | value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign ); |
---|
450 | valid->lookupval_func( i, value, valid ); |
---|
451 | } |
---|
452 | |
---|
453 | valid->subtable_length = p - table; |
---|
454 | GXV_EXIT; |
---|
455 | } |
---|
456 | |
---|
457 | |
---|
458 | /* ================= Segment Single Format 2 Loolup Table ============== */ |
---|
459 | /* |
---|
460 | * Apple spec says: |
---|
461 | * |
---|
462 | * To guarantee that a binary search terminates, you must include one or |
---|
463 | * more special `end of search table' values at the end of the data to |
---|
464 | * be searched. The number of termination values that need to be |
---|
465 | * included is table-specific. The value that indicates binary search |
---|
466 | * termination is 0xFFFF. |
---|
467 | * |
---|
468 | * The problem is that nUnits does not include this end-marker. It's |
---|
469 | * quite difficult to discriminate whether the following 0xFFFF comes from |
---|
470 | * the end-marker or some next data. |
---|
471 | * |
---|
472 | * -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp> |
---|
473 | */ |
---|
474 | static void |
---|
475 | gxv_LookupTable_fmt2_skip_endmarkers( FT_Bytes table, |
---|
476 | FT_UShort unitSize, |
---|
477 | GXV_Validator valid ) |
---|
478 | { |
---|
479 | FT_Bytes p = table; |
---|
480 | |
---|
481 | |
---|
482 | while ( ( p + 4 ) < valid->root->limit ) |
---|
483 | { |
---|
484 | if ( p[0] != 0xFF || p[1] != 0xFF || /* lastGlyph */ |
---|
485 | p[2] != 0xFF || p[3] != 0xFF ) /* firstGlyph */ |
---|
486 | break; |
---|
487 | p += unitSize; |
---|
488 | } |
---|
489 | |
---|
490 | valid->subtable_length = p - table; |
---|
491 | } |
---|
492 | |
---|
493 | |
---|
494 | static void |
---|
495 | gxv_LookupTable_fmt2_validate( FT_Bytes table, |
---|
496 | FT_Bytes limit, |
---|
497 | GXV_Validator valid ) |
---|
498 | { |
---|
499 | FT_Bytes p = table; |
---|
500 | FT_UShort gid; |
---|
501 | |
---|
502 | FT_UShort unitSize; |
---|
503 | FT_UShort nUnits; |
---|
504 | FT_UShort unit; |
---|
505 | FT_UShort lastGlyph; |
---|
506 | FT_UShort firstGlyph; |
---|
507 | GXV_LookupValueDesc value; |
---|
508 | |
---|
509 | |
---|
510 | GXV_NAME_ENTER( "LookupTable format 2" ); |
---|
511 | |
---|
512 | unitSize = nUnits = 0; |
---|
513 | gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, valid ); |
---|
514 | p += valid->subtable_length; |
---|
515 | |
---|
516 | GXV_UNITSIZE_VALIDATE( "format2", unitSize, nUnits, 6 ); |
---|
517 | |
---|
518 | for ( unit = 0, gid = 0; unit < nUnits; unit++ ) |
---|
519 | { |
---|
520 | GXV_LIMIT_CHECK( 2 + 2 + 2 ); |
---|
521 | lastGlyph = FT_NEXT_USHORT( p ); |
---|
522 | firstGlyph = FT_NEXT_USHORT( p ); |
---|
523 | value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign ); |
---|
524 | |
---|
525 | gxv_glyphid_validate( firstGlyph, valid ); |
---|
526 | gxv_glyphid_validate( lastGlyph, valid ); |
---|
527 | |
---|
528 | if ( lastGlyph < gid ) |
---|
529 | { |
---|
530 | GXV_TRACE(( "reverse ordered segment specification:" |
---|
531 | " lastGlyph[%d]=%d < lastGlyph[%d]=%d\n", |
---|
532 | unit, lastGlyph, unit - 1 , gid )); |
---|
533 | if ( valid->root->level >= FT_VALIDATE_PARANOID ) |
---|
534 | FT_INVALID_GLYPH_ID; |
---|
535 | } |
---|
536 | |
---|
537 | if ( lastGlyph < firstGlyph ) |
---|
538 | { |
---|
539 | GXV_TRACE(( "reverse ordered range specification at unit %d:", |
---|
540 | " lastGlyph %d < firstGlyph %d ", |
---|
541 | unit, lastGlyph, firstGlyph )); |
---|
542 | if ( valid->root->level >= FT_VALIDATE_PARANOID ) |
---|
543 | FT_INVALID_GLYPH_ID; |
---|
544 | |
---|
545 | if ( valid->root->level == FT_VALIDATE_TIGHT ) |
---|
546 | continue; /* ftxvalidator silently skips such an entry */ |
---|
547 | |
---|
548 | FT_TRACE4(( "continuing with exchanged values\n" )); |
---|
549 | gid = firstGlyph; |
---|
550 | firstGlyph = lastGlyph; |
---|
551 | lastGlyph = gid; |
---|
552 | } |
---|
553 | |
---|
554 | for ( gid = firstGlyph; gid <= lastGlyph; gid++ ) |
---|
555 | valid->lookupval_func( gid, value, valid ); |
---|
556 | } |
---|
557 | |
---|
558 | gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, valid ); |
---|
559 | p += valid->subtable_length; |
---|
560 | |
---|
561 | valid->subtable_length = p - table; |
---|
562 | GXV_EXIT; |
---|
563 | } |
---|
564 | |
---|
565 | |
---|
566 | /* ================= Segment Array Format 4 Lookup Table =============== */ |
---|
567 | static void |
---|
568 | gxv_LookupTable_fmt4_validate( FT_Bytes table, |
---|
569 | FT_Bytes limit, |
---|
570 | GXV_Validator valid ) |
---|
571 | { |
---|
572 | FT_Bytes p = table; |
---|
573 | FT_UShort unit; |
---|
574 | FT_UShort gid; |
---|
575 | |
---|
576 | FT_UShort unitSize; |
---|
577 | FT_UShort nUnits; |
---|
578 | FT_UShort lastGlyph; |
---|
579 | FT_UShort firstGlyph; |
---|
580 | GXV_LookupValueDesc base_value; |
---|
581 | GXV_LookupValueDesc value; |
---|
582 | |
---|
583 | |
---|
584 | GXV_NAME_ENTER( "LookupTable format 4" ); |
---|
585 | |
---|
586 | unitSize = nUnits = 0; |
---|
587 | gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, valid ); |
---|
588 | p += valid->subtable_length; |
---|
589 | |
---|
590 | GXV_UNITSIZE_VALIDATE( "format4", unitSize, nUnits, 6 ); |
---|
591 | |
---|
592 | for ( unit = 0, gid = 0; unit < nUnits; unit++ ) |
---|
593 | { |
---|
594 | GXV_LIMIT_CHECK( 2 + 2 ); |
---|
595 | lastGlyph = FT_NEXT_USHORT( p ); |
---|
596 | firstGlyph = FT_NEXT_USHORT( p ); |
---|
597 | |
---|
598 | gxv_glyphid_validate( firstGlyph, valid ); |
---|
599 | gxv_glyphid_validate( lastGlyph, valid ); |
---|
600 | |
---|
601 | if ( lastGlyph < gid ) |
---|
602 | { |
---|
603 | GXV_TRACE(( "reverse ordered segment specification:" |
---|
604 | " lastGlyph[%d]=%d < lastGlyph[%d]=%d\n", |
---|
605 | unit, lastGlyph, unit - 1 , gid )); |
---|
606 | if ( valid->root->level >= FT_VALIDATE_PARANOID ) |
---|
607 | FT_INVALID_GLYPH_ID; |
---|
608 | } |
---|
609 | |
---|
610 | if ( lastGlyph < firstGlyph ) |
---|
611 | { |
---|
612 | GXV_TRACE(( "reverse ordered range specification at unit %d:", |
---|
613 | " lastGlyph %d < firstGlyph %d ", |
---|
614 | unit, lastGlyph, firstGlyph )); |
---|
615 | if ( valid->root->level >= FT_VALIDATE_PARANOID ) |
---|
616 | FT_INVALID_GLYPH_ID; |
---|
617 | |
---|
618 | if ( valid->root->level == FT_VALIDATE_TIGHT ) |
---|
619 | continue; /* ftxvalidator silently skips such an entry */ |
---|
620 | |
---|
621 | FT_TRACE4(( "continuing with exchanged values\n" )); |
---|
622 | gid = firstGlyph; |
---|
623 | firstGlyph = lastGlyph; |
---|
624 | lastGlyph = gid; |
---|
625 | } |
---|
626 | |
---|
627 | GXV_LIMIT_CHECK( 2 ); |
---|
628 | base_value = GXV_LOOKUP_VALUE_LOAD( p, GXV_LOOKUPVALUE_UNSIGNED ); |
---|
629 | |
---|
630 | for ( gid = firstGlyph; gid <= lastGlyph; gid++ ) |
---|
631 | { |
---|
632 | value = valid->lookupfmt4_trans( (FT_UShort)( gid - firstGlyph ), |
---|
633 | base_value, |
---|
634 | limit, |
---|
635 | valid ); |
---|
636 | |
---|
637 | valid->lookupval_func( gid, value, valid ); |
---|
638 | } |
---|
639 | } |
---|
640 | |
---|
641 | gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, valid ); |
---|
642 | p += valid->subtable_length; |
---|
643 | |
---|
644 | valid->subtable_length = p - table; |
---|
645 | GXV_EXIT; |
---|
646 | } |
---|
647 | |
---|
648 | |
---|
649 | /* ================= Segment Table Format 6 Lookup Table =============== */ |
---|
650 | static void |
---|
651 | gxv_LookupTable_fmt6_skip_endmarkers( FT_Bytes table, |
---|
652 | FT_UShort unitSize, |
---|
653 | GXV_Validator valid ) |
---|
654 | { |
---|
655 | FT_Bytes p = table; |
---|
656 | |
---|
657 | |
---|
658 | while ( p < valid->root->limit ) |
---|
659 | { |
---|
660 | if ( p[0] != 0xFF || p[1] != 0xFF ) |
---|
661 | break; |
---|
662 | p += unitSize; |
---|
663 | } |
---|
664 | |
---|
665 | valid->subtable_length = p - table; |
---|
666 | } |
---|
667 | |
---|
668 | |
---|
669 | static void |
---|
670 | gxv_LookupTable_fmt6_validate( FT_Bytes table, |
---|
671 | FT_Bytes limit, |
---|
672 | GXV_Validator valid ) |
---|
673 | { |
---|
674 | FT_Bytes p = table; |
---|
675 | FT_UShort unit; |
---|
676 | FT_UShort prev_glyph; |
---|
677 | |
---|
678 | FT_UShort unitSize; |
---|
679 | FT_UShort nUnits; |
---|
680 | FT_UShort glyph; |
---|
681 | GXV_LookupValueDesc value; |
---|
682 | |
---|
683 | |
---|
684 | GXV_NAME_ENTER( "LookupTable format 6" ); |
---|
685 | |
---|
686 | unitSize = nUnits = 0; |
---|
687 | gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, valid ); |
---|
688 | p += valid->subtable_length; |
---|
689 | |
---|
690 | GXV_UNITSIZE_VALIDATE( "format6", unitSize, nUnits, 4 ); |
---|
691 | |
---|
692 | for ( unit = 0, prev_glyph = 0; unit < nUnits; unit++ ) |
---|
693 | { |
---|
694 | GXV_LIMIT_CHECK( 2 + 2 ); |
---|
695 | glyph = FT_NEXT_USHORT( p ); |
---|
696 | value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign ); |
---|
697 | |
---|
698 | if ( gxv_glyphid_validate( glyph, valid ) ) |
---|
699 | GXV_TRACE(( " endmarker found within defined range" |
---|
700 | " (entry %d < nUnits=%d)\n", |
---|
701 | unit, nUnits )); |
---|
702 | |
---|
703 | if ( prev_glyph > glyph ) |
---|
704 | { |
---|
705 | GXV_TRACE(( "current gid 0x%04x < previous gid 0x%04x\n", |
---|
706 | glyph, prev_glyph )); |
---|
707 | if ( valid->root->level >= FT_VALIDATE_PARANOID ) |
---|
708 | FT_INVALID_GLYPH_ID; |
---|
709 | } |
---|
710 | prev_glyph = glyph; |
---|
711 | |
---|
712 | valid->lookupval_func( glyph, value, valid ); |
---|
713 | } |
---|
714 | |
---|
715 | gxv_LookupTable_fmt6_skip_endmarkers( p, unitSize, valid ); |
---|
716 | p += valid->subtable_length; |
---|
717 | |
---|
718 | valid->subtable_length = p - table; |
---|
719 | GXV_EXIT; |
---|
720 | } |
---|
721 | |
---|
722 | |
---|
723 | /* ================= Trimmed Array Format 8 Lookup Table =============== */ |
---|
724 | static void |
---|
725 | gxv_LookupTable_fmt8_validate( FT_Bytes table, |
---|
726 | FT_Bytes limit, |
---|
727 | GXV_Validator valid ) |
---|
728 | { |
---|
729 | FT_Bytes p = table; |
---|
730 | FT_UShort i; |
---|
731 | |
---|
732 | GXV_LookupValueDesc value; |
---|
733 | FT_UShort firstGlyph; |
---|
734 | FT_UShort glyphCount; |
---|
735 | |
---|
736 | |
---|
737 | GXV_NAME_ENTER( "LookupTable format 8" ); |
---|
738 | |
---|
739 | /* firstGlyph + glyphCount */ |
---|
740 | GXV_LIMIT_CHECK( 2 + 2 ); |
---|
741 | firstGlyph = FT_NEXT_USHORT( p ); |
---|
742 | glyphCount = FT_NEXT_USHORT( p ); |
---|
743 | |
---|
744 | gxv_glyphid_validate( firstGlyph, valid ); |
---|
745 | gxv_glyphid_validate( (FT_UShort)( firstGlyph + glyphCount ), valid ); |
---|
746 | |
---|
747 | /* valueArray */ |
---|
748 | for ( i = 0; i < glyphCount; i++ ) |
---|
749 | { |
---|
750 | GXV_LIMIT_CHECK( 2 ); |
---|
751 | value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign ); |
---|
752 | valid->lookupval_func( (FT_UShort)( firstGlyph + i ), value, valid ); |
---|
753 | } |
---|
754 | |
---|
755 | valid->subtable_length = p - table; |
---|
756 | GXV_EXIT; |
---|
757 | } |
---|
758 | |
---|
759 | |
---|
760 | FT_LOCAL_DEF( void ) |
---|
761 | gxv_LookupTable_validate( FT_Bytes table, |
---|
762 | FT_Bytes limit, |
---|
763 | GXV_Validator valid ) |
---|
764 | { |
---|
765 | FT_Bytes p = table; |
---|
766 | FT_UShort format; |
---|
767 | |
---|
768 | GXV_Validate_Func fmt_funcs_table[] = |
---|
769 | { |
---|
770 | gxv_LookupTable_fmt0_validate, /* 0 */ |
---|
771 | NULL, /* 1 */ |
---|
772 | gxv_LookupTable_fmt2_validate, /* 2 */ |
---|
773 | NULL, /* 3 */ |
---|
774 | gxv_LookupTable_fmt4_validate, /* 4 */ |
---|
775 | NULL, /* 5 */ |
---|
776 | gxv_LookupTable_fmt6_validate, /* 6 */ |
---|
777 | NULL, /* 7 */ |
---|
778 | gxv_LookupTable_fmt8_validate, /* 8 */ |
---|
779 | }; |
---|
780 | |
---|
781 | GXV_Validate_Func func; |
---|
782 | |
---|
783 | |
---|
784 | GXV_NAME_ENTER( "LookupTable" ); |
---|
785 | |
---|
786 | /* lookuptbl_head may be used in fmt4 transit function. */ |
---|
787 | valid->lookuptbl_head = table; |
---|
788 | |
---|
789 | /* format */ |
---|
790 | GXV_LIMIT_CHECK( 2 ); |
---|
791 | format = FT_NEXT_USHORT( p ); |
---|
792 | GXV_TRACE(( " (format %d)\n", format )); |
---|
793 | |
---|
794 | if ( format > 8 ) |
---|
795 | FT_INVALID_FORMAT; |
---|
796 | |
---|
797 | func = fmt_funcs_table[format]; |
---|
798 | if ( func == NULL ) |
---|
799 | FT_INVALID_FORMAT; |
---|
800 | |
---|
801 | func( p, limit, valid ); |
---|
802 | p += valid->subtable_length; |
---|
803 | |
---|
804 | valid->subtable_length = p - table; |
---|
805 | |
---|
806 | GXV_EXIT; |
---|
807 | } |
---|
808 | |
---|
809 | |
---|
810 | /*************************************************************************/ |
---|
811 | /*************************************************************************/ |
---|
812 | /***** *****/ |
---|
813 | /***** Glyph ID *****/ |
---|
814 | /***** *****/ |
---|
815 | /*************************************************************************/ |
---|
816 | /*************************************************************************/ |
---|
817 | |
---|
818 | FT_LOCAL_DEF( FT_Int ) |
---|
819 | gxv_glyphid_validate( FT_UShort gid, |
---|
820 | GXV_Validator valid ) |
---|
821 | { |
---|
822 | FT_Face face; |
---|
823 | |
---|
824 | |
---|
825 | if ( gid == 0xFFFFU ) |
---|
826 | { |
---|
827 | GXV_EXIT; |
---|
828 | return 1; |
---|
829 | } |
---|
830 | |
---|
831 | face = valid->face; |
---|
832 | if ( face->num_glyphs < gid ) |
---|
833 | { |
---|
834 | GXV_TRACE(( " gxv_glyphid_check() gid overflow: num_glyphs %d < %d\n", |
---|
835 | face->num_glyphs, gid )); |
---|
836 | if ( valid->root->level >= FT_VALIDATE_PARANOID ) |
---|
837 | FT_INVALID_GLYPH_ID; |
---|
838 | } |
---|
839 | |
---|
840 | return 0; |
---|
841 | } |
---|
842 | |
---|
843 | |
---|
844 | /*************************************************************************/ |
---|
845 | /*************************************************************************/ |
---|
846 | /***** *****/ |
---|
847 | /***** CONTROL POINT *****/ |
---|
848 | /***** *****/ |
---|
849 | /*************************************************************************/ |
---|
850 | /*************************************************************************/ |
---|
851 | |
---|
852 | FT_LOCAL_DEF( void ) |
---|
853 | gxv_ctlPoint_validate( FT_UShort gid, |
---|
854 | FT_Short ctl_point, |
---|
855 | GXV_Validator valid ) |
---|
856 | { |
---|
857 | FT_Face face; |
---|
858 | FT_Error error; |
---|
859 | |
---|
860 | FT_GlyphSlot glyph; |
---|
861 | FT_Outline outline; |
---|
862 | short n_points; |
---|
863 | |
---|
864 | |
---|
865 | face = valid->face; |
---|
866 | |
---|
867 | error = FT_Load_Glyph( face, |
---|
868 | gid, |
---|
869 | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM ); |
---|
870 | if ( error ) |
---|
871 | FT_INVALID_GLYPH_ID; |
---|
872 | |
---|
873 | glyph = face->glyph; |
---|
874 | outline = glyph->outline; |
---|
875 | n_points = outline.n_points; |
---|
876 | |
---|
877 | |
---|
878 | if ( !( ctl_point < n_points ) ) |
---|
879 | FT_INVALID_DATA; |
---|
880 | } |
---|
881 | |
---|
882 | |
---|
883 | /*************************************************************************/ |
---|
884 | /*************************************************************************/ |
---|
885 | /***** *****/ |
---|
886 | /***** SFNT NAME *****/ |
---|
887 | /***** *****/ |
---|
888 | /*************************************************************************/ |
---|
889 | /*************************************************************************/ |
---|
890 | |
---|
891 | FT_LOCAL_DEF( void ) |
---|
892 | gxv_sfntName_validate( FT_UShort name_index, |
---|
893 | FT_UShort min_index, |
---|
894 | FT_UShort max_index, |
---|
895 | GXV_Validator valid ) |
---|
896 | { |
---|
897 | FT_SfntName name; |
---|
898 | FT_UInt i; |
---|
899 | FT_UInt nnames; |
---|
900 | |
---|
901 | |
---|
902 | GXV_NAME_ENTER( "sfntName" ); |
---|
903 | |
---|
904 | if ( name_index < min_index || max_index < name_index ) |
---|
905 | FT_INVALID_FORMAT; |
---|
906 | |
---|
907 | nnames = FT_Get_Sfnt_Name_Count( valid->face ); |
---|
908 | for ( i = 0; i < nnames; i++ ) |
---|
909 | { |
---|
910 | if ( FT_Get_Sfnt_Name( valid->face, i, &name ) != FT_Err_Ok ) |
---|
911 | continue ; |
---|
912 | |
---|
913 | if ( name.name_id == name_index ) |
---|
914 | goto Out; |
---|
915 | } |
---|
916 | |
---|
917 | GXV_TRACE(( " nameIndex = %d (UNTITLED)\n", name_index )); |
---|
918 | FT_INVALID_DATA; |
---|
919 | goto Exit; /* make compiler happy */ |
---|
920 | |
---|
921 | Out: |
---|
922 | FT_TRACE1(( " nameIndex = %d (", name_index )); |
---|
923 | GXV_TRACE_HEXDUMP_SFNTNAME( name ); |
---|
924 | FT_TRACE1(( ")\n" )); |
---|
925 | |
---|
926 | Exit: |
---|
927 | GXV_EXIT; |
---|
928 | } |
---|
929 | |
---|
930 | |
---|
931 | /*************************************************************************/ |
---|
932 | /*************************************************************************/ |
---|
933 | /***** *****/ |
---|
934 | /***** STATE TABLE *****/ |
---|
935 | /***** *****/ |
---|
936 | /*************************************************************************/ |
---|
937 | /*************************************************************************/ |
---|
938 | |
---|
939 | /* -------------------------- Class Table --------------------------- */ |
---|
940 | |
---|
941 | /* |
---|
942 | * highestClass specifies how many classes are defined in this |
---|
943 | * Class Subtable. Apple spec does not mention whether undefined |
---|
944 | * holes in the class (e.g.: 0-3 are predefined, 4 is unused, 5 is used) |
---|
945 | * are permitted. At present, holes in a defined class are not checked. |
---|
946 | * -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp> |
---|
947 | */ |
---|
948 | |
---|
949 | static void |
---|
950 | gxv_ClassTable_validate( FT_Bytes table, |
---|
951 | FT_UShort* length_p, |
---|
952 | FT_UShort stateSize, |
---|
953 | FT_Byte* maxClassID_p, |
---|
954 | GXV_Validator valid ) |
---|
955 | { |
---|
956 | FT_Bytes p = table; |
---|
957 | FT_Bytes limit = table + *length_p; |
---|
958 | FT_UShort firstGlyph; |
---|
959 | FT_UShort nGlyphs; |
---|
960 | |
---|
961 | |
---|
962 | GXV_NAME_ENTER( "ClassTable" ); |
---|
963 | |
---|
964 | *maxClassID_p = 3; /* Classes 0, 2, and 3 are predefined */ |
---|
965 | |
---|
966 | GXV_LIMIT_CHECK( 2 + 2 ); |
---|
967 | firstGlyph = FT_NEXT_USHORT( p ); |
---|
968 | nGlyphs = FT_NEXT_USHORT( p ); |
---|
969 | |
---|
970 | GXV_TRACE(( " (firstGlyph = %d, nGlyphs = %d)\n", firstGlyph, nGlyphs )); |
---|
971 | |
---|
972 | if ( !nGlyphs ) |
---|
973 | goto Out; |
---|
974 | |
---|
975 | gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs ), valid ); |
---|
976 | |
---|
977 | { |
---|
978 | FT_Byte nGlyphInClass[256]; |
---|
979 | FT_Byte classID; |
---|
980 | FT_UShort i; |
---|
981 | |
---|
982 | |
---|
983 | ft_memset( nGlyphInClass, 0, 256 ); |
---|
984 | |
---|
985 | |
---|
986 | for ( i = 0; i < nGlyphs; i++ ) |
---|
987 | { |
---|
988 | GXV_LIMIT_CHECK( 1 ); |
---|
989 | classID = FT_NEXT_BYTE( p ); |
---|
990 | switch ( classID ) |
---|
991 | { |
---|
992 | /* following classes should not appear in class array */ |
---|
993 | case 0: /* end of text */ |
---|
994 | case 2: /* out of bounds */ |
---|
995 | case 3: /* end of line */ |
---|
996 | FT_INVALID_DATA; |
---|
997 | break; |
---|
998 | |
---|
999 | case 1: /* out of bounds */ |
---|
1000 | default: /* user-defined: 4 - ( stateSize - 1 ) */ |
---|
1001 | if ( classID >= stateSize ) |
---|
1002 | FT_INVALID_DATA; /* assign glyph to undefined state */ |
---|
1003 | |
---|
1004 | nGlyphInClass[classID]++; |
---|
1005 | break; |
---|
1006 | } |
---|
1007 | } |
---|
1008 | *length_p = (FT_UShort)( p - table ); |
---|
1009 | |
---|
1010 | /* scan max ClassID in use */ |
---|
1011 | for ( i = 0; i < stateSize; i++ ) |
---|
1012 | if ( ( 3 < i ) && ( nGlyphInClass[i] > 0 ) ) |
---|
1013 | *maxClassID_p = (FT_Byte)i; /* XXX: Check Range? */ |
---|
1014 | } |
---|
1015 | |
---|
1016 | Out: |
---|
1017 | GXV_TRACE(( "Declared stateSize=0x%02x, Used maxClassID=0x%02x\n", |
---|
1018 | stateSize, *maxClassID_p )); |
---|
1019 | GXV_EXIT; |
---|
1020 | } |
---|
1021 | |
---|
1022 | |
---|
1023 | /* --------------------------- State Array ----------------------------- */ |
---|
1024 | |
---|
1025 | static void |
---|
1026 | gxv_StateArray_validate( FT_Bytes table, |
---|
1027 | FT_UShort* length_p, |
---|
1028 | FT_Byte maxClassID, |
---|
1029 | FT_UShort stateSize, |
---|
1030 | FT_Byte* maxState_p, |
---|
1031 | FT_Byte* maxEntry_p, |
---|
1032 | GXV_Validator valid ) |
---|
1033 | { |
---|
1034 | FT_Bytes p = table; |
---|
1035 | FT_Bytes limit = table + *length_p; |
---|
1036 | FT_Byte clazz; |
---|
1037 | FT_Byte entry; |
---|
1038 | |
---|
1039 | FT_UNUSED( stateSize ); /* for the non-debugging case */ |
---|
1040 | |
---|
1041 | |
---|
1042 | GXV_NAME_ENTER( "StateArray" ); |
---|
1043 | |
---|
1044 | GXV_TRACE(( "parse %d bytes by stateSize=%d maxClassID=%d\n", |
---|
1045 | (int)(*length_p), stateSize, (int)(maxClassID) )); |
---|
1046 | |
---|
1047 | /* |
---|
1048 | * 2 states are predefined and must be described in StateArray: |
---|
1049 | * state 0 (start of text), 1 (start of line) |
---|
1050 | */ |
---|
1051 | GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 ); |
---|
1052 | |
---|
1053 | *maxState_p = 0; |
---|
1054 | *maxEntry_p = 0; |
---|
1055 | |
---|
1056 | /* read if enough to read another state */ |
---|
1057 | while ( p + ( 1 + maxClassID ) <= limit ) |
---|
1058 | { |
---|
1059 | (*maxState_p)++; |
---|
1060 | for ( clazz = 0; clazz <= maxClassID; clazz++ ) |
---|
1061 | { |
---|
1062 | entry = FT_NEXT_BYTE( p ); |
---|
1063 | *maxEntry_p = (FT_Byte)FT_MAX( *maxEntry_p, entry ); |
---|
1064 | } |
---|
1065 | } |
---|
1066 | GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n", |
---|
1067 | *maxState_p, *maxEntry_p )); |
---|
1068 | |
---|
1069 | *length_p = (FT_UShort)( p - table ); |
---|
1070 | |
---|
1071 | GXV_EXIT; |
---|
1072 | } |
---|
1073 | |
---|
1074 | |
---|
1075 | /* --------------------------- Entry Table ----------------------------- */ |
---|
1076 | |
---|
1077 | static void |
---|
1078 | gxv_EntryTable_validate( FT_Bytes table, |
---|
1079 | FT_UShort* length_p, |
---|
1080 | FT_Byte maxEntry, |
---|
1081 | FT_UShort stateArray, |
---|
1082 | FT_UShort stateArray_length, |
---|
1083 | FT_Byte maxClassID, |
---|
1084 | FT_Bytes statetable_table, |
---|
1085 | FT_Bytes statetable_limit, |
---|
1086 | GXV_Validator valid ) |
---|
1087 | { |
---|
1088 | FT_Bytes p = table; |
---|
1089 | FT_Bytes limit = table + *length_p; |
---|
1090 | FT_Byte entry; |
---|
1091 | FT_Byte state; |
---|
1092 | FT_Int entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( statetable ); |
---|
1093 | |
---|
1094 | GXV_XStateTable_GlyphOffsetDesc glyphOffset; |
---|
1095 | |
---|
1096 | |
---|
1097 | GXV_NAME_ENTER( "EntryTable" ); |
---|
1098 | |
---|
1099 | GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize )); |
---|
1100 | |
---|
1101 | if ( ( maxEntry + 1 ) * entrySize > *length_p ) |
---|
1102 | { |
---|
1103 | if ( valid->root->level >= FT_VALIDATE_PARANOID ) |
---|
1104 | FT_INVALID_TOO_SHORT; |
---|
1105 | |
---|
1106 | /* ftxvalidator and FontValidator both warn and continue */ |
---|
1107 | maxEntry = (FT_Byte)( *length_p / entrySize - 1 ); |
---|
1108 | GXV_TRACE(( "too large maxEntry, shrinking to %d fit EntryTable length\n", |
---|
1109 | maxEntry )); |
---|
1110 | } |
---|
1111 | |
---|
1112 | for ( entry = 0; entry <= maxEntry; entry++ ) |
---|
1113 | { |
---|
1114 | FT_UShort newState; |
---|
1115 | FT_UShort flags; |
---|
1116 | |
---|
1117 | |
---|
1118 | GXV_LIMIT_CHECK( 2 + 2 ); |
---|
1119 | newState = FT_NEXT_USHORT( p ); |
---|
1120 | flags = FT_NEXT_USHORT( p ); |
---|
1121 | |
---|
1122 | |
---|
1123 | if ( newState < stateArray || |
---|
1124 | stateArray + stateArray_length < newState ) |
---|
1125 | { |
---|
1126 | GXV_TRACE(( " newState offset 0x%04x is out of stateArray\n", |
---|
1127 | newState )); |
---|
1128 | if ( valid->root->level >= FT_VALIDATE_PARANOID ) |
---|
1129 | FT_INVALID_OFFSET; |
---|
1130 | continue; |
---|
1131 | } |
---|
1132 | |
---|
1133 | if ( 0 != ( ( newState - stateArray ) % ( 1 + maxClassID ) ) ) |
---|
1134 | { |
---|
1135 | GXV_TRACE(( " newState offset 0x%04x is not aligned to %d-classes\n", |
---|
1136 | newState, 1 + maxClassID )); |
---|
1137 | if ( valid->root->level >= FT_VALIDATE_PARANOID ) |
---|
1138 | FT_INVALID_OFFSET; |
---|
1139 | continue; |
---|
1140 | } |
---|
1141 | |
---|
1142 | state = (FT_Byte)( ( newState - stateArray ) / ( 1 + maxClassID ) ); |
---|
1143 | |
---|
1144 | switch ( GXV_GLYPHOFFSET_FMT( statetable ) ) |
---|
1145 | { |
---|
1146 | case GXV_GLYPHOFFSET_NONE: |
---|
1147 | glyphOffset.uc = 0; /* make compiler happy */ |
---|
1148 | break; |
---|
1149 | |
---|
1150 | case GXV_GLYPHOFFSET_UCHAR: |
---|
1151 | glyphOffset.uc = FT_NEXT_BYTE( p ); |
---|
1152 | break; |
---|
1153 | |
---|
1154 | case GXV_GLYPHOFFSET_CHAR: |
---|
1155 | glyphOffset.c = FT_NEXT_CHAR( p ); |
---|
1156 | break; |
---|
1157 | |
---|
1158 | case GXV_GLYPHOFFSET_USHORT: |
---|
1159 | glyphOffset.u = FT_NEXT_USHORT( p ); |
---|
1160 | break; |
---|
1161 | |
---|
1162 | case GXV_GLYPHOFFSET_SHORT: |
---|
1163 | glyphOffset.s = FT_NEXT_SHORT( p ); |
---|
1164 | break; |
---|
1165 | |
---|
1166 | case GXV_GLYPHOFFSET_ULONG: |
---|
1167 | glyphOffset.ul = FT_NEXT_ULONG( p ); |
---|
1168 | break; |
---|
1169 | |
---|
1170 | case GXV_GLYPHOFFSET_LONG: |
---|
1171 | glyphOffset.l = FT_NEXT_LONG( p ); |
---|
1172 | break; |
---|
1173 | |
---|
1174 | default: |
---|
1175 | if ( valid->root->level >= FT_VALIDATE_PARANOID ) |
---|
1176 | FT_INVALID_FORMAT; |
---|
1177 | goto Exit; |
---|
1178 | } |
---|
1179 | |
---|
1180 | if ( NULL != valid->statetable.entry_validate_func ) |
---|
1181 | valid->statetable.entry_validate_func( state, |
---|
1182 | flags, |
---|
1183 | glyphOffset, |
---|
1184 | statetable_table, |
---|
1185 | statetable_limit, |
---|
1186 | valid ); |
---|
1187 | } |
---|
1188 | |
---|
1189 | Exit: |
---|
1190 | *length_p = (FT_UShort)( p - table ); |
---|
1191 | |
---|
1192 | GXV_EXIT; |
---|
1193 | } |
---|
1194 | |
---|
1195 | |
---|
1196 | /* =========================== State Table ============================= */ |
---|
1197 | |
---|
1198 | FT_LOCAL_DEF( void ) |
---|
1199 | gxv_StateTable_subtable_setup( FT_UShort table_size, |
---|
1200 | FT_UShort classTable, |
---|
1201 | FT_UShort stateArray, |
---|
1202 | FT_UShort entryTable, |
---|
1203 | FT_UShort* classTable_length_p, |
---|
1204 | FT_UShort* stateArray_length_p, |
---|
1205 | FT_UShort* entryTable_length_p, |
---|
1206 | GXV_Validator valid ) |
---|
1207 | { |
---|
1208 | FT_UShort o[3]; |
---|
1209 | FT_UShort* l[3]; |
---|
1210 | FT_UShort buff[4]; |
---|
1211 | |
---|
1212 | |
---|
1213 | o[0] = classTable; |
---|
1214 | o[1] = stateArray; |
---|
1215 | o[2] = entryTable; |
---|
1216 | l[0] = classTable_length_p; |
---|
1217 | l[1] = stateArray_length_p; |
---|
1218 | l[2] = entryTable_length_p; |
---|
1219 | |
---|
1220 | gxv_set_length_by_ushort_offset( o, l, buff, 3, table_size, valid ); |
---|
1221 | } |
---|
1222 | |
---|
1223 | |
---|
1224 | FT_LOCAL_DEF( void ) |
---|
1225 | gxv_StateTable_validate( FT_Bytes table, |
---|
1226 | FT_Bytes limit, |
---|
1227 | GXV_Validator valid ) |
---|
1228 | { |
---|
1229 | FT_UShort stateSize; |
---|
1230 | FT_UShort classTable; /* offset to Class(Sub)Table */ |
---|
1231 | FT_UShort stateArray; /* offset to StateArray */ |
---|
1232 | FT_UShort entryTable; /* offset to EntryTable */ |
---|
1233 | |
---|
1234 | FT_UShort classTable_length; |
---|
1235 | FT_UShort stateArray_length; |
---|
1236 | FT_UShort entryTable_length; |
---|
1237 | FT_Byte maxClassID; |
---|
1238 | FT_Byte maxState; |
---|
1239 | FT_Byte maxEntry; |
---|
1240 | |
---|
1241 | GXV_StateTable_Subtable_Setup_Func setup_func; |
---|
1242 | |
---|
1243 | FT_Bytes p = table; |
---|
1244 | |
---|
1245 | |
---|
1246 | GXV_NAME_ENTER( "StateTable" ); |
---|
1247 | |
---|
1248 | GXV_TRACE(( "StateTable header\n" )); |
---|
1249 | |
---|
1250 | GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 ); |
---|
1251 | stateSize = FT_NEXT_USHORT( p ); |
---|
1252 | classTable = FT_NEXT_USHORT( p ); |
---|
1253 | stateArray = FT_NEXT_USHORT( p ); |
---|
1254 | entryTable = FT_NEXT_USHORT( p ); |
---|
1255 | |
---|
1256 | GXV_TRACE(( "stateSize=0x%04x\n", stateSize )); |
---|
1257 | GXV_TRACE(( "offset to classTable=0x%04x\n", classTable )); |
---|
1258 | GXV_TRACE(( "offset to stateArray=0x%04x\n", stateArray )); |
---|
1259 | GXV_TRACE(( "offset to entryTable=0x%04x\n", entryTable )); |
---|
1260 | |
---|
1261 | if ( stateSize > 0xFF ) |
---|
1262 | FT_INVALID_DATA; |
---|
1263 | |
---|
1264 | if ( valid->statetable.optdata_load_func != NULL ) |
---|
1265 | valid->statetable.optdata_load_func( p, limit, valid ); |
---|
1266 | |
---|
1267 | if ( valid->statetable.subtable_setup_func != NULL) |
---|
1268 | setup_func = valid->statetable.subtable_setup_func; |
---|
1269 | else |
---|
1270 | setup_func = gxv_StateTable_subtable_setup; |
---|
1271 | |
---|
1272 | setup_func( (FT_UShort)( limit - table ), |
---|
1273 | classTable, |
---|
1274 | stateArray, |
---|
1275 | entryTable, |
---|
1276 | &classTable_length, |
---|
1277 | &stateArray_length, |
---|
1278 | &entryTable_length, |
---|
1279 | valid ); |
---|
1280 | |
---|
1281 | GXV_TRACE(( "StateTable Subtables\n" )); |
---|
1282 | |
---|
1283 | if ( classTable != 0 ) |
---|
1284 | gxv_ClassTable_validate( table + classTable, |
---|
1285 | &classTable_length, |
---|
1286 | stateSize, |
---|
1287 | &maxClassID, |
---|
1288 | valid ); |
---|
1289 | else |
---|
1290 | maxClassID = (FT_Byte)( stateSize - 1 ); |
---|
1291 | |
---|
1292 | if ( stateArray != 0 ) |
---|
1293 | gxv_StateArray_validate( table + stateArray, |
---|
1294 | &stateArray_length, |
---|
1295 | maxClassID, |
---|
1296 | stateSize, |
---|
1297 | &maxState, |
---|
1298 | &maxEntry, |
---|
1299 | valid ); |
---|
1300 | else |
---|
1301 | { |
---|
1302 | maxState = 1; /* 0:start of text, 1:start of line are predefined */ |
---|
1303 | maxEntry = 0; |
---|
1304 | } |
---|
1305 | |
---|
1306 | if ( maxEntry > 0 && entryTable == 0 ) |
---|
1307 | FT_INVALID_OFFSET; |
---|
1308 | |
---|
1309 | if ( entryTable != 0 ) |
---|
1310 | gxv_EntryTable_validate( table + entryTable, |
---|
1311 | &entryTable_length, |
---|
1312 | maxEntry, |
---|
1313 | stateArray, |
---|
1314 | stateArray_length, |
---|
1315 | maxClassID, |
---|
1316 | table, |
---|
1317 | limit, |
---|
1318 | valid ); |
---|
1319 | |
---|
1320 | GXV_EXIT; |
---|
1321 | } |
---|
1322 | |
---|
1323 | |
---|
1324 | /* ================= eXtended State Table (for morx) =================== */ |
---|
1325 | |
---|
1326 | FT_LOCAL_DEF( void ) |
---|
1327 | gxv_XStateTable_subtable_setup( FT_ULong table_size, |
---|
1328 | FT_ULong classTable, |
---|
1329 | FT_ULong stateArray, |
---|
1330 | FT_ULong entryTable, |
---|
1331 | FT_ULong* classTable_length_p, |
---|
1332 | FT_ULong* stateArray_length_p, |
---|
1333 | FT_ULong* entryTable_length_p, |
---|
1334 | GXV_Validator valid ) |
---|
1335 | { |
---|
1336 | FT_ULong o[3]; |
---|
1337 | FT_ULong* l[3]; |
---|
1338 | FT_ULong buff[4]; |
---|
1339 | |
---|
1340 | |
---|
1341 | o[0] = classTable; |
---|
1342 | o[1] = stateArray; |
---|
1343 | o[2] = entryTable; |
---|
1344 | l[0] = classTable_length_p; |
---|
1345 | l[1] = stateArray_length_p; |
---|
1346 | l[2] = entryTable_length_p; |
---|
1347 | |
---|
1348 | gxv_set_length_by_ulong_offset( o, l, buff, 4, table_size, valid ); |
---|
1349 | } |
---|
1350 | |
---|
1351 | |
---|
1352 | static void |
---|
1353 | gxv_XClassTable_lookupval_validate( FT_UShort glyph, |
---|
1354 | GXV_LookupValueDesc value, |
---|
1355 | GXV_Validator valid ) |
---|
1356 | { |
---|
1357 | FT_UNUSED( glyph ); |
---|
1358 | |
---|
1359 | if ( value.u >= valid->xstatetable.nClasses ) |
---|
1360 | FT_INVALID_DATA; |
---|
1361 | if ( value.u > valid->xstatetable.maxClassID ) |
---|
1362 | valid->xstatetable.maxClassID = value.u; |
---|
1363 | } |
---|
1364 | |
---|
1365 | |
---|
1366 | /* |
---|
1367 | +===============+ --------+ |
---|
1368 | | lookup header | | |
---|
1369 | +===============+ | |
---|
1370 | | BinSrchHeader | | |
---|
1371 | +===============+ | |
---|
1372 | | lastGlyph[0] | | |
---|
1373 | +---------------+ | |
---|
1374 | | firstGlyph[0] | | head of lookup table |
---|
1375 | +---------------+ | + |
---|
1376 | | offset[0] | -> | offset [byte] |
---|
1377 | +===============+ | + |
---|
1378 | | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] |
---|
1379 | +---------------+ | |
---|
1380 | | firstGlyph[1] | | |
---|
1381 | +---------------+ | |
---|
1382 | | offset[1] | | |
---|
1383 | +===============+ | |
---|
1384 | | |
---|
1385 | .... | |
---|
1386 | | |
---|
1387 | 16bit value array | |
---|
1388 | +===============+ | |
---|
1389 | | value | <-------+ |
---|
1390 | .... |
---|
1391 | */ |
---|
1392 | static GXV_LookupValueDesc |
---|
1393 | gxv_XClassTable_lookupfmt4_transit( FT_UShort relative_gindex, |
---|
1394 | GXV_LookupValueDesc base_value, |
---|
1395 | FT_Bytes lookuptbl_limit, |
---|
1396 | GXV_Validator valid ) |
---|
1397 | { |
---|
1398 | FT_Bytes p; |
---|
1399 | FT_Bytes limit; |
---|
1400 | FT_UShort offset; |
---|
1401 | GXV_LookupValueDesc value; |
---|
1402 | |
---|
1403 | /* XXX: check range? */ |
---|
1404 | offset = (FT_UShort)( base_value.u + |
---|
1405 | relative_gindex * sizeof ( FT_UShort ) ); |
---|
1406 | |
---|
1407 | p = valid->lookuptbl_head + offset; |
---|
1408 | limit = lookuptbl_limit; |
---|
1409 | |
---|
1410 | GXV_LIMIT_CHECK ( 2 ); |
---|
1411 | value.u = FT_NEXT_USHORT( p ); |
---|
1412 | |
---|
1413 | return value; |
---|
1414 | } |
---|
1415 | |
---|
1416 | |
---|
1417 | static void |
---|
1418 | gxv_XStateArray_validate( FT_Bytes table, |
---|
1419 | FT_ULong* length_p, |
---|
1420 | FT_UShort maxClassID, |
---|
1421 | FT_ULong stateSize, |
---|
1422 | FT_UShort* maxState_p, |
---|
1423 | FT_UShort* maxEntry_p, |
---|
1424 | GXV_Validator valid ) |
---|
1425 | { |
---|
1426 | FT_Bytes p = table; |
---|
1427 | FT_Bytes limit = table + *length_p; |
---|
1428 | FT_UShort clazz; |
---|
1429 | FT_UShort entry; |
---|
1430 | |
---|
1431 | FT_UNUSED( stateSize ); /* for the non-debugging case */ |
---|
1432 | |
---|
1433 | |
---|
1434 | GXV_NAME_ENTER( "XStateArray" ); |
---|
1435 | |
---|
1436 | GXV_TRACE(( "parse % 3d bytes by stateSize=% 3d maxClassID=% 3d\n", |
---|
1437 | (int)(*length_p), stateSize, (int)(maxClassID) )); |
---|
1438 | |
---|
1439 | /* |
---|
1440 | * 2 states are predefined and must be described: |
---|
1441 | * state 0 (start of text), 1 (start of line) |
---|
1442 | */ |
---|
1443 | GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 * 2 ); |
---|
1444 | |
---|
1445 | *maxState_p = 0; |
---|
1446 | *maxEntry_p = 0; |
---|
1447 | |
---|
1448 | /* read if enough to read another state */ |
---|
1449 | while ( p + ( ( 1 + maxClassID ) * 2 ) <= limit ) |
---|
1450 | { |
---|
1451 | (*maxState_p)++; |
---|
1452 | for ( clazz = 0; clazz <= maxClassID; clazz++ ) |
---|
1453 | { |
---|
1454 | entry = FT_NEXT_USHORT( p ); |
---|
1455 | *maxEntry_p = (FT_UShort)FT_MAX( *maxEntry_p, entry ); |
---|
1456 | } |
---|
1457 | } |
---|
1458 | GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n", |
---|
1459 | *maxState_p, *maxEntry_p )); |
---|
1460 | |
---|
1461 | *length_p = p - table; |
---|
1462 | |
---|
1463 | GXV_EXIT; |
---|
1464 | } |
---|
1465 | |
---|
1466 | |
---|
1467 | static void |
---|
1468 | gxv_XEntryTable_validate( FT_Bytes table, |
---|
1469 | FT_ULong* length_p, |
---|
1470 | FT_UShort maxEntry, |
---|
1471 | FT_ULong stateArray_length, |
---|
1472 | FT_UShort maxClassID, |
---|
1473 | FT_Bytes xstatetable_table, |
---|
1474 | FT_Bytes xstatetable_limit, |
---|
1475 | GXV_Validator valid ) |
---|
1476 | { |
---|
1477 | FT_Bytes p = table; |
---|
1478 | FT_Bytes limit = table + *length_p; |
---|
1479 | FT_UShort entry; |
---|
1480 | FT_UShort state; |
---|
1481 | FT_Int entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( xstatetable ); |
---|
1482 | |
---|
1483 | |
---|
1484 | GXV_NAME_ENTER( "XEntryTable" ); |
---|
1485 | GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize )); |
---|
1486 | |
---|
1487 | if ( ( p + ( maxEntry + 1 ) * entrySize ) > limit ) |
---|
1488 | FT_INVALID_TOO_SHORT; |
---|
1489 | |
---|
1490 | for (entry = 0; entry <= maxEntry ; entry++ ) |
---|
1491 | { |
---|
1492 | FT_UShort newState_idx; |
---|
1493 | FT_UShort flags; |
---|
1494 | GXV_XStateTable_GlyphOffsetDesc glyphOffset; |
---|
1495 | |
---|
1496 | |
---|
1497 | GXV_LIMIT_CHECK( 2 + 2 ); |
---|
1498 | newState_idx = FT_NEXT_USHORT( p ); |
---|
1499 | flags = FT_NEXT_USHORT( p ); |
---|
1500 | |
---|
1501 | if ( stateArray_length < (FT_ULong)( newState_idx * 2 ) ) |
---|
1502 | { |
---|
1503 | GXV_TRACE(( " newState index 0x%04x points out of stateArray\n", |
---|
1504 | newState_idx )); |
---|
1505 | if ( valid->root->level >= FT_VALIDATE_PARANOID ) |
---|
1506 | FT_INVALID_OFFSET; |
---|
1507 | } |
---|
1508 | |
---|
1509 | state = (FT_UShort)( newState_idx / ( 1 + maxClassID ) ); |
---|
1510 | if ( 0 != ( newState_idx % ( 1 + maxClassID ) ) ) |
---|
1511 | { |
---|
1512 | FT_TRACE4(( "-> new state = %d (supposed)\n" |
---|
1513 | "but newState index 0x%04x is not aligned to %d-classes\n", |
---|
1514 | state, newState_idx, 1 + maxClassID )); |
---|
1515 | if ( valid->root->level >= FT_VALIDATE_PARANOID ) |
---|
1516 | FT_INVALID_OFFSET; |
---|
1517 | } |
---|
1518 | |
---|
1519 | switch ( GXV_GLYPHOFFSET_FMT( xstatetable ) ) |
---|
1520 | { |
---|
1521 | case GXV_GLYPHOFFSET_NONE: |
---|
1522 | glyphOffset.uc = 0; /* make compiler happy */ |
---|
1523 | break; |
---|
1524 | |
---|
1525 | case GXV_GLYPHOFFSET_UCHAR: |
---|
1526 | glyphOffset.uc = FT_NEXT_BYTE( p ); |
---|
1527 | break; |
---|
1528 | |
---|
1529 | case GXV_GLYPHOFFSET_CHAR: |
---|
1530 | glyphOffset.c = FT_NEXT_CHAR( p ); |
---|
1531 | break; |
---|
1532 | |
---|
1533 | case GXV_GLYPHOFFSET_USHORT: |
---|
1534 | glyphOffset.u = FT_NEXT_USHORT( p ); |
---|
1535 | break; |
---|
1536 | |
---|
1537 | case GXV_GLYPHOFFSET_SHORT: |
---|
1538 | glyphOffset.s = FT_NEXT_SHORT( p ); |
---|
1539 | break; |
---|
1540 | |
---|
1541 | case GXV_GLYPHOFFSET_ULONG: |
---|
1542 | glyphOffset.ul = FT_NEXT_ULONG( p ); |
---|
1543 | break; |
---|
1544 | |
---|
1545 | case GXV_GLYPHOFFSET_LONG: |
---|
1546 | glyphOffset.l = FT_NEXT_LONG( p ); |
---|
1547 | break; |
---|
1548 | |
---|
1549 | default: |
---|
1550 | if ( valid->root->level >= FT_VALIDATE_PARANOID ) |
---|
1551 | FT_INVALID_FORMAT; |
---|
1552 | goto Exit; |
---|
1553 | } |
---|
1554 | |
---|
1555 | if ( NULL != valid->xstatetable.entry_validate_func ) |
---|
1556 | valid->xstatetable.entry_validate_func( state, |
---|
1557 | flags, |
---|
1558 | glyphOffset, |
---|
1559 | xstatetable_table, |
---|
1560 | xstatetable_limit, |
---|
1561 | valid ); |
---|
1562 | } |
---|
1563 | |
---|
1564 | Exit: |
---|
1565 | *length_p = p - table; |
---|
1566 | |
---|
1567 | GXV_EXIT; |
---|
1568 | } |
---|
1569 | |
---|
1570 | |
---|
1571 | FT_LOCAL_DEF( void ) |
---|
1572 | gxv_XStateTable_validate( FT_Bytes table, |
---|
1573 | FT_Bytes limit, |
---|
1574 | GXV_Validator valid ) |
---|
1575 | { |
---|
1576 | /* StateHeader members */ |
---|
1577 | FT_ULong classTable; /* offset to Class(Sub)Table */ |
---|
1578 | FT_ULong stateArray; /* offset to StateArray */ |
---|
1579 | FT_ULong entryTable; /* offset to EntryTable */ |
---|
1580 | |
---|
1581 | FT_ULong classTable_length; |
---|
1582 | FT_ULong stateArray_length; |
---|
1583 | FT_ULong entryTable_length; |
---|
1584 | FT_UShort maxState; |
---|
1585 | FT_UShort maxEntry; |
---|
1586 | |
---|
1587 | GXV_XStateTable_Subtable_Setup_Func setup_func; |
---|
1588 | |
---|
1589 | FT_Bytes p = table; |
---|
1590 | |
---|
1591 | |
---|
1592 | GXV_NAME_ENTER( "XStateTable" ); |
---|
1593 | |
---|
1594 | GXV_TRACE(( "XStateTable header\n" )); |
---|
1595 | |
---|
1596 | GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 ); |
---|
1597 | valid->xstatetable.nClasses = FT_NEXT_ULONG( p ); |
---|
1598 | classTable = FT_NEXT_ULONG( p ); |
---|
1599 | stateArray = FT_NEXT_ULONG( p ); |
---|
1600 | entryTable = FT_NEXT_ULONG( p ); |
---|
1601 | |
---|
1602 | GXV_TRACE(( "nClasses =0x%08x\n", valid->xstatetable.nClasses )); |
---|
1603 | GXV_TRACE(( "offset to classTable=0x%08x\n", classTable )); |
---|
1604 | GXV_TRACE(( "offset to stateArray=0x%08x\n", stateArray )); |
---|
1605 | GXV_TRACE(( "offset to entryTable=0x%08x\n", entryTable )); |
---|
1606 | |
---|
1607 | if ( valid->xstatetable.nClasses > 0xFFFFU ) |
---|
1608 | FT_INVALID_DATA; |
---|
1609 | |
---|
1610 | GXV_TRACE(( "StateTable Subtables\n" )); |
---|
1611 | |
---|
1612 | if ( valid->xstatetable.optdata_load_func != NULL ) |
---|
1613 | valid->xstatetable.optdata_load_func( p, limit, valid ); |
---|
1614 | |
---|
1615 | if ( valid->xstatetable.subtable_setup_func != NULL ) |
---|
1616 | setup_func = valid->xstatetable.subtable_setup_func; |
---|
1617 | else |
---|
1618 | setup_func = gxv_XStateTable_subtable_setup; |
---|
1619 | |
---|
1620 | setup_func( limit - table, |
---|
1621 | classTable, |
---|
1622 | stateArray, |
---|
1623 | entryTable, |
---|
1624 | &classTable_length, |
---|
1625 | &stateArray_length, |
---|
1626 | &entryTable_length, |
---|
1627 | valid ); |
---|
1628 | |
---|
1629 | if ( classTable != 0 ) |
---|
1630 | { |
---|
1631 | valid->xstatetable.maxClassID = 0; |
---|
1632 | valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; |
---|
1633 | valid->lookupval_func = gxv_XClassTable_lookupval_validate; |
---|
1634 | valid->lookupfmt4_trans = gxv_XClassTable_lookupfmt4_transit; |
---|
1635 | gxv_LookupTable_validate( table + classTable, |
---|
1636 | table + classTable + classTable_length, |
---|
1637 | valid ); |
---|
1638 | if ( valid->subtable_length < classTable_length ) |
---|
1639 | classTable_length = valid->subtable_length; |
---|
1640 | } |
---|
1641 | else |
---|
1642 | { |
---|
1643 | /* XXX: check range? */ |
---|
1644 | valid->xstatetable.maxClassID = |
---|
1645 | (FT_UShort)( valid->xstatetable.nClasses - 1 ); |
---|
1646 | } |
---|
1647 | |
---|
1648 | if ( stateArray != 0 ) |
---|
1649 | gxv_XStateArray_validate( table + stateArray, |
---|
1650 | &stateArray_length, |
---|
1651 | valid->xstatetable.maxClassID, |
---|
1652 | valid->xstatetable.nClasses, |
---|
1653 | &maxState, |
---|
1654 | &maxEntry, |
---|
1655 | valid ); |
---|
1656 | else |
---|
1657 | { |
---|
1658 | maxState = 1; /* 0:start of text, 1:start of line are predefined */ |
---|
1659 | maxEntry = 0; |
---|
1660 | } |
---|
1661 | |
---|
1662 | if ( maxEntry > 0 && entryTable == 0 ) |
---|
1663 | FT_INVALID_OFFSET; |
---|
1664 | |
---|
1665 | if ( entryTable != 0 ) |
---|
1666 | gxv_XEntryTable_validate( table + entryTable, |
---|
1667 | &entryTable_length, |
---|
1668 | maxEntry, |
---|
1669 | stateArray_length, |
---|
1670 | valid->xstatetable.maxClassID, |
---|
1671 | table, |
---|
1672 | limit, |
---|
1673 | valid ); |
---|
1674 | |
---|
1675 | GXV_EXIT; |
---|
1676 | } |
---|
1677 | |
---|
1678 | |
---|
1679 | /*************************************************************************/ |
---|
1680 | /*************************************************************************/ |
---|
1681 | /***** *****/ |
---|
1682 | /***** Table overlapping *****/ |
---|
1683 | /***** *****/ |
---|
1684 | /*************************************************************************/ |
---|
1685 | /*************************************************************************/ |
---|
1686 | |
---|
1687 | static int |
---|
1688 | gxv_compare_ranges( FT_Bytes table1_start, |
---|
1689 | FT_ULong table1_length, |
---|
1690 | FT_Bytes table2_start, |
---|
1691 | FT_ULong table2_length ) |
---|
1692 | { |
---|
1693 | if ( table1_start == table2_start ) |
---|
1694 | { |
---|
1695 | if ( ( table1_length == 0 || table2_length == 0 ) ) |
---|
1696 | goto Out; |
---|
1697 | } |
---|
1698 | else if ( table1_start < table2_start ) |
---|
1699 | { |
---|
1700 | if ( ( table1_start + table1_length ) <= table2_start ) |
---|
1701 | goto Out; |
---|
1702 | } |
---|
1703 | else if ( table1_start > table2_start ) |
---|
1704 | { |
---|
1705 | if ( ( table1_start >= table2_start + table2_length ) ) |
---|
1706 | goto Out; |
---|
1707 | } |
---|
1708 | return 1; |
---|
1709 | |
---|
1710 | Out: |
---|
1711 | return 0; |
---|
1712 | } |
---|
1713 | |
---|
1714 | |
---|
1715 | FT_LOCAL_DEF( void ) |
---|
1716 | gxv_odtect_add_range( FT_Bytes start, |
---|
1717 | FT_ULong length, |
---|
1718 | const FT_String* name, |
---|
1719 | GXV_odtect_Range odtect ) |
---|
1720 | { |
---|
1721 | odtect->range[ odtect->nRanges ].start = start; |
---|
1722 | odtect->range[ odtect->nRanges ].length = length; |
---|
1723 | odtect->range[ odtect->nRanges ].name = (FT_String*)name; |
---|
1724 | odtect->nRanges++; |
---|
1725 | } |
---|
1726 | |
---|
1727 | |
---|
1728 | FT_LOCAL_DEF( void ) |
---|
1729 | gxv_odtect_validate( GXV_odtect_Range odtect, |
---|
1730 | GXV_Validator valid ) |
---|
1731 | { |
---|
1732 | FT_UInt i, j; |
---|
1733 | |
---|
1734 | |
---|
1735 | GXV_NAME_ENTER( "check overlap among multi ranges" ); |
---|
1736 | |
---|
1737 | for ( i = 0; i < odtect->nRanges; i++ ) |
---|
1738 | for ( j = 0; j < i; j++ ) |
---|
1739 | if ( 0 != gxv_compare_ranges( odtect->range[i].start, |
---|
1740 | odtect->range[i].length, |
---|
1741 | odtect->range[j].start, |
---|
1742 | odtect->range[j].length ) ) |
---|
1743 | { |
---|
1744 | if ( odtect->range[i].name || odtect->range[j].name ) |
---|
1745 | GXV_TRACE(( "found overlap between range %d and range %d\n", |
---|
1746 | i, j )); |
---|
1747 | else |
---|
1748 | GXV_TRACE(( "found overlap between `%s' and `%s\'\n", |
---|
1749 | odtect->range[i].name, |
---|
1750 | odtect->range[j].name )); |
---|
1751 | FT_INVALID_OFFSET; |
---|
1752 | } |
---|
1753 | |
---|
1754 | GXV_EXIT; |
---|
1755 | } |
---|
1756 | |
---|
1757 | |
---|
1758 | /* END */ |
---|