📄 ftmac.c
字号:
base_assoc = assoc;
/* Let's do a little range checking before we get too excited here */
if ( face_index < count_faces_sfnt( fond_data ) )
{
assoc += face_index; /* add on the face_index! */
/* if the face at this index is not scalable,
fall back to the first one (old behavior) */
if ( EndianS16_BtoN( assoc->fontSize ) == 0 )
{
*have_sfnt = 1;
*sfnt_id = EndianS16_BtoN( assoc->fontID );
}
else if ( base_assoc->fontSize == 0 )
{
*have_sfnt = 1;
*sfnt_id = EndianS16_BtoN( base_assoc->fontID );
}
}
if ( EndianS32_BtoN( fond->ffStylOff ) )
{
unsigned char* p = (unsigned char*)fond_data;
StyleTable* style;
unsigned short string_count;
char ps_name[256];
unsigned char* names[64];
int i;
p += EndianS32_BtoN( fond->ffStylOff );
style = (StyleTable*)p;
p += sizeof ( StyleTable );
string_count = EndianS16_BtoN( *(short*)(p) );
p += sizeof ( short );
for ( i = 0; i < string_count && i < 64; i++ )
{
names[i] = p;
p += names[i][0];
p++;
}
{
size_t ps_name_len = (size_t)names[0][0];
if ( ps_name_len != 0 )
{
ft_memcpy(ps_name, names[0] + 1, ps_name_len);
ps_name[ps_name_len] = 0;
}
if ( style->indexes[0] > 1 )
{
unsigned char* suffixes = names[style->indexes[0] - 1];
for ( i = 1; i <= suffixes[0]; i++ )
{
unsigned char* s;
size_t j = suffixes[i] - 1;
if ( j < string_count && ( s = names[j] ) != NULL )
{
size_t s_len = (size_t)s[0];
if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) )
{
ft_memcpy( ps_name + ps_name_len, s + 1, s_len );
ps_name_len += s_len;
ps_name[ps_name_len] = 0;
}
}
}
}
}
create_lwfn_name( ps_name, lwfn_file_name );
}
}
static FT_Error
lookup_lwfn_by_fond( const UInt8* path_fond,
const StringPtr base_lwfn,
UInt8* path_lwfn,
int path_size )
{
FSRef ref, par_ref;
int dirname_len;
/* Pathname for FSRef can be in various formats: HFS, HFS+, and POSIX. */
/* We should not extract parent directory by string manipulation. */
if ( noErr != FSPathMakeRef( path_fond, &ref, FALSE ) )
return FT_Err_Invalid_Argument;
if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone,
NULL, NULL, NULL, &par_ref ) )
return FT_Err_Invalid_Argument;
if ( noErr != FSRefMakePath( &par_ref, path_lwfn, path_size ) )
return FT_Err_Invalid_Argument;
if ( ft_strlen( (char *)path_lwfn ) + 1 + base_lwfn[0] > path_size )
return FT_Err_Invalid_Argument;
/* now we have absolute dirname in lookup_path */
if ( path_lwfn[0] == '/' )
ft_strcat( (char *)path_lwfn, "/" );
else
ft_strcat( (char *)path_lwfn, ":" );
dirname_len = ft_strlen( (char *)path_lwfn );
ft_strcat( (char *)path_lwfn, (char *)base_lwfn + 1 );
path_lwfn[dirname_len + base_lwfn[0]] = '\0';
if ( noErr != FSPathMakeRef( path_lwfn, &ref, FALSE ) )
return FT_Err_Cannot_Open_Resource;
if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone,
NULL, NULL, NULL, NULL ) )
return FT_Err_Cannot_Open_Resource;
return FT_Err_Ok;
}
static short
count_faces( Handle fond,
const UInt8* pathname )
{
short sfnt_id;
short have_sfnt, have_lwfn;
Str255 lwfn_file_name;
UInt8 buff[HFS_MAXPATHLEN];
FT_Error err;
short num_faces;
have_sfnt = have_lwfn = 0;
HLock( fond );
parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, 0 );
if ( lwfn_file_name[0] )
{
err = lookup_lwfn_by_fond( pathname, lwfn_file_name,
buff, sizeof ( buff ) );
if ( FT_Err_Ok == err )
have_lwfn = 1;
}
if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
num_faces = 1;
else
num_faces = count_faces_scalable( *fond );
HUnlock( fond );
return num_faces;
}
/* Read Type 1 data from the POST resources inside the LWFN file,
return a PFB buffer. This is somewhat convoluted because the FT2
PFB parser wants the ASCII header as one chunk, and the LWFN
chunks are often not organized that way, so we glue chunks
of the same type together. */
static FT_Error
read_lwfn( FT_Memory memory,
short res,
FT_Byte** pfb_data,
FT_ULong* size )
{
FT_Error error = FT_Err_Ok;
short res_id;
unsigned char *buffer, *p, *size_p = NULL;
FT_ULong total_size = 0;
FT_ULong old_total_size = 0;
FT_ULong post_size, pfb_chunk_size;
Handle post_data;
char code, last_code;
UseResFile( res );
/* First pass: load all POST resources, and determine the size of */
/* the output buffer. */
res_id = 501;
last_code = -1;
for (;;)
{
post_data = Get1Resource( 'POST', res_id++ );
if ( post_data == NULL )
break; /* we are done */
code = (*post_data)[0];
if ( code != last_code )
{
if ( code == 5 )
total_size += 2; /* just the end code */
else
total_size += 6; /* code + 4 bytes chunk length */
}
total_size += GetHandleSize( post_data ) - 2;
last_code = code;
/* detect integer overflows */
if ( total_size < old_total_size )
{
error = FT_Err_Array_Too_Large;
goto Error;
}
old_total_size = total_size;
}
if ( FT_ALLOC( buffer, (FT_Long)total_size ) )
goto Error;
/* Second pass: append all POST data to the buffer, add PFB fields. */
/* Glue all consecutive chunks of the same type together. */
p = buffer;
res_id = 501;
last_code = -1;
pfb_chunk_size = 0;
for (;;)
{
post_data = Get1Resource( 'POST', res_id++ );
if ( post_data == NULL )
break; /* we are done */
post_size = (FT_ULong)GetHandleSize( post_data ) - 2;
code = (*post_data)[0];
if ( code != last_code )
{
if ( last_code != -1 )
{
/* we are done adding a chunk, fill in the size field */
if ( size_p != NULL )
{
*size_p++ = (FT_Byte)( pfb_chunk_size & 0xFF );
*size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8 ) & 0xFF );
*size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF );
*size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF );
}
pfb_chunk_size = 0;
}
*p++ = 0x80;
if ( code == 5 )
*p++ = 0x03; /* the end */
else if ( code == 2 )
*p++ = 0x02; /* binary segment */
else
*p++ = 0x01; /* ASCII segment */
if ( code != 5 )
{
size_p = p; /* save for later */
p += 4; /* make space for size field */
}
}
ft_memcpy( p, *post_data + 2, post_size );
pfb_chunk_size += post_size;
p += post_size;
last_code = code;
}
*pfb_data = buffer;
*size = total_size;
Error:
CloseResFile( res );
return error;
}
/* Finalizer for a memory stream; gets called by FT_Done_Face().
It frees the memory it uses. */
static void
memory_stream_close( FT_Stream stream )
{
FT_Memory memory = stream->memory;
FT_FREE( stream->base );
stream->size = 0;
stream->base = 0;
stream->close = 0;
}
/* Create a new memory stream from a buffer and a size. */
static FT_Error
new_memory_stream( FT_Library library,
FT_Byte* base,
FT_ULong size,
FT_Stream_CloseFunc close,
FT_Stream* astream )
{
FT_Error error;
FT_Memory memory;
FT_Stream stream;
if ( !library )
return FT_Err_Invalid_Library_Handle;
if ( !base )
return FT_Err_Invalid_Argument;
*astream = 0;
memory = library->memory;
if ( FT_NEW( stream ) )
goto Exit;
FT_Stream_OpenMemory( stream, base, size );
stream->close = close;
*astream = stream;
Exit:
return error;
}
/* Create a new FT_Face given a buffer and a driver name. */
static FT_Error
open_face_from_buffer( FT_Library library,
FT_Byte* base,
FT_ULong size,
FT_Long face_index,
char* driver_name,
FT_Face* aface )
{
FT_Open_Args args;
FT_Error error;
FT_Stream stream;
FT_Memory memory = library->memory;
error = new_memory_stream( library,
base,
size,
memory_stream_close,
&stream );
if ( error )
{
FT_FREE( base );
return error;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -