📄 ttcmap.c
字号:
FT_CALLBACK_DEF( FT_Error )
tt_cmap4_validate( FT_Byte* table,
FT_Validator valid )
{
FT_Byte* p = table + 2; /* skip format */
FT_UInt length = TT_NEXT_USHORT( p );
FT_Byte *ends, *starts, *offsets, *deltas, *glyph_ids;
FT_UInt num_segs;
FT_Error error = SFNT_Err_Ok;
if ( length < 16 )
FT_INVALID_TOO_SHORT;
/* in certain fonts, the `length' field is invalid and goes */
/* out of bound. We try to correct this here... */
if ( table + length > valid->limit )
{
if ( valid->level >= FT_VALIDATE_TIGHT )
FT_INVALID_TOO_SHORT;
length = (FT_UInt)( valid->limit - table );
}
p = table + 6;
num_segs = TT_NEXT_USHORT( p ); /* read segCountX2 */
if ( valid->level >= FT_VALIDATE_PARANOID )
{
/* check that we have an even value here */
if ( num_segs & 1 )
FT_INVALID_DATA;
}
num_segs /= 2;
if ( length < 16 + num_segs * 2 * 4 )
FT_INVALID_TOO_SHORT;
/* check the search parameters - even though we never use them */
/* */
if ( valid->level >= FT_VALIDATE_PARANOID )
{
/* check the values of 'searchRange', 'entrySelector', 'rangeShift' */
FT_UInt search_range = TT_NEXT_USHORT( p );
FT_UInt entry_selector = TT_NEXT_USHORT( p );
FT_UInt range_shift = TT_NEXT_USHORT( p );
if ( ( search_range | range_shift ) & 1 ) /* must be even values */
FT_INVALID_DATA;
search_range /= 2;
range_shift /= 2;
/* `search range' is the greatest power of 2 that is <= num_segs */
if ( search_range > num_segs ||
search_range * 2 < num_segs ||
search_range + range_shift != num_segs ||
search_range != ( 1U << entry_selector ) )
FT_INVALID_DATA;
}
ends = table + 14;
starts = table + 16 + num_segs * 2;
deltas = starts + num_segs * 2;
offsets = deltas + num_segs * 2;
glyph_ids = offsets + num_segs * 2;
/* check last segment, its end count must be FFFF */
if ( valid->level >= FT_VALIDATE_PARANOID )
{
p = ends + ( num_segs - 1 ) * 2;
if ( TT_PEEK_USHORT( p ) != 0xFFFFU )
FT_INVALID_DATA;
}
{
FT_UInt start, end, offset, n;
FT_UInt last_start = 0, last_end = 0;
FT_Int delta;
FT_Byte* p_start = starts;
FT_Byte* p_end = ends;
FT_Byte* p_delta = deltas;
FT_Byte* p_offset = offsets;
for ( n = 0; n < num_segs; n++ )
{
p = p_offset;
start = TT_NEXT_USHORT( p_start );
end = TT_NEXT_USHORT( p_end );
delta = TT_NEXT_SHORT( p_delta );
offset = TT_NEXT_USHORT( p_offset );
if ( start > end )
FT_INVALID_DATA;
/* this test should be performed at default validation level; */
/* unfortunately, some popular Asian fonts present overlapping */
/* ranges in their charmaps */
/* */
if ( start <= last_end && n > 0 )
{
if ( valid->level >= FT_VALIDATE_TIGHT )
FT_INVALID_DATA;
else
{
/* allow overlapping segments, provided their start points */
/* and end points, respectively, are in ascending order. */
/* */
if ( last_start > start || last_end > end )
error |= TT_CMAP_FLAG_UNSORTED;
else
error |= TT_CMAP_FLAG_OVERLAPPING;
}
}
if ( offset && offset != 0xFFFFU )
{
p += offset; /* start of glyph id array */
/* check that we point within the glyph ids table only */
if ( valid->level >= FT_VALIDATE_TIGHT )
{
if ( p < glyph_ids ||
p + ( end - start + 1 ) * 2 > table + length )
FT_INVALID_DATA;
}
else
{
if ( p < glyph_ids ||
p + ( end - start + 1 ) * 2 > valid->limit )
FT_INVALID_DATA;
}
/* check glyph indices within the segment range */
if ( valid->level >= FT_VALIDATE_TIGHT )
{
FT_UInt i, idx;
for ( i = start; i < end; i++ )
{
idx = FT_NEXT_USHORT( p );
if ( idx != 0 )
{
idx = (FT_UInt)( idx + delta ) & 0xFFFFU;
if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
FT_INVALID_GLYPH_ID;
}
}
}
}
else if ( offset == 0xFFFFU )
{
/* Some fonts (erroneously?) use a range offset of 0xFFFF */
/* to mean missing glyph in cmap table */
/* */
if ( valid->level >= FT_VALIDATE_PARANOID ||
n != num_segs - 1 ||
!( start == 0xFFFFU && end == 0xFFFFU && delta == 0x1U ) )
FT_INVALID_DATA;
}
last_start = start;
last_end = end;
}
}
return error;
}
static FT_UInt
tt_cmap4_char_map_linear( TT_CMap cmap,
FT_UInt* pcharcode,
FT_Bool next )
{
FT_UInt num_segs2, start, end, offset;
FT_Int delta;
FT_UInt i, num_segs;
FT_UInt32 charcode = *pcharcode;
FT_UInt gindex = 0;
FT_Byte* p;
p = cmap->data + 6;
num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 );
num_segs = num_segs2 >> 1;
if ( !num_segs )
return 0;
if ( next )
charcode++;
/* linear search */
for ( ; charcode <= 0xFFFFU; charcode++ )
{
FT_Byte* q;
p = cmap->data + 14; /* ends table */
q = cmap->data + 16 + num_segs2; /* starts table */
for ( i = 0; i < num_segs; i++ )
{
end = TT_NEXT_USHORT( p );
start = TT_NEXT_USHORT( q );
if ( charcode >= start && charcode <= end )
{
p = q - 2 + num_segs2;
delta = TT_PEEK_SHORT( p );
p += num_segs2;
offset = TT_PEEK_USHORT( p );
if ( offset == 0xFFFFU )
continue;
if ( offset )
{
p += offset + ( charcode - start ) * 2;
gindex = TT_PEEK_USHORT( p );
if ( gindex != 0 )
gindex = (FT_UInt)( gindex + delta ) & 0xFFFFU;
}
else
gindex = (FT_UInt)( charcode + delta ) & 0xFFFFU;
break;
}
}
if ( !next || gindex )
break;
}
if ( next && gindex )
*pcharcode = charcode;
return gindex;
}
static FT_UInt
tt_cmap4_char_map_binary( TT_CMap cmap,
FT_UInt* pcharcode,
FT_Bool next )
{
FT_UInt num_segs2, start, end, offset;
FT_Int delta;
FT_UInt max, min, mid, num_segs;
FT_UInt charcode = *pcharcode;
FT_UInt gindex = 0;
FT_Byte* p;
p = cmap->data + 6;
num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 );
if ( !num_segs2 )
return 0;
num_segs = num_segs2 >> 1;
/* make compiler happy */
mid = num_segs;
end = 0xFFFFU;
if ( next )
charcode++;
min = 0;
max = num_segs;
/* binary search */
while ( min < max )
{
mid = ( min + max ) >> 1;
p = cmap->data + 14 + mid * 2;
end = TT_PEEK_USHORT( p );
p += 2 + num_segs2;
start = TT_PEEK_USHORT( p );
if ( charcode < start )
max = mid;
else if ( charcode > end )
min = mid + 1;
else
{
p += num_segs2;
delta = TT_PEEK_SHORT( p );
p += num_segs2;
offset = TT_PEEK_USHORT( p );
/* search the first segment containing `charcode' */
if ( cmap->flags & TT_CMAP_FLAG_OVERLAPPING )
{
FT_UInt i;
/* call the current segment `max' */
max = mid;
if ( offset == 0xFFFFU )
mid = max + 1;
/* search in segments before the current segment */
for ( i = max ; i > 0; i-- )
{
FT_UInt prev_end;
FT_Byte* old_p;
old_p = p;
p = cmap->data + 14 + ( i - 1 ) * 2;
prev_end = TT_PEEK_USHORT( p );
if ( charcode > prev_end )
{
p = old_p;
break;
}
end = prev_end;
p += 2 + num_segs2;
start = TT_PEEK_USHORT( p );
p += num_segs2;
delta = TT_PEEK_SHORT( p );
p += num_segs2;
offset = TT_PEEK_USHORT( p );
if ( offset != 0xFFFFU )
mid = i - 1;
}
/* no luck */
if ( mid == max + 1 )
{
if ( i != max )
{
p = cmap->data + 14 + max * 2;
end = TT_PEEK_USHORT( p );
p += 2 + num_segs2;
start = TT_PEEK_USHORT( p );
p += num_segs2;
delta = TT_PEEK_SHORT( p );
p += num_segs2;
offset = TT_PEEK_USHORT( p );
}
mid = max;
/* search in segments after the current segment */
for ( i = max + 1; i < num_segs; i++ )
{
FT_UInt next_end, next_start;
p = cmap->data + 14 + i * 2;
next_end = TT_PEEK_USHORT( p );
p += 2 + num_segs2;
next_start = TT_PEEK_USHORT( p );
if ( charcode < next_start )
break;
end = next_end;
start = next_start;
p += num_segs2;
delta = TT_PEEK_SHORT( p );
p += num_segs2;
offset = TT_PEEK_USHORT( p );
if ( offset != 0xFFFFU )
mid = i;
}
i--;
/* still no luck */
if ( mid == max )
{
mid = i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -