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 | |