1 /****************************************************************************
5 * TrueTypeGX/AAT common tables validation (body).
7 * Copyright (C) 2004-2023 by
8 * suzuki toshiya, Masatake YAMATO, Red Hat K.K.,
9 * David Turner, Robert Wilhelm, and Werner Lemberg.
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.
19 /****************************************************************************
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.
31 /**************************************************************************
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.
38 #define FT_COMPONENT gxvcommon
41 /*************************************************************************/
42 /*************************************************************************/
44 /***** 16bit offset sorter *****/
46 /*************************************************************************/
47 /*************************************************************************/
50 gxv_compare_ushort_offset( const void* a,
53 return *(FT_UShort*)a - *(FT_UShort*)b;
58 gxv_set_length_by_ushort_offset( FT_UShort* offset,
63 GXV_Validator gxvalid )
68 for ( i = 0; i < nmemb; i++ )
71 for ( i = 0; i < nmemb; i++ )
75 ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_UShort ),
76 gxv_compare_ushort_offset );
78 if ( buff[nmemb] > limit )
81 for ( i = 0; i < nmemb; i++ )
86 for ( j = 0; j < nmemb; j++ )
87 if ( buff[j] == offset[i] )
93 *(length[i]) = (FT_UShort)( buff[j + 1] - buff[j] );
95 if ( 0 != offset[i] && 0 == *(length[i]) )
101 /*************************************************************************/
102 /*************************************************************************/
104 /***** 32bit offset sorter *****/
106 /*************************************************************************/
107 /*************************************************************************/
109 FT_COMPARE_DEF( int )
110 gxv_compare_ulong_offset( const void* a,
113 FT_ULong a_ = *(FT_ULong*)a;
114 FT_ULong b_ = *(FT_ULong*)b;
127 gxv_set_length_by_ulong_offset( FT_ULong* offset,
132 GXV_Validator gxvalid)
137 for ( i = 0; i < nmemb; i++ )
140 for ( i = 0; i < nmemb; i++ )
144 ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_ULong ),
145 gxv_compare_ulong_offset );
147 if ( buff[nmemb] > limit )
150 for ( i = 0; i < nmemb; i++ )
155 for ( j = 0; j < nmemb; j++ )
156 if ( buff[j] == offset[i] )
162 *(length[i]) = buff[j + 1] - buff[j];
164 if ( 0 != offset[i] && 0 == *(length[i]) )
170 /*************************************************************************/
171 /*************************************************************************/
173 /***** scan value array and get min & max *****/
175 /*************************************************************************/
176 /*************************************************************************/
180 gxv_array_getlimits_byte( FT_Bytes table,
184 GXV_Validator gxvalid )
197 GXV_LIMIT_CHECK( 1 );
198 val = FT_NEXT_BYTE( p );
200 *min = (FT_Byte)FT_MIN( *min, val );
201 *max = (FT_Byte)FT_MAX( *max, val );
204 gxvalid->subtable_length = (FT_ULong)( p - table );
209 gxv_array_getlimits_ushort( FT_Bytes table,
213 GXV_Validator gxvalid )
226 GXV_LIMIT_CHECK( 2 );
227 val = FT_NEXT_USHORT( p );
229 *min = (FT_Byte)FT_MIN( *min, val );
230 *max = (FT_Byte)FT_MAX( *max, val );
233 gxvalid->subtable_length = (FT_ULong)( p - table );
237 /*************************************************************************/
238 /*************************************************************************/
240 /***** BINSEARCHHEADER *****/
242 /*************************************************************************/
243 /*************************************************************************/
245 typedef struct GXV_BinSrchHeader_
249 FT_UShort searchRange;
250 FT_UShort entrySelector;
251 FT_UShort rangeShift;
257 gxv_BinSrchHeader_check_consistency( GXV_BinSrchHeader* binSrchHeader,
258 GXV_Validator gxvalid )
260 FT_UShort searchRange;
261 FT_UShort entrySelector;
262 FT_UShort rangeShift;
265 if ( binSrchHeader->unitSize == 0 )
268 if ( binSrchHeader->nUnits == 0 )
270 if ( binSrchHeader->searchRange == 0 &&
271 binSrchHeader->entrySelector == 0 &&
272 binSrchHeader->rangeShift == 0 )
278 for ( searchRange = 1, entrySelector = 1;
279 ( searchRange * 2 ) <= binSrchHeader->nUnits &&
280 searchRange < 0x8000U;
281 searchRange *= 2, entrySelector++ )
285 searchRange = (FT_UShort)( searchRange * binSrchHeader->unitSize );
286 rangeShift = (FT_UShort)( binSrchHeader->nUnits * binSrchHeader->unitSize
289 if ( searchRange != binSrchHeader->searchRange ||
290 entrySelector != binSrchHeader->entrySelector ||
291 rangeShift != binSrchHeader->rangeShift )
293 GXV_TRACE(( "Inconsistency found in BinSrchHeader\n" ));
294 GXV_TRACE(( "originally: unitSize=%d, nUnits=%d, "
295 "searchRange=%d, entrySelector=%d, "
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, "
303 binSrchHeader->unitSize, binSrchHeader->nUnits,
304 searchRange, entrySelector, rangeShift ));
306 GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA );
312 * parser & validator of BinSrchHeader
313 * which is used in LookupTable format 2, 4, 6.
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.
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>
327 gxv_BinSrchHeader_validate( FT_Bytes table,
329 FT_UShort* unitSize_p,
331 GXV_Validator gxvalid )
334 GXV_BinSrchHeader binSrchHeader;
337 GXV_NAME_ENTER( "BinSrchHeader validate" );
339 if ( *unitSize_p == 0 )
341 GXV_LIMIT_CHECK( 2 );
342 binSrchHeader.unitSize = FT_NEXT_USHORT( p );
345 binSrchHeader.unitSize = *unitSize_p;
347 if ( *nUnits_p == 0 )
349 GXV_LIMIT_CHECK( 2 );
350 binSrchHeader.nUnits = FT_NEXT_USHORT( p );
353 binSrchHeader.nUnits = *nUnits_p;
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 ));
361 gxv_BinSrchHeader_check_consistency( &binSrchHeader, gxvalid );
363 if ( *unitSize_p == 0 )
364 *unitSize_p = binSrchHeader.unitSize;
366 if ( *nUnits_p == 0 )
367 *nUnits_p = binSrchHeader.nUnits;
369 gxvalid->subtable_length = (FT_ULong)( p - table );
374 /*************************************************************************/
375 /*************************************************************************/
377 /***** LOOKUP TABLE *****/
379 /*************************************************************************/
380 /*************************************************************************/
382 #define GXV_LOOKUP_VALUE_LOAD( P, SIGNSPEC ) \
383 ( P += 2, gxv_lookup_value_load( P - 2, SIGNSPEC ) )
385 static GXV_LookupValueDesc
386 gxv_lookup_value_load( FT_Bytes p,
387 GXV_LookupValue_SignSpec signspec )
389 GXV_LookupValueDesc v;
392 if ( signspec == GXV_LOOKUPVALUE_UNSIGNED )
393 v.u = FT_NEXT_USHORT( p );
395 v.s = FT_NEXT_SHORT( p );
401 #define GXV_UNITSIZE_VALIDATE( FORMAT, UNITSIZE, NUNITS, CORRECTSIZE ) \
403 if ( UNITSIZE != CORRECTSIZE ) \
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 ) \
411 FT_ERROR(( " cannot validate anymore\n" )); \
415 FT_ERROR(( " forcibly continues\n" )); \
420 /* ================= Simple Array Format 0 Lookup Table ================ */
422 gxv_LookupTable_fmt0_validate( FT_Bytes table,
424 GXV_Validator gxvalid )
429 GXV_LookupValueDesc value;
432 GXV_NAME_ENTER( "LookupTable format 0" );
434 GXV_LIMIT_CHECK( 2 * gxvalid->face->num_glyphs );
436 for ( i = 0; i < gxvalid->face->num_glyphs; i++ )
438 GXV_LIMIT_CHECK( 2 );
439 if ( p + 2 >= limit ) /* some fonts have too-short fmt0 array */
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 );
447 value = GXV_LOOKUP_VALUE_LOAD( p, gxvalid->lookupval_sign );
448 gxvalid->lookupval_func( i, &value, gxvalid );
451 gxvalid->subtable_length = (FT_ULong)( p - table );
456 /* ================= Segment Single Format 2 Lookup Table ============== */
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.
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.
470 * -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp>
473 gxv_LookupTable_fmt2_skip_endmarkers( FT_Bytes table,
475 GXV_Validator gxvalid )
480 while ( ( p + 4 ) < gxvalid->root->limit )
482 if ( p[0] != 0xFF || p[1] != 0xFF || /* lastGlyph */
483 p[2] != 0xFF || p[3] != 0xFF ) /* firstGlyph */
488 gxvalid->subtable_length = (FT_ULong)( p - table );
493 gxv_LookupTable_fmt2_validate( FT_Bytes table,
495 GXV_Validator gxvalid )
504 FT_UShort firstGlyph;
505 GXV_LookupValueDesc value;
508 GXV_NAME_ENTER( "LookupTable format 2" );
510 unitSize = nUnits = 0;
511 gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, gxvalid );
512 p += gxvalid->subtable_length;
514 GXV_UNITSIZE_VALIDATE( "format2", unitSize, nUnits, 6 );
516 for ( unit = 0, gid = 0; unit < nUnits; unit++ )
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 );
523 gxv_glyphid_validate( firstGlyph, gxvalid );
524 gxv_glyphid_validate( lastGlyph, gxvalid );
526 if ( lastGlyph < gid )
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 );
534 if ( lastGlyph < firstGlyph )
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 );
541 if ( gxvalid->root->level == FT_VALIDATE_TIGHT )
542 continue; /* ftxvalidator silently skips such an entry */
544 FT_TRACE4(( "continuing with exchanged values\n" ));
546 firstGlyph = lastGlyph;
550 for ( gid = firstGlyph; gid <= lastGlyph; gid++ )
551 gxvalid->lookupval_func( gid, &value, gxvalid );
554 gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, gxvalid );
555 p += gxvalid->subtable_length;
557 gxvalid->subtable_length = (FT_ULong)( p - table );
562 /* ================= Segment Array Format 4 Lookup Table =============== */
564 gxv_LookupTable_fmt4_validate( FT_Bytes table,
566 GXV_Validator gxvalid )
575 FT_UShort firstGlyph;
576 GXV_LookupValueDesc base_value;
577 GXV_LookupValueDesc value;
580 GXV_NAME_ENTER( "LookupTable format 4" );
582 unitSize = nUnits = 0;
583 gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, gxvalid );
584 p += gxvalid->subtable_length;
586 GXV_UNITSIZE_VALIDATE( "format4", unitSize, nUnits, 6 );
588 for ( unit = 0, gid = 0; unit < nUnits; unit++ )
590 GXV_LIMIT_CHECK( 2 + 2 );
591 lastGlyph = FT_NEXT_USHORT( p );
592 firstGlyph = FT_NEXT_USHORT( p );
594 gxv_glyphid_validate( firstGlyph, gxvalid );
595 gxv_glyphid_validate( lastGlyph, gxvalid );
597 if ( lastGlyph < gid )
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 );
605 if ( lastGlyph < firstGlyph )
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 );
612 if ( gxvalid->root->level == FT_VALIDATE_TIGHT )
613 continue; /* ftxvalidator silently skips such an entry */
615 FT_TRACE4(( "continuing with exchanged values\n" ));
617 firstGlyph = lastGlyph;
621 GXV_LIMIT_CHECK( 2 );
622 base_value = GXV_LOOKUP_VALUE_LOAD( p, GXV_LOOKUPVALUE_UNSIGNED );
624 for ( gid = firstGlyph; gid <= lastGlyph; gid++ )
626 value = gxvalid->lookupfmt4_trans( (FT_UShort)( gid - firstGlyph ),
631 gxvalid->lookupval_func( gid, &value, gxvalid );
635 gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, gxvalid );
636 p += gxvalid->subtable_length;
638 gxvalid->subtable_length = (FT_ULong)( p - table );
643 /* ================= Segment Table Format 6 Lookup Table =============== */
645 gxv_LookupTable_fmt6_skip_endmarkers( FT_Bytes table,
647 GXV_Validator gxvalid )
652 while ( p < gxvalid->root->limit )
654 if ( p[0] != 0xFF || p[1] != 0xFF )
659 gxvalid->subtable_length = (FT_ULong)( p - table );
664 gxv_LookupTable_fmt6_validate( FT_Bytes table,
666 GXV_Validator gxvalid )
670 FT_UShort prev_glyph;
675 GXV_LookupValueDesc value;
678 GXV_NAME_ENTER( "LookupTable format 6" );
680 unitSize = nUnits = 0;
681 gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, gxvalid );
682 p += gxvalid->subtable_length;
684 GXV_UNITSIZE_VALIDATE( "format6", unitSize, nUnits, 4 );
686 for ( unit = 0, prev_glyph = 0; unit < nUnits; unit++ )
688 GXV_LIMIT_CHECK( 2 + 2 );
689 glyph = FT_NEXT_USHORT( p );
690 value = GXV_LOOKUP_VALUE_LOAD( p, gxvalid->lookupval_sign );
692 if ( gxv_glyphid_validate( glyph, gxvalid ) )
693 GXV_TRACE(( " endmarker found within defined range"
694 " (entry %d < nUnits=%d)\n",
697 if ( prev_glyph > glyph )
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 );
705 gxvalid->lookupval_func( glyph, &value, gxvalid );
708 gxv_LookupTable_fmt6_skip_endmarkers( p, unitSize, gxvalid );
709 p += gxvalid->subtable_length;
711 gxvalid->subtable_length = (FT_ULong)( p - table );
716 /* ================= Trimmed Array Format 8 Lookup Table =============== */
718 gxv_LookupTable_fmt8_validate( FT_Bytes table,
720 GXV_Validator gxvalid )
725 GXV_LookupValueDesc value;
726 FT_UShort firstGlyph;
727 FT_UShort glyphCount;
730 GXV_NAME_ENTER( "LookupTable format 8" );
732 /* firstGlyph + glyphCount */
733 GXV_LIMIT_CHECK( 2 + 2 );
734 firstGlyph = FT_NEXT_USHORT( p );
735 glyphCount = FT_NEXT_USHORT( p );
737 gxv_glyphid_validate( firstGlyph, gxvalid );
738 gxv_glyphid_validate( (FT_UShort)( firstGlyph + glyphCount ), gxvalid );
741 for ( i = 0; i < glyphCount; i++ )
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 );
748 gxvalid->subtable_length = (FT_ULong)( p - table );
754 gxv_LookupTable_validate( FT_Bytes table,
756 GXV_Validator gxvalid )
761 GXV_Validate_Func fmt_funcs_table[] =
763 gxv_LookupTable_fmt0_validate, /* 0 */
765 gxv_LookupTable_fmt2_validate, /* 2 */
767 gxv_LookupTable_fmt4_validate, /* 4 */
769 gxv_LookupTable_fmt6_validate, /* 6 */
771 gxv_LookupTable_fmt8_validate, /* 8 */
774 GXV_Validate_Func func;
777 GXV_NAME_ENTER( "LookupTable" );
779 /* lookuptbl_head may be used in fmt4 transit function. */
780 gxvalid->lookuptbl_head = table;
783 GXV_LIMIT_CHECK( 2 );
784 format = FT_NEXT_USHORT( p );
785 GXV_TRACE(( " (format %d)\n", format ));
790 func = fmt_funcs_table[format];
794 func( p, limit, gxvalid );
795 p += gxvalid->subtable_length;
797 gxvalid->subtable_length = (FT_ULong)( p - table );
803 /*************************************************************************/
804 /*************************************************************************/
806 /***** Glyph ID *****/
808 /*************************************************************************/
809 /*************************************************************************/
811 FT_LOCAL_DEF( FT_Int )
812 gxv_glyphid_validate( FT_UShort gid,
813 GXV_Validator gxvalid )
818 if ( gid == 0xFFFFU )
824 face = gxvalid->face;
825 if ( face->num_glyphs < gid )
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 );
836 /*************************************************************************/
837 /*************************************************************************/
839 /***** CONTROL POINT *****/
841 /*************************************************************************/
842 /*************************************************************************/
845 gxv_ctlPoint_validate( FT_UShort gid,
847 GXV_Validator gxvalid )
857 face = gxvalid->face;
859 error = FT_Load_Glyph( face,
861 FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM );
866 outline = glyph->outline;
867 n_points = (FT_UShort)outline.n_points;
869 if ( !( ctl_point < n_points ) )
874 /*************************************************************************/
875 /*************************************************************************/
877 /***** SFNT NAME *****/
879 /*************************************************************************/
880 /*************************************************************************/
883 gxv_sfntName_validate( FT_UShort name_index,
886 GXV_Validator gxvalid )
893 GXV_NAME_ENTER( "sfntName" );
895 if ( name_index < min_index || max_index < name_index )
898 nnames = FT_Get_Sfnt_Name_Count( gxvalid->face );
899 for ( i = 0; i < nnames; i++ )
901 if ( FT_Get_Sfnt_Name( gxvalid->face, i, &name ) != FT_Err_Ok )
904 if ( name.name_id == name_index )
908 GXV_TRACE(( " nameIndex = %d (UNTITLED)\n", name_index ));
910 goto Exit; /* make compiler happy */
913 FT_TRACE1(( " nameIndex = %d (", name_index ));
914 GXV_TRACE_HEXDUMP_SFNTNAME( name );
915 FT_TRACE1(( ")\n" ));
922 /*************************************************************************/
923 /*************************************************************************/
925 /***** STATE TABLE *****/
927 /*************************************************************************/
928 /*************************************************************************/
930 /* -------------------------- Class Table --------------------------- */
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>
941 gxv_ClassTable_validate( FT_Bytes table,
944 FT_Byte* maxClassID_p,
945 GXV_Validator gxvalid )
948 FT_Bytes limit = table + *length_p;
949 FT_UShort firstGlyph;
953 GXV_NAME_ENTER( "ClassTable" );
955 *maxClassID_p = 3; /* Classes 0, 2, and 3 are predefined */
957 GXV_LIMIT_CHECK( 2 + 2 );
958 firstGlyph = FT_NEXT_USHORT( p );
959 nGlyphs = FT_NEXT_USHORT( p );
961 GXV_TRACE(( " (firstGlyph = %d, nGlyphs = %d)\n", firstGlyph, nGlyphs ));
966 gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs ), gxvalid );
969 FT_Byte nGlyphInClass[256];
974 FT_MEM_ZERO( nGlyphInClass, 256 );
977 for ( i = 0; i < nGlyphs; i++ )
979 GXV_LIMIT_CHECK( 1 );
980 classID = FT_NEXT_BYTE( p );
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 */
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 */
995 nGlyphInClass[classID]++;
999 *length_p = (FT_UShort)( p - table );
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? */
1008 GXV_TRACE(( "Declared stateSize=0x%02x, Used maxClassID=0x%02x\n",
1009 stateSize, *maxClassID_p ));
1014 /* --------------------------- State Array ----------------------------- */
1017 gxv_StateArray_validate( FT_Bytes table,
1018 FT_UShort* length_p,
1020 FT_UShort stateSize,
1021 FT_Byte* maxState_p,
1022 FT_Byte* maxEntry_p,
1023 GXV_Validator gxvalid )
1026 FT_Bytes limit = table + *length_p;
1030 FT_UNUSED( stateSize ); /* for the non-debugging case */
1033 GXV_NAME_ENTER( "StateArray" );
1035 GXV_TRACE(( "parse %d bytes by stateSize=%d maxClassID=%d\n",
1036 (int)( *length_p ), stateSize, (int)maxClassID ));
1039 * 2 states are predefined and must be described in StateArray:
1040 * state 0 (start of text), 1 (start of line)
1042 GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 );
1047 /* read if enough to read another state */
1048 while ( p + ( 1 + maxClassID ) <= limit )
1051 for ( clazz = 0; clazz <= maxClassID; clazz++ )
1053 entry = FT_NEXT_BYTE( p );
1054 *maxEntry_p = (FT_Byte)FT_MAX( *maxEntry_p, entry );
1057 GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n",
1058 *maxState_p, *maxEntry_p ));
1060 *length_p = (FT_UShort)( p - table );
1066 /* --------------------------- Entry Table ----------------------------- */
1069 gxv_EntryTable_validate( FT_Bytes table,
1070 FT_UShort* length_p,
1072 FT_UShort stateArray,
1073 FT_UShort stateArray_length,
1075 FT_Bytes statetable_table,
1076 FT_Bytes statetable_limit,
1077 GXV_Validator gxvalid )
1080 FT_Bytes limit = table + *length_p;
1083 FT_Int entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( statetable );
1085 GXV_XStateTable_GlyphOffsetDesc glyphOffset;
1088 GXV_NAME_ENTER( "EntryTable" );
1090 GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize ));
1092 if ( ( maxEntry + 1 ) * entrySize > *length_p )
1094 GXV_SET_ERR_IF_PARANOID( FT_INVALID_TOO_SHORT );
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",
1102 for ( entry = 0; entry <= maxEntry; entry++ )
1108 GXV_LIMIT_CHECK( 2 + 2 );
1109 newState = FT_NEXT_USHORT( p );
1110 flags = FT_NEXT_USHORT( p );
1113 if ( newState < stateArray ||
1114 stateArray + stateArray_length < newState )
1116 GXV_TRACE(( " newState offset 0x%04x is out of stateArray\n",
1118 GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
1122 if ( 0 != ( ( newState - stateArray ) % ( 1 + maxClassID ) ) )
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 );
1130 state = (FT_Byte)( ( newState - stateArray ) / ( 1 + maxClassID ) );
1132 switch ( GXV_GLYPHOFFSET_FMT( statetable ) )
1134 case GXV_GLYPHOFFSET_NONE:
1135 glyphOffset.uc = 0; /* make compiler happy */
1138 case GXV_GLYPHOFFSET_UCHAR:
1139 glyphOffset.uc = FT_NEXT_BYTE( p );
1142 case GXV_GLYPHOFFSET_CHAR:
1143 glyphOffset.c = FT_NEXT_CHAR( p );
1146 case GXV_GLYPHOFFSET_USHORT:
1147 glyphOffset.u = FT_NEXT_USHORT( p );
1150 case GXV_GLYPHOFFSET_SHORT:
1151 glyphOffset.s = FT_NEXT_SHORT( p );
1154 case GXV_GLYPHOFFSET_ULONG:
1155 glyphOffset.ul = FT_NEXT_ULONG( p );
1158 case GXV_GLYPHOFFSET_LONG:
1159 glyphOffset.l = FT_NEXT_LONG( p );
1163 if ( gxvalid->statetable.entry_validate_func )
1164 gxvalid->statetable.entry_validate_func( state,
1172 *length_p = (FT_UShort)( p - table );
1178 /* =========================== State Table ============================= */
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 )
1198 l[0] = classTable_length_p;
1199 l[1] = stateArray_length_p;
1200 l[2] = entryTable_length_p;
1202 gxv_set_length_by_ushort_offset( o, l, buff, 3, table_size, gxvalid );
1206 FT_LOCAL_DEF( void )
1207 gxv_StateTable_validate( FT_Bytes table,
1209 GXV_Validator gxvalid )
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 */
1216 FT_UShort classTable_length;
1217 FT_UShort stateArray_length;
1218 FT_UShort entryTable_length;
1223 GXV_StateTable_Subtable_Setup_Func setup_func;
1228 GXV_NAME_ENTER( "StateTable" );
1230 GXV_TRACE(( "StateTable header\n" ));
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 );
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 ));
1243 if ( stateSize > 0xFF )
1246 if ( gxvalid->statetable.optdata_load_func )
1247 gxvalid->statetable.optdata_load_func( p, limit, gxvalid );
1249 if ( gxvalid->statetable.subtable_setup_func )
1250 setup_func = gxvalid->statetable.subtable_setup_func;
1252 setup_func = gxv_StateTable_subtable_setup;
1254 setup_func( (FT_UShort)( limit - table ),
1263 GXV_TRACE(( "StateTable Subtables\n" ));
1265 if ( classTable != 0 )
1266 gxv_ClassTable_validate( table + classTable,
1272 maxClassID = (FT_Byte)( stateSize - 1 );
1274 if ( stateArray != 0 )
1275 gxv_StateArray_validate( table + stateArray,
1285 maxState = 1; /* 0:start of text, 1:start of line are predefined */
1290 if ( maxEntry > 0 && entryTable == 0 )
1293 if ( entryTable != 0 )
1294 gxv_EntryTable_validate( table + entryTable,
1308 /* ================= eXtended State Table (for morx) =================== */
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 )
1328 l[0] = classTable_length_p;
1329 l[1] = stateArray_length_p;
1330 l[2] = entryTable_length_p;
1332 gxv_set_length_by_ulong_offset( o, l, buff, 3, table_size, gxvalid );
1337 gxv_XClassTable_lookupval_validate( FT_UShort glyph,
1338 GXV_LookupValueCPtr value_p,
1339 GXV_Validator gxvalid )
1343 if ( value_p->u >= gxvalid->xstatetable.nClasses )
1345 if ( value_p->u > gxvalid->xstatetable.maxClassID )
1346 gxvalid->xstatetable.maxClassID = value_p->u;
1351 +===============+ --------+
1358 | firstGlyph[0] | | head of lookup table
1359 +---------------+ | +
1360 | offset[0] | -> | offset [byte]
1361 +===============+ | +
1362 | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte]
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 )
1385 GXV_LookupValueDesc value;
1387 /* XXX: check range? */
1388 offset = (FT_UShort)( base_value_p->u +
1389 relative_gindex * sizeof ( FT_UShort ) );
1391 p = gxvalid->lookuptbl_head + offset;
1392 limit = lookuptbl_limit;
1394 GXV_LIMIT_CHECK ( 2 );
1395 value.u = FT_NEXT_USHORT( p );
1402 gxv_XStateArray_validate( FT_Bytes table,
1404 FT_UShort maxClassID,
1406 FT_UShort* maxState_p,
1407 FT_UShort* maxEntry_p,
1408 GXV_Validator gxvalid )
1411 FT_Bytes limit = table + *length_p;
1415 FT_UNUSED( stateSize ); /* for the non-debugging case */
1418 GXV_NAME_ENTER( "XStateArray" );
1420 GXV_TRACE(( "parse % 3d bytes by stateSize=% 3d maxClassID=% 3d\n",
1421 (int)( *length_p ), (int)stateSize, (int)maxClassID ));
1424 * 2 states are predefined and must be described:
1425 * state 0 (start of text), 1 (start of line)
1427 GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 * 2 );
1432 /* read if enough to read another state */
1433 while ( p + ( ( 1 + maxClassID ) * 2 ) <= limit )
1436 for ( clazz = 0; clazz <= maxClassID; clazz++ )
1438 entry = FT_NEXT_USHORT( p );
1439 *maxEntry_p = (FT_UShort)FT_MAX( *maxEntry_p, entry );
1442 GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n",
1443 *maxState_p, *maxEntry_p ));
1445 *length_p = (FT_ULong)( p - table );
1452 gxv_XEntryTable_validate( FT_Bytes table,
1455 FT_ULong stateArray_length,
1456 FT_UShort maxClassID,
1457 FT_Bytes xstatetable_table,
1458 FT_Bytes xstatetable_limit,
1459 GXV_Validator gxvalid )
1462 FT_Bytes limit = table + *length_p;
1465 FT_Int entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( xstatetable );
1468 GXV_NAME_ENTER( "XEntryTable" );
1469 GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize ));
1471 if ( ( p + ( maxEntry + 1 ) * entrySize ) > limit )
1472 FT_INVALID_TOO_SHORT;
1474 for (entry = 0; entry <= maxEntry; entry++ )
1476 FT_UShort newState_idx;
1478 GXV_XStateTable_GlyphOffsetDesc glyphOffset;
1481 GXV_LIMIT_CHECK( 2 + 2 );
1482 newState_idx = FT_NEXT_USHORT( p );
1483 flags = FT_NEXT_USHORT( p );
1485 if ( stateArray_length < (FT_ULong)( newState_idx * 2 ) )
1487 GXV_TRACE(( " newState index 0x%04x points out of stateArray\n",
1489 GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
1492 state = (FT_UShort)( newState_idx / ( 1 + maxClassID ) );
1493 if ( 0 != ( newState_idx % ( 1 + maxClassID ) ) )
1495 FT_TRACE4(( "-> new state = %d (supposed)\n",
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 );
1503 switch ( GXV_GLYPHOFFSET_FMT( xstatetable ) )
1505 case GXV_GLYPHOFFSET_NONE:
1506 glyphOffset.uc = 0; /* make compiler happy */
1509 case GXV_GLYPHOFFSET_UCHAR:
1510 glyphOffset.uc = FT_NEXT_BYTE( p );
1513 case GXV_GLYPHOFFSET_CHAR:
1514 glyphOffset.c = FT_NEXT_CHAR( p );
1517 case GXV_GLYPHOFFSET_USHORT:
1518 glyphOffset.u = FT_NEXT_USHORT( p );
1521 case GXV_GLYPHOFFSET_SHORT:
1522 glyphOffset.s = FT_NEXT_SHORT( p );
1525 case GXV_GLYPHOFFSET_ULONG:
1526 glyphOffset.ul = FT_NEXT_ULONG( p );
1529 case GXV_GLYPHOFFSET_LONG:
1530 glyphOffset.l = FT_NEXT_LONG( p );
1534 GXV_SET_ERR_IF_PARANOID( FT_INVALID_FORMAT );
1538 if ( gxvalid->xstatetable.entry_validate_func )
1539 gxvalid->xstatetable.entry_validate_func( state,
1548 *length_p = (FT_ULong)( p - table );
1554 FT_LOCAL_DEF( void )
1555 gxv_XStateTable_validate( FT_Bytes table,
1557 GXV_Validator gxvalid )
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 */
1564 FT_ULong classTable_length;
1565 FT_ULong stateArray_length;
1566 FT_ULong entryTable_length;
1570 GXV_XStateTable_Subtable_Setup_Func setup_func;
1575 GXV_NAME_ENTER( "XStateTable" );
1577 GXV_TRACE(( "XStateTable header\n" ));
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 );
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 ));
1590 if ( gxvalid->xstatetable.nClasses > 0xFFFFU )
1593 GXV_TRACE(( "StateTable Subtables\n" ));
1595 if ( gxvalid->xstatetable.optdata_load_func )
1596 gxvalid->xstatetable.optdata_load_func( p, limit, gxvalid );
1598 if ( gxvalid->xstatetable.subtable_setup_func )
1599 setup_func = gxvalid->xstatetable.subtable_setup_func;
1601 setup_func = gxv_XStateTable_subtable_setup;
1603 setup_func( (FT_ULong)( limit - table ),
1612 if ( classTable != 0 )
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,
1622 if ( gxvalid->subtable_length < classTable_length )
1623 classTable_length = gxvalid->subtable_length;
1628 /* XXX: check range? */
1629 gxvalid->xstatetable.maxClassID =
1630 (FT_UShort)( gxvalid->xstatetable.nClasses - 1 );
1633 if ( stateArray != 0 )
1634 gxv_XStateArray_validate( table + stateArray,
1636 gxvalid->xstatetable.maxClassID,
1637 gxvalid->xstatetable.nClasses,
1644 maxState = 1; /* 0:start of text, 1:start of line are predefined */
1649 if ( maxEntry > 0 && entryTable == 0 )
1652 if ( entryTable != 0 )
1653 gxv_XEntryTable_validate( table + entryTable,
1657 gxvalid->xstatetable.maxClassID,
1666 /*************************************************************************/
1667 /*************************************************************************/
1669 /***** Table overlapping *****/
1671 /*************************************************************************/
1672 /*************************************************************************/
1675 gxv_compare_ranges( FT_Bytes table1_start,
1676 FT_ULong table1_length,
1677 FT_Bytes table2_start,
1678 FT_ULong table2_length )
1680 if ( table1_start == table2_start )
1682 if ( ( table1_length == 0 || table2_length == 0 ) )
1685 else if ( table1_start < table2_start )
1687 if ( ( table1_start + table1_length ) <= table2_start )
1690 else if ( table1_start > table2_start )
1692 if ( ( table1_start >= table2_start + table2_length ) )
1702 FT_LOCAL_DEF( void )
1703 gxv_odtect_add_range( FT_Bytes start,
1705 const FT_String* name,
1706 GXV_odtect_Range odtect )
1708 odtect->range[odtect->nRanges].start = start;
1709 odtect->range[odtect->nRanges].length = length;
1710 odtect->range[odtect->nRanges].name = (FT_String*)name;
1715 FT_LOCAL_DEF( void )
1716 gxv_odtect_validate( GXV_odtect_Range odtect,
1717 GXV_Validator gxvalid )
1722 GXV_NAME_ENTER( "check overlap among multi ranges" );
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 ) )
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",
1736 GXV_TRACE(( "found overlap between `%s' and `%s\'\n",
1737 odtect->range[i].name,
1738 odtect->range[j].name ));