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