to pass number of lookups. Update all callers. Don't call otl_lookup_list_validate but otl_lookup_validate. (otl_gpos_validate): Call otl_lookup_list_validate instead of otl_gpos_subtable_validate. * src/otlayout/otlgpos.h: Updated. * src/otlayout/otljstf.c (otl_jstf_max_validate): Add argument to pass number of lookups. Update all callers. * src/cff/cffparse.c (cff_parse_real): s/exp/exponent/ to avoid compiler warning. * src/sfnt/ttcmap0.c, src/sfnt/ttcmap0.h: Renamed to... * src/sfnt/ttcmap.c, src/sfnt/ttcmap.h: This. * src/sfnt/Jamfile, src/sfnt/rules.mk, src/sfnt/sfdriver.c, src/sfnt/sfnt.c, src/sfnt/sfobjs.c: Updated. * builds/compiler/gcc-dev.mk (CFLAGS): Don't add `-Wnested-externs' if compiler is g++ (v3.3.3 emits a warning otherwise).
1103 lines
32 KiB
C
1103 lines
32 KiB
C
/***************************************************************************/
|
|
/* */
|
|
/* otlgpos.c */
|
|
/* */
|
|
/* OpenType layout support, GPOS 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 "otlgpos.h"
|
|
#include "otlcommn.h"
|
|
|
|
|
|
/* forward declaration */
|
|
static OTL_ValidateFunc otl_gpos_validate_funcs[];
|
|
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
/***** *****/
|
|
/***** VALUE RECORDS *****/
|
|
/***** *****/
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
static OTL_UInt
|
|
otl_value_length( OTL_UInt format )
|
|
{
|
|
OTL_UInt count;
|
|
|
|
|
|
count = ( ( format & 0xAA ) >> 1 ) + ( format & 0x55 );
|
|
count = ( ( count & 0xCC ) >> 2 ) + ( count & 0x33 );
|
|
count = ( ( count & 0xF0 ) >> 4 ) + ( count & 0x0F );
|
|
|
|
return count * 2;
|
|
}
|
|
|
|
|
|
static void
|
|
otl_value_validate( OTL_Bytes table,
|
|
OTL_Bytes pos_table,
|
|
OTL_UInt format,
|
|
OTL_Validator valid )
|
|
{
|
|
OTL_Bytes p = table;
|
|
OTL_UInt count, device;
|
|
|
|
|
|
if ( format >= 0x100 )
|
|
OTL_INVALID_DATA;
|
|
|
|
for ( count = 4; count > 0; count-- )
|
|
{
|
|
if ( format & 1 )
|
|
{
|
|
OTL_CHECK( 2 );
|
|
p += 2;
|
|
}
|
|
|
|
format >>= 1;
|
|
}
|
|
|
|
for ( count = 4; count > 0; count-- )
|
|
{
|
|
if ( format & 1 )
|
|
{
|
|
OTL_CHECK( 2 );
|
|
device = OTL_NEXT_USHORT( p );
|
|
if ( device )
|
|
otl_device_table_validate( pos_table + device, valid );
|
|
}
|
|
format >>= 1;
|
|
}
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
/***** *****/
|
|
/***** ANCHORS *****/
|
|
/***** *****/
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
static void
|
|
otl_anchor_validate( OTL_Bytes table,
|
|
OTL_Validator valid )
|
|
{
|
|
OTL_Bytes p = table;
|
|
OTL_UInt format;
|
|
|
|
|
|
OTL_CHECK( 6 );
|
|
format = OTL_NEXT_USHORT( p );
|
|
p += 4; /* skip coordinates */
|
|
|
|
switch ( format )
|
|
{
|
|
case 1:
|
|
break;
|
|
|
|
case 2:
|
|
OTL_CHECK( 2 ); /* anchor point */
|
|
break;
|
|
|
|
case 3:
|
|
{
|
|
OTL_UInt x_device, y_device;
|
|
|
|
|
|
OTL_CHECK( 4 );
|
|
x_device = OTL_NEXT_USHORT( p );
|
|
y_device = OTL_NEXT_USHORT( p );
|
|
|
|
if ( x_device )
|
|
otl_device_table_validate( table + x_device, valid );
|
|
|
|
if ( y_device )
|
|
otl_device_table_validate( table + y_device, valid );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
OTL_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
/***** *****/
|
|
/***** MARK ARRAY *****/
|
|
/***** *****/
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
static void
|
|
otl_mark_array_validate( OTL_Bytes table,
|
|
OTL_Validator valid )
|
|
{
|
|
OTL_Bytes p = table;
|
|
OTL_UInt count;
|
|
|
|
OTL_CHECK( 2 );
|
|
|
|
count = OTL_NEXT_USHORT( p );
|
|
OTL_CHECK( count * 4 );
|
|
for ( ; count > 0; count-- )
|
|
{
|
|
p += 2; /* ignore class index */
|
|
otl_anchor_validate( table + OTL_NEXT_USHORT( p ), valid );
|
|
}
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
/***** *****/
|
|
/***** GPOS LOOKUP TYPE 1 *****/
|
|
/***** *****/
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
static void
|
|
otl_gpos_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_UNUSED( glyph_count );
|
|
|
|
|
|
OTL_CHECK( 2 );
|
|
format = OTL_NEXT_USHORT( p );
|
|
switch ( format )
|
|
{
|
|
case 1:
|
|
{
|
|
OTL_UInt coverage, value_format;
|
|
|
|
|
|
OTL_CHECK( 4 );
|
|
coverage = OTL_NEXT_USHORT( p );
|
|
value_format = OTL_NEXT_USHORT( p );
|
|
|
|
otl_coverage_validate( table + coverage, valid );
|
|
otl_value_validate( p, table, value_format, valid );
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
{
|
|
OTL_UInt coverage, value_format, num_values, len_value;
|
|
|
|
|
|
OTL_CHECK( 6 );
|
|
coverage = OTL_NEXT_USHORT( p );
|
|
value_format = OTL_NEXT_USHORT( p );
|
|
num_values = OTL_NEXT_USHORT( p );
|
|
|
|
len_value = otl_value_length( value_format );
|
|
|
|
otl_coverage_validate( table + coverage, valid );
|
|
|
|
OTL_CHECK( num_values * len_value );
|
|
|
|
/* scan value records */
|
|
for ( ; num_values > 0; num_values-- )
|
|
{
|
|
otl_value_validate( p, table, value_format, valid );
|
|
p += len_value;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
OTL_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
/***** *****/
|
|
/***** GPOS LOOKUP TYPE 2 *****/
|
|
/***** *****/
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
static void
|
|
otl_gpos_pairset_validate( OTL_Bytes table,
|
|
OTL_Bytes pos_table,
|
|
OTL_UInt format1,
|
|
OTL_UInt format2,
|
|
OTL_Validator valid )
|
|
{
|
|
OTL_Bytes p = table;
|
|
OTL_UInt value_len1, value_len2, num_pairvalues;
|
|
|
|
|
|
OTL_CHECK( 2 );
|
|
num_pairvalues = OTL_NEXT_USHORT( p );
|
|
value_len1 = otl_value_length( format1 );
|
|
value_len2 = otl_value_length( format2 );
|
|
|
|
OTL_CHECK( num_pairvalues * ( value_len1 + value_len2 + 2 ) );
|
|
|
|
/* scan pair value records */
|
|
for ( ; num_pairvalues > 0; num_pairvalues-- )
|
|
{
|
|
p += 2; /* ignore glyph id */
|
|
|
|
otl_value_validate( p, pos_table, format1, valid );
|
|
p += value_len1;
|
|
|
|
otl_value_validate( p, pos_table, format2, valid );
|
|
p += value_len2;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
otl_gpos_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_UNUSED( glyph_count );
|
|
|
|
|
|
OTL_CHECK( 2 );
|
|
format = OTL_NEXT_USHORT( p );
|
|
switch ( format )
|
|
{
|
|
case 1:
|
|
{
|
|
OTL_UInt coverage, value1, value2, num_pairsets;
|
|
|
|
|
|
OTL_CHECK( 8 );
|
|
coverage = OTL_NEXT_USHORT( p );
|
|
value1 = OTL_NEXT_USHORT( p );
|
|
value2 = OTL_NEXT_USHORT( p );
|
|
num_pairsets = OTL_NEXT_USHORT( p );
|
|
|
|
otl_coverage_validate( table + coverage, valid );
|
|
|
|
OTL_CHECK( num_pairsets * 2 );
|
|
|
|
for ( ; num_pairsets > 0; num_pairsets-- )
|
|
otl_gpos_pairset_validate( table + OTL_NEXT_USHORT( p ),
|
|
table, value1, value2, valid );
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
{
|
|
OTL_UInt coverage, value1, value2, class1, class2;
|
|
OTL_UInt num_classes1, num_classes2, len_value1, len_value2, count;
|
|
|
|
|
|
OTL_CHECK( 14 );
|
|
coverage = OTL_NEXT_USHORT( p );
|
|
value1 = OTL_NEXT_USHORT( p );
|
|
value2 = OTL_NEXT_USHORT( p );
|
|
class1 = OTL_NEXT_USHORT( p );
|
|
class2 = OTL_NEXT_USHORT( p );
|
|
num_classes1 = OTL_NEXT_USHORT( p );
|
|
num_classes2 = OTL_NEXT_USHORT( p );
|
|
|
|
len_value1 = otl_value_length( value1 );
|
|
len_value2 = otl_value_length( value2 );
|
|
|
|
otl_coverage_validate( table + coverage, valid );
|
|
otl_class_definition_validate( table + class1, valid );
|
|
otl_class_definition_validate( table + class2, valid );
|
|
|
|
OTL_CHECK( num_classes1 * num_classes2 *
|
|
( len_value1 + len_value2 ) );
|
|
|
|
for ( ; num_classes1 > 0; num_classes1-- )
|
|
{
|
|
for ( count = num_classes2; count > 0; count-- )
|
|
{
|
|
otl_value_validate( p, table, value1, valid );
|
|
p += len_value1;
|
|
|
|
otl_value_validate( p, table, value2, valid );
|
|
p += len_value2;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
OTL_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
/***** *****/
|
|
/***** GPOS LOOKUP TYPE 3 *****/
|
|
/***** *****/
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
static void
|
|
otl_gpos_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_UNUSED( glyph_count );
|
|
|
|
|
|
OTL_CHECK( 2 );
|
|
format = OTL_NEXT_USHORT( p );
|
|
switch ( format )
|
|
{
|
|
case 1:
|
|
{
|
|
OTL_UInt coverage, num_entryexit, anchor1, anchor2;
|
|
|
|
|
|
OTL_CHECK( 4 );
|
|
coverage = OTL_NEXT_USHORT( p );
|
|
num_entryexit = OTL_NEXT_USHORT( p );
|
|
|
|
otl_coverage_validate( table + coverage, valid );
|
|
|
|
OTL_CHECK( num_entryexit * 4 );
|
|
|
|
/* scan entry-exit records */
|
|
for ( ; num_entryexit > 0; num_entryexit-- )
|
|
{
|
|
anchor1 = OTL_NEXT_USHORT( p );
|
|
anchor2 = OTL_NEXT_USHORT( p );
|
|
|
|
if ( anchor1 )
|
|
otl_anchor_validate( table + anchor1, valid );
|
|
|
|
if ( anchor2 )
|
|
otl_anchor_validate( table + anchor2, valid );
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
OTL_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
/***** *****/
|
|
/***** GPOS LOOKUP TYPE 4 *****/
|
|
/***** *****/
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
static void
|
|
otl_base_array_validate( OTL_Bytes table,
|
|
OTL_UInt class_count,
|
|
OTL_Validator valid )
|
|
{
|
|
OTL_Bytes p = table;
|
|
OTL_UInt num_bases, count;
|
|
|
|
|
|
OTL_CHECK( 2 );
|
|
num_bases = OTL_NEXT_USHORT( p );
|
|
|
|
OTL_CHECK( num_bases * class_count * 2 );
|
|
|
|
/* scan base array records */
|
|
for ( ; num_bases > 0; num_bases-- )
|
|
/* scan base records */
|
|
for ( count = class_count; count > 0; count-- )
|
|
otl_anchor_validate( table + OTL_NEXT_USHORT( p ), valid );
|
|
}
|
|
|
|
|
|
static void
|
|
otl_gpos_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_UNUSED( glyph_count );
|
|
|
|
|
|
OTL_CHECK( 2 );
|
|
format = OTL_NEXT_USHORT( p );
|
|
switch ( format )
|
|
{
|
|
case 1:
|
|
{
|
|
OTL_UInt mark_coverage, base_coverage, num_classes;
|
|
OTL_UInt mark_array, base_array;
|
|
|
|
|
|
OTL_CHECK( 10 );
|
|
mark_coverage = OTL_NEXT_USHORT( p );
|
|
base_coverage = OTL_NEXT_USHORT( p );
|
|
num_classes = OTL_NEXT_USHORT( p );
|
|
mark_array = OTL_NEXT_USHORT( p );
|
|
base_array = OTL_NEXT_USHORT( p );
|
|
|
|
otl_coverage_validate( table + mark_coverage, valid );
|
|
otl_coverage_validate( table + base_coverage, valid );
|
|
|
|
otl_mark_array_validate( table + mark_array, valid );
|
|
otl_base_array_validate( table + base_array, num_classes, valid );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
OTL_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
/***** *****/
|
|
/***** GPOS LOOKUP TYPE 5 *****/
|
|
/***** *****/
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
/* used by lookup type 5 and 6 */
|
|
static void
|
|
otl_liga_mark2_validate( OTL_Bytes table,
|
|
OTL_UInt class_count,
|
|
OTL_Bool maybe_zero,
|
|
OTL_Validator valid )
|
|
{
|
|
OTL_Bytes p = table;
|
|
OTL_UInt num_components, count;
|
|
|
|
|
|
OTL_CHECK( 2 );
|
|
num_components = OTL_NEXT_USHORT( p );
|
|
|
|
OTL_CHECK( num_components * class_count * 2 );
|
|
|
|
/* scan component records */
|
|
for ( ; num_components > 0; num_components-- )
|
|
/* scan ligature anchor records */
|
|
for ( count = class_count; count > 0; count-- )
|
|
{
|
|
OTL_UInt offset = OTL_NEXT_USHORT( p );
|
|
|
|
|
|
if ( !offset && maybe_zero )
|
|
continue;
|
|
|
|
otl_anchor_validate( table + offset, valid );
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
otl_liga_array_validate( OTL_Bytes table,
|
|
OTL_UInt class_count,
|
|
OTL_Validator valid )
|
|
{
|
|
OTL_Bytes p = table;
|
|
OTL_UInt ligature_count;
|
|
|
|
|
|
OTL_CHECK( 2 );
|
|
ligature_count = OTL_NEXT_USHORT( p );
|
|
|
|
OTL_CHECK( ligature_count * 2 );
|
|
|
|
/* scan ligature attach records */
|
|
for ( ; ligature_count > 0; ligature_count-- )
|
|
otl_liga_mark2_validate( table + OTL_NEXT_USHORT( p ), class_count, 1,
|
|
valid );
|
|
}
|
|
|
|
|
|
static void
|
|
otl_gpos_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( lookup_count );
|
|
OTL_UNUSED( glyph_count );
|
|
|
|
|
|
OTL_CHECK( 2 );
|
|
format = OTL_NEXT_USHORT( p );
|
|
switch ( format )
|
|
{
|
|
case 1:
|
|
{
|
|
OTL_UInt mark_coverage, liga_coverage, num_classes;
|
|
OTL_UInt mark_array, liga_array;
|
|
|
|
|
|
OTL_CHECK( 10 );
|
|
mark_coverage = OTL_NEXT_USHORT( p );
|
|
liga_coverage = OTL_NEXT_USHORT( p );
|
|
num_classes = OTL_NEXT_USHORT( p );
|
|
mark_array = OTL_NEXT_USHORT( p );
|
|
liga_array = OTL_NEXT_USHORT( p );
|
|
|
|
otl_coverage_validate( table + mark_coverage, valid );
|
|
otl_coverage_validate( table + liga_coverage, valid );
|
|
|
|
otl_mark_array_validate( table + mark_array, valid );
|
|
otl_liga_array_validate( table + liga_array, num_classes, valid );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
OTL_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
/***** *****/
|
|
/***** GPOS LOOKUP TYPE 6 *****/
|
|
/***** *****/
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
static void
|
|
otl_gpos_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( lookup_count );
|
|
OTL_UNUSED( glyph_count );
|
|
|
|
|
|
OTL_CHECK( 2 );
|
|
format = OTL_NEXT_USHORT( p );
|
|
switch ( format )
|
|
{
|
|
case 1:
|
|
{
|
|
OTL_UInt coverage1, coverage2, num_classes, array1, array2;
|
|
|
|
|
|
OTL_CHECK( 10 );
|
|
coverage1 = OTL_NEXT_USHORT( p );
|
|
coverage2 = OTL_NEXT_USHORT( p );
|
|
num_classes = OTL_NEXT_USHORT( p );
|
|
array1 = OTL_NEXT_USHORT( p );
|
|
array2 = OTL_NEXT_USHORT( p );
|
|
|
|
otl_coverage_validate( table + coverage1, valid );
|
|
otl_coverage_validate( table + coverage2, valid );
|
|
|
|
otl_mark_array_validate( table + array1, valid );
|
|
otl_liga_mark2_validate( table + array2, num_classes, 0, valid );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
OTL_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
/***** *****/
|
|
/***** GPOS LOOKUP TYPE 7 *****/
|
|
/***** *****/
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
/* used for both format 1 and 2 */
|
|
static void
|
|
otl_pos_rule_validate( OTL_Bytes table,
|
|
OTL_UInt lookup_count,
|
|
OTL_Validator valid )
|
|
{
|
|
OTL_Bytes p = table;
|
|
OTL_UInt num_glyphs, num_pos;
|
|
|
|
|
|
OTL_CHECK( 4 );
|
|
num_glyphs = OTL_NEXT_USHORT( p );
|
|
num_pos = OTL_NEXT_USHORT( p );
|
|
|
|
if ( num_glyphs == 0 )
|
|
OTL_INVALID_DATA;
|
|
|
|
OTL_CHECK( ( num_glyphs - 1 ) * 2 + num_pos * 4 );
|
|
|
|
for ( ; num_pos > 0; num_pos-- )
|
|
{
|
|
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_pos_rule_set_validate( OTL_Bytes table,
|
|
OTL_UInt lookup_count,
|
|
OTL_Validator valid )
|
|
{
|
|
OTL_Bytes p = table;
|
|
OTL_UInt num_posrules;
|
|
|
|
|
|
OTL_CHECK( 2 );
|
|
num_posrules = OTL_NEXT_USHORT( p );
|
|
|
|
OTL_CHECK( num_posrules * 2 );
|
|
|
|
/* scan posrule records */
|
|
for ( ; num_posrules > 0; num_posrules-- )
|
|
otl_pos_rule_validate( table + OTL_NEXT_USHORT( p ), lookup_count,
|
|
valid );
|
|
}
|
|
|
|
|
|
static void
|
|
otl_gpos_lookup7_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_posrule_sets;
|
|
|
|
|
|
OTL_CHECK( 4 );
|
|
coverage = OTL_NEXT_USHORT( p );
|
|
num_posrule_sets = OTL_NEXT_USHORT( p );
|
|
|
|
otl_coverage_validate( table + coverage, valid );
|
|
|
|
OTL_CHECK( num_posrule_sets * 2 );
|
|
|
|
/* scan posrule set records */
|
|
for ( ; num_posrule_sets > 0; num_posrule_sets-- )
|
|
otl_pos_rule_set_validate( table + OTL_NEXT_USHORT( p ),
|
|
lookup_count, valid );
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
{
|
|
OTL_UInt coverage, class_def, num_posclass_sets;
|
|
|
|
|
|
OTL_CHECK( 6 );
|
|
coverage = OTL_NEXT_USHORT( p );
|
|
class_def = OTL_NEXT_USHORT( p );
|
|
num_posclass_sets = OTL_NEXT_USHORT( p );
|
|
|
|
otl_coverage_validate( table + coverage, valid );
|
|
otl_class_definition_validate( table + class_def, valid );
|
|
|
|
OTL_CHECK( num_posclass_sets * 2 );
|
|
|
|
/* scan pos class set rules */
|
|
for ( ; num_posclass_sets > 0; num_posclass_sets-- )
|
|
{
|
|
OTL_UInt offset = OTL_NEXT_USHORT( p );
|
|
|
|
|
|
if ( offset )
|
|
otl_pos_rule_set_validate( table + offset, lookup_count, valid );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
{
|
|
OTL_UInt num_glyphs, num_pos, count;
|
|
|
|
|
|
OTL_CHECK( 4 );
|
|
num_glyphs = OTL_NEXT_USHORT( p );
|
|
num_pos = OTL_NEXT_USHORT( p );
|
|
|
|
OTL_CHECK( num_glyphs * 2 + num_pos * 4 );
|
|
|
|
for ( count = num_glyphs; count > 0; count-- )
|
|
otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
|
|
|
|
for ( ; num_pos > 0; num_pos-- )
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
/***** *****/
|
|
/***** GPOS LOOKUP TYPE 8 *****/
|
|
/***** *****/
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
/* used for both format 1 and 2 */
|
|
static void
|
|
otl_chain_pos_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_pos;
|
|
|
|
|
|
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_pos = OTL_NEXT_USHORT( p );
|
|
OTL_CHECK( num_pos * 4 );
|
|
|
|
for ( ; num_pos > 0; num_pos-- )
|
|
{
|
|
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_pos_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 pos rule records */
|
|
for ( ; num_chain_subrules > 0; num_chain_subrules-- )
|
|
otl_chain_pos_rule_validate( table + OTL_NEXT_USHORT( p ),
|
|
lookup_count, valid );
|
|
}
|
|
|
|
|
|
static void
|
|
otl_gpos_lookup8_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_pos_rulesets;
|
|
|
|
|
|
OTL_CHECK( 4 );
|
|
coverage = OTL_NEXT_USHORT( p );
|
|
num_chain_pos_rulesets = OTL_NEXT_USHORT( p );
|
|
|
|
otl_coverage_validate( table + coverage, valid );
|
|
|
|
OTL_CHECK( num_chain_pos_rulesets * 2 );
|
|
|
|
/* scan chain pos ruleset records */
|
|
for ( ; num_chain_pos_rulesets > 0; num_chain_pos_rulesets-- )
|
|
otl_chain_pos_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_chainpos_class_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_chainpos_class_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_chainpos_class_sets * 2 );
|
|
|
|
/* scan chainpos class set records */
|
|
for ( ; num_chainpos_class_sets > 0; num_chainpos_class_sets-- )
|
|
{
|
|
OTL_UInt offset = OTL_NEXT_USHORT( p );
|
|
|
|
|
|
if ( offset )
|
|
otl_chain_pos_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_pos, 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_pos = OTL_NEXT_USHORT( p );
|
|
OTL_CHECK( num_pos * 4 );
|
|
|
|
for ( ; num_pos > 0; num_pos-- )
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
/***** *****/
|
|
/***** GPOS LOOKUP TYPE 9 *****/
|
|
/***** *****/
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
static void
|
|
otl_gpos_lookup9_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 >= 9 )
|
|
OTL_INVALID_DATA;
|
|
|
|
validate = otl_gpos_validate_funcs[lookup_type - 1];
|
|
validate( table + lookup_offset, lookup_count, glyph_count, valid );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
OTL_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
|
|
static OTL_ValidateFunc otl_gpos_validate_funcs[9] =
|
|
{
|
|
otl_gpos_lookup1_validate,
|
|
otl_gpos_lookup2_validate,
|
|
otl_gpos_lookup3_validate,
|
|
otl_gpos_lookup4_validate,
|
|
otl_gpos_lookup5_validate,
|
|
otl_gpos_lookup6_validate,
|
|
otl_gpos_lookup7_validate,
|
|
otl_gpos_lookup8_validate,
|
|
otl_gpos_lookup9_validate
|
|
};
|
|
|
|
|
|
OTL_LOCALDEF( void )
|
|
otl_gpos_subtable_validate( OTL_Bytes table,
|
|
OTL_UInt lookup_count,
|
|
OTL_UInt glyph_count,
|
|
OTL_Validator valid )
|
|
{
|
|
otl_lookup_validate( table, 9, otl_gpos_validate_funcs,
|
|
lookup_count, glyph_count, valid );
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
/***** *****/
|
|
/***** GPOS TABLE *****/
|
|
/***** *****/
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
OTL_LOCALDEF( void )
|
|
otl_gpos_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, 9, otl_gpos_validate_funcs,
|
|
glyph_count, valid );
|
|
otl_feature_list_validate( table + features, table + lookups, valid );
|
|
otl_script_list_validate( table + scripts, table + features, valid );
|
|
}
|
|
|
|
|
|
/* END */
|