📄 ttcmap.c
字号:
/***************************************************************************/
/* */
/* ttcmap.c */
/* */
/* TrueType character mapping table (cmap) support (body). */
/* */
/* Copyright 2002, 2003, 2004, 2005, 2006, 2007 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 <ft2build.h>
#include FT_INTERNAL_DEBUG_H
#include "sferrors.h" /* must come before FT_INTERNAL_VALIDATE_H */
#include FT_INTERNAL_VALIDATE_H
#include FT_INTERNAL_STREAM_H
#include "ttload.h"
#include "ttcmap.h"
/*************************************************************************/
/* */
/* The macro FT_COMPONENT is used in trace mode. It is an implicit */
/* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
/* messages during execution. */
/* */
#undef FT_COMPONENT
#define FT_COMPONENT trace_ttcmap
#define TT_PEEK_SHORT FT_PEEK_SHORT
#define TT_PEEK_USHORT FT_PEEK_USHORT
#define TT_PEEK_LONG FT_PEEK_LONG
#define TT_PEEK_ULONG FT_PEEK_ULONG
#define TT_NEXT_SHORT FT_NEXT_SHORT
#define TT_NEXT_USHORT FT_NEXT_USHORT
#define TT_NEXT_LONG FT_NEXT_LONG
#define TT_NEXT_ULONG FT_NEXT_ULONG
FT_CALLBACK_DEF( FT_Error )
tt_cmap_init( TT_CMap cmap,
FT_Byte* table )
{
cmap->data = table;
return SFNT_Err_Ok;
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** FORMAT 0 *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/* */
/* TABLE OVERVIEW */
/* -------------- */
/* */
/* NAME OFFSET TYPE DESCRIPTION */
/* */
/* format 0 USHORT must be 0 */
/* length 2 USHORT table length in bytes */
/* language 4 USHORT Mac language code */
/* glyph_ids 6 BYTE[256] array of glyph indices */
/* 262 */
/* */
#ifdef TT_CONFIG_CMAP_FORMAT_0
FT_CALLBACK_DEF( FT_Error )
tt_cmap0_validate( FT_Byte* table,
FT_Validator valid )
{
FT_Byte* p = table + 2;
FT_UInt length = TT_NEXT_USHORT( p );
if ( table + length > valid->limit || length < 262 )
FT_INVALID_TOO_SHORT;
/* check glyph indices whenever necessary */
if ( valid->level >= FT_VALIDATE_TIGHT )
{
FT_UInt n, idx;
p = table + 6;
for ( n = 0; n < 256; n++ )
{
idx = *p++;
if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
FT_INVALID_GLYPH_ID;
}
}
return SFNT_Err_Ok;
}
FT_CALLBACK_DEF( FT_UInt )
tt_cmap0_char_index( TT_CMap cmap,
FT_UInt32 char_code )
{
FT_Byte* table = cmap->data;
return char_code < 256 ? table[6 + char_code] : 0;
}
FT_CALLBACK_DEF( FT_UInt )
tt_cmap0_char_next( TT_CMap cmap,
FT_UInt32 *pchar_code )
{
FT_Byte* table = cmap->data;
FT_UInt32 charcode = *pchar_code;
FT_UInt32 result = 0;
FT_UInt gindex = 0;
table += 6; /* go to glyph ids */
while ( ++charcode < 256 )
{
gindex = table[charcode];
if ( gindex != 0 )
{
result = charcode;
break;
}
}
*pchar_code = result;
return gindex;
}
FT_CALLBACK_DEF( FT_Error )
tt_cmap0_get_info( TT_CMap cmap,
TT_CMapInfo *cmap_info )
{
FT_Byte* p = cmap->data + 4;
cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
return SFNT_Err_Ok;
}
FT_CALLBACK_TABLE_DEF
const TT_CMap_ClassRec tt_cmap0_class_rec =
{
{
sizeof ( TT_CMapRec ),
(FT_CMap_InitFunc) tt_cmap_init,
(FT_CMap_DoneFunc) NULL,
(FT_CMap_CharIndexFunc)tt_cmap0_char_index,
(FT_CMap_CharNextFunc) tt_cmap0_char_next
},
0,
(TT_CMap_ValidateFunc) tt_cmap0_validate,
(TT_CMap_Info_GetFunc) tt_cmap0_get_info
};
#endif /* TT_CONFIG_CMAP_FORMAT_0 */
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** FORMAT 2 *****/
/***** *****/
/***** This is used for certain CJK encodings that encode text in a *****/
/***** mixed 8/16 bits encoding along the following lines: *****/
/***** *****/
/***** * Certain byte values correspond to an 8-bit character code *****/
/***** (typically in the range 0..127 for ASCII compatibility). *****/
/***** *****/
/***** * Certain byte values signal the first byte of a 2-byte *****/
/***** character code (but these values are also valid as the *****/
/***** second byte of a 2-byte character). *****/
/***** *****/
/***** The following charmap lookup and iteration functions all *****/
/***** assume that the value "charcode" correspond to following: *****/
/***** *****/
/***** - For one byte characters, "charcode" is simply the *****/
/***** character code. *****/
/***** *****/
/***** - For two byte characters, "charcode" is the 2-byte *****/
/***** character code in big endian format. More exactly: *****/
/***** *****/
/***** (charcode >> 8) is the first byte value *****/
/***** (charcode & 0xFF) is the second byte value *****/
/***** *****/
/***** Note that not all values of "charcode" are valid according *****/
/***** to these rules, and the function moderately check the *****/
/***** arguments. *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/* */
/* TABLE OVERVIEW */
/* -------------- */
/* */
/* NAME OFFSET TYPE DESCRIPTION */
/* */
/* format 0 USHORT must be 2 */
/* length 2 USHORT table length in bytes */
/* language 4 USHORT Mac language code */
/* keys 6 USHORT[256] sub-header keys */
/* subs 518 SUBHEAD[NSUBS] sub-headers array */
/* glyph_ids 518+NSUB*8 USHORT[] glyph id array */
/* */
/* The `keys' table is used to map charcode high-bytes to sub-headers. */
/* The value of `NSUBS' is the number of sub-headers defined in the */
/* table and is computed by finding the maximum of the `keys' table. */
/* */
/* Note that for any n, `keys[n]' is a byte offset within the `subs' */
/* table, i.e., it is the corresponding sub-header index multiplied */
/* by 8. */
/* */
/* Each sub-header has the following format: */
/* */
/* NAME OFFSET TYPE DESCRIPTION */
/* */
/* first 0 USHORT first valid low-byte */
/* count 2 USHORT number of valid low-bytes */
/* delta 4 SHORT see below */
/* offset 6 USHORT see below */
/* */
/* A sub-header defines, for each high-byte, the range of valid */
/* low-bytes within the charmap. Note that the range defined by `first' */
/* and `count' must be completely included in the interval [0..255] */
/* according to the specification. */
/* */
/* If a character code is contained within a given sub-header, then */
/* mapping it to a glyph index is done as follows: */
/* */
/* * The value of `offset' is read. This is a _byte_ distance from the */
/* location of the `offset' field itself into a slice of the */
/* `glyph_ids' table. Let's call it `slice' (it's a USHORT[] too). */
/* */
/* * The value `slice[char.lo - first]' is read. If it is 0, there is */
/* no glyph for the charcode. Otherwise, the value of `delta' is */
/* added to it (modulo 65536) to form a new glyph index. */
/* */
/* It is up to the validation routine to check that all offsets fall */
/* within the glyph ids table (and not within the `subs' table itself or */
/* outside of the CMap). */
/* */
#ifdef TT_CONFIG_CMAP_FORMAT_2
FT_CALLBACK_DEF( FT_Error )
tt_cmap2_validate( FT_Byte* table,
FT_Validator valid )
{
FT_Byte* p = table + 2; /* skip format */
FT_UInt length = TT_PEEK_USHORT( p );
FT_UInt n, max_subs;
FT_Byte* keys; /* keys table */
FT_Byte* subs; /* sub-headers */
FT_Byte* glyph_ids; /* glyph id array */
if ( table + length > valid->limit || length < 6 + 512 )
FT_INVALID_TOO_SHORT;
keys = table + 6;
/* parse keys to compute sub-headers count */
p = keys;
max_subs = 0;
for ( n = 0; n < 256; n++ )
{
FT_UInt idx = TT_NEXT_USHORT( p );
/* value must be multiple of 8 */
if ( valid->level >= FT_VALIDATE_PARANOID && ( idx & 7 ) != 0 )
FT_INVALID_DATA;
idx >>= 3;
if ( idx > max_subs )
max_subs = idx;
}
FT_ASSERT( p == table + 518 );
subs = p;
glyph_ids = subs + (max_subs + 1) * 8;
if ( glyph_ids > valid->limit )
FT_INVALID_TOO_SHORT;
/* parse sub-headers */
for ( n = 0; n <= max_subs; n++ )
{
FT_UInt first_code, code_count, offset;
FT_Int delta;
FT_Byte* ids;
first_code = TT_NEXT_USHORT( p );
code_count = TT_NEXT_USHORT( p );
delta = TT_NEXT_SHORT( p );
offset = TT_NEXT_USHORT( p );
/* check range within 0..255 */
if ( valid->level >= FT_VALIDATE_PARANOID )
{
if ( first_code >= 256 || first_code + code_count > 256 )
FT_INVALID_DATA;
}
/* check offset */
if ( offset != 0 )
{
ids = p - 2 + offset;
if ( ids < glyph_ids || ids + code_count*2 > table + length )
FT_INVALID_OFFSET;
/* check glyph ids */
if ( valid->level >= FT_VALIDATE_TIGHT )
{
FT_Byte* limit = p + code_count * 2;
FT_UInt idx;
for ( ; p < limit; )
{
idx = TT_NEXT_USHORT( p );
if ( idx != 0 )
{
idx = ( idx + delta ) & 0xFFFFU;
if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
FT_INVALID_GLYPH_ID;
}
}
}
}
}
return SFNT_Err_Ok;
}
/* return sub header corresponding to a given character code */
/* NULL on invalid charcode */
static FT_Byte*
tt_cmap2_get_subheader( FT_Byte* table,
FT_UInt32 char_code )
{
FT_Byte* result = NULL;
if ( char_code < 0x10000UL )
{
FT_UInt char_lo = (FT_UInt)( char_code & 0xFF );
FT_UInt char_hi = (FT_UInt)( char_code >> 8 );
FT_Byte* p = table + 6; /* keys table */
FT_Byte* subs = table + 518; /* subheaders table */
FT_Byte* sub;
if ( char_hi == 0 )
{
/* an 8-bit character code -- we use subHeader 0 in this case */
/* to test whether the character code is in the charmap */
/* */
sub = subs; /* jump to first sub-header */
/* check that the sub-header for this byte is 0, which */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -