| /**************************************************************************** |
| * |
| * ttbdf.c |
| * |
| * TrueType and OpenType embedded BDF properties (body). |
| * |
| * Copyright (C) 2005-2022 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 */ |