ref: af4a4fdd30ee57bfa4e0279e276af0d71ff09f2d
dir: /src/otlayout/otlgsub.c/
/***************************************************************************/ /* */ /* otlgsub.c */ /* */ /* OpenType layout support, GSUB table (body). */ /* */ /* Copyright 2002, 2004 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ /* modified, and distributed under the terms of the FreeType project */ /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ /* this file you indicate that you have read the license and */ /* understand and accept it fully. */ /* */ /***************************************************************************/ #include "otlgsub.h" #include "otlcommn.h" #include "otlparse.h" /* forward declaration */ static OTL_ValidateFunc otl_gsub_validate_funcs[]; /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** GSUB LOOKUP TYPE 1 *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ /* * 1: Single Substitution - Table format(s) * * This table is used to substitute individual glyph indices * with another one. There are only two sub-formats: * * Name Offset Size Description * -------------------------------------------------------------- * format 0 2 sub-table format (1) * offset 2 2 offset to coverage table * delta 4 2 16-bit delta to apply on all * covered glyph indices * * Name Offset Size Description * -------------------------------------------------------------- * format 0 2 sub-table format (2) * offset 2 2 offset to coverage table * count 4 2 coverage table count * substs[] 6 2*count substituted glyph indices, * */ static void otl_gsub_lookup1_validate( OTL_Bytes table, OTL_UInt lookup_count, OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; OTL_UNUSED( lookup_count ); OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); switch ( format ) { case 1: { OTL_Bytes coverage; OTL_Int delta; OTL_Long idx; OTL_CHECK( 4 ); coverage = table + OTL_NEXT_USHORT( p ); delta = OTL_NEXT_SHORT( p ); otl_coverage_validate( coverage, valid ); idx = otl_coverage_get_first( coverage ) + delta; if ( idx < 0 ) OTL_INVALID_DATA; idx = otl_coverage_get_last( coverage ) + delta; if ( (OTL_UInt)idx >= glyph_count ) OTL_INVALID_DATA; } break; case 2: { OTL_UInt coverage, num_glyphs; OTL_CHECK( 4 ); coverage = OTL_NEXT_USHORT( p ); num_glyphs = OTL_NEXT_USHORT( p ); otl_coverage_validate( table + coverage, valid ); OTL_CHECK( num_glyphs * 2 ); for ( ; num_glyphs > 0; num_glyphs-- ) if ( OTL_NEXT_USHORT( p ) >= glyph_count ) OTL_INVALID_DATA; } break; default: OTL_INVALID_DATA; } } #if 0 static OTL_Bool otl_gsub_lookup1_apply( OTL_Bytes table, OTL_Parser parser ) { OTL_Bytes p = table; OTL_Bytes coverage; OTL_UInt format, gindex, property; OTL_Long index; OTL_Bool subst = 0; if ( parser->context_len != 0xFFFFU && parser->context_len < 1 ) goto Exit; gindex = otl_parser_get_gindex( parser ); otl_parser_check_property( parser, gindex, &property ); if ( parser->error ) goto Exit; format = OTL_NEXT_USHORT(p); coverage = table + OTL_NEXT_USHORT(p); index = otl_coverage_get_index( coverage, gindex ); if ( index >= 0 ) { switch ( format ) { case 1: { OTL_Int delta = OTL_NEXT_SHORT( p ); gindex = ( gindex + delta ) & 0xFFFFU; otl_parser_replace_1( parser, gindex ); subst = 1; } break; case 2: { OTL_UInt count = OTL_NEXT_USHORT( p ); if ( (OTL_UInt)index < count ) { p += index * 2; otl_parser_replace_1( parser, OTL_PEEK_USHORT( p ) ); subst = 1; } } break; default: ; } } Exit: return subst; } #endif /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** GSUB LOOKUP TYPE 2 *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ /* * 2: Multiple Substitution - Table format(s) * * Replaces a single glyph with one or more glyphs. * * Name Offset Size Description * -------------------------------------------------------------- * format 0 2 sub-table format (1) * offset 2 2 offset to coverage table * count 4 2 coverage table count * sequencess[] 6 2*count offsets to sequence items * * each sequence item has the following format: * * Name Offset Size Description * -------------------------------------------------------------- * count 0 2 number of replacement glyphs * gindices[] 2 2*count string of glyph indices * */ static void otl_sequence_validate( OTL_Bytes table, OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt num_glyphs; OTL_CHECK( 2 ); num_glyphs = OTL_NEXT_USHORT( p ); /* according to the specification, `num_glyphs' should be > 0; */ /* we can deal with these cases pretty well, however */ OTL_CHECK( num_glyphs * 2 ); for ( ; num_glyphs > 0; num_glyphs-- ) if ( OTL_NEXT_USHORT( p ) >= glyph_count ) OTL_INVALID_DATA; } static void otl_gsub_lookup2_validate( OTL_Bytes table, OTL_UInt lookup_count, OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; OTL_UNUSED( lookup_count ); OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); switch ( format ) { case 1: { OTL_UInt coverage, num_sequences; OTL_CHECK( 4 ); coverage = OTL_NEXT_USHORT( p ); num_sequences = OTL_NEXT_USHORT( p ); otl_coverage_validate( table + coverage, valid ); OTL_CHECK( num_sequences * 2 ); /* scan sequence records */ for ( ; num_sequences > 0; num_sequences-- ) otl_sequence_validate( table + OTL_NEXT_USHORT( p ), glyph_count, valid ); } break; default: OTL_INVALID_DATA; } } #if 0 static OTL_Bool otl_gsub_lookup2_apply( OTL_Bytes table, OTL_Parser parser ) { OTL_Bytes p = table; OTL_Bytes coverage, sequence; OTL_UInt format, gindex, property, context_len, seq_count, count; OTL_Long index; OTL_Bool subst = 0; if ( parser->context_len != 0xFFFFU && parser->context_len < 1 ) goto Exit; gindex = otl_parser_get_gindex( parser ); otl_parser_check_property( parser, gindex, &property ); if ( parser->error ) goto Exit; p += 2; /* skip format */ coverage = table + OTL_NEXT_USHORT( p ); seq_count = OTL_NEXT_USHORT( p ); index = otl_coverage_get_index( coverage, gindex ); if ( (OTL_UInt)index >= seq_count || index < 0 ) goto Exit; p += index * 2; sequence = table + OTL_PEEK_USHORT( p ); p = sequence; count = OTL_NEXT_USHORT( p ); otl_parser_replace_n( parser, count, p ); subst = 1; Exit: return subst; } #endif /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** GSUB LOOKUP TYPE 3 *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ /* * 3: Alternate Substitution - Table format(s) * * Replaces a single glyph by another one taken liberally * in a list of alternatives. * * Name Offset Size Description * --------------------------------------------------------------- * format 0 2 sub-table format (1) * offset 2 2 offset to coverage table * count 4 2 coverage table count * alternates[] 6 2*count offsets to alternate items * * each alternate item has the following format: * * Name Offset Size Description * --------------------------------------------------------------- * count 0 2 number of replacement glyphs * gindices[] 2 2*count string of glyph indices, each * one is a valid alternative * */ static void otl_alternate_set_validate( OTL_Bytes table, OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt num_glyphs; OTL_CHECK( 2 ); num_glyphs = OTL_NEXT_USHORT( p ); OTL_CHECK( num_glyphs * 2 ); for ( ; num_glyphs > 0; num_glyphs-- ) if ( OTL_NEXT_USHORT( p ) >= glyph_count ) OTL_INVALID_DATA; } static void otl_gsub_lookup3_validate( OTL_Bytes table, OTL_UInt lookup_count, OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; OTL_UNUSED( lookup_count ); OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); switch ( format ) { case 1: { OTL_UInt coverage, num_alternate_sets; OTL_CHECK( 4 ); coverage = OTL_NEXT_USHORT( p ); num_alternate_sets = OTL_NEXT_USHORT( p ); otl_coverage_validate( table + coverage, valid ); OTL_CHECK( num_alternate_sets * 2 ); /* scan alternate set records */ for ( ; num_alternate_sets > 0; num_alternate_sets-- ) otl_alternate_set_validate( table + OTL_NEXT_USHORT( p ), glyph_count, valid ); } break; default: OTL_INVALID_DATA; } } #if 0 static OTL_Bool otl_gsub_lookup3_apply( OTL_Bytes table, OTL_Parser parser ) { OTL_Bytes p = table; OTL_Bytes coverage, alternates; OTL_UInt format, gindex, property, seq_count, count; OTL_Long index; OTL_Bool subst = 0; OTL_GSUB_Alternate alternate = parser->alternate; if ( parser->context_len != 0xFFFFU && parser->context_len < 1 ) goto Exit; if ( alternate == 0 ) goto Exit; gindex = otl_parser_get_gindex( parser ); otl_parser_check_property( parser, gindex, &property ); if ( parser->error ) goto Exit; p += 2; /* skip format */ coverage = table + OTL_NEXT_USHORT( p ); seq_count = OTL_NEXT_USHORT( p ); index = otl_coverage_get_index( coverage, gindex ); if ( (OTL_UInt)index >= seq_count || index < 0 ) goto Exit; p += index * 2; alternates = table + OTL_PEEK_USHORT( p ); p = alternates; count = OTL_NEXT_USHORT( p ); gindex = alternate->handler_func( gindex, count, p, alternate->handler_data ); otl_parser_replace_1( parser, gindex ); subst = 1; Exit: return subst; } #endif /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** GSUB LOOKUP TYPE 4 *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ static void otl_ligature_validate( OTL_Bytes table, OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt glyph_id, num_components; OTL_CHECK( 4 ); glyph_id = OTL_NEXT_USHORT( p ); if ( glyph_id >= glyph_count ) OTL_INVALID_DATA; num_components = OTL_NEXT_USHORT( p ); if ( num_components == 0 ) OTL_INVALID_DATA; num_components--; OTL_CHECK( num_components * 2 ); } static void otl_ligature_set_validate( OTL_Bytes table, OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt num_ligatures; OTL_CHECK( 2 ); num_ligatures = OTL_NEXT_USHORT( p ); OTL_CHECK( num_ligatures * 2 ); /* scan ligature records */ for ( ; num_ligatures > 0; num_ligatures-- ) otl_ligature_validate( table + OTL_NEXT_USHORT( p ), glyph_count, valid ); } static void otl_gsub_lookup4_validate( OTL_Bytes table, OTL_UInt lookup_count, OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; OTL_UNUSED( lookup_count); OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); switch ( format ) { case 1: { OTL_UInt coverage, num_ligsets; OTL_CHECK( 4 ); coverage = OTL_NEXT_USHORT( p ); num_ligsets = OTL_NEXT_USHORT( p ); otl_coverage_validate( table + coverage, valid ); OTL_CHECK( num_ligsets * 2 ); /* scan ligature set records */ for ( ; num_ligsets > 0; num_ligsets-- ) otl_ligature_set_validate( table + OTL_NEXT_USHORT( p ), glyph_count, valid ); } break; default: OTL_INVALID_DATA; } } /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** GSUB LOOKUP TYPE 5 *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ /* used for both format 1 and 2 */ static void otl_sub_rule_validate( OTL_Bytes table, OTL_UInt lookup_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt num_glyphs, num_subst; OTL_CHECK( 4 ); num_glyphs = OTL_NEXT_USHORT( p ); num_subst = OTL_NEXT_USHORT( p ); if ( num_glyphs == 0 ) OTL_INVALID_DATA; OTL_CHECK( ( num_glyphs - 1 ) * 2 + num_subst * 4 ); for ( ; num_subst > 0; num_subst-- ) { if ( OTL_NEXT_USHORT( p ) >= num_glyphs ) OTL_INVALID_DATA; if ( OTL_NEXT_USHORT( p ) >= lookup_count ) OTL_INVALID_DATA; } /* no need to check glyph indices/classes used as input for this */ /* context rule since even invalid glyph indices/classes return a */ /* meaningful result */ } /* used for both format 1 and 2 */ static void otl_sub_rule_set_validate( OTL_Bytes table, OTL_UInt lookup_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt num_subrules; OTL_CHECK( 2 ); num_subrules = OTL_NEXT_USHORT( p ); OTL_CHECK( num_subrules * 2 ); /* scan subrule records */ for ( ; num_subrules > 0; num_subrules-- ) otl_sub_rule_validate( table + OTL_NEXT_USHORT( p ), lookup_count, valid ); } static void otl_gsub_lookup5_validate( OTL_Bytes table, OTL_UInt lookup_count, OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; OTL_UNUSED( glyph_count ); OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); switch ( format ) { case 1: { OTL_UInt coverage, num_subrulesets; OTL_CHECK( 4 ); coverage = OTL_NEXT_USHORT( p ); num_subrulesets = OTL_NEXT_USHORT( p ); otl_coverage_validate( table + coverage, valid ); OTL_CHECK( num_subrulesets * 2 ); /* scan subrule set records */ for ( ; num_subrulesets > 0; num_subrulesets-- ) otl_sub_rule_set_validate( table + OTL_NEXT_USHORT( p ), lookup_count, valid ); } break; case 2: { OTL_UInt coverage, class_def, num_subclass_sets; OTL_CHECK( 6 ); coverage = OTL_NEXT_USHORT( p ); class_def = OTL_NEXT_USHORT( p ); num_subclass_sets = OTL_NEXT_USHORT( p ); otl_coverage_validate( table + coverage, valid ); otl_class_definition_validate( table + class_def, valid ); OTL_CHECK( num_subclass_sets * 2 ); /* scan subclass set records */ for ( ; num_subclass_sets > 0; num_subclass_sets-- ) { OTL_UInt offset = OTL_NEXT_USHORT( p ); if ( offset ) otl_sub_rule_set_validate( table + offset, lookup_count, valid ); } } break; case 3: { OTL_UInt num_glyphs, num_subst, count; OTL_CHECK( 4 ); num_glyphs = OTL_NEXT_USHORT( p ); num_subst = OTL_NEXT_USHORT( p ); OTL_CHECK( num_glyphs * 2 + num_subst * 4 ); for ( count = num_glyphs; count > 0; count-- ) otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid ); for ( ; num_subst > 0; num_subst-- ) { if ( OTL_NEXT_USHORT( p ) >= num_glyphs ) OTL_INVALID_DATA; if ( OTL_NEXT_USHORT( p ) >= lookup_count ) OTL_INVALID_DATA; } } break; default: OTL_INVALID_DATA; } } /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** GSUB LOOKUP TYPE 6 *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ /* used for both format 1 and 2 */ static void otl_chain_sub_rule_validate( OTL_Bytes table, OTL_UInt lookup_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt num_backtrack_glyphs, num_input_glyphs, num_lookahead_glyphs; OTL_UInt num_subst; OTL_CHECK( 2 ); num_backtrack_glyphs = OTL_NEXT_USHORT( p ); OTL_CHECK( num_backtrack_glyphs * 2 + 2 ); p += num_backtrack_glyphs * 2; num_input_glyphs = OTL_NEXT_USHORT( p ); if ( num_input_glyphs == 0 ) OTL_INVALID_DATA; OTL_CHECK( num_input_glyphs * 2 ); p += ( num_input_glyphs - 1 ) * 2; num_lookahead_glyphs = OTL_NEXT_USHORT( p ); OTL_CHECK( num_lookahead_glyphs * 2 + 2 ); p += num_lookahead_glyphs * 2; num_subst = OTL_NEXT_USHORT( p ); OTL_CHECK( num_subst * 4 ); for ( ; num_subst > 0; num_subst-- ) { if ( OTL_NEXT_USHORT( p ) >= num_input_glyphs ) OTL_INVALID_DATA; if ( OTL_NEXT_USHORT( p ) >= lookup_count ) OTL_INVALID_DATA; } /* no need to check glyph indices/classes used as input for this */ /* context rule since even invalid glyph indices/classes return a */ /* meaningful result */ } /* used for both format 1 and 2 */ static void otl_chain_sub_rule_set_validate( OTL_Bytes table, OTL_UInt lookup_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt num_chain_subrules; OTL_CHECK( 2 ); num_chain_subrules = OTL_NEXT_USHORT( p ); OTL_CHECK( num_chain_subrules * 2 ); /* scan chain subst rule records */ for ( ; num_chain_subrules > 0; num_chain_subrules-- ) otl_chain_sub_rule_validate( table + OTL_NEXT_USHORT( p ), lookup_count, valid ); } static void otl_gsub_lookup6_validate( OTL_Bytes table, OTL_UInt lookup_count, OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; OTL_UNUSED( glyph_count ); OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); switch ( format ) { case 1: { OTL_UInt coverage, num_chain_subrulesets; OTL_CHECK( 4 ); coverage = OTL_NEXT_USHORT( p ); num_chain_subrulesets = OTL_NEXT_USHORT( p ); otl_coverage_validate( table + coverage, valid ); OTL_CHECK( num_chain_subrulesets * 2 ); /* scan chain subrule set records */ for ( ; num_chain_subrulesets > 0; num_chain_subrulesets-- ) otl_chain_sub_rule_set_validate( table + OTL_NEXT_USHORT( p ), lookup_count, valid ); } break; case 2: { OTL_UInt coverage, back_class, input_class, ahead_class; OTL_UInt num_chain_subclass_sets; OTL_CHECK( 10 ); coverage = OTL_NEXT_USHORT( p ); back_class = OTL_NEXT_USHORT( p ); input_class = OTL_NEXT_USHORT( p ); ahead_class = OTL_NEXT_USHORT( p ); num_chain_subclass_sets = OTL_NEXT_USHORT( p ); otl_coverage_validate( table + coverage, valid ); otl_class_definition_validate( table + back_class, valid ); otl_class_definition_validate( table + input_class, valid ); otl_class_definition_validate( table + ahead_class, valid ); OTL_CHECK( num_chain_subclass_sets * 2 ); /* scan chain subclass set records */ for ( ; num_chain_subclass_sets > 0; num_chain_subclass_sets-- ) { OTL_UInt offset = OTL_NEXT_USHORT( p ); if ( offset ) otl_chain_sub_rule_set_validate( table + offset, lookup_count, valid ); } } break; case 3: { OTL_UInt num_backtrack_glyphs, num_input_glyphs; OTL_UInt num_lookahead_glyphs, num_subst, count; OTL_CHECK( 2 ); num_backtrack_glyphs = OTL_NEXT_USHORT( p ); OTL_CHECK( num_backtrack_glyphs * 2 + 2 ); for ( ; num_backtrack_glyphs > 0; num_backtrack_glyphs-- ) otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid ); num_input_glyphs = OTL_NEXT_USHORT( p ); OTL_CHECK( num_input_glyphs * 2 + 2 ); for ( count = num_input_glyphs; count > 0; count-- ) otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid ); num_lookahead_glyphs = OTL_NEXT_USHORT( p ); OTL_CHECK( num_lookahead_glyphs * 2 + 2 ); for ( ; num_lookahead_glyphs > 0; num_lookahead_glyphs-- ) otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid ); num_subst = OTL_NEXT_USHORT( p ); OTL_CHECK( num_subst * 4 ); for ( ; num_subst > 0; num_subst-- ) { if ( OTL_NEXT_USHORT( p ) >= num_input_glyphs ) OTL_INVALID_DATA; if ( OTL_NEXT_USHORT( p ) >= lookup_count ) OTL_INVALID_DATA; } } break; default: OTL_INVALID_DATA; } } /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** GSUB LOOKUP TYPE 7 *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ static void otl_gsub_lookup7_validate( OTL_Bytes table, OTL_UInt lookup_count, OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); switch ( format ) { case 1: { OTL_UInt lookup_type, lookup_offset; OTL_ValidateFunc validate; OTL_CHECK( 6 ); lookup_type = OTL_NEXT_USHORT( p ); lookup_offset = OTL_NEXT_ULONG( p ); if ( lookup_type == 0 || lookup_type == 7 || lookup_type > 8 ) OTL_INVALID_DATA; validate = otl_gsub_validate_funcs[lookup_type - 1]; validate( table + lookup_offset, lookup_count, glyph_count, valid ); } break; default: OTL_INVALID_DATA; } } /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** GSUB LOOKUP TYPE 8 *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ static void otl_gsub_lookup8_validate( OTL_Bytes table, OTL_UInt lookup_count, OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table, coverage; OTL_UInt format; OTL_UInt num_backtrack_glyphs, num_lookahead_glyphs, num_glyphs; OTL_UNUSED( lookup_count ); OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); switch ( format ) { case 1: OTL_CHECK( 4 ); coverage = table + OTL_NEXT_USHORT( p ); num_backtrack_glyphs = OTL_NEXT_USHORT( p ); otl_coverage_validate( coverage, valid ); OTL_CHECK( num_backtrack_glyphs * 2 + 2 ); for ( ; num_backtrack_glyphs > 0; num_backtrack_glyphs-- ) otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid ); num_lookahead_glyphs = OTL_NEXT_USHORT( p ); OTL_CHECK( num_lookahead_glyphs * 2 + 2 ); for ( ; num_lookahead_glyphs > 0; num_lookahead_glyphs-- ) otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid ); num_glyphs = OTL_NEXT_USHORT( p ); if ( num_glyphs != otl_coverage_get_count( coverage ) ) OTL_INVALID_DATA; OTL_CHECK( num_glyphs * 2 ); for ( ; num_glyphs > 0; num_glyphs-- ) if ( OTL_NEXT_USHORT( p ) >= glyph_count ) OTL_INVALID_DATA; break; default: OTL_INVALID_DATA; } } static OTL_ValidateFunc otl_gsub_validate_funcs[8] = { otl_gsub_lookup1_validate, otl_gsub_lookup2_validate, otl_gsub_lookup3_validate, otl_gsub_lookup4_validate, otl_gsub_lookup5_validate, otl_gsub_lookup6_validate, otl_gsub_lookup7_validate, otl_gsub_lookup8_validate }; /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** GSUB TABLE *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ OTL_LOCALDEF( void ) otl_gsub_validate( OTL_Bytes table, OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt scripts, features, lookups; OTL_CHECK( 10 ); if ( OTL_NEXT_USHORT( p ) != 0x10000UL ) OTL_INVALID_DATA; scripts = OTL_NEXT_USHORT( p ); features = OTL_NEXT_USHORT( p ); lookups = OTL_NEXT_USHORT( p ); otl_lookup_list_validate( table + lookups, 8, otl_gsub_validate_funcs, glyph_count, valid ); otl_feature_list_validate( table + features, table + lookups, valid ); otl_script_list_validate( table + scripts, table + features, valid ); } /* END */