blob: a287d3afc4764227137e7d7d635a1999f0df41df [file] [log] [blame]
/****************************************************************************
*
* ttbdf.c
*
* TrueType and OpenType embedded BDF properties (body).
*
* Copyright (C) 2005-2020 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/ftstream.h>
#include <freetype/tttags.h>
#include "ttbdf.h"
#include "sferrors.h"
#ifdef TT_CONFIG_OPTION_BDF
/**************************************************************************
*
* 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 ttbdf
FT_LOCAL_DEF( void )
tt_face_free_bdf_props( TT_Face face )
{
TT_BDF bdf = &face->bdf;
if ( bdf->loaded )
{
FT_Stream stream = FT_FACE( face )->stream;
if ( bdf->table )
FT_FRAME_RELEASE( bdf->table );
bdf->table_end = NULL;
bdf->strings = NULL;
bdf->strings_size = 0;
}
}
static FT_Error
tt_face_load_bdf_props( TT_Face face,
FT_Stream stream )
{
TT_BDF bdf = &face->bdf;
FT_ULong length;
FT_Error error;
FT_ZERO( bdf );
error = tt_face_goto_table( face, TTAG_BDF, stream, &length );
if ( error ||
length < 8 ||
FT_FRAME_EXTRACT( length, bdf->table ) )
{
error = FT_THROW( Invalid_Table );
goto Exit;
}
bdf->table_end = bdf->table + length;
{
FT_Byte* p = bdf->table;
FT_UInt version = FT_NEXT_USHORT( p );
FT_UInt num_strikes = FT_NEXT_USHORT( p );
FT_ULong strings = FT_NEXT_ULONG ( p );
FT_UInt count;
FT_Byte* strike;
if ( version != 0x0001 ||
strings < 8 ||
( strings - 8 ) / 4 < num_strikes ||
strings + 1 > length )
{
goto BadTable;
}
bdf->num_strikes = num_strikes;
bdf->strings = bdf->table + strings;
bdf->strings_size = length - strings;
count = bdf->num_strikes;
p = bdf->table + 8;
strike = p + count * 4;
for ( ; count > 0; count-- )
{
FT_UInt num_items = FT_PEEK_USHORT( p + 2 );
/*
* We don't need to check the value sets themselves, since this
* is done later.
*/
strike += 10 * num_items;
p += 4;
}
if ( strike > bdf->strings )
goto BadTable;
}
bdf->loaded = 1;
Exit:
return error;
BadTable:
FT_FRAME_RELEASE( bdf->table );
FT_ZERO( bdf );
error = FT_THROW( Invalid_Table );
goto Exit;
}
FT_LOCAL_DEF( FT_Error )
tt_face_find_bdf_prop( TT_Face face,
const char* property_name,
BDF_PropertyRec *aprop )
{
TT_BDF bdf = &face->bdf;
FT_Size size = FT_FACE( face )->size;
FT_Error error = FT_Err_Ok;
FT_Byte* p;
FT_UInt count;
FT_Byte* strike;
FT_Offset property_len;
aprop->type = BDF_PROPERTY_TYPE_NONE;
if ( bdf->loaded == 0 )
{
error = tt_face_load_bdf_props( face, FT_FACE( face )->stream );
if ( error )
goto Exit;
}
count = bdf->num_strikes;
p = bdf->table + 8;
strike = p + 4 * count;
error = FT_ERR( Invalid_Argument );
if ( !size || !property_name )
goto Exit;
property_len = ft_strlen( property_name );
if ( property_len == 0 )
goto Exit;
for ( ; count > 0; count-- )
{
FT_UInt _ppem = FT_NEXT_USHORT( p );
FT_UInt _count = FT_NEXT_USHORT( p );
if ( _ppem == size->metrics.y_ppem )
{
count = _count;
goto FoundStrike;
}
strike += 10 * _count;
}
goto Exit;
FoundStrike:
p = strike;
for ( ; count > 0; count-- )
{
FT_UInt type = FT_PEEK_USHORT( p + 4 );
if ( ( type & 0x10 ) != 0 )
{
FT_UInt32 name_offset = FT_PEEK_ULONG( p );
FT_UInt32 value = FT_PEEK_ULONG( p + 6 );
/* be a bit paranoid for invalid entries here */
if ( name_offset < bdf->strings_size &&
property_len < bdf->strings_size - name_offset &&
ft_strncmp( property_name,
(const char*)bdf->strings + name_offset,
bdf->strings_size - name_offset ) == 0 )
{
switch ( type & 0x0F )
{
case 0x00: /* string */
case 0x01: /* atoms */
/* check that the content is really 0-terminated */
if ( value < bdf->strings_size &&
ft_memchr( bdf->strings + value, 0, bdf->strings_size ) )
{
aprop->type = BDF_PROPERTY_TYPE_ATOM;
aprop->u.atom = (const char*)bdf->strings + value;
error = FT_Err_Ok;
goto Exit;
}
break;
case 0x02:
aprop->type = BDF_PROPERTY_TYPE_INTEGER;
aprop->u.integer = (FT_Int32)value;
error = FT_Err_Ok;
goto Exit;
case 0x03:
aprop->type = BDF_PROPERTY_TYPE_CARDINAL;
aprop->u.cardinal = value;
error = FT_Err_Ok;
goto Exit;
default:
;
}
}
}
p += 10;
}
Exit:
return error;
}
#else /* !TT_CONFIG_OPTION_BDF */
/* ANSI C doesn't like empty source files */
typedef int _tt_bdf_dummy;
#endif /* !TT_CONFIG_OPTION_BDF */
/* END */