1/****************************************************************************
2 *
3 * ttbdf.c
4 *
5 * TrueType and OpenType embedded BDF properties (body).
6 *
7 * Copyright (C) 2005-2023 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( FT_Face face, /* TT_Face */
140 const char* property_name,
141 BDF_PropertyRec *aprop )
142 {
143 TT_Face ttface = (TT_Face)face;
144 TT_BDF bdf = &ttface->bdf;
145 FT_Size size = FT_FACE_SIZE( face );
146 FT_Error error = FT_Err_Ok;
147 FT_Byte* p;
148 FT_UInt count;
149 FT_Byte* strike;
150 FT_Offset property_len;
151
152
153 aprop->type = BDF_PROPERTY_TYPE_NONE;
154
155 if ( bdf->loaded == 0 )
156 {
157 error = tt_face_load_bdf_props( ttface, FT_FACE_STREAM( face ) );
158 if ( error )
159 goto Exit;
160 }
161
162 count = bdf->num_strikes;
163 p = bdf->table + 8;
164 strike = p + 4 * count;
165
166 error = FT_ERR( Invalid_Argument );
167
168 if ( !size || !property_name )
169 goto Exit;
170
171 property_len = ft_strlen( property_name );
172 if ( property_len == 0 )
173 goto Exit;
174
175 for ( ; count > 0; count-- )
176 {
177 FT_UInt _ppem = FT_NEXT_USHORT( p );
178 FT_UInt _count = FT_NEXT_USHORT( p );
179
180
181 if ( _ppem == size->metrics.y_ppem )
182 {
183 count = _count;
184 goto FoundStrike;
185 }
186
187 strike += 10 * _count;
188 }
189 goto Exit;
190
191 FoundStrike:
192 p = strike;
193 for ( ; count > 0; count-- )
194 {
195 FT_UInt type = FT_PEEK_USHORT( p + 4 );
196
197
198 if ( ( type & 0x10 ) != 0 )
199 {
200 FT_UInt32 name_offset = FT_PEEK_ULONG( p );
201 FT_UInt32 value = FT_PEEK_ULONG( p + 6 );
202
203 /* be a bit paranoid for invalid entries here */
204 if ( name_offset < bdf->strings_size &&
205 property_len < bdf->strings_size - name_offset &&
206 ft_strncmp( property_name,
207 (const char*)bdf->strings + name_offset,
208 bdf->strings_size - name_offset ) == 0 )
209 {
210 switch ( type & 0x0F )
211 {
212 case 0x00: /* string */
213 case 0x01: /* atoms */
214 /* check that the content is really 0-terminated */
215 if ( value < bdf->strings_size &&
216 ft_memchr( bdf->strings + value, 0, bdf->strings_size ) )
217 {
218 aprop->type = BDF_PROPERTY_TYPE_ATOM;
219 aprop->u.atom = (const char*)bdf->strings + value;
220 error = FT_Err_Ok;
221 goto Exit;
222 }
223 break;
224
225 case 0x02:
226 aprop->type = BDF_PROPERTY_TYPE_INTEGER;
227 aprop->u.integer = (FT_Int32)value;
228 error = FT_Err_Ok;
229 goto Exit;
230
231 case 0x03:
232 aprop->type = BDF_PROPERTY_TYPE_CARDINAL;
233 aprop->u.cardinal = value;
234 error = FT_Err_Ok;
235 goto Exit;
236
237 default:
238 ;
239 }
240 }
241 }
242 p += 10;
243 }
244
245 Exit:
246 return error;
247 }
248
249#else /* !TT_CONFIG_OPTION_BDF */
250
251 /* ANSI C doesn't like empty source files */
252 typedef int tt_bdf_dummy_;
253
254#endif /* !TT_CONFIG_OPTION_BDF */
255
256
257/* END */
258