adding several experimental sources:

- OpenType Layout validation and parsing (common tables)
  - Type 1 charmap processing
This commit is contained in:
David Turner 2002-02-27 21:25:47 +00:00
parent 53b3fa1da5
commit 617a2e1c3c
7 changed files with 2017 additions and 231 deletions

View File

@ -74,6 +74,159 @@ FT_BEGIN_HEADER
#endif #endif
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/**** ****/
/**** ****/
/**** V A L I D A T I O N ****/
/**** ****/
/**** ****/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/* handle to a validation object */
typedef struct FT_ValidatorRec_* FT_Validator;
/**************************************************************************
*
* there are three distinct validation levels defined here:
*
* FT_VALIDATE_DEFAULT ::
* a table that passes this validation level can be used reliably by
* FreeType. It generally means that all offsets have been checked to
* prevent out-of-bound reads, array counts are correct, etc..
*
*
* FT_VALIDATE_TIGHT ::
* a table that passes this validation level can be used reliably and
* doesn't contain invalid data. For example, a charmap table that
* returns invalid glyph indices will not pass, even though it can
* be used with FreeType in default mode (the library will simply
* return an error later when trying to load the glyph)
*
* it also check that fields that must be a multiple of 2, 4 or 8 don't
* have incorrect values, etc..
*
*
* FT_VALIDATE_PARANOID ::
* only for font facists. Checks that a table follows the specification
* 100%. Very few fonts will be able to pass this level anyway but it
* can be useful for certain tools like font editors/converters..
*/
typedef enum FT_ValidationLevel_
{
FT_VALIDATE_DEFAULT = 0,
FT_VALIDATE_TIGHT,
FT_VALIDATE_PARANOID
} FT_ValidationLevel;
/* validator structure */
typedef struct FT_ValidatorRec_
{
FT_Byte* base; /* address of table in memory */
FT_Byte* limit; /* 'base' + sizeof(table) in memory */
FT_ValidationLevel level; /* validation level */
FT_Error error; /* error returned. 0 means success */
jmp_buf jump_buffer; /* used for exception handling */
} FT_ValidatorRec;
/* sets the error field in a validator, then calls 'longjmp' to return */
/* to high-level caller. Using 'setjmp/longjmp' avoids many stupid */
/* error checks within the validation routines.. */
/* */
FT_BASE( void )
ft_validate_error( FT_Valid valid,
FT_Error error );
/* calls ft_validate_error. Assumes that the 'valid' local variable holds */
/* a pointer to the current validator object.. */
/* */
#define FT_INVALID(_error) ft_validate_error( valid, _error )
/* called when a broken table is detected */
#define FT_INVALID_TOO_SHORT FT_INVALID( FT_Err_Invalid_Format )
/* called when an invalid offset is detected */
#define FT_INVALID_OFFSET FT_INVALID( FT_Err_Invalid_Offset )
/* called when an invalid format/value is detected */
#define FT_INVALID_FORMAT FT_INVALID( FT_Err_Invalid_Format )
/* called when an invalid glyph index is detected */
#define FT_INVALID_GLYPH_ID FT_INVALID( FT_Err_Invalid_Glyph_Id )
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/**** ****/
/**** ****/
/**** C H A R M A P S ****/
/**** ****/
/**** ****/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/* handle to internal charmap object */
typedef struct FT_CMapRec_* FT_CMap;
/* handle to charmap class structure */
typedef const struct FT_CMap_ClassRec_* FT_CMap_Class;
/* internal charmap object structure */
typedef struct FT_CMapRec_
{
FT_CharMapRec charmap;
FT_CMap_Class clazz;
FT_Pointer data;
} FT_CMapRec;
/* typecase any pointer to a charmap handle */
#define FT_CMAP(x) ((FT_CMap)(x))
/* obvious macros */
#define FT_CMAP_PLATFORM_ID(x) FT_CMAP(x)->charmap.platform_id
#define FT_CMAP_ENCODING_ID(x) FT_CMAP(x)->charmap.encoding_id
#define FT_CMAP_ENCODING(x) FT_CMAP(x)->charmap.encoding
#define FT_CMAP_FACE(x) FT_CMAP(x)->charmap.face
/* class method definitions */
typedef FT_Error (*FT_CMap_InitFunc)( FT_CMap cmap,
FT_Pointer data );
typedef void (*FT_CMap_DoneFunc)( FT_CMap cmap );
typedef FT_Error (*FT_CMap_ValidateFunc)( FT_Pointer cmap_data,
FT_Validator valid );
typedef FT_UInt (*FT_CMap_CharIndexFunc)( FT_Pointer cmap_data,
FT_ULong char_code );
typedef FT_UInt (*FT_CMap_CharNextFunc)( FT_Pointer cmap_data,
FT_ULong *achar_code );
typedef struct FT_CMap_ClassRec_
{
FT_UInt size;
FT_CMap_InitFunc init;
FT_CMap_DoneFunc done;
FT_CMap_ValidateFunc validate;
FT_CMap_CharIndexFunc char_index;
FT_CMap_CharNextFunc char_next;
} FT_CMap_ClassRec;
/*************************************************************************/ /*************************************************************************/
/* */ /* */
/* <Struct> */ /* <Struct> */
@ -330,109 +483,6 @@ FT_BEGIN_HEADER
FT_Done_GlyphSlot( FT_GlyphSlot slot ); FT_Done_GlyphSlot( FT_GlyphSlot slot );
#if 0
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/**** ****/
/**** ****/
/**** G L Y P H L O A D E R ****/
/**** ****/
/**** ****/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
#define FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS 1
#define FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES 2
#define FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID 4
#define FT_SUBGLYPH_FLAG_SCALE 8
#define FT_SUBGLYPH_FLAG_XY_SCALE 0x40
#define FT_SUBGLYPH_FLAG_2X2 0x80
#define FT_SUBGLYPH_FLAG_USE_MY_METRICS 0x200
enum
{
FT_GLYPH_OWN_BITMAP = 1
};
struct FT_SubGlyph_
{
FT_Int index;
FT_UShort flags;
FT_Int arg1;
FT_Int arg2;
FT_Matrix transform;
};
typedef struct FT_GlyphLoad_
{
FT_Outline outline; /* outline */
FT_UInt num_subglyphs; /* number of subglyphs */
FT_SubGlyph* subglyphs; /* subglyphs */
FT_Vector* extra_points; /* extra points table */
} FT_GlyphLoad;
struct FT_GlyphLoader_
{
FT_Memory memory;
FT_UInt max_points;
FT_UInt max_contours;
FT_UInt max_subglyphs;
FT_Bool use_extra;
FT_GlyphLoad base;
FT_GlyphLoad current;
void* other; /* for possible future extension? */
};
FT_BASE( FT_Error )
FT_GlyphLoader_New( FT_Memory memory,
FT_GlyphLoader* *aloader );
FT_BASE( FT_Error )
FT_GlyphLoader_Create_Extra( FT_GlyphLoader* loader );
FT_BASE( void )
FT_GlyphLoader_Done( FT_GlyphLoader* loader );
FT_BASE( void )
FT_GlyphLoader_Reset( FT_GlyphLoader* loader );
FT_BASE( void )
FT_GlyphLoader_Rewind( FT_GlyphLoader* loader );
FT_BASE( FT_Error )
FT_GlyphLoader_Check_Points( FT_GlyphLoader* loader,
FT_UInt n_points,
FT_UInt n_contours );
FT_BASE( FT_Error )
FT_GlyphLoader_Check_Subglyphs( FT_GlyphLoader* loader,
FT_UInt n_subs );
FT_BASE( void )
FT_GlyphLoader_Prepare( FT_GlyphLoader* loader );
FT_BASE( void )
FT_GlyphLoader_Add( FT_GlyphLoader* loader );
FT_BASE( FT_Error )
FT_GlyphLoader_Copy_Points( FT_GlyphLoader* target,
FT_GlyphLoader* source );
#endif
/*************************************************************************/ /*************************************************************************/
/*************************************************************************/ /*************************************************************************/
/*************************************************************************/ /*************************************************************************/

820
src/otlayout/otlcommn.c Normal file
View File

@ -0,0 +1,820 @@
#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 );
}
}

211
src/otlayout/otlcommn.h Normal file
View File

@ -0,0 +1,211 @@
/***************************************************************************
*
* otlcommn.h
*
* OpenType Layout common tables processing
*
* this header provides several routines used to process common table
* found in various OpenType Layout tables..
*/
#ifndef __OTLAYOUT_COMMON_H__
#define __OTLAYOUT_COMMON_H__
#include "otlayout.h"
OTL_BEGIN_HEADER
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** COVERAGE TABLE *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/* validate coverage table */
OTL_LOCALDEF( void )
otl_coverage_validate( OTL_Bytes base,
OTL_Validator valid );
/* return number of covered glyphs */
OTL_LOCALDEF( OTL_UInt )
otl_coverage_get_count( OTL_Bytes base );
/* return the coverage index corresponding to a glyph glyph index. */
/* returns -1 if the glyph isn't covered.. */
OTL_LOCALDEF( OTL_Int )
otl_coverage_get_index( OTL_Bytes base,
OTL_UInt glyph_index );
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** CLASS DEFINITION TABLE *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/* validate class definition table */
OTL_LOCALDEF( void )
otl_class_definition_validate( OTL_Bytes table,
OTL_Validator valid );
/* return class value for a given glyph index */
OTL_LOCALDEF( OTL_UInt )
otl_class_definition_get_value( OTL_Bytes table,
OTL_UInt glyph_index );
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** DEVICE TABLE *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/* validate a device table */
OTL_LOCALDEF( void )
otl_device_table_validate( OTL_Bytes table,
OTL_Validator valid );
/* return a device table's first size */
OTL_LOCALDEF( OTL_UInt )
otl_device_table_get_start( OTL_Bytes table );
/* return a device table's last size */
OTL_LOCALDEF( OTL_UInt )
otl_device_table_get_end( OTL_Bytes table );
/* return pixel adjustment for a given size */
OTL_LOCALDEF( OTL_Int )
otl_device_table_get_delta( OTL_Bytes table,
OTL_UInt size );
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** LOOKUPS *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/* validate lookup table */
OTL_LOCALDEF( void )
otl_lookup_validate( OTL_Bytes table,
OTL_Validator valid );
/* return number of sub-tables in a lookup */
OTL_LOCALDEF( OTL_UInt )
otl_lookup_get_count( OTL_Bytes table );
/* return lookup sub-table */
OTL_LOCALDEF( OTL_Bytes )
otl_lookup_get_table( OTL_Bytes table,
OTL_UInt index );
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** LOOKUP LISTS *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/* validate lookup list */
OTL_LOCALDEF( void )
otl_lookup_list_validate( OTL_Bytes table,
OTL_Validator valid );
/* return number of lookups in list */
OTL_LOCALDEF( OTL_UInt )
otl_lookup_list_get_count( OTL_Bytes table );
/* return a given lookup from a list */
OTL_LOCALDEF( OTL_Bytes )
otl_lookup_list_get_lookup( OTL_Bytes table,
OTL_UInt index );
/* return lookup sub-table from a list */
OTL_LOCALDEF( OTL_Bytes )
otl_lookup_list_get_table( OTL_Bytes table,
OTL_UInt lookup_index,
OTL_UInt table_index );
/* iterate over lookup list */
OTL_LOCALDEF( void )
otl_lookup_list_foreach( OTL_Bytes table,
OTL_ForeachFunc func,
OTL_Pointer func_data );
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** FEATURES *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/* validate feature table */
OTL_LOCALDEF( void )
otl_feature_validate( OTL_Bytes table,
OTL_Validator valid );
/* return feature's lookup count */
OTL_LOCALDEF( OTL_UInt )
otl_feature_get_count( OTL_Bytes table );
/* get several lookups from a feature. returns the number of lookups grabbed */
OTL_LOCALDEF( OTL_UInt )
otl_feature_get_lookups( OTL_Bytes table,
OTL_UInt start,
OTL_UInt count,
OTL_UInt *lookups );
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** FEATURE LIST *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/* validate a feature list */
OTL_LOCALDEF( void )
otl_feature_list_validate( OTL_Bytes table,
OTL_Validator valid );
/* return number of features in list */
OTL_LOCALDEF( OTL_UInt )
otl_feature_list_get_count( OTL_Bytes table );
/* return a given feature from a list */
OTL_LOCALDEF( OTL_Bytes )
otl_feature_list_get_feature( OTL_Bytes table,
OTL_UInt index );
/* iterate over all features in a list */
OTL_LOCALDEF( void )
otl_feature_list_foreach( OTL_Bytes table,
OTL_ForeachFunc func,
OTL_Pointer func_data );
/* */
OTL_END_HEADER
#endif /* __OTLAYOUT_COMMON_H__ */

View File

@ -301,6 +301,7 @@
(void)LOAD_( max_profile ); (void)LOAD_( max_profile );
(void)LOAD_( charmaps ); (void)LOAD_( charmaps );
/* the following tables are optional in PCL fonts -- */ /* the following tables are optional in PCL fonts -- */
/* don't check for errors */ /* don't check for errors */
(void)LOAD_( names ); (void)LOAD_( names );

View File

@ -34,8 +34,8 @@
#define TT_PEEK_Short FT_PEEK_SHORT #define TT_PEEK_SHORT FT_PEEK_SHORT
#define TT_PEEK_UShort FT_PEEK16_UBE #define TT_PEEK_USHORT FT_PEEK16_UBE
#define TT_PEEK_Long FT_PEEK32_BE #define TT_PEEK_Long FT_PEEK32_BE
#define TT_PEEK_ULong FT_PEEK32_UBE #define TT_PEEK_ULong FT_PEEK32_UBE
@ -72,7 +72,7 @@
tt_cmap0_validate( FT_Byte* table, tt_cmap0_validate( FT_Byte* table,
FT_Validator valid ) FT_Validator valid )
{ {
FT_Byte* p = table + 2; /* skip format */ FT_Byte* p = table + 2;
FT_UInt length = TT_NEXT_USHORT(p); FT_UInt length = TT_NEXT_USHORT(p);
if ( table + length > valid->limit || length < 262 ) if ( table + length > valid->limit || length < 262 )
@ -83,6 +83,7 @@
{ {
FT_UInt n, index; FT_UInt n, index;
p = table + 6;
for ( n = 0; n < 256; n++ ) for ( n = 0; n < 256; n++ )
{ {
index = *p++; index = *p++;
@ -228,7 +229,7 @@
FT_Validator valid ) FT_Validator valid )
{ {
FT_Byte* p = table + 2; /* skip format */ FT_Byte* p = table + 2; /* skip format */
FT_UInt length = PEEK_UShort(p); FT_UInt length = TT_PEEK_USHORT(p);
FT_UInt n, max_subs; FT_UInt n, max_subs;
FT_Byte* keys; /* keys table */ FT_Byte* keys; /* keys table */
FT_Byte* subs; /* sub-headers */ FT_Byte* subs; /* sub-headers */
@ -256,6 +257,8 @@
max_subs = index; max_subs = index;
} }
FT_ASSERT( p == table + 518 );
subs = p; subs = p;
glyph_ids = subs + (max_subs + 1)*8; glyph_ids = subs + (max_subs + 1)*8;
if ( glyph_ids > valid->limit ) if ( glyph_ids > valid->limit )
@ -322,8 +325,8 @@
{ {
FT_UInt char_lo = (FT_UInt)( char_code & 0xFF ); FT_UInt char_lo = (FT_UInt)( char_code & 0xFF );
FT_UInt char_hi = (FT_UInt)( char_code >> 8 ); FT_UInt char_hi = (FT_UInt)( char_code >> 8 );
FT_Byte* p = table + 6; /* keys table */ FT_Byte* p = table + 6; /* keys table */
FT_Byte* subs = p + 512; /* subheaders table */ FT_Byte* subs = table + 518; /* subheaders table */
FT_Byte* sub; FT_Byte* sub;
@ -339,14 +342,14 @@
/* Otherwise, return 0 */ /* Otherwise, return 0 */
/* */ /* */
p += char_lo*2; p += char_lo*2;
if ( PEEK_UShort(p) != 0 ) if ( TT_PEEK_USHORT(p) != 0 )
goto Exit; goto Exit;
} }
else else
{ {
/* a 16-bit character code */ /* a 16-bit character code */
p += char_hi*2; /* jump to key entry */ p += char_hi*2; /* jump to key entry */
sub = subs + PEEK_UShort(p); /* jump to sub-header */ sub = subs + ( TT_PEEK_USHORT(p) & -8 ); /* jump to sub-header */
/* check that the hi byte isn't a valid one-byte value */ /* check that the hi byte isn't a valid one-byte value */
if ( sub == subs ) if ( sub == subs )
@ -378,75 +381,22 @@
start = TT_NEXT_USHORT(p); start = TT_NEXT_USHORT(p);
count = TT_NEXT_USHORT(p); count = TT_NEXT_USHORT(p);
delta = TT_NEXT_SHORT(p); delta = TT_NEXT_SHORT(p);
offset = PEEK_UShort(p); offset = TT_PEEK_USHORT(p);
index -= start; index -= start;
if ( index < count && offset != 0 ) if ( index < count && offset != 0 )
{ {
p += offset + 2*index; p += offset + 2*index;
index = PEEK_UShort(p); index = TT_PEEK_USHORT(p);
if ( index == 0 ) if ( index != 0 )
goto Exit; result = (FT_UInt)( index + delta ) & 0xFFFFU;
result = (FT_UInt)( index + delta ) & 0xFFFFU;
} }
} }
Exit:
return result; return result;
} }
/* return first valid charcode in a format 2 sub-header */
static FT_ULong
tt_cmap2_subheader_first( FT_Byte* subheader,
FT_UInt char_hi,
FT_UInt *agindex )
{
FT_ULong result = 0;
FT_UInt n, gindex = 0;
FT_Byte* p = subheader;
FT_UInt start = TT_NEXT_USHORT(p);
FT_UInt count = TT_NEXT_USHORT(p);
if ( count > 0 )
{
FT_Int delta = TT_NEXT_SHORT(p);
FT_UInt offset = TT_NEXT_USHORT(p);
if ( offset == 0 )
{
/* simple difference, compute directly */
result = char_hi*256 + start;
gindex = (FT_UInt)( start + delta ) & 0xFFFFU;
}
else
{
FT_UInt i, index;
/* parse glyph id table for non-0 indices */
p += offset - 2;
for (; i < count; i++ )
{
index = TT_NEXT_USHORT(p);
if ( index != 0 )
{
result = char_hi*256 + start + i;
gindex = (FT_UInt)(index + delta) & 0xFFFFU;
break;
}
}
}
}
if ( agindex )
*agindex = gindex;
return result;
}
static FT_UInt static FT_UInt
tt_cmap2_char_next( FT_Byte* table, tt_cmap2_char_next( FT_Byte* table,
@ -459,7 +409,7 @@
FT_Byte* p; FT_Byte* p;
++char_code; ++char_code;
for (;;) while ( char_code < 0x10000U )
{ {
subheader = tt_cmap2_get_subheader( table, char_code ); subheader = tt_cmap2_get_subheader( table, char_code );
if ( subheader ) if ( subheader )
@ -468,7 +418,7 @@
FT_UInt start = TT_NEXT_USHORT(p); FT_UInt start = TT_NEXT_USHORT(p);
FT_UInt count = TT_NEXT_USHORT(p); FT_UInt count = TT_NEXT_USHORT(p);
FT_Int delta = TT_NEXT_SHORT(p); FT_Int delta = TT_NEXT_SHORT(p);
FT_UInt offset = PEEK_UShort(p); FT_UInt offset = TT_PEEK_USHORT(p);
FT_UInt char_lo = (FT_UInt)( char_code & 0xFF ); FT_UInt char_lo = (FT_UInt)( char_code & 0xFF );
FT_UInt pos, index; FT_UInt pos, index;
@ -505,8 +455,6 @@
/* jump to next sub-header, i.e. higher byte value */ /* jump to next sub-header, i.e. higher byte value */
Next_SubHeader: Next_SubHeader:
char_code = (char_code & -256) + 256; char_code = (char_code & -256) + 256;
if ( char_code >= 0x10000U )
break;
} }
Exit: Exit:
@ -534,6 +482,58 @@
/************************************************************************/ /************************************************************************/
/************************************************************************/ /************************************************************************/
/*************************************************************************
*
* TABLE OVERVIEW:
* ---------------
*
* NAME OFFSET TYPE DESCRIPTION
*
* format 0 USHORT must be 4
* length 2 USHORT table length in bytes
* language 4 USHORT Mac language code
*
* segCountX2 6 USHORT 2*NUM_SEGS
* searchRange 8 USHORT 2*(1 << LOG_SEGS)
* entrySelector 10 USHORT LOG_SEGS
* rangeShift 12 USHORT segCountX2 - searchRange
*
* endCount 14 USHORT[NUM_SEGS] end charcode for each
* segment. last is 0xFFFF
*
* pad 14+NUM_SEGS*2 USHORT padding
*
* startCount 16+NUM_SEGS*2 USHORT[NUM_SEGS] first charcode for each
* segment
*
* idDelta 16+NUM_SEGS*4 SHORT[NUM_SEGS] delta for each segment
*
* idOffset 16+NUM_SEGS*6 SHORT[NUM_SEGS] range offset for each
* segment. can be 0
*
* glyphIds 16+NUM_SEGS*8 USHORT[] array og glyph id ranges
*
*
* Charcodes are modelled by a series of ordered (increasing) intervals
* called segments. Each segment has start and end codes, provided by
* the 'startCount' and 'endCount' arrays. Segments must not be over-lapping
* and the last segment should always contain the '0xFFFF' endCount.
*
* The fields 'searchRange', 'entrySelector' and 'rangeShift' are better
* ignored (they're traces of over-engineering in the TT specification)
*
* Each segment also has a signed 'delta', as well as an optional offset
* within the 'glyphIds' table.
*
* if a segment's idOffset is 0, then the glyph index corresponding to
* any charcode within the segment is obtained by adding the value of
* 'idDelta' directly to the charcode, modulo 65536
*
* otherwise, a glyph index is taken from the glyph ids sub-array for the
* segment, and the value of 'idDelta' is added to it..
*/
#ifdef TT_CONFIG_CMAP_FORMAT_4 #ifdef TT_CONFIG_CMAP_FORMAT_4
static void static void
@ -542,14 +542,13 @@
{ {
FT_Byte* p = table + 2; /* skip format */ FT_Byte* p = table + 2; /* skip format */
FT_UInt length = TT_NEXT_USHORT(p); FT_UInt length = TT_NEXT_USHORT(p);
FT_Byte *ends, *starts, *offsets, *glyph_ids; FT_Byte *ends, *starts, *offsets, *deltas, *glyph_ids;
FT_UInt n, num_segs; FT_UInt n, num_segs;
if ( table + length > valid->limit || length < 16 ) if ( table + length > valid->limit || length < 16 )
TOO_SHORT; TOO_SHORT;
p += 2; /* skip language */ p = table + 6;
num_segs = TT_NEXT_USHORT(p); /* read segCountX2 */ num_segs = TT_NEXT_USHORT(p); /* read segCountX2 */
if ( valid->level >= FT_VALIDATE_PARANOID ) if ( valid->level >= FT_VALIDATE_PARANOID )
@ -584,12 +583,11 @@
search_range != (1 << entry_selector) ) search_range != (1 << entry_selector) )
INVALID_DATA; INVALID_DATA;
} }
else
p += 6;
ends = p; ends = table + 14;
starts = ends + num_segs*2 + 2; starts = table + 16 + num_segs*2;
offsets = starts + num_segs*4; deltas = starts + num_segs*2;
offsets = deltas + num_segs*2;
glyph_ids = offsets + num_segs*2; glyph_ids = offsets + num_segs*2;
if ( glyph_ids >= table + length ) if ( glyph_ids >= table + length )
@ -599,7 +597,7 @@
if ( valid->level >= FT_VALIDATE_PARANOID ) if ( valid->level >= FT_VALIDATE_PARANOID )
{ {
p = ends + (num_segs-1)*2; p = ends + (num_segs-1)*2;
if ( PEEK_UShort(p) != 0xFFFFU ) if ( TT_PEEK_USHORT(p) != 0xFFFFU )
INVALID_DATA; INVALID_DATA;
} }
@ -607,12 +605,14 @@
/* check also the offsets.. */ /* check also the offsets.. */
{ {
FT_UInt start, end, last = 0,offset, n; FT_UInt start, end, last = 0,offset, n;
FT_Int delta;
for ( n = 0; n < num_segs; n++ ) for ( n = 0; n < num_segs; n++ )
{ {
p = starts + n*2; start = PEEK_UShort(p); p = starts + n*2; start = TT_PEEK_USHORT(p);
p = ends + n*2; end = PEEK_UShort(p); p = ends + n*2; end = TT_PEEK_USHORT(p);
p = offsets + n*2; offset = PEEK_UShort(p); p = deltas + n*2; delta = TT_PEEK_SHORT(p);
p = offsets + n*2; offset = TT_PEEK_USHORT(p);
if ( end > start ) if ( end > start )
INVALID_DATA; INVALID_DATA;
@ -625,10 +625,26 @@
p += offset; /* start of glyph id array */ p += offset; /* start of glyph id array */
/* check that we point within the glyph ids table only */ /* check that we point within the glyph ids table only */
if ( p < glyph_ids || p + (end - start + 1) > table + length ) if ( p < glyph_ids || p + (end - start + 1)*2 > table + length )
INVALID_DATA; INVALID_DATA;
/* XXXX: check glyph ids !! */ /* check glyph indices within the segment range */
if ( valid->level >= FT_VALIDATE_TIGHT )
{
FT_UInt index;
for ( ; start < end; )
{
index = NEXT_USHORT(p);
if ( index != 0 )
{
index = (FT_UInt)(index + delta) & 0xFFFFU;
if ( index >= valid->num_glyphs )
INVALID_GLYPH_ID;
}
}
}
} }
last = end; last = end;
} }
@ -651,7 +667,7 @@
FT_UInt code = (FT_UInt)char_code; FT_UInt code = (FT_UInt)char_code;
p = table + 6; p = table + 6;
num_segs2 = PEEK_UShort(p); num_segs2 = TT_PEEK_USHORT(p) & -2; /* be paranoid !! */
p = table + 14; /* ends table */ p = table + 14; /* ends table */
q = table + 16 + num_segs2; /* starts table */ q = table + 16 + num_segs2; /* starts table */
@ -668,13 +684,13 @@
{ {
index = (FT_UInt)( char_code - start ); index = (FT_UInt)( char_code - start );
p = q + num_segs2 - 2; delta = PEEK_Short(p); p = q + num_segs2 - 2; delta = TT_PEEK_SHORT(p);
p += num_segs2; offset = PEEK_UShort(p); p += num_segs2; offset = TT_PEEK_USHORT(p);
if ( offset != 0 ) if ( offset != 0 )
{ {
p += offset + 2*index; p += offset + 2*index;
index = PEEK_UShort(p); index = TT_PEEK_USHORT(p);
} }
if ( index != 0 ) if ( index != 0 )
@ -703,7 +719,7 @@
code = (FT_UInt)char_code; code = (FT_UInt)char_code;
p = table + 6; p = table + 6;
num_segs2 = PEEK_UShort(p) & -2; /* ensure even-ness */ num_segs2 = TT_PEEK_USHORT(p) & -2; /* ensure even-ness */
for (;;) for (;;)
{ {
@ -723,8 +739,8 @@
if ( code <= end ) if ( code <= end )
{ {
p = q + num_segs2 - 2; delta = PEEK_Short(p); p = q + num_segs2 - 2; delta = TT_PEEK_SHORT(p);
p += num_segs2; offset = PEEK_UShort(p); p += num_segs2; offset = TT_PEEK_USHORT(p);
if ( offset != 0 ) if ( offset != 0 )
{ {
@ -785,20 +801,41 @@
/************************************************************************/ /************************************************************************/
/************************************************************************/ /************************************************************************/
/*************************************************************************
*
* TABLE OVERVIEW:
* ---------------
*
* NAME OFFSET TYPE DESCRIPTION
*
* format 0 USHORT must be 4
* length 2 USHORT table length in bytes
* language 4 USHORT Mac language code
*
* first 6 USHORT first segment code
* count 8 USHORT segment size in chars
* glyphIds 10 USHORT[count] glyph ids
*
*
* A very simplified segment mapping
*/
#ifdef TT_CONFIG_CMAP_FORMAT_6 #ifdef TT_CONFIG_CMAP_FORMAT_6
static void static void
tt_cmap6_validate( FT_Byte* table, tt_cmap6_validate( FT_Byte* table,
FT_Validator valid ) FT_Validator valid )
{ {
FT_Byte* p = table + 2; FT_Byte* p;
FT_UInt length, start, count; FT_UInt length, start, count;
if ( table + 10 > valid->limit ) if ( table + 10 > valid->limit )
INVALID_TOO_SHORT; INVALID_TOO_SHORT;
p = table + 2;
length = TT_NEXT_USHORT(p); length = TT_NEXT_USHORT(p);
p += 2; /* skip language */
p = table + 6; /* skip language */
start = TT_NEXT_USHORT(p); start = TT_NEXT_USHORT(p);
count = TT_NEXT_USHORT(p); count = TT_NEXT_USHORT(p);
@ -833,7 +870,7 @@
if ( index < count ) if ( index < count )
{ {
p += 2*index; p += 2*index;
result = PEEK_UShort(p); result = TT_PEEK_USHORT(p);
} }
return result; return result;
} }
@ -924,6 +961,28 @@
/************************************************************************/ /************************************************************************/
/************************************************************************/ /************************************************************************/
/*************************************************************************
*
* TABLE OVERVIEW:
* ---------------
*
* NAME OFFSET TYPE DESCRIPTION
*
* format 0 USHORT must be 8
* reseved 2 USHORT reserved
* length 4 ULONG length in bytes
* language 8 ULONG Mac language code
* is32 12 BYTE[8192] 32-bitness bitmap
* count 8204 ULONG number of groups
*
* this header is followed by 'count' groups of the following format:
*
* start 0 ULONG first charcode
* end 4 ULONG last charcode
* startId 8 ULONG start glyph id for
* the group
*/
#ifdef TT_CONFIG_CMAP_FORMAT_8 #ifdef TT_CONFIG_CMAP_FORMAT_8
static void static void
@ -939,11 +998,11 @@
INVALID_TOO_SHORT; INVALID_TOO_SHORT;
length = TT_NEXT_ULONG(p); length = TT_NEXT_ULONG(p);
if ( table + length > valid->limit || length < 16 + 8192 ) if ( table + length > valid->limit || length < 8208 )
INVALID_TOO_SHORT; INVALID_TOO_SHORT;
is32 = p + 4; /* skip language */ is32 = table + 12;
p = is32 + 8192; /* skip 'is32' array */ p = is32 + 8192; /* skip 'is32' array */
num_groups = TT_NEXT_ULONG(p); num_groups = TT_NEXT_ULONG(p);
if ( p + num_groups*12 > valid->limit ) if ( p + num_groups*12 > valid->limit )
@ -1009,6 +1068,8 @@
} }
} }
} }
last = end;
} }
} }
} }
@ -1019,7 +1080,7 @@
FT_ULong char_code ) FT_ULong char_code )
{ {
FT_UInt result = 0; FT_UInt result = 0;
FT_Byte* p = table + 12 + 8192; FT_Byte* p = table + 8204;
FT_ULong num_groups = TT_NEXT_ULONG(p); FT_ULong num_groups = TT_NEXT_ULONG(p);
FT_ULong n, start, end, start_id; FT_ULong n, start, end, start_id;
@ -1049,12 +1110,12 @@
{ {
FT_ULong result = 0; FT_ULong result = 0;
FT_UInt gindex = 0; FT_UInt gindex = 0;
FT_Byte* p = table + 12 + 8192; FT_Byte* p = table + 8204;
FT_ULong num_groups = TT_NEXT_USHORT(p); FT_ULong num_groups = TT_NEXT_ULONG(p);
FT_ULong n, start, end, start_id; FT_ULong n, start, end, start_id;
++char_code; ++char_code;
p = table + 16 + 8192; p = table + 8208;
for ( n = 0; n < num_groups++; n++ ) for ( n = 0; n < num_groups++; n++ )
{ {
@ -1101,20 +1162,37 @@
/************************************************************************/ /************************************************************************/
/************************************************************************/ /************************************************************************/
/*************************************************************************
*
* TABLE OVERVIEW:
* ---------------
*
* NAME OFFSET TYPE DESCRIPTION
*
* format 0 USHORT must be 10
* reseved 2 USHORT reserved
* length 4 ULONG length in bytes
* language 8 ULONG Mac language code
*
* start 12 ULONG first char in range
* count 16 ULONG number of chars in range
* glyphIds 20 USHORT[count] glyph indices covered
*/
#ifdef TT_CONFIG_CMAP_FORMAT_10 #ifdef TT_CONFIG_CMAP_FORMAT_10
static void static void
tt_cmap10_validate( FT_Byte* table, tt_cmap10_validate( FT_Byte* table,
FT_Validator valid ) FT_Validator valid )
{ {
FT_Byte* p = table + 2; FT_Byte* p = table + 4;
FT_ULong length, start, count; FT_ULong length, start, count;
if ( table + 20 > valid->limit ) if ( table + 20 > valid->limit )
INVALID_TOO_SHORT; INVALID_TOO_SHORT;
length = TT_NEXT_USHORT(p); length = TT_NEXT_ULONG(p);
p += 4; /* skip language */ p = table + 12;
start = TT_NEXT_ULONG(p); start = TT_NEXT_ULONG(p);
count = TT_NEXT_ULONG(p); count = TT_NEXT_ULONG(p);
@ -1148,8 +1226,8 @@
if ( index < count ) if ( index < count )
{ {
p += 2*index; p += 2*index;
result = PEEK_UShort(p); result = TT_PEEK_USHORT(p);
} }
return result; return result;
} }
@ -1168,9 +1246,6 @@
FT_ULong index; FT_ULong index;
char_code++; char_code++;
if ( char_code >= 0x10000U )
goto Exit;
if ( char_code < start ) if ( char_code < start )
char_code = start; char_code = start;
@ -1213,19 +1288,107 @@
/************************************************************************/ /************************************************************************/
/************************************************************************/ /************************************************************************/
/*************************************************************************
*
* TABLE OVERVIEW:
* ---------------
*
* NAME OFFSET TYPE DESCRIPTION
*
* format 0 USHORT must be 12
* reseved 2 USHORT reserved
* length 4 ULONG length in bytes
* language 8 ULONG Mac language code
* count 12 ULONG number of groups
* 16
*
* this header is followed by 'count' groups of the following format:
*
* start 0 ULONG first charcode
* end 4 ULONG last charcode
* startId 8 ULONG start glyph id for
* the group
*/
#ifdef TT_CONFIG_CMAP_FORMAT_12 #ifdef TT_CONFIG_CMAP_FORMAT_12
static void static void
tt_cmap12_validate( FT_Byte* table, tt_cmap12_validate( FT_Byte* table,
FT_Validator valid ) FT_Validator valid )
{ {
FT_Byte* p;
FT_ULong length;
FT_ULong num_groups;
if ( table + 16 > valid->limit )
INVALID_TOO_SHORT;
p = table + 4;
length = TT_NEXT_ULONG(p);
p = table + 12;
num_groups = TT_NEXT_ULONG(p);
if ( table + length > valid->limit || length < 16 + 12*num_groups )
INVALID_TOO_SHORT;
/* check groups, they must be in increasing order */
{
FT_ULong n, start, end, start_id, count, last = 0;
for ( n = 0; n < num_groups; n++ )
{
FT_Bytes* q;
FT_UInt hi, lo;
start = TT_NEXT_ULONG(p);
end = TT_NEXT_ULONG(p);
start_id = TT_NEXT_ULONG(p);
if ( start > end )
INVALID_DATA;
if ( n > 0 && start <= last )
INVALID_DATA;
if ( valid->level >= FT_VALIDATE_TIGHT )
{
if ( start_id + end - start >= valid->num_glyphs )
INVALID_GLYPH_ID;
}
last = end;
}
}
} }
static FT_UInt static FT_UInt
tt_cmap12_char_index( FT_Byte* table, tt_cmap12_char_index( FT_Byte* table,
FT_ULong char_code ) FT_ULong char_code )
{ {
FT_UInt result = 0;
FT_Byte* p = table + 12;
FT_ULong num_groups = TT_NEXT_ULONG(p);
FT_ULong n, start, end, start_id;
for ( ; num_groups > 0; num_groups-- )
{
start = TT_NEXT_ULONG(p);
end = TT_NEXT_ULONG(p);
start_id = TT_NEXT_ULONG(p);
if ( char_code < start )
break;
if ( char_code <= end )
{
result = start_id + char_code - start;
break;
}
}
return result;
} }
@ -1234,6 +1397,40 @@
FT_ULong char_code, FT_ULong char_code,
FT_UInt *agindex ) FT_UInt *agindex )
{ {
FT_ULong result = 0;
FT_UInt gindex = 0;
FT_Byte* p = table + 12;
FT_ULong num_groups = TT_NEXT_ULONG(p);
FT_ULong n, start, end, start_id;
++char_code;
p = table + 8208;
for ( n = 0; n < num_groups++; n++ )
{
start = TT_NEXT_ULONG(p);
end = TT_NEXT_ULONG(p);
start_id = TT_NEXT_ULONG(p);
if ( char_code < start )
char_code = start;
if ( char_code <= end )
{
gindex = (FT_UInt)(char_code - start + start_id);
if ( gindex != 0 )
{
result = char_code;
goto Exit;
}
}
}
Exit:
if ( agindex )
*agindex = gindex;
return result;
} }
@ -1246,3 +1443,4 @@
#endif /* TT_CONFIG_CMAP_FORMAT_12 */ #endif /* TT_CONFIG_CMAP_FORMAT_12 */
/* END */

414
src/type1/t1cmap.c Normal file
View File

@ -0,0 +1,414 @@
#include "t1cmap.h"
/***************************************************************************/
/***************************************************************************/
/***** *****/
/***** TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS *****/
/***** *****/
/***************************************************************************/
/***************************************************************************/
static( void )
t1_cmap_std_init( T1_CMapStd cmap,
FT_Int is_expert )
{
T1_Face face = (T1_Face) FT_CMAP_FACE(cmap);
PSNames_Interface* psnames = face->psnames;
cmap->num_glyphs = face->type1.num_glyphs;
cmap->glyph_names = face->type1.glyph_names;
cmap->sid_strings = sid_strings;
cmap->code_to_sid = is_expert ? psnames->adobe_expert_encoding
: psnames->adobe_std_encoding;
FT_ASSERT( cmap->code_to_sid != NULL );
}
FT_CALLBACK_DEF( void )
t1_cmap_std_done( T1_CMapStd cmap )
{
cmap->num_glyphs = 0;
cmap->glyph_names = NULL;
cmap->sid_strings = NULL;
cmap->code_to_sid = NULL;
}
FT_CALLBACK_DEF( FT_UInt )
t1_cmap_std_char_index( T1_CMapStd cmap,
FT_UInt32 char_code )
{
FT_UInt result = 0;
if ( char_code < 256 )
{
FT_UInt code;
const char* glyph_name;
FT_Int n;
/* conver character code to Adobe SID string */
code = cmap->code_to_sid[ char_code ];
glyph_name = cmap->adobe_sid_strings[ code ];
/* look for the corresponding glyph name */
for ( n = 0; n < cmap->num_glyphs; n++ )
{
const char* gname = cmap->glyph_names[n];
if ( gname && gname[0] == glyph_name[0] &&
strcmp( gname, glyph_name ) == 0 )
{
result = n;
break;
}
}
}
return result;
}
FT_CALLBACK_DEF( FT_UInt )
t1_cmap_std_char_next( T1_CMapStd cmap,
FT_UInt32 *pchar_code )
{
FT_UInt result = 0;
FT_UInt32 char_code = *pchar_code;
++char_code;
while ( char_code < 256 )
{
result = t1_cmap_standard_char_index( cmap, char_code );
if ( result != 0 )
goto Exit;
char_code++;
}
char_code = 0;
Exit:
*pchar_code = char_code;
return result;
}
FT_CALLBACK_DEF( FT_Error )
t1_cmap_standard_init( T1_CMapStd cmap )
{
t1_cmap_std_init( cmap, 0 );
return 0;
}
FT_CALLBACK_TABLE const T1_CMap_ClassRec
t1_cmap_standard_class_rec =
{
sizeof( T1_CMapStdRec ),
t1_cmap_standard_init,
t1_cmap_std_done,
t1_cmap_std_char_index,
t1_cmap_std_char_next
};
FT_LOCAL_DEF T1_CMap_Class
t1_cmap_standard_class = &t1_cmap_standard_class_rec;
FT_CALLBACK_DEF( void )
t1_cmap_expert_init( T1_CMapStd cmap )
{
t1_cmap_std_init( cmap, 1 );
return 0;
}
FT_CALLBACK_TABLE const T1_CMap_ClassRec
t1_cmap_expert_class_rec =
{
sizeof( T1_CMapStdRec ),
t1_cmap_expert_init,
t1_cmap_std_done,
t1_cmap_std_char_index,
t1_cmap_std_char_next
};
FT_LOCAL_DEF T1_CMap_Class
t1_cmap_expert_class = &t1_cmap_expert_class_rec;
/***************************************************************************/
/***************************************************************************/
/***** *****/
/***** TYPE1 CUSTOM ENCODING CMAP *****/
/***** *****/
/***************************************************************************/
/***************************************************************************/
FT_CALLBACK_DEF( FT_Error )
t1_cmap_custom_init( T1_CMapCustom cmap )
{
T1_Face face = (T1_Face) FT_CMAP_FACE(cmap);
T1_Encoding* encoding = face->type1.encoding;
cmap->first = encoding->code_first;
cmap->count = (FT_UInt)(encoding->code_last - cmap->first + 1);
cmap->indices = encoding->char_index;
FT_ASSERT( cmap->indices != NULL );
FT_ASSERT( encoding->code_first <= encoding->code_last );
return 0;
}
FT_CALLBACK_DEF( void )
t1_cmap_custom_done( T1_CMapCustom cmap )
{
cmap->indices = NULL;
cmap->first = 0;
cmap->count = 0;
}
FT_CALLBACK_DEF( FT_UInt )
t1_cmap_custom_char_index( T1_CMapCustom cmap,
FT_UInt32 char_code )
{
FT_UInt result = 0;
FT_UInt32 index;
index = (FT_UInt32)( char_code - cmap->first );
if ( index < cmap->count )
result = cmap->indices[ index ];
return result;
}
FT_CALLBACK_DEF( FT_UInt )
t1_cmap_custom_char_next( T1_CMapCustion cmap,
FT_UInt32 *pchar_code )
{
FT_UInt result = 0;
FT_UInt32 char_code = *pchar_code;
FT_UInt32 index;
++char_code;
if ( char_code < cmap->first )
char_code = cmap->first;
index = (FT_UInt32)( char_code - cmap->first );
while ( index < cmap->count; index++, char_code++ )
{
result = cmap->indices[index];
if ( result != 0 )
goto Exit;
}
char_code = 0;
Exit:
*pchar_code = char_code;
return result;
}
FT_CALLBACK_TABLE const FT_CMap_ClassRec
t1_cmap_custom_class_rec =
{
sizeof( T1_CMapCustomRec ),
t1_cmap_custom_init,
t1_cmap_custom_done,
t1_cmap_custom_char_index,
t1_cmap_custom_char_next
};
FT_LOCAL_DEF FT_CMap_Class
t1_cmap_custom_class = &t1_cmap_custom_class_rec;
/***************************************************************************/
/***************************************************************************/
/***** *****/
/***** TYPE1 SYNTHETIC UNICODE ENCODING CMAP *****/
/***** *****/
/***************************************************************************/
/***************************************************************************/
FT_CALLBACK_DEF( FT_Error )
t1_cmap_unicode_init( T1_CMapUnicode cmap )
{
FT_Error error;
FT_UInt count;
T1_Face face = (T1_Face) FT_CMAP_FACE(cmap);
FT_Memory memory = FT_FACE_MEMORY(face);
cmap->num_pairs = 0;
cmap->pairs = NULL;
count = face->type1.num_glyphs;
if ( !ALLOC_ARRAY( cmap->pairs, count, T1_CMapUniPairRec ) )
{
FT_UInt n, new_count;
T1_CMapUniPair pair;
FT_UInt32 uni_code;
pair = cmap->pairs;
for ( n = 0; n < count; n++ )
{
const char* gname = face->type1.glyph_names[n];
/* build unsorted pair table by matching glyph names */
if ( gname )
{
uni_code = PS_Unicode_Value( gname );
if ( uni_code != 0 )
{
pair->unicode = uni_code;
pair->gindex = n;
pair++;
}
}
if ( new_count == 0 )
{
/* there are no unicode characters in here !! */
FREE( cmap->pairs );
error = FT_Err_Invalid_Argument;
}
else
{
/* re-allocate if the new array is much smaller than the original */
/* one.. */
if ( new_count != count && new_count < count/2 )
REALLOC_ARRAY( cmap->pairs, count, new_count, T1_CMapUniPairRec )
/* sort the pairs table to allow efficient binary searches */
qsort( cmap->pairs,
new_count,
sizeof(T1_CMapUniPairRec),
t1_cmap_uni_pair_compare );
cmap->num_pairs = new_count;
}
}
}
return error;
}
FT_CALLBACK_DEF( void )
t1_cmap_unicode_done( T1_CMapUnicode cmap )
{
FT_Face face = FT_CMAP_FACE(cmap);
FT_Memory memory = FT_FACE_MEMORY(face);
FREE( cmap->pairs );
cmap->num_pairs = 0;
}
FT_CALLBACK_DEF( FT_UInt )
t1_cmap_unicode_char_index( T1_CMapUnicode cmap,
FT_UInt32 char_code )
{
FT_UInt min = 0;
FT_UInt max = cmap->num_pairs;
FT_UInt mid;
T1_CMapUniPair pair;
while ( min < max )
{
mid = min + (max - min)/2;
pair = cmap->pairs + mid;
if ( pair->unicode == char_code )
return pair->gindex;
if ( pair->unicode < char_code )
min = mid+1;
else
max = mid;
}
return 0;
}
FT_CALLBACK_DEF( FT_UInt )
t1_cmap_unicode_char_next( T1_CMapUnicode cmap,
FT_UInt32 *pchar_code )
{
FT_UInt32 char_code = *pchar_code + 1;
Restart:
{
FT_UInt min = 0;
FT_UInt max = cmap->num_pairs;
FT_UInt mid;
T1_CMapUniPair pair;
while ( min < max )
{
mid = min + (max - min)/2;
pair = cmap->pairs + mid;
if ( pair->unicode == char_code )
{
result = pair->gindex;
if ( result != 0 )
goto Exit;
char_code++;
goto Restart;
}
if ( pair->unicode < char_code )
min = mid+1;
else
max = mid;
}
/* we didn't find it, but we have a pair just above it */
char_code = 0;
if ( min < cmap->num_pairs )
{
pair = cmap->num_pairs + min;
result = pair->gindex;
if ( result != 0 )
char_code = pair->unicode;
}
}
Exit:
*pchar_code = char_code;
return result;
}
FT_CALLBACK_TABLE const FT_CMap_ClassRec
t1_cmap_unicode_class_rec =
{
sizeof( T1_CMapUnicodeRec ),
t1_cmap_unicode_init,
t1_cmap_unicode_done,
t1_cmap_unicode_char_index,
t1_cmap_unicode_char_next
};

92
src/type1/t1cmap.h Normal file
View File

@ -0,0 +1,92 @@
#ifndef __FT_TYPE1_CMAP_H__
#define __FT_TYPE1_CMAP_H__
FT_BEGIN_HEADER
/***************************************************************************/
/***************************************************************************/
/***** *****/
/***** TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS *****/
/***** *****/
/***************************************************************************/
/***************************************************************************/
typedef struct T1_CMapStrRec_* T1_CMapStd;
typedef struct T1_CMapUnicodeRec_* T1_CMapUnicode;
typedef struct T1_CMapStdRec_
{
FT_CMapRec cmap;
const FT_UShort* charcode_to_sid;
const char* const* adobe_sid_strings;
FT_UInt num_glyphs;
const char** glyph_names;
} T1_CMapStdRec;
FT_LOCAL( FT_CMap_Class ) t1_cmap_standard_class;
FT_LOCAL( FT_CMap_Class ) t1_cmap_expert_class;
/***************************************************************************/
/***************************************************************************/
/***** *****/
/***** TYPE1 CUSTOM ENCODING CMAP *****/
/***** *****/
/***************************************************************************/
/***************************************************************************/
typedef struct T1_CMapCustomRec_* T1_CMapCustom;
typedef struct T1_CMapCustomRec_
{
FT_CMapRec cmap;
FT_UInt first;
FT_UInt count;
FT_UInt* indices;
} T1_CMapCustomRec;
FT_LOCAL( FT_CMap_Class ) t1_cmap_custom_class;
/***************************************************************************/
/***************************************************************************/
/***** *****/
/***** TYPE1 SYNTHETIC UNICODE ENCODING CMAP *****/
/***** *****/
/***************************************************************************/
/***************************************************************************/
typedef struct T1_CMapUniPairRec_* T1_CMapUniPair;
typedef struct T1_CMapUniPairRec_
{
FT_UInt32 unicode;
FT_UInt gindex;
} T1_CMapUniPairRec;
typedef struct T1_CMapUnicodeRec_
{
FT_CMapRec cmap;
FT_UInt num_pairs;
T1_CMapUniPair pairs;
} T1_CMapUnicodeRec;
FT_LOCAL( FT_CMap_Class ) t1_cmap_unicode_class;
/* */
FT_END_HEADER
#endif /* __FT_TYPE1_CMAP_H__ */