ref: 2282f341d6aae03f4c8d09a0922a7ba6f25e7643
dir: /src/otlayout/otlcommn.c/
#include "otlayout.h" /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** COVERAGE TABLE *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ OTL_LOCALDEF( void ) otl_coverage_validate( OTL_Bytes table, OTL_Validator valid ) { OTL_Bytes p; OTL_UInt format; if ( table + 4 > valid->limit ) OTL_INVALID_TOO_SHORT; format = OTL_NEXT_UShort(p); switch (format) { case 1: { OTL_UInt count = OTL_NEXT_UShort(p); if ( p + count*2 >= valid->limit ) OTL_INVALID_TOO_SHORT; /* XXX: check glyph indices */ } break; case 2: { OTL_UInt n, num_ranges = OTL_NEXT_UShort(p); OTL_UInt start, end, start_cover, total = 0, last = 0; if ( p + num_ranges*6 >= valid->limit ) OTL_INVALID_TOO_SHORT; for ( n = 0; n < num_ranges; n++ ) { start = OTL_NEXT_UShort(p); end = OTL_NEXT_UShort(p); start_cover = OTL_NEXT_UShort(p); if ( start > end || start_cover != total ) OTL_INVALID_DATA; if ( n > 0 && start <= last ) OTL_INVALID_DATA; total += (end - start + 1); last = end; } } break; default: OTL_INVALID_FORMAT; } } OTL_LOCALDEF( OTL_UInt ) otl_coverage_get_count( OTL_Bytes table ) { OTL_Bytes p = table; OTL_UInt format = OTL_NEXT_UShort(p); OTL_UInt count = OTL_NEXT_UShort(p); OTL_UInt result = 0; switch ( format ) { case 1: return count; case 2: { OTL_UInt start, end; for ( ; count > 0; count-- ) { start = OTL_NEXT_UShort(p); end = OTL_NEXT_UShort(p); p += 2; /* skip start_index */ result += ( end - start + 1 ); } } break; default: ; } return result; } OTL_LOCALDEF( OTL_Int ) otl_coverage_get_index( OTL_Bytes table, OTL_UInt glyph_index ) { OTL_Bytes p = table; OTL_UInt format = OTL_NEXT_UShort(p); OTL_UInt count = OTL_NEXT_UShort(p); switch ( format ) { case 1: { OTL_UInt min = 0, max = count, mid, gindex; table += 4; while ( min < max ) { mid = ( min + max ) >> 1; p = table + 2*mid; gindex = OTL_PEEK_UShort(p); if ( glyph_index == gindex ) return (OTL_Int)mid; if ( glyph_index < gindex ) max = mid; else min = mid + 1; } } break; case 2: { OTL_UInt min = 0, max = count, mid; OTL_UInt start, end, delta, start_cover; table += 4; while ( min < max ) { mid = ( min + max ) >> 1; p = table + 6*mid; start = OTL_NEXT_UShort(p); end = OTL_NEXT_UShort(p); if ( glyph_index < start ) max = mid; else if ( glyph_index > end ) min = mid + 1; else return (OTL_Int)( glyph_index + OTL_NEXT_UShort(p) - start ); } } break; default: ; } return -1; } /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** CLASS DEFINITION TABLE *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ OTL_LOCALDEF( void ) otl_class_definition_validate( OTL_Bytes table, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; if ( p + 4 > valid->limit ) OTL_INVALID_TOO_SHORT; format = OTL_NEXT_UShort(p); switch ( format ) { case 1: { OTL_UInt count, start = OTL_NEXT_UShort(p); if ( p + 2 > valid->limit ) OTL_INVALID_TOO_SHORT; count = OTL_NEXT_UShort(p); if ( p + count*2 > valid->limit ) OTL_INVALID_TOO_SHORT; /* XXX: check glyph indices */ } break; case 2: { OTL_UInt n, num_ranges = OTL_NEXT_UShort(p); OTL_UInt start, end, value, last = 0; if ( p + num_ranges*6 > valid->limit ) OTL_INVALID_TOO_SHORT; for ( n = 0; n < num_ranges; n++ ) { start = OTL_NEXT_UShort(p); end = OTL_NEXT_UShort(p); value = OTL_NEXT_UShort(p); /* ignored */ if ( start > end || ( n > 0 && start <= last ) ) OTL_INVALID_DATA; last = end; } } break; default: OTL_INVALID_FORMAT; } } OTL_LOCALDEF( OTL_UInt ) otl_class_definition_get_value( OTL_Bytes table, OTL_UInt glyph_index ) { OTL_Bytes p = table; OTL_UInt format = OTL_NEXT_UShort(p); switch ( format ) { case 1: { OTL_UInt start = OTL_NEXT_UShort(p); OTL_UInt count = OTL_NEXT_UShort(p); OTL_UInt index = (OTL_UInt)( glyph_index - start ); if ( index < count ) { p += 2*index; return OTL_PEEK_UShort(p); } } break; case 2: { OTL_UInt count = OTL_NEXT_UShort(p); OTL_UInt min = 0, max = count, mid, gindex; table += 4; while ( min < max ) { mid = ( min + max ) >> 1; p = table + 6*mid; start = OTL_NEXT_UShort(p); end = OTL_NEXT_UShort(p); if ( glyph_index < start ) max = mid; else if ( glyph_index > end ) min = mid+1; else return OTL_PEEK_UShort(p); } } break; default: ; } return 0; } /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** DEVICE TABLE *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ OTL_LOCALDEF( void ) otl_device_table_validate( OTL_Bytes table, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt start, end, count, format, count; if ( p + 8 > valid->limit ) OTL_INVALID_TOO_SHORT; start = OTL_NEXT_UShort(p); end = OTL_NEXT_UShort(p); format = OTL_NEXT_UShort(p); if ( format < 1 || format > 3 || end < start ) OTL_INVALID_DATA; count = (OTL_UInt)( end - start + 1 ); if ( p + ((1 << format)*count)/8> valid->limit ) OTL_INVALID_TOO_SHORT; } OTL_LOCALDEF( OTL_UInt ) otl_device_table_get_start( OTL_Bytes table ) { OTL_Bytes p = table; return OTL_PEEK_UShort(p); } OTL_LOCALDEF( OTL_UInt ) otl_device_table_get_end( OTL_Bytes table ) { OTL_Bytes p = table + 2; return OTL_PEEK_UShort(p); } OTL_LOCALDEF( OTL_Int ) otl_device_table_get_delta( OTL_Bytes table, OTL_UInt size ) { OTL_Bytes p = table; OTL_Int result = 0; OTL_UInt start, end, format, index, value; start = OTL_NEXT_UShort(p); end = OTL_NEXT_UShort(p); format = OTL_NEXT_UShort(p); if ( size >= start && size <= end ) { /* we could do that with clever bit operations, but a switch is simply */ /* much simpler to understand and maintain !! */ /* */ switch ( format ) { case 1: { index = (OTL_UInt)(( size - start )*2); p += (index/16); value = OTL_PEEK_UShort(p); shift = index & 15; result = (OTL_Short)(value << shift) >> (14-shift); } break; case 2: { index = (OTL_UInt)(( size - start )*4); p += (index/16); value = OTL_PEEK_UShort(p); shift = index & 15; result = (OTL_Short)(value << shift) >> (12-shift); } break; case 3: { index = (OTL_UInt)(( size - start )*8); p += (index/16); value = OTL_PEEK_UShort(p); shift = index & 15; result = (OTL_Short)(value << shift) >> (8-shift); } break; default: ; } } return result; } /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** LOOKUP LISTS *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ OTL_LOCALDEF( void ) otl_lookup_validate( OTL_Bytes table, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt num_tables; if ( table + 6 > valid->limit ) OTL_INVALID_TOO_SHORT; p += 4; num_tables = OTL_NEXT_UShort(p); if ( p + num_tables*2 > valid->limit ) OTL_INVALID_TOO_SHORT; for ( ; num_tables > 0; num_tables-- ) { offset = OTL_NEXT_UShort(p); if ( table + offset >= valid->limit ) OTL_INVALID_OFFSET; } /* XXX: check sub-tables ?? */ } OTL_LOCALDEF( OTL_UInt ) otl_lookup_get_count( OTL_Bytes table ) { OTL_Bytes p = table + 4; return OTL_PEEK_UShort(p); } OTL_LOCALDEF( OTL_Bytes ) otl_lookup_get_table( OTL_Bytes table, OTL_UInt index ) { OTL_Bytes p, result = NULL; OTL_UInt count; p = table + 4; count = OTL_NEXT_UShort(p); if ( index < count ) { p += index*2; result = table + OTL_PEEK_UShort(p); } return result; } /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** LOOKUP LISTS *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ OTL_LOCALDEF( void ) otl_lookup_list_validate( OTL_Bytes table, OTL_Validator valid ) { OTL_Bytes p = table, q; OTL_UInt num_lookups, offset; if ( p + 2 > valid->limit ) OTL_INVALID_TOO_SHORT; num_lookups = OTL_NEXT_UShort(p); if ( p + num_lookups*2 > valid->limit ) OTL_INVALID_TOO_SHORT; for ( ; num_lookups > 0; num_lookups-- ) { offset = OTL_NEXT_UShort(p); otl_lookup_validate( table + offset, valid ); } } OTL_LOCALDEF( OTL_UInt ) otl_lookup_list_get_count( OTL_Bytes table ) { OTL_Bytes p = table; return OTL_PEEK_UShort(p); } OTL_LOCALDEF( OTL_Bytes ) otl_lookup_list_get_lookup( OTL_Bytes table, OTL_UInt index ) { OTL_Bytes p, result = 0; OTL_UInt count; p = table; count = OTL_NEXT_UShort(p); if ( index < count ) { p += index*2; result = table + OTL_PEEK_UShort(p); } return result; } OTL_LOCALDEF( OTL_Bytes ) otl_lookup_list_get_table( OTL_Bytes table, OTL_UInt lookup_index, OTL_UInt table_index ) { OTL_Bytes result = NULL; result = otl_lookup_list_get_lookup( table, lookup_index ); if ( result ) result = otl_lookup_get_table( result, table_index ); return result; } OTL_LOCALDEF( void ) otl_lookup_list_foreach( OTL_Bytes table, OTL_ForeachFunc func, OTL_Pointer func_data ) { OTL_Bytes p = table; OTL_UInt count = OTL_NEXT_UShort(p); for ( ; count > 0; count-- ) func( table + OTL_NEXT_USHORT(p), func_data ); } /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** FEATURES *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ OTL_LOCALDEF( void ) otl_feature_validate( OTL_Bytes table, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt feat_params, num_lookups; if ( p + 4 > valid->limit ) OTL_INVALID_TOO_SHORT; feat_params = OTL_NEXT_UShort(p); /* ignored */ num_lookups = OTL_NEXT_UShort(p); if ( p + num_lookups*2 > valid->limit ) OTL_INVALID_TOO_SHORT; /* XXX: check lookup indices */ } OTL_LOCALDEF( OTL_UInt ) otl_feature_get_count( OTL_Bytes table ) { OTL_Bytes p = table + 4; return OTL_PEEK_UShort(p); } OTL_LOCALDEF( OTL_UInt ) otl_feature_get_lookups( OTL_Bytes table, OTL_UInt start, OTL_UInt count, OTL_UInt *lookups ) { OTL_Bytes p; OTL_UInt num_features, result = 0; p = table + 4; num_features = OTL_NEXT_UShort(p); p += start*2; for ( ; count > 0 && start < num_features; count--, start++ ) { lookups[0] = OTL_NEXT_UShort(p); lookups++; result++; } return result; } /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** FEATURE LIST *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ OTL_LOCALDEF( void ) otl_feature_list_validate( OTL_Bytes table, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt num_features, offset; if ( table + 2 > valid->limit ) OTL_INVALID_TOO_SHORT; num_features = OTL_NEXT_UShort(p); if ( p + num_features*2 > valid->limit ) OTL_INVALID_TOO_SHORT; for ( ; num_features > 0; num_features-- ) { p += 4; /* skip tag */ offset = OTL_NEXT_UShort(p); otl_feature_table_validate( table + offset, valid ); } } OTL_LOCALDEF( OTL_UInt ) otl_feature_list_get_count( OTL_Bytes table ) { OTL_Bytes p = table; return OTL_PEEK_UShort(p); } OTL_LOCALDEF( OTL_Bytes ) otl_feature_list_get_feature( OTL_Bytes table, OTL_UInt index ) { OTL_Bytes p, result = NULL; OTL_UInt count; p = table; count = OTL_NEXT_UShort(p); if ( index < count ) { p += index*2; result = table + OTL_PEEK_UShort(p); } return result; } OTL_LOCALDEF( void ) otl_feature_list_foreach( OTL_Bytes table, OTL_ForeachFunc func, OTL_Pointer func_data ) { OTL_Bytes p; OTL_UInt count; p = table; count = OTL_NEXT_UShort(p); for ( ; count > 0; count-- ) func( table + OTL_NEXT_UShort(p), func_data ); } /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ OTL_LOCALDEF( void ) otl_lang_validate( OTL_Bytes table, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt lookup_order; OTL_UInt req_feature; OTL_UInt num_features; if ( table + 6 >= valid->limit ) OTL_INVALID_TOO_SHORT; lookup_order = OTL_NEXT_UShort(p); req_feature = OTL_NEXT_UShort(p); num_features = OTL_NEXT_UShort(p); /* XXX: check req_feature if not 0xFFFFU */ if ( p + 2*num_features >= valid->limit ) OTL_INVALID_TOO_SHORT; /* XXX: check features indices !! */ } OTL_LOCALDEF( OTL_UInt ) otl_lang_get_count( OTL_Bytes table ) { OTL_Bytes p = table + 4; return OTL_PEEK_UShort(p); } OTL_LOCALDEF( OTL_UInt ) otl_lang_get_features( OTL_Bytes table, OTL_UInt start, OTL_UInt count, OTL_UInt *features ) { OTL_Bytes p = table + 4; OTL_UInt num_features = OTL_NEXT_UShort(p); OTL_UInt result = 0; p += start*2; for ( ; count > 0 && start < num_features; start++, count-- ) { features[0] = OTL_NEXT_UShort(p); features++; result++; } return result; } OTL_LOCALDEF( OTL_UInt ) otl_lang_get_req_feature( OTL_Bytes table ) { OTL_Bytes p = table + 2; return OTL_PEEK_UShort(p); } /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ OTL_LOCALDEF( void ) otl_script_table_validate( OTL_Bytes table, OTL_Validator valid ) { OTL_UInt default_lang; OTL_Bytes p = table; if ( table + 4 > valid->limit ) OTL_INVALID_TOO_SHORT; default_lang = OTL_NEXT_UShort(p); num_langs = OTL_NEXT_UShort(p); if ( default_lang != 0 ) { if ( table + default_lang >= valid->limit ) OTL_INVALID_OFFSET; } if ( p + num_langs*6 >= valid->limit ) OTL_INVALID_OFFSET; for ( ; num_langs > 0; num_langs-- ) { OTL_UInt offset; p += 4; /* skip tag */ offset = OTL_NEXT_UShort(p); otl_lang_validate( table + offset, valid ); } } OTL_LOCALDEF( void ) otl_script_list_validate( OTL_Bytes list, OTL_Validator valid ) { OTL_UInt num_scripts; OTL_Bytes p = list; if ( list + 2 > valid->limit ) OTL_INVALID_TOO_SHORT; num_scripts = OTL_NEXT_UShort(p); if ( p + num_scripts*6 > valid->limit ) OTL_INVALID_TOO_SHORT; for ( ; num_scripts > 0; num_scripts-- ) { OTL_UInt offset; p += 4; /* skip tag */ offset = OTL_NEXT_UShort(p); otl_script_table_validate( list + offset, valid ); } }