Home | History | Annotate | Line # | Download | only in sfnt
      1 /****************************************************************************
      2  *
      3  * ttbdf.c
      4  *
      5  *   TrueType and OpenType embedded BDF properties (body).
      6  *
      7  * Copyright (C) 2005-2020 by
      8  * David Turner, Robert Wilhelm, and Werner Lemberg.
      9  *
     10  * This file is part of the FreeType project, and may only be used,
     11  * modified, and distributed under the terms of the FreeType project
     12  * license, LICENSE.TXT.  By continuing to use, modify, or distribute
     13  * this file you indicate that you have read the license and
     14  * understand and accept it fully.
     15  *
     16  */
     17 
     18 
     19 #include <freetype/internal/ftdebug.h>
     20 #include <freetype/internal/ftstream.h>
     21 #include <freetype/tttags.h>
     22 #include "ttbdf.h"
     23 
     24 #include "sferrors.h"
     25 
     26 
     27 #ifdef TT_CONFIG_OPTION_BDF
     28 
     29   /**************************************************************************
     30    *
     31    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
     32    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
     33    * messages during execution.
     34    */
     35 #undef  FT_COMPONENT
     36 #define FT_COMPONENT  ttbdf
     37 
     38 
     39   FT_LOCAL_DEF( void )
     40   tt_face_free_bdf_props( TT_Face  face )
     41   {
     42     TT_BDF  bdf = &face->bdf;
     43 
     44 
     45     if ( bdf->loaded )
     46     {
     47       FT_Stream  stream = FT_FACE( face )->stream;
     48 
     49 
     50       if ( bdf->table )
     51         FT_FRAME_RELEASE( bdf->table );
     52 
     53       bdf->table_end    = NULL;
     54       bdf->strings      = NULL;
     55       bdf->strings_size = 0;
     56     }
     57   }
     58 
     59 
     60   static FT_Error
     61   tt_face_load_bdf_props( TT_Face    face,
     62                           FT_Stream  stream )
     63   {
     64     TT_BDF    bdf = &face->bdf;
     65     FT_ULong  length;
     66     FT_Error  error;
     67 
     68 
     69     FT_ZERO( bdf );
     70 
     71     error = tt_face_goto_table( face, TTAG_BDF, stream, &length );
     72     if ( error                                  ||
     73          length < 8                             ||
     74          FT_FRAME_EXTRACT( length, bdf->table ) )
     75     {
     76       error = FT_THROW( Invalid_Table );
     77       goto Exit;
     78     }
     79 
     80     bdf->table_end = bdf->table + length;
     81 
     82     {
     83       FT_Byte*   p           = bdf->table;
     84       FT_UInt    version     = FT_NEXT_USHORT( p );
     85       FT_UInt    num_strikes = FT_NEXT_USHORT( p );
     86       FT_ULong   strings     = FT_NEXT_ULONG ( p );
     87       FT_UInt    count;
     88       FT_Byte*   strike;
     89 
     90 
     91       if ( version != 0x0001                 ||
     92            strings < 8                       ||
     93            ( strings - 8 ) / 4 < num_strikes ||
     94            strings + 1 > length              )
     95       {
     96         goto BadTable;
     97       }
     98 
     99       bdf->num_strikes  = num_strikes;
    100       bdf->strings      = bdf->table + strings;
    101       bdf->strings_size = length - strings;
    102 
    103       count  = bdf->num_strikes;
    104       p      = bdf->table + 8;
    105       strike = p + count * 4;
    106 
    107 
    108       for ( ; count > 0; count-- )
    109       {
    110         FT_UInt  num_items = FT_PEEK_USHORT( p + 2 );
    111 
    112         /*
    113          * We don't need to check the value sets themselves, since this
    114          * is done later.
    115          */
    116         strike += 10 * num_items;
    117 
    118         p += 4;
    119       }
    120 
    121       if ( strike > bdf->strings )
    122         goto BadTable;
    123     }
    124 
    125     bdf->loaded = 1;
    126 
    127   Exit:
    128     return error;
    129 
    130   BadTable:
    131     FT_FRAME_RELEASE( bdf->table );
    132     FT_ZERO( bdf );
    133     error = FT_THROW( Invalid_Table );
    134     goto Exit;
    135   }
    136 
    137 
    138   FT_LOCAL_DEF( FT_Error )
    139   tt_face_find_bdf_prop( TT_Face           face,
    140                          const char*       property_name,
    141                          BDF_PropertyRec  *aprop )
    142   {
    143     TT_BDF     bdf   = &face->bdf;
    144     FT_Size    size  = FT_FACE( face )->size;
    145     FT_Error   error = FT_Err_Ok;
    146     FT_Byte*   p;
    147     FT_UInt    count;
    148     FT_Byte*   strike;
    149     FT_Offset  property_len;
    150 
    151 
    152     aprop->type = BDF_PROPERTY_TYPE_NONE;
    153 
    154     if ( bdf->loaded == 0 )
    155     {
    156       error = tt_face_load_bdf_props( face, FT_FACE( face )->stream );
    157       if ( error )
    158         goto Exit;
    159     }
    160 
    161     count  = bdf->num_strikes;
    162     p      = bdf->table + 8;
    163     strike = p + 4 * count;
    164 
    165     error = FT_ERR( Invalid_Argument );
    166 
    167     if ( !size || !property_name )
    168       goto Exit;
    169 
    170     property_len = ft_strlen( property_name );
    171     if ( property_len == 0 )
    172       goto Exit;
    173 
    174     for ( ; count > 0; count-- )
    175     {
    176       FT_UInt  _ppem  = FT_NEXT_USHORT( p );
    177       FT_UInt  _count = FT_NEXT_USHORT( p );
    178 
    179 
    180       if ( _ppem == size->metrics.y_ppem )
    181       {
    182         count = _count;
    183         goto FoundStrike;
    184       }
    185 
    186       strike += 10 * _count;
    187     }
    188     goto Exit;
    189 
    190   FoundStrike:
    191     p = strike;
    192     for ( ; count > 0; count-- )
    193     {
    194       FT_UInt  type = FT_PEEK_USHORT( p + 4 );
    195 
    196 
    197       if ( ( type & 0x10 ) != 0 )
    198       {
    199         FT_UInt32  name_offset = FT_PEEK_ULONG( p     );
    200         FT_UInt32  value       = FT_PEEK_ULONG( p + 6 );
    201 
    202         /* be a bit paranoid for invalid entries here */
    203         if ( name_offset < bdf->strings_size                    &&
    204              property_len < bdf->strings_size - name_offset     &&
    205              ft_strncmp( property_name,
    206                          (const char*)bdf->strings + name_offset,
    207                          bdf->strings_size - name_offset ) == 0 )
    208         {
    209           switch ( type & 0x0F )
    210           {
    211           case 0x00:  /* string */
    212           case 0x01:  /* atoms */
    213             /* check that the content is really 0-terminated */
    214             if ( value < bdf->strings_size &&
    215                  ft_memchr( bdf->strings + value, 0, bdf->strings_size ) )
    216             {
    217               aprop->type   = BDF_PROPERTY_TYPE_ATOM;
    218               aprop->u.atom = (const char*)bdf->strings + value;
    219               error         = FT_Err_Ok;
    220               goto Exit;
    221             }
    222             break;
    223 
    224           case 0x02:
    225             aprop->type      = BDF_PROPERTY_TYPE_INTEGER;
    226             aprop->u.integer = (FT_Int32)value;
    227             error            = FT_Err_Ok;
    228             goto Exit;
    229 
    230           case 0x03:
    231             aprop->type       = BDF_PROPERTY_TYPE_CARDINAL;
    232             aprop->u.cardinal = value;
    233             error             = FT_Err_Ok;
    234             goto Exit;
    235 
    236           default:
    237             ;
    238           }
    239         }
    240       }
    241       p += 10;
    242     }
    243 
    244   Exit:
    245     return error;
    246   }
    247 
    248 #else /* !TT_CONFIG_OPTION_BDF */
    249 
    250   /* ANSI C doesn't like empty source files */
    251   typedef int  _tt_bdf_dummy;
    252 
    253 #endif /* !TT_CONFIG_OPTION_BDF */
    254 
    255 
    256 /* END */
    257