1 | /**************************************************************************** |
2 | * |
3 | * ttbdf.c |
4 | * |
5 | * TrueType and OpenType embedded BDF properties (body). |
6 | * |
7 | * Copyright (C) 2005-2019 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 <ft2build.h> |
20 | #include FT_INTERNAL_DEBUG_H |
21 | #include FT_INTERNAL_STREAM_H |
22 | #include FT_TRUETYPE_TAGS_H |
23 | #include "ttbdf.h" |
24 | |
25 | #include "sferrors.h" |
26 | |
27 | |
28 | #ifdef TT_CONFIG_OPTION_BDF |
29 | |
30 | /************************************************************************** |
31 | * |
32 | * The macro FT_COMPONENT is used in trace mode. It is an implicit |
33 | * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log |
34 | * messages during execution. |
35 | */ |
36 | #undef FT_COMPONENT |
37 | #define FT_COMPONENT ttbdf |
38 | |
39 | |
40 | FT_LOCAL_DEF( void ) |
41 | tt_face_free_bdf_props( TT_Face face ) |
42 | { |
43 | TT_BDF bdf = &face->bdf; |
44 | |
45 | |
46 | if ( bdf->loaded ) |
47 | { |
48 | FT_Stream stream = FT_FACE( face )->stream; |
49 | |
50 | |
51 | if ( bdf->table ) |
52 | FT_FRAME_RELEASE( bdf->table ); |
53 | |
54 | bdf->table_end = NULL; |
55 | bdf->strings = NULL; |
56 | bdf->strings_size = 0; |
57 | } |
58 | } |
59 | |
60 | |
61 | static FT_Error |
62 | tt_face_load_bdf_props( TT_Face face, |
63 | FT_Stream stream ) |
64 | { |
65 | TT_BDF bdf = &face->bdf; |
66 | FT_ULong length; |
67 | FT_Error error; |
68 | |
69 | |
70 | FT_ZERO( bdf ); |
71 | |
72 | error = tt_face_goto_table( face, TTAG_BDF, stream, &length ); |
73 | if ( error || |
74 | length < 8 || |
75 | FT_FRAME_EXTRACT( length, bdf->table ) ) |
76 | { |
77 | error = FT_THROW( Invalid_Table ); |
78 | goto Exit; |
79 | } |
80 | |
81 | bdf->table_end = bdf->table + length; |
82 | |
83 | { |
84 | FT_Byte* p = bdf->table; |
85 | FT_UInt version = FT_NEXT_USHORT( p ); |
86 | FT_UInt num_strikes = FT_NEXT_USHORT( p ); |
87 | FT_ULong strings = FT_NEXT_ULONG ( p ); |
88 | FT_UInt count; |
89 | FT_Byte* strike; |
90 | |
91 | |
92 | if ( version != 0x0001 || |
93 | strings < 8 || |
94 | ( strings - 8 ) / 4 < num_strikes || |
95 | strings + 1 > length ) |
96 | { |
97 | goto BadTable; |
98 | } |
99 | |
100 | bdf->num_strikes = num_strikes; |
101 | bdf->strings = bdf->table + strings; |
102 | bdf->strings_size = length - strings; |
103 | |
104 | count = bdf->num_strikes; |
105 | p = bdf->table + 8; |
106 | strike = p + count * 4; |
107 | |
108 | |
109 | for ( ; count > 0; count-- ) |
110 | { |
111 | FT_UInt num_items = FT_PEEK_USHORT( p + 2 ); |
112 | |
113 | /* |
114 | * We don't need to check the value sets themselves, since this |
115 | * is done later. |
116 | */ |
117 | strike += 10 * num_items; |
118 | |
119 | p += 4; |
120 | } |
121 | |
122 | if ( strike > bdf->strings ) |
123 | goto BadTable; |
124 | } |
125 | |
126 | bdf->loaded = 1; |
127 | |
128 | Exit: |
129 | return error; |
130 | |
131 | BadTable: |
132 | FT_FRAME_RELEASE( bdf->table ); |
133 | FT_ZERO( bdf ); |
134 | error = FT_THROW( Invalid_Table ); |
135 | goto Exit; |
136 | } |
137 | |
138 | |
139 | FT_LOCAL_DEF( FT_Error ) |
140 | tt_face_find_bdf_prop( TT_Face face, |
141 | const char* property_name, |
142 | BDF_PropertyRec *aprop ) |
143 | { |
144 | TT_BDF bdf = &face->bdf; |
145 | FT_Size size = FT_FACE( face )->size; |
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( face, FT_FACE( face )->stream ); |
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 | |