2000-05-29 22:55:13 +02:00
|
|
|
/***************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* t2load.h */
|
|
|
|
/* */
|
|
|
|
/* TrueType glyph data/program tables loader (body). */
|
|
|
|
/* */
|
|
|
|
/* Copyright 1996-1999 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 <freetype/internal/ftdebug.h>
|
|
|
|
#include <freetype/internal/ftobjs.h>
|
|
|
|
#include <freetype/internal/ftstream.h>
|
2000-05-30 01:03:15 +02:00
|
|
|
#include <freetype/internal/psnames.h>
|
2000-05-29 22:55:13 +02:00
|
|
|
|
|
|
|
#include <freetype/fterrors.h>
|
|
|
|
#include <freetype/tttags.h>
|
|
|
|
#include <t2load.h>
|
|
|
|
#include <t2parse.h>
|
|
|
|
#include <t2errors.h>
|
|
|
|
|
|
|
|
#undef FT_COMPONENT
|
|
|
|
#define FT_COMPONENT trace_ttload
|
|
|
|
|
|
|
|
/* read a CFF offset from memory */
|
2000-05-30 01:03:15 +02:00
|
|
|
static
|
|
|
|
FT_ULong t2_get_offset( FT_Byte* p,
|
2000-05-29 22:55:13 +02:00
|
|
|
FT_Byte off_size )
|
|
|
|
{
|
|
|
|
FT_ULong result;
|
|
|
|
for ( result = 0; off_size > 0; off_size-- )
|
|
|
|
result = (result <<= 8) | *p++;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-05-30 01:03:15 +02:00
|
|
|
static
|
|
|
|
FT_Error t2_new_cff_index( CFF_Index* index,
|
|
|
|
FT_Stream stream,
|
|
|
|
FT_Bool load )
|
|
|
|
{
|
|
|
|
FT_Error error;
|
|
|
|
FT_Memory memory = stream->memory;
|
|
|
|
FT_UShort count;
|
2000-05-29 22:55:13 +02:00
|
|
|
|
2000-05-30 01:03:15 +02:00
|
|
|
MEM_Set( index, 0, sizeof(*index) );
|
|
|
|
if ( !READ_UShort( count ) &&
|
|
|
|
count > 0 )
|
2000-05-29 22:55:13 +02:00
|
|
|
{
|
2000-05-30 01:03:15 +02:00
|
|
|
FT_Byte* p;
|
|
|
|
FT_Byte offsize;
|
|
|
|
FT_ULong data_size;
|
|
|
|
FT_ULong* poff;
|
2000-05-29 22:55:13 +02:00
|
|
|
|
2000-05-30 01:03:15 +02:00
|
|
|
/* there is at least one element, read the offset size */
|
|
|
|
/* then access the offset table to compute the index's total size */
|
|
|
|
if ( READ_Byte( offsize ) )
|
|
|
|
goto Exit;
|
|
|
|
|
|
|
|
index->stream = stream;
|
|
|
|
index->count = count;
|
|
|
|
index->off_size = offsize;
|
|
|
|
data_size = (FT_ULong)(count+1) * offsize;
|
|
|
|
|
|
|
|
if ( ALLOC_ARRAY( index->offsets, count+1, FT_ULong ) ||
|
|
|
|
ACCESS_Frame( data_size ))
|
|
|
|
goto Exit;
|
|
|
|
|
|
|
|
poff = index->offsets;
|
|
|
|
p = (FT_Byte*)stream->cursor;
|
|
|
|
for ( ; (FT_Short)count >= 0; count-- )
|
|
|
|
{
|
|
|
|
poff[0] = t2_get_offset( p, offsize );
|
|
|
|
poff++;
|
|
|
|
p += offsize;
|
|
|
|
}
|
|
|
|
|
|
|
|
FORGET_Frame();
|
|
|
|
|
|
|
|
index->data_offset = FILE_Pos();
|
|
|
|
data_size = poff[-1]-1;
|
|
|
|
|
|
|
|
if (load)
|
|
|
|
{
|
|
|
|
/* load the data */
|
|
|
|
if ( EXTRACT_Frame( data_size, index->bytes ) )
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* skip the data */
|
|
|
|
(void)FILE_Skip( data_size );
|
|
|
|
}
|
2000-05-29 22:55:13 +02:00
|
|
|
}
|
2000-05-30 01:03:15 +02:00
|
|
|
Exit:
|
|
|
|
if (error)
|
|
|
|
FREE( index->offsets );
|
2000-05-29 22:55:13 +02:00
|
|
|
|
2000-05-30 01:03:15 +02:00
|
|
|
return error;
|
2000-05-29 22:55:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-05-30 01:03:15 +02:00
|
|
|
static
|
|
|
|
void t2_done_cff_index( CFF_Index* index )
|
|
|
|
{
|
|
|
|
FT_Stream stream = index->stream;
|
|
|
|
FT_Memory memory = stream->memory;
|
|
|
|
|
|
|
|
if (index->bytes)
|
|
|
|
RELEASE_Frame( index->bytes );
|
|
|
|
|
|
|
|
FREE( index->offsets );
|
|
|
|
MEM_Set( index, 0, sizeof(*index) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static
|
|
|
|
FT_Error t2_access_element( CFF_Index* index,
|
2000-05-29 22:55:13 +02:00
|
|
|
FT_UInt element,
|
|
|
|
FT_Byte* *pbytes,
|
|
|
|
FT_ULong *pbyte_len )
|
|
|
|
{
|
2000-05-30 01:03:15 +02:00
|
|
|
FT_Error error = 0;
|
2000-05-29 22:55:13 +02:00
|
|
|
|
2000-05-30 01:03:15 +02:00
|
|
|
if ( index && index->count > element )
|
2000-05-29 22:55:13 +02:00
|
|
|
{
|
2000-05-30 01:03:15 +02:00
|
|
|
/* compute start and end offsets */
|
2000-05-29 22:55:13 +02:00
|
|
|
FT_ULong off1, off2;
|
2000-05-30 01:03:15 +02:00
|
|
|
|
|
|
|
off1 = index->offsets[element];
|
2000-05-29 22:55:13 +02:00
|
|
|
if (off1)
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
2000-05-30 01:03:15 +02:00
|
|
|
element++;
|
|
|
|
off2 = index->offsets[element];
|
2000-05-29 22:55:13 +02:00
|
|
|
}
|
2000-05-30 01:03:15 +02:00
|
|
|
while (off2 == 0 && element < index->count);
|
|
|
|
if (!off2)
|
2000-05-29 22:55:13 +02:00
|
|
|
off1 = 0;
|
|
|
|
}
|
2000-05-30 01:03:15 +02:00
|
|
|
|
|
|
|
/* access element */
|
2000-05-29 22:55:13 +02:00
|
|
|
if (off1)
|
|
|
|
{
|
|
|
|
*pbyte_len = off2 - off1;
|
2000-05-30 01:03:15 +02:00
|
|
|
|
|
|
|
if (index->bytes)
|
|
|
|
{
|
|
|
|
/* this index was completely loaded in memory, that's easy */
|
|
|
|
*pbytes = index->bytes + off1 - 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* this index is still on disk/file, access it through a frame */
|
|
|
|
FT_Stream stream = index->stream;
|
|
|
|
|
|
|
|
if ( FILE_Seek( index->data_offset + off1 - 1 ) ||
|
|
|
|
EXTRACT_Frame( off2-off1, *pbytes ) )
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* empty index element */
|
|
|
|
*pbytes = 0;
|
|
|
|
*pbyte_len = 0;
|
2000-05-29 22:55:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
error = FT_Err_Invalid_Argument;
|
2000-05-30 01:03:15 +02:00
|
|
|
|
|
|
|
Exit:
|
2000-05-29 22:55:13 +02:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-05-30 01:03:15 +02:00
|
|
|
static
|
|
|
|
void t2_forget_element( CFF_Index* index,
|
|
|
|
FT_Byte* *pbytes )
|
2000-05-29 22:55:13 +02:00
|
|
|
{
|
2000-05-30 01:03:15 +02:00
|
|
|
if (index->bytes == 0)
|
2000-05-29 22:55:13 +02:00
|
|
|
{
|
2000-05-30 01:03:15 +02:00
|
|
|
FT_Stream stream = index->stream;
|
|
|
|
RELEASE_Frame( *pbytes );
|
2000-05-29 22:55:13 +02:00
|
|
|
}
|
2000-05-30 01:03:15 +02:00
|
|
|
}
|
2000-05-29 22:55:13 +02:00
|
|
|
|
|
|
|
|
2000-05-30 01:03:15 +02:00
|
|
|
static
|
|
|
|
FT_String* t2_get_name( CFF_Index* index,
|
|
|
|
FT_UInt element )
|
2000-05-29 22:55:13 +02:00
|
|
|
{
|
2000-05-30 01:03:15 +02:00
|
|
|
FT_Memory memory = index->stream->memory;
|
|
|
|
FT_Byte* bytes;
|
|
|
|
FT_ULong byte_len;
|
2000-05-29 22:55:13 +02:00
|
|
|
FT_Error error;
|
2000-05-30 01:03:15 +02:00
|
|
|
FT_String* name = 0;
|
|
|
|
|
|
|
|
error = t2_access_element( index, element, &bytes, &byte_len );
|
|
|
|
if (error) goto Exit;
|
|
|
|
|
|
|
|
if ( !ALLOC( name, byte_len+1 ) )
|
2000-05-29 22:55:13 +02:00
|
|
|
{
|
2000-05-30 01:03:15 +02:00
|
|
|
MEM_Copy( name, bytes, byte_len );
|
|
|
|
name[byte_len] = 0;
|
2000-05-29 22:55:13 +02:00
|
|
|
}
|
2000-05-30 01:03:15 +02:00
|
|
|
t2_forget_element( index, &bytes );
|
|
|
|
|
2000-05-29 22:55:13 +02:00
|
|
|
Exit:
|
2000-05-30 01:03:15 +02:00
|
|
|
return name;
|
|
|
|
}
|
2000-05-29 22:55:13 +02:00
|
|
|
|
|
|
|
|
2000-05-30 01:03:15 +02:00
|
|
|
#if 0
|
2000-05-29 22:55:13 +02:00
|
|
|
LOCAL_FUNC
|
2000-05-30 01:03:15 +02:00
|
|
|
FT_String* T2_Get_String( CFF_Index* index,
|
|
|
|
FT_UInt sid,
|
|
|
|
PSNames_Interface* interface )
|
2000-05-29 22:55:13 +02:00
|
|
|
{
|
2000-05-30 01:03:15 +02:00
|
|
|
/* if it's not a standard string, return it */
|
|
|
|
if ( sid > 390 )
|
|
|
|
return t2_get_name( index, sid - 390 );
|
|
|
|
|
|
|
|
/* that's a standard string, fetch a copy from the psnamed module */
|
|
|
|
{
|
|
|
|
FT_String* name = 0;
|
|
|
|
const char* adobe_name = interface->adobe_std_strings( sid );
|
|
|
|
FT_UInt len;
|
|
|
|
|
|
|
|
if (adobe_name)
|
|
|
|
{
|
|
|
|
FT_Memory memory = index->stream->memory;
|
|
|
|
FT_Error error;
|
|
|
|
|
|
|
|
len = (FT_UInt)strlen(adobe_name);
|
|
|
|
if ( !ALLOC( name, len+1 ) )
|
|
|
|
{
|
|
|
|
MEM_Copy( name, adobe_name, len );
|
|
|
|
name[len] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2000-05-29 22:55:13 +02:00
|
|
|
|
|
|
|
LOCAL_FUNC
|
|
|
|
FT_Error T2_Load_CFF_Font( FT_Stream stream,
|
2000-05-30 01:03:15 +02:00
|
|
|
FT_Int face_index,
|
2000-05-29 22:55:13 +02:00
|
|
|
CFF_Font* font )
|
|
|
|
{
|
|
|
|
static const FT_Frame_Field cff_header_fields[] = {
|
|
|
|
FT_FRAME_START(4),
|
|
|
|
FT_FRAME_BYTE( CFF_Font, version_major ),
|
|
|
|
FT_FRAME_BYTE( CFF_Font, version_minor ),
|
|
|
|
FT_FRAME_BYTE( CFF_Font, header_size ),
|
|
|
|
FT_FRAME_BYTE( CFF_Font, absolute_offsize ),
|
|
|
|
FT_FRAME_END };
|
|
|
|
|
|
|
|
FT_Error error;
|
2000-05-30 01:03:15 +02:00
|
|
|
FT_Memory memory = stream->memory;
|
|
|
|
FT_ULong base_offset;
|
2000-05-29 22:55:13 +02:00
|
|
|
|
|
|
|
MEM_Set( font, 0, sizeof(*font) );
|
|
|
|
font->stream = stream;
|
2000-05-30 01:03:15 +02:00
|
|
|
font->memory = memory;
|
|
|
|
base_offset = FILE_Pos();
|
2000-05-29 22:55:13 +02:00
|
|
|
|
|
|
|
/* read CFF font header */
|
|
|
|
if ( READ_Fields( cff_header_fields, font ) )
|
|
|
|
goto Exit;
|
|
|
|
|
|
|
|
/* check format */
|
|
|
|
if ( font->version_major != 1 ||
|
|
|
|
font->header_size < 4 ||
|
|
|
|
font->absolute_offsize > 4 )
|
|
|
|
{
|
|
|
|
FT_ERROR(( "incorrect CFF font header !!\n" ));
|
|
|
|
error = FT_Err_Unknown_File_Format;
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* skip the rest of the header */
|
|
|
|
(void)FILE_Skip( font->header_size - 4 );
|
|
|
|
|
2000-05-30 01:03:15 +02:00
|
|
|
/* read the name, top dict, string and global subrs index */
|
|
|
|
error = t2_new_cff_index( &font->name_index, stream, 0 ) ||
|
|
|
|
t2_new_cff_index( &font->top_dict_index, stream, 0 ) ||
|
|
|
|
t2_new_cff_index( &font->string_index, stream, 0 ) ||
|
|
|
|
t2_new_cff_index( &font->global_subrs_index, stream, 1 );
|
2000-05-29 22:55:13 +02:00
|
|
|
if (error) goto Exit;
|
|
|
|
|
2000-05-30 01:03:15 +02:00
|
|
|
/* well, we don't really forget the "disabled" fonts.. */
|
2000-05-29 22:55:13 +02:00
|
|
|
font->num_faces = font->name_index.count;
|
2000-05-30 01:03:15 +02:00
|
|
|
if (face_index >= font->num_faces)
|
|
|
|
{
|
|
|
|
FT_ERROR(( "T2.Load_Font: incorrect face index = %d\n", face_index ));
|
|
|
|
error = FT_Err_Invalid_Argument;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* in case of a font format check, simply exit now */
|
|
|
|
if (face_index >= 0)
|
|
|
|
{
|
|
|
|
T2_Parser parser;
|
|
|
|
FT_Byte* dict;
|
|
|
|
FT_ULong dict_len;
|
|
|
|
CFF_Index* index = &font->top_dict_index;
|
|
|
|
|
|
|
|
/* parse the top-level font dictionary */
|
|
|
|
T2_Parser_Init( &parser, T2CODE_TOPDICT, &font->top_dict );
|
|
|
|
|
|
|
|
error = t2_access_element( index, face_index, &dict, &dict_len ) ||
|
|
|
|
T2_Parser_Run( &parser, dict, dict + dict_len );
|
|
|
|
|
|
|
|
t2_forget_element( &font->top_dict_index, &dict );
|
|
|
|
if (error) goto Exit;
|
|
|
|
|
|
|
|
/* parse the private dictionary, if any */
|
|
|
|
if (font->top_dict.private_offset && font->top_dict.private_size)
|
|
|
|
{
|
|
|
|
T2_Parser_Init( &parser, T2CODE_PRIVATE, &font->private_dict );
|
|
|
|
|
|
|
|
if ( FILE_Seek( base_offset + font->top_dict.private_offset ) ||
|
|
|
|
ACCESS_Frame( font->top_dict.private_size ) )
|
|
|
|
goto Exit;
|
|
|
|
|
|
|
|
error = T2_Parser_Run( &parser,
|
|
|
|
(FT_Byte*)stream->cursor,
|
|
|
|
(FT_Byte*)stream->limit );
|
|
|
|
FORGET_Frame();
|
|
|
|
if (error) goto Exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* read the charstrings index now */
|
|
|
|
if ( font->top_dict.charstrings_offset == 0 )
|
|
|
|
{
|
|
|
|
FT_ERROR(( "T2.New_CFF_Font: no charstrings offset !!\n" ));
|
|
|
|
error = FT_Err_Unknown_File_Format;
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( FILE_Seek( base_offset + font->top_dict.charstrings_offset ) )
|
|
|
|
goto Exit;
|
|
|
|
|
|
|
|
error = t2_new_cff_index( &font->charstrings_index, stream, 0 );
|
|
|
|
if (error) goto Exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get the font name */
|
|
|
|
font->font_name = t2_get_name( &font->name_index, face_index );
|
2000-05-29 22:55:13 +02:00
|
|
|
|
|
|
|
Exit:
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCAL_FUNC
|
|
|
|
void T2_Done_CFF_Font( CFF_Font* font )
|
|
|
|
{
|
2000-05-30 01:03:15 +02:00
|
|
|
t2_done_cff_index( &font->global_subrs_index );
|
|
|
|
t2_done_cff_index( &font->string_index );
|
|
|
|
t2_done_cff_index( &font->top_dict_index );
|
|
|
|
t2_done_cff_index( &font->name_index );
|
|
|
|
t2_done_cff_index( &font->charstrings_index );
|
2000-05-29 22:55:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/***********************************************************************/
|
|
|
|
/***********************************************************************/
|
|
|
|
/***** *****/
|
|
|
|
/***** TYPE 2 TABLES DECODING.. *****/
|
|
|
|
/***** *****/
|
|
|
|
/***********************************************************************/
|
|
|
|
/***********************************************************************/
|
|
|
|
/***********************************************************************/
|
|
|
|
|
|
|
|
/* END */
|