📄 gxvcommn.c
字号:
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** SFNT NAME *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
FT_LOCAL_DEF( void )
gxv_sfntName_validate( FT_UShort name_index,
FT_UShort min_index,
FT_UShort max_index,
GXV_Validator valid )
{
FT_SfntName name;
FT_UInt i;
FT_UInt nnames;
GXV_NAME_ENTER( "sfntName" );
if ( name_index < min_index || max_index < name_index )
FT_INVALID_FORMAT;
nnames = FT_Get_Sfnt_Name_Count( valid->face );
for ( i = 0; i < nnames; i++ )
{
if ( FT_Get_Sfnt_Name( valid->face, i, &name ) != FT_Err_Ok )
continue ;
if ( name.name_id == name_index )
goto Out;
}
GXV_TRACE(( " nameIndex = %d (UNTITLED)\n", name_index ));
FT_INVALID_DATA;
goto Exit; /* make compiler happy */
Out:
FT_TRACE1(( " nameIndex = %d (", name_index ));
GXV_TRACE_HEXDUMP_SFNTNAME( name );
FT_TRACE1(( ")\n" ));
Exit:
GXV_EXIT;
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** STATE TABLE *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/* -------------------------- Class Table --------------------------- */
/*
* highestClass specifies how many classes are defined in this
* Class Subtable. Apple spec does not mention whether undefined
* holes in the class (e.g.: 0-3 are predefined, 4 is unused, 5 is used)
* are permitted. At present, holes in a defined class are not checked.
* -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp>
*/
static void
gxv_ClassTable_validate( FT_Bytes table,
FT_UShort* length_p,
FT_UShort stateSize,
FT_Byte* maxClassID_p,
GXV_Validator valid )
{
FT_Bytes p = table;
FT_Bytes limit = table + *length_p;
FT_UShort firstGlyph;
FT_UShort nGlyphs;
GXV_NAME_ENTER( "ClassTable" );
*maxClassID_p = 3; /* Classes 0, 2, and 3 are predefined */
GXV_LIMIT_CHECK( 2 + 2 );
firstGlyph = FT_NEXT_USHORT( p );
nGlyphs = FT_NEXT_USHORT( p );
GXV_TRACE(( " (firstGlyph = %d, nGlyphs = %d)\n", firstGlyph, nGlyphs ));
if ( !nGlyphs )
goto Out;
gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs ), valid );
{
FT_Byte nGlyphInClass[256];
FT_Byte classID;
FT_UShort i;
ft_memset( nGlyphInClass, 0, 256 );
for ( i = 0; i < nGlyphs; i++ )
{
GXV_LIMIT_CHECK( 1 );
classID = FT_NEXT_BYTE( p );
switch ( classID )
{
/* following classes should not appear in class array */
case 0: /* end of text */
case 2: /* out of bounds */
case 3: /* end of line */
FT_INVALID_DATA;
break;
case 1: /* out of bounds */
default: /* user-defined: 4 - ( stateSize - 1 ) */
if ( classID >= stateSize )
FT_INVALID_DATA; /* assign glyph to undefined state */
nGlyphInClass[classID]++;
break;
}
}
*length_p = (FT_UShort)( p - table );
/* scan max ClassID in use */
for ( i = 0; i < stateSize; i++ )
if ( ( 3 < i ) && ( nGlyphInClass[i] > 0 ) )
*maxClassID_p = (FT_Byte)i; /* XXX: Check Range? */
}
Out:
GXV_TRACE(( "Declared stateSize=0x%02x, Used maxClassID=0x%02x\n",
stateSize, *maxClassID_p ));
GXV_EXIT;
}
/* --------------------------- State Array ----------------------------- */
static void
gxv_StateArray_validate( FT_Bytes table,
FT_UShort* length_p,
FT_Byte maxClassID,
FT_UShort stateSize,
FT_Byte* maxState_p,
FT_Byte* maxEntry_p,
GXV_Validator valid )
{
FT_Bytes p = table;
FT_Bytes limit = table + *length_p;
FT_Byte clazz;
FT_Byte entry;
FT_UNUSED( stateSize ); /* for the non-debugging case */
GXV_NAME_ENTER( "StateArray" );
GXV_TRACE(( "parse %d bytes by stateSize=%d maxClassID=%d\n",
(int)(*length_p), stateSize, (int)(maxClassID) ));
/*
* 2 states are predefined and must be described in StateArray:
* state 0 (start of text), 1 (start of line)
*/
GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 );
*maxState_p = 0;
*maxEntry_p = 0;
/* read if enough to read another state */
while ( p + ( 1 + maxClassID ) <= limit )
{
(*maxState_p)++;
for ( clazz = 0; clazz <= maxClassID; clazz++ )
{
entry = FT_NEXT_BYTE( p );
*maxEntry_p = (FT_Byte)FT_MAX( *maxEntry_p, entry );
}
}
GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n",
*maxState_p, *maxEntry_p ));
*length_p = (FT_UShort)( p - table );
GXV_EXIT;
}
/* --------------------------- Entry Table ----------------------------- */
static void
gxv_EntryTable_validate( FT_Bytes table,
FT_UShort* length_p,
FT_Byte maxEntry,
FT_UShort stateArray,
FT_UShort stateArray_length,
FT_Byte maxClassID,
FT_Bytes statetable_table,
FT_Bytes statetable_limit,
GXV_Validator valid )
{
FT_Bytes p = table;
FT_Bytes limit = table + *length_p;
FT_Byte entry;
FT_Byte state;
FT_Int entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( statetable );
GXV_XStateTable_GlyphOffsetDesc glyphOffset;
GXV_NAME_ENTER( "EntryTable" );
GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize ));
if ( ( maxEntry + 1 ) * entrySize > *length_p )
{
if ( valid->root->level >= FT_VALIDATE_PARANOID )
FT_INVALID_TOO_SHORT;
/* ftxvalidator and FontValidator both warn and continue */
maxEntry = (FT_Byte)( *length_p / entrySize - 1 );
GXV_TRACE(( "too large maxEntry, shrinking to %d fit EntryTable length\n",
maxEntry ));
}
for ( entry = 0; entry <= maxEntry; entry++ )
{
FT_UShort newState;
FT_UShort flags;
GXV_LIMIT_CHECK( 2 + 2 );
newState = FT_NEXT_USHORT( p );
flags = FT_NEXT_USHORT( p );
if ( newState < stateArray ||
stateArray + stateArray_length < newState )
{
GXV_TRACE(( " newState offset 0x%04x is out of stateArray\n",
newState ));
if ( valid->root->level >= FT_VALIDATE_PARANOID )
FT_INVALID_OFFSET;
continue;
}
if ( 0 != ( ( newState - stateArray ) % ( 1 + maxClassID ) ) )
{
GXV_TRACE(( " newState offset 0x%04x is not aligned to %d-classes\n",
newState, 1 + maxClassID ));
if ( valid->root->level >= FT_VALIDATE_PARANOID )
FT_INVALID_OFFSET;
continue;
}
state = (FT_Byte)( ( newState - stateArray ) / ( 1 + maxClassID ) );
switch ( GXV_GLYPHOFFSET_FMT( statetable ) )
{
case GXV_GLYPHOFFSET_NONE:
glyphOffset.uc = 0; /* make compiler happy */
break;
case GXV_GLYPHOFFSET_UCHAR:
glyphOffset.uc = FT_NEXT_BYTE( p );
break;
case GXV_GLYPHOFFSET_CHAR:
glyphOffset.c = FT_NEXT_CHAR( p );
break;
case GXV_GLYPHOFFSET_USHORT:
glyphOffset.u = FT_NEXT_USHORT( p );
break;
case GXV_GLYPHOFFSET_SHORT:
glyphOffset.s = FT_NEXT_SHORT( p );
break;
case GXV_GLYPHOFFSET_ULONG:
glyphOffset.ul = FT_NEXT_ULONG( p );
break;
case GXV_GLYPHOFFSET_LONG:
glyphOffset.l = FT_NEXT_LONG( p );
break;
default:
if ( valid->root->level >= FT_VALIDATE_PARANOID )
FT_INVALID_FORMAT;
goto Exit;
}
if ( NULL != valid->statetable.entry_validate_func )
valid->statetable.entry_validate_func( state,
flags,
glyphOffset,
statetable_table,
statetable_limit,
valid );
}
Exit:
*length_p = (FT_UShort)( p - table );
GXV_EXIT;
}
/* =========================== State Table ============================= */
FT_LOCAL_DEF( void )
gxv_StateTable_subtable_setup( FT_UShort table_size,
FT_UShort classTable,
FT_UShort stateArray,
FT_UShort entryTable,
FT_UShort* classTable_length_p,
FT_UShort* stateArray_length_p,
FT_UShort* entryTable_length_p,
GXV_Validator valid )
{
FT_UShort o[3];
FT_UShort* l[3];
FT_UShort buff[4];
o[0] = classTable;
o[1] = stateArray;
o[2] = entryTable;
l[0] = classTable_length_p;
l[1] = stateArray_length_p;
l[2] = entryTable_length_p;
gxv_set_length_by_ushort_offset( o, l, buff, 3, table_size, valid );
}
FT_LOCAL_DEF( void )
gxv_StateTable_validate( FT_Bytes table,
FT_Bytes limit,
GXV_Validator valid )
{
FT_UShort stateSize;
FT_UShort classTable; /* offset to Class(Sub)Table */
FT_UShort stateArray; /* offset to StateArray */
FT_UShort entryTable; /* offset to EntryTable */
FT_UShort classTable_length;
FT_UShort stateArray_length;
FT_UShort entryTable_length;
FT_Byte maxClassID;
FT_Byte maxState;
FT_Byte maxEntry;
GXV_StateTable_Subtable_Setup_Func setup_func;
FT_Bytes p = table;
GXV_NAME_ENTER( "StateTable" );
GXV_TRACE(( "StateTable header\n" ));
GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
stateSize = FT_NEXT_USHORT( p );
classTable = FT_NEXT_USHORT( p );
stateArray = FT_NEXT_USHORT( p );
entryTable = FT_NEXT_USHORT( p );
GXV_TRACE(( "stateSize=0x%04x\n", stateSize ));
GXV_TRACE(( "offset to classTable=0x%04x\n", classTable ));
GXV_TRACE(( "offset to stateArray=0x%04x\n", stateArray ));
GXV_TRACE(( "offset to entryTable=0x%04x\n", entryTable ));
if ( stateSize > 0xFF )
FT_INVALID_DATA;
if ( valid->statetable.optdata_load_func != NULL )
valid->statetable.optdata_load_func( p, limit, valid );
if ( valid->statetable.subtable_setup_func != NULL)
setup_func = valid->statetable.subtable_setup_func;
else
setup_func = gxv_StateTable_subtable_setup;
setup_func( (FT_UShort)( limit - table ),
classTable,
stateArray,
entryTable,
&classTable_length,
&stateArray_length,
&entryTable_length,
valid );
GXV_TRACE(( "StateTable Subtables\n" ));
if ( classTable != 0 )
gxv_ClassTable_validate( table + classTable,
&classTable_length,
stateSize,
&maxClassID,
valid );
else
maxClassID = (FT_Byte)( stateSize - 1 );
if ( stateArray != 0 )
gxv_StateArray_validate( table + stateArray,
&stateArray_length,
maxClassID,
stateSize,
&maxState,
&maxEntry,
valid );
else
{
maxState = 1; /* 0:start of text, 1:start of line are predefined */
maxEntry = 0;
}
if ( maxEntry > 0 && entryTable == 0 )
FT_INVALID_OFFSET;
if ( entryTable != 0 )
gxv_EntryTable_validate( table + entryTable,
&entryTable_length,
maxEntry,
stateArray,
stateArray_length,
maxClassID,
table,
limit,
valid );
GXV_EXIT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -