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 ) tt_face_free_bdf_props(TT_Face face)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 tt_face_load_bdf_props(TT_Face face,FT_Stream stream)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 ) tt_face_find_bdf_prop(TT_Face face,const char * property_name,BDF_PropertyRec * aprop)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