Merge 25584, 25588.
[reactos.git] / reactos / dll / 3rdparty / freetype / src / gxvalid / gxvcommn.c
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 */