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