blob: b02d643f36bdcf0e8d981eef4fa11f98330a2653 [file] [log] [blame]
David Turner993a8d02002-05-18 12:03:43 +00001/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
Werner Lemberg059bc332013-03-14 10:27:35 +01003 * Copyright 2001-2013
Werner Lemberg442bfb82007-02-12 21:44:10 +00004 * Francesco Zappa Nardelli
David Turner993a8d02002-05-18 12:03:43 +00005 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
Werner Lemberg7cf4d372002-05-21 14:13:01 +000025 /*************************************************************************/
26 /* */
27 /* This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 */
28 /* */
29 /* taken from Mark Leisher's xmbdfed package */
30 /* */
31 /*************************************************************************/
32
David Turner993a8d02002-05-18 12:03:43 +000033
34#include <ft2build.h>
35
Werner Lemberg02d4d592002-05-28 22:38:05 +000036#include FT_FREETYPE_H
David Turner993a8d02002-05-18 12:03:43 +000037#include FT_INTERNAL_DEBUG_H
38#include FT_INTERNAL_STREAM_H
39#include FT_INTERNAL_OBJECTS_H
40
41#include "bdf.h"
David Turner993a8d02002-05-18 12:03:43 +000042#include "bdferror.h"
43
David Turner993a8d02002-05-18 12:03:43 +000044
Werner Lemberg7cf4d372002-05-21 14:13:01 +000045 /*************************************************************************/
46 /* */
47 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
48 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
49 /* messages during execution. */
50 /* */
51#undef FT_COMPONENT
52#define FT_COMPONENT trace_bdflib
David Turner993a8d02002-05-18 12:03:43 +000053
David Turner993a8d02002-05-18 12:03:43 +000054
Werner Lemberg7cf4d372002-05-21 14:13:01 +000055 /*************************************************************************/
56 /* */
57 /* Default BDF font options. */
58 /* */
59 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000060
David Turner993a8d02002-05-18 12:03:43 +000061
David Turnerb1b47622002-05-21 21:17:43 +000062 static const bdf_options_t _bdf_opts =
Werner Lemberg7cf4d372002-05-21 14:13:01 +000063 {
David Turner993a8d02002-05-18 12:03:43 +000064 1, /* Correct metrics. */
65 1, /* Preserve unencoded glyphs. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000066 0, /* Preserve comments. */
67 BDF_PROPORTIONAL /* Default spacing. */
68 };
David Turner993a8d02002-05-18 12:03:43 +000069
David Turner993a8d02002-05-18 12:03:43 +000070
Werner Lemberg7cf4d372002-05-21 14:13:01 +000071 /*************************************************************************/
72 /* */
73 /* Builtin BDF font properties. */
74 /* */
75 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000076
Werner Lemberg7cf4d372002-05-21 14:13:01 +000077 /* List of most properties that might appear in a font. Doesn't include */
78 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
David Turner993a8d02002-05-18 12:03:43 +000079
David Turnerb1b47622002-05-21 21:17:43 +000080 static const bdf_property_t _bdf_properties[] =
David Turner993a8d02002-05-18 12:03:43 +000081 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +000082 { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
83 { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
84 { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
85 { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
86 { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
87 { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
88 { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
89 { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
90 { (char *)"COMMENT", BDF_ATOM, 1, { 0 } },
91 { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } },
92 { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
93 { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } },
94 { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
95 { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } },
96 { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } },
97 { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } },
98 { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
99 { (char *)"FONT", BDF_ATOM, 1, { 0 } },
100 { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
101 { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
102 { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
103 { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } },
104 { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } },
105 { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
106 { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } },
107 { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } },
108 { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } },
109 { (char *)"NOTICE", BDF_ATOM, 1, { 0 } },
110 { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
111 { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } },
112 { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
113 { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
114 { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
115 { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
116 { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
117 { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
118 { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
119 { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
120 { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
121 { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
122 { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
123 { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
124 { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
125 { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
126 { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
127 { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
128 { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
129 { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
130 { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
131 { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
132 { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
133 { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
134 { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
135 { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
136 { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
137 { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
138 { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
139 { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
140 { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
141 { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
142 { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
143 { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } },
144 { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
145 { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
146 { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
147 { (char *)"SLANT", BDF_ATOM, 1, { 0 } },
148 { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
149 { (char *)"SPACING", BDF_ATOM, 1, { 0 } },
150 { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
151 { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
152 { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
153 { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
154 { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
155 { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
156 { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
157 { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
158 { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
159 { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
160 { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } },
161 { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
162 { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } },
163 { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
164 { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
165 };
David Turner993a8d02002-05-18 12:03:43 +0000166
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000167 static const unsigned long
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000168 _num_bdf_properties = sizeof ( _bdf_properties ) /
169 sizeof ( _bdf_properties[0] );
David Turner993a8d02002-05-18 12:03:43 +0000170
171
Werner Lemberge01406b2011-11-25 09:44:28 +0100172 /* Auto correction messages. */
173#define ACMSG1 "FONT_ASCENT property missing. " \
174 "Added `FONT_ASCENT %hd'.\n"
175#define ACMSG2 "FONT_DESCENT property missing. " \
176 "Added `FONT_DESCENT %hd'.\n"
177#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
178#define ACMSG4 "Font left bearing != actual left bearing. " \
179 "Old: %hd New: %hd.\n"
180#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
181#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
182#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
183#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
184#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
185#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
186#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
187#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
188#define ACMSG13 "Glyph %ld extra rows removed.\n"
189#define ACMSG14 "Glyph %ld extra columns removed.\n"
190#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
Werner Lemberg0b1c0c62012-02-25 10:23:04 +0100191#define ACMSG16 "Glyph %ld missing columns padded with zero bits.\n"
Werner Lemberge01406b2011-11-25 09:44:28 +0100192
193 /* Error messages. */
194#define ERRMSG1 "[line %ld] Missing `%s' line.\n"
195#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
196#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
197#define ERRMSG4 "[line %ld] BBX too big.\n"
198#define ERRMSG5 "[line %ld] `%s' value too big.\n"
199#define ERRMSG6 "[line %ld] Input line too long.\n"
200#define ERRMSG7 "[line %ld] Font name too long.\n"
201#define ERRMSG8 "[line %ld] Invalid `%s' value.\n"
202#define ERRMSG9 "[line %ld] Invalid keyword.\n"
203
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +0100204 /* Debug messages. */
205#define DBGMSG1 " [%6ld] %s" /* no \n */
206#define DBGMSG2 " (0x%lX)\n"
207
Werner Lemberge01406b2011-11-25 09:44:28 +0100208
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000209 /*************************************************************************/
210 /* */
211 /* Hash table utilities for the properties. */
212 /* */
213 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +0000214
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000215 /* XXX: Replace this with FreeType's hash functions */
David Turner993a8d02002-05-18 12:03:43 +0000216
David Turner993a8d02002-05-18 12:03:43 +0000217
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000218#define INITIAL_HT_SIZE 241
219
220 typedef void
221 (*hash_free_func)( hashnode node );
222
223 static hashnode*
Werner Lemberg428c2e42003-04-25 05:35:04 +0000224 hash_bucket( const char* key,
225 hashtable* ht )
David Turner993a8d02002-05-18 12:03:43 +0000226 {
Werner Lemberg428c2e42003-04-25 05:35:04 +0000227 const char* kp = key;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000228 unsigned long res = 0;
229 hashnode* bp = ht->table, *ndp;
230
231
232 /* Mocklisp hash function. */
233 while ( *kp )
234 res = ( res << 5 ) - res + *kp++;
235
236 ndp = bp + ( res % ht->size );
237 while ( *ndp )
David Turner993a8d02002-05-18 12:03:43 +0000238 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000239 kp = (*ndp)->key;
240 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
241 break;
242 ndp--;
243 if ( ndp < bp )
244 ndp = bp + ( ht->size - 1 );
David Turner993a8d02002-05-18 12:03:43 +0000245 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000246
247 return ndp;
David Turner993a8d02002-05-18 12:03:43 +0000248 }
David Turner993a8d02002-05-18 12:03:43 +0000249
250
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000251 static FT_Error
252 hash_rehash( hashtable* ht,
253 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000254 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000255 hashnode* obp = ht->table, *bp, *nbp;
David Turner993a8d02002-05-18 12:03:43 +0000256 int i, sz = ht->size;
Werner Lemberge3c93012013-03-14 11:21:17 +0100257 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000258
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000259
260 ht->size <<= 1;
261 ht->limit = ht->size / 3;
262
263 if ( FT_NEW_ARRAY( ht->table, ht->size ) )
264 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000265
266 for ( i = 0, bp = obp; i < sz; i++, bp++ )
David Turner993a8d02002-05-18 12:03:43 +0000267 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000268 if ( *bp )
269 {
270 nbp = hash_bucket( (*bp)->key, ht );
271 *nbp = *bp;
272 }
David Turner993a8d02002-05-18 12:03:43 +0000273 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000274 FT_FREE( obp );
275
276 Exit:
277 return error;
David Turner993a8d02002-05-18 12:03:43 +0000278 }
David Turner993a8d02002-05-18 12:03:43 +0000279
280
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000281 static FT_Error
282 hash_init( hashtable* ht,
283 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000284 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100285 int sz = INITIAL_HT_SIZE;
Werner Lemberge3c93012013-03-14 11:21:17 +0100286 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000287
David Turner993a8d02002-05-18 12:03:43 +0000288
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000289 ht->size = sz;
290 ht->limit = sz / 3;
291 ht->used = 0;
David Turner993a8d02002-05-18 12:03:43 +0000292
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000293 if ( FT_NEW_ARRAY( ht->table, sz ) )
294 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000295
296 Exit:
297 return error;
David Turner993a8d02002-05-18 12:03:43 +0000298 }
David Turner993a8d02002-05-18 12:03:43 +0000299
300
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000301 static void
302 hash_free( hashtable* ht,
303 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000304 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000305 if ( ht != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000306 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000307 int i, sz = ht->size;
308 hashnode* bp = ht->table;
David Turner993a8d02002-05-18 12:03:43 +0000309
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000310
311 for ( i = 0; i < sz; i++, bp++ )
312 FT_FREE( *bp );
313
314 FT_FREE( ht->table );
315 }
David Turner993a8d02002-05-18 12:03:43 +0000316 }
317
David Turner993a8d02002-05-18 12:03:43 +0000318
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000319 static FT_Error
320 hash_insert( char* key,
suzuki toshiya704f4d72009-09-13 00:50:14 +0900321 size_t data,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000322 hashtable* ht,
323 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000324 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100325 hashnode nn;
326 hashnode* bp = hash_bucket( key, ht );
Werner Lemberge3c93012013-03-14 11:21:17 +0100327 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000328
329
330 nn = *bp;
331 if ( !nn )
332 {
333 if ( FT_NEW( nn ) )
334 goto Exit;
335 *bp = nn;
336
337 nn->key = key;
338 nn->data = data;
339
340 if ( ht->used >= ht->limit )
341 {
342 error = hash_rehash( ht, memory );
343 if ( error )
344 goto Exit;
345 }
346 ht->used++;
347 }
David Turner993a8d02002-05-18 12:03:43 +0000348 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000349 nn->data = data;
350
351 Exit:
352 return error;
David Turner993a8d02002-05-18 12:03:43 +0000353 }
354
David Turner993a8d02002-05-18 12:03:43 +0000355
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000356 static hashnode
Werner Lemberg428c2e42003-04-25 05:35:04 +0000357 hash_lookup( const char* key,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000358 hashtable* ht )
359 {
360 hashnode *np = hash_bucket( key, ht );
361
362
363 return *np;
364 }
365
366
367 /*************************************************************************/
368 /* */
369 /* Utility types and functions. */
370 /* */
371 /*************************************************************************/
372
373
374 /* Function type for parsing lines of a BDF font. */
375
376 typedef FT_Error
377 (*_bdf_line_func_t)( char* line,
378 unsigned long linelen,
379 unsigned long lineno,
380 void* call_data,
381 void* client_data );
382
383
384 /* List structure for splitting lines into fields. */
385
386 typedef struct _bdf_list_t_
387 {
388 char** field;
389 unsigned long size;
390 unsigned long used;
David Turner68df4f72005-03-15 18:18:57 +0000391 FT_Memory memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000392
393 } _bdf_list_t;
394
395
396 /* Structure used while loading BDF fonts. */
397
398 typedef struct _bdf_parse_t_
399 {
400 unsigned long flags;
401 unsigned long cnt;
402 unsigned long row;
403
404 short minlb;
405 short maxlb;
406 short maxrb;
407 short maxas;
408 short maxds;
409
410 short rbearing;
411
412 char* glyph_name;
413 long glyph_enc;
414
415 bdf_font_t* font;
416 bdf_options_t* opts;
417
Werner Lemberged54e432011-11-27 16:39:53 +0100418 unsigned long have[34816]; /* must be in sync with `nmod' and `umod' */
419 /* arrays from `bdf_font_t' structure */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000420 _bdf_list_t list;
421
422 FT_Memory memory;
423
424 } _bdf_parse_t;
425
426
Werner Lemberga08b2172007-03-28 07:17:17 +0000427#define setsbit( m, cc ) \
428 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
429#define sbitset( m, cc ) \
430 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000431
432
David Turner68df4f72005-03-15 18:18:57 +0000433 static void
434 _bdf_list_init( _bdf_list_t* list,
435 FT_Memory memory )
436 {
Werner Lembergebf55852005-03-16 01:49:54 +0000437 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000438 list->memory = memory;
439 }
440
Werner Lembergebf55852005-03-16 01:49:54 +0000441
David Turner68df4f72005-03-15 18:18:57 +0000442 static void
443 _bdf_list_done( _bdf_list_t* list )
444 {
445 FT_Memory memory = list->memory;
446
Werner Lembergebf55852005-03-16 01:49:54 +0000447
David Turner68df4f72005-03-15 18:18:57 +0000448 if ( memory )
449 {
450 FT_FREE( list->field );
Werner Lembergebf55852005-03-16 01:49:54 +0000451 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000452 }
453 }
454
455
456 static FT_Error
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900457 _bdf_list_ensure( _bdf_list_t* list,
458 unsigned long num_items ) /* same as _bdf_list_t.used */
David Turner68df4f72005-03-15 18:18:57 +0000459 {
Werner Lemberge3c93012013-03-14 11:21:17 +0100460 FT_Error error = FT_Err_Ok;
Werner Lembergebf55852005-03-16 01:49:54 +0000461
David Turner68df4f72005-03-15 18:18:57 +0000462
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900463 if ( num_items > list->size )
David Turner68df4f72005-03-15 18:18:57 +0000464 {
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900465 unsigned long oldsize = list->size; /* same as _bdf_list_t.size */
Werner Lembergcee5d592012-03-01 09:26:03 +0100466 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 5;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900467 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
468 FT_Memory memory = list->memory;
David Turner68df4f72005-03-15 18:18:57 +0000469
Werner Lembergebf55852005-03-16 01:49:54 +0000470
David Turner68df4f72005-03-15 18:18:57 +0000471 if ( oldsize == bigsize )
472 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100473 error = FT_THROW( Out_Of_Memory );
David Turner68df4f72005-03-15 18:18:57 +0000474 goto Exit;
475 }
476 else if ( newsize < oldsize || newsize > bigsize )
477 newsize = bigsize;
478
479 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
480 goto Exit;
481
482 list->size = newsize;
483 }
Werner Lembergebf55852005-03-16 01:49:54 +0000484
David Turner68df4f72005-03-15 18:18:57 +0000485 Exit:
486 return error;
487 }
488
489
490 static void
491 _bdf_list_shift( _bdf_list_t* list,
492 unsigned long n )
493 {
494 unsigned long i, u;
495
496
497 if ( list == 0 || list->used == 0 || n == 0 )
498 return;
499
500 if ( n >= list->used )
501 {
502 list->used = 0;
503 return;
504 }
505
506 for ( u = n, i = 0; u < list->used; i++, u++ )
507 list->field[i] = list->field[u];
508 list->used -= n;
509 }
510
511
Werner Lembergf4c94d42010-06-19 16:08:31 +0200512 /* An empty string for empty fields. */
513
514 static const char empty[1] = { 0 }; /* XXX eliminate this */
515
516
David Turner68df4f72005-03-15 18:18:57 +0000517 static char *
518 _bdf_list_join( _bdf_list_t* list,
519 int c,
520 unsigned long *alen )
521 {
522 unsigned long i, j;
Werner Lembergdc624ca2013-06-04 10:30:48 +0200523 char* dp;
David Turner68df4f72005-03-15 18:18:57 +0000524
525
526 *alen = 0;
527
528 if ( list == 0 || list->used == 0 )
529 return 0;
530
531 dp = list->field[0];
532 for ( i = j = 0; i < list->used; i++ )
533 {
Werner Lembergdc624ca2013-06-04 10:30:48 +0200534 char* fp = list->field[i];
535
536
David Turner68df4f72005-03-15 18:18:57 +0000537 while ( *fp )
538 dp[j++] = *fp++;
539
540 if ( i + 1 < list->used )
541 dp[j++] = (char)c;
542 }
Werner Lembergf4c94d42010-06-19 16:08:31 +0200543 if ( dp != empty )
544 dp[j] = 0;
David Turner68df4f72005-03-15 18:18:57 +0000545
546 *alen = j;
547 return dp;
548 }
549
550
Werner Lemberg03242f52012-02-26 06:52:56 +0100551 /* The code below ensures that we have at least 4 + 1 `field' */
552 /* elements in `list' (which are possibly NULL) so that we */
553 /* don't have to check the number of fields in most cases. */
554
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000555 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000556 _bdf_list_split( _bdf_list_t* list,
557 char* separators,
558 char* line,
559 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000560 {
561 int mult, final_empty;
562 char *sp, *ep, *end;
563 char seps[32];
Werner Lemberge3c93012013-03-14 11:21:17 +0100564 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000565
566
567 /* Initialize the list. */
568 list->used = 0;
Werner Lembergd9c16592012-03-01 15:15:00 +0100569 if ( list->size )
570 {
571 list->field[0] = (char*)empty;
572 list->field[1] = (char*)empty;
573 list->field[2] = (char*)empty;
574 list->field[3] = (char*)empty;
Werner Lemberg649c6732012-03-16 21:12:41 +0100575 list->field[4] = (char*)empty;
Werner Lembergd9c16592012-03-01 15:15:00 +0100576 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000577
578 /* If the line is empty, then simply return. */
579 if ( linelen == 0 || line[0] == 0 )
580 goto Exit;
581
582 /* In the original code, if the `separators' parameter is NULL or */
583 /* empty, the list is split into individual bytes. We don't need */
584 /* this, so an error is signaled. */
585 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000586 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100587 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000588 goto Exit;
589 }
590
591 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000592 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000593
594 /* If the very last character of the separator string is a plus, then */
595 /* set the `mult' flag to indicate that multiple separators should be */
596 /* collapsed into one. */
597 for ( mult = 0, sp = separators; sp && *sp; sp++ )
598 {
599 if ( *sp == '+' && *( sp + 1 ) == 0 )
600 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000601 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000602 setsbit( seps, *sp );
603 }
604
605 /* Break the line up into fields. */
606 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
607 sp < end && *sp; )
608 {
609 /* Collect everything that is not a separator. */
610 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
611 ;
612
613 /* Resize the list if necessary. */
614 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000615 {
Werner Lembergebf55852005-03-16 01:49:54 +0000616 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000617 if ( error )
618 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000619 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000620
621 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000622 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000623
624 sp = ep;
625
626 if ( mult )
627 {
628 /* If multiple separators should be collapsed, do it now by */
629 /* setting all the separator characters to 0. */
630 for ( ; *ep && sbitset( seps, *ep ); ep++ )
631 *ep = 0;
632 }
633 else if ( *ep != 0 )
634 /* Don't collapse multiple separators by making them 0, so just */
635 /* make the one encountered 0. */
636 *ep++ = 0;
637
638 final_empty = ( ep > sp && *ep == 0 );
639 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000640 }
641
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000642 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000643 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000644 {
Werner Lembergebf55852005-03-16 01:49:54 +0000645 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000646 if ( error )
647 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000648 }
649
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000650 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000651 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000652
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000653 list->field[list->used] = 0;
654
655 Exit:
656 return error;
David Turner993a8d02002-05-18 12:03:43 +0000657 }
658
David Turner993a8d02002-05-18 12:03:43 +0000659
David Turner68df4f72005-03-15 18:18:57 +0000660#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000661
Werner Lembergebf55852005-03-16 01:49:54 +0000662
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000663 static FT_Error
664 _bdf_readstream( FT_Stream stream,
665 _bdf_line_func_t callback,
666 void* client_data,
667 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000668 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000669 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000670 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900671 int refill, hold, to_skip;
672 ptrdiff_t bytes, start, end, cursor, avail;
Werner Lemberg059bc332013-03-14 10:27:35 +0100673 char* buf = 0;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000674 FT_Memory memory = stream->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100675 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000676
David Turner993a8d02002-05-18 12:03:43 +0000677
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000678 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000679 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100680 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000681 goto Exit;
682 }
David Turner993a8d02002-05-18 12:03:43 +0000683
Werner Lembergebf55852005-03-16 01:49:54 +0000684 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000685 buf_size = 1024;
686
687 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000688 goto Exit;
689
Werner Lembergebf55852005-03-16 01:49:54 +0000690 cb = callback;
691 lineno = 1;
692 buf[0] = 0;
693 start = 0;
694 end = 0;
695 avail = 0;
696 cursor = 0;
697 refill = 1;
698 to_skip = NO_SKIP;
699 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000700
David Turner68df4f72005-03-15 18:18:57 +0000701 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000702 {
David Turner68df4f72005-03-15 18:18:57 +0000703 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000704 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +0200705 bytes = (ptrdiff_t)FT_Stream_TryRead(
706 stream, (FT_Byte*)buf + cursor,
707 (FT_ULong)( buf_size - cursor ) );
David Turner68df4f72005-03-15 18:18:57 +0000708 avail = cursor + bytes;
709 cursor = 0;
710 refill = 0;
711 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000712
David Turner68df4f72005-03-15 18:18:57 +0000713 end = start;
714
Werner Lembergebf55852005-03-16 01:49:54 +0000715 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000716 if ( start < avail && buf[start] == to_skip )
717 {
718 start += 1;
719 to_skip = NO_SKIP;
720 continue;
721 }
722
723 /* try to find the end of the line */
724 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
725 end++;
726
Werner Lembergebf55852005-03-16 01:49:54 +0000727 /* if we hit the end of the buffer, try shifting its content */
728 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000729 if ( end >= avail )
730 {
731 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
732 break; /* ignore it then exit */
733
734 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000735 {
Werner Lembergebf55852005-03-16 01:49:54 +0000736 /* this line is definitely too long; try resizing the input */
737 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000738 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000739
Werner Lembergebf55852005-03-16 01:49:54 +0000740
741 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000742 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100743 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +0100744 error = FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +0000745 goto Exit;
746 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000747
Werner Lembergebf55852005-03-16 01:49:54 +0000748 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000749 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
750 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000751
David Turner68df4f72005-03-15 18:18:57 +0000752 cursor = buf_size;
753 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000754 }
755 else
756 {
David Turner68df4f72005-03-15 18:18:57 +0000757 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000758
Werner Lemberg04e547b2013-04-03 07:37:56 +0200759 FT_MEM_MOVE( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000760
David Turner68df4f72005-03-15 18:18:57 +0000761 cursor = bytes;
762 avail -= bytes;
763 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000764 }
David Turner68df4f72005-03-15 18:18:57 +0000765 refill = 1;
766 continue;
David Turner993a8d02002-05-18 12:03:43 +0000767 }
David Turner68df4f72005-03-15 18:18:57 +0000768
769 /* Temporarily NUL-terminate the line. */
770 hold = buf[end];
771 buf[end] = 0;
772
773 /* XXX: Use encoding independent value for 0x1a */
774 if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
775 {
Werner Lemberga9f6f852012-12-17 09:08:09 +0100776 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergebf55852005-03-16 01:49:54 +0000777 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200778 /* Redo if we have encountered CHARS without properties. */
779 if ( error == -1 )
Werner Lemberga9f6f852012-12-17 09:08:09 +0100780 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200781 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000782 if ( error )
783 break;
784 }
785
786 lineno += 1;
787 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000788 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000789
790 if ( hold == '\n' )
791 to_skip = '\r';
792 else if ( hold == '\r' )
793 to_skip = '\n';
794 else
795 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000796 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000797
David Turner68df4f72005-03-15 18:18:57 +0000798 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000799
800 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000801 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000802 return error;
David Turner993a8d02002-05-18 12:03:43 +0000803 }
David Turner993a8d02002-05-18 12:03:43 +0000804
805
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000806 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000807
David Turnerb1b47622002-05-21 21:17:43 +0000808 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000809 {
David Turner993a8d02002-05-18 12:03:43 +0000810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
811 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
812 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
813 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
814 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
815 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
816 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
817 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
818 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
819 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
820 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000821 };
David Turner993a8d02002-05-18 12:03:43 +0000822
David Turnerb1b47622002-05-21 21:17:43 +0000823 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000824 {
David Turner993a8d02002-05-18 12:03:43 +0000825 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
826 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
827 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
828 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000829 };
David Turner993a8d02002-05-18 12:03:43 +0000830
David Turnerb1b47622002-05-21 21:17:43 +0000831 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000832 {
David Turner993a8d02002-05-18 12:03:43 +0000833 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
834 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
835 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
836 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000837 };
David Turner993a8d02002-05-18 12:03:43 +0000838
David Turnerb1b47622002-05-21 21:17:43 +0000839 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000840 {
David Turner993a8d02002-05-18 12:03:43 +0000841 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
842 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
843 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
844 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000845 };
David Turner993a8d02002-05-18 12:03:43 +0000846
David Turner993a8d02002-05-18 12:03:43 +0000847
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000848 /* Routine to convert an ASCII string into an unsigned long integer. */
849 static unsigned long
850 _bdf_atoul( char* s,
851 char** end,
852 int base )
David Turner993a8d02002-05-18 12:03:43 +0000853 {
David Turnerb1b47622002-05-21 21:17:43 +0000854 unsigned long v;
855 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000856
857
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000858 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000859 return 0;
860
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000861 /* Make sure the radix is something recognizable. Default to 10. */
862 switch ( base )
863 {
864 case 8:
865 dmap = odigits;
866 break;
867 case 16:
868 dmap = hdigits;
869 break;
870 default:
871 base = 10;
872 dmap = ddigits;
873 break;
David Turner993a8d02002-05-18 12:03:43 +0000874 }
875
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000876 /* Check for the special hex prefix. */
877 if ( *s == '0' &&
878 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
879 {
880 base = 16;
881 dmap = hdigits;
882 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000883 }
884
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +0100885 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000886 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000887
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000888 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000889 *end = s;
890
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000891 return v;
892 }
David Turner993a8d02002-05-18 12:03:43 +0000893
David Turner993a8d02002-05-18 12:03:43 +0000894
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000895 /* Routine to convert an ASCII string into an signed long integer. */
896 static long
897 _bdf_atol( char* s,
898 char** end,
899 int base )
900 {
David Turnerb1b47622002-05-21 21:17:43 +0000901 long v, neg;
902 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000903
904
905 if ( s == 0 || *s == 0 )
906 return 0;
907
908 /* Make sure the radix is something recognizable. Default to 10. */
909 switch ( base )
910 {
911 case 8:
912 dmap = odigits;
913 break;
914 case 16:
915 dmap = hdigits;
916 break;
917 default:
918 base = 10;
919 dmap = ddigits;
920 break;
921 }
922
923 /* Check for a minus sign. */
924 neg = 0;
925 if ( *s == '-' )
926 {
927 s++;
928 neg = 1;
929 }
930
931 /* Check for the special hex prefix. */
932 if ( *s == '0' &&
933 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
934 {
935 base = 16;
936 dmap = hdigits;
937 s += 2;
938 }
939
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +0100940 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000941 v = v * base + a2i[(int)*s];
942
943 if ( end != 0 )
944 *end = s;
945
946 return ( !neg ) ? v : -v;
947 }
948
949
950 /* Routine to convert an ASCII string into an signed short integer. */
951 static short
952 _bdf_atos( char* s,
953 char** end,
954 int base )
955 {
David Turnerb1b47622002-05-21 21:17:43 +0000956 short v, neg;
957 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000958
959
960 if ( s == 0 || *s == 0 )
961 return 0;
962
963 /* Make sure the radix is something recognizable. Default to 10. */
964 switch ( base )
965 {
966 case 8:
967 dmap = odigits;
968 break;
969 case 16:
970 dmap = hdigits;
971 break;
972 default:
973 base = 10;
974 dmap = ddigits;
975 break;
976 }
977
978 /* Check for a minus. */
979 neg = 0;
980 if ( *s == '-' )
981 {
982 s++;
983 neg = 1;
984 }
985
986 /* Check for the special hex prefix. */
987 if ( *s == '0' &&
988 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
989 {
990 base = 16;
991 dmap = hdigits;
992 s += 2;
993 }
994
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +0100995 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +0000996 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000997
998 if ( end != 0 )
999 *end = s;
1000
Werner Lemberg233302a2002-05-22 05:41:06 +00001001 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001002 }
1003
1004
1005 /* Routine to compare two glyphs by encoding so they can be sorted. */
1006 static int
1007 by_encoding( const void* a,
1008 const void* b )
1009 {
1010 bdf_glyph_t *c1, *c2;
1011
1012
1013 c1 = (bdf_glyph_t *)a;
1014 c2 = (bdf_glyph_t *)b;
1015
1016 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001017 return -1;
David Turner68df4f72005-03-15 18:18:57 +00001018
1019 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001020 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001021
David Turner993a8d02002-05-18 12:03:43 +00001022 return 0;
David Turner993a8d02002-05-18 12:03:43 +00001023 }
1024
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001025
1026 static FT_Error
1027 bdf_create_property( char* name,
1028 int format,
1029 bdf_font_t* font )
1030 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001031 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001032 bdf_property_t* p;
1033 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001034 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001035
1036
Werner Lemberg96ddc672011-06-29 09:15:54 +02001037 /* First check whether the property has */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001038 /* already been added or not. If it has, then */
1039 /* simply ignore it. */
1040 if ( hash_lookup( name, &(font->proptbl) ) )
1041 goto Exit;
1042
David Turner68df4f72005-03-15 18:18:57 +00001043 if ( FT_RENEW_ARRAY( font->user_props,
1044 font->nuser_props,
1045 font->nuser_props + 1 ) )
1046 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001047
1048 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +00001049 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001050
suzuki toshiya704f4d72009-09-13 00:50:14 +09001051 n = ft_strlen( name ) + 1;
1052 if ( n > FT_ULONG_MAX )
Werner Lemberg059bc332013-03-14 10:27:35 +01001053 return FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +00001054
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001055 if ( FT_NEW_ARRAY( p->name, n ) )
1056 goto Exit;
1057
1058 FT_MEM_COPY( (char *)p->name, name, n );
1059
1060 p->format = format;
1061 p->builtin = 0;
1062
1063 n = _num_bdf_properties + font->nuser_props;
1064
suzuki toshiya704f4d72009-09-13 00:50:14 +09001065 error = hash_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001066 if ( error )
1067 goto Exit;
1068
1069 font->nuser_props++;
1070
1071 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001072 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001073 }
David Turner993a8d02002-05-18 12:03:43 +00001074
1075
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001076 FT_LOCAL_DEF( bdf_property_t * )
1077 bdf_get_property( char* name,
1078 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001079 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001080 hashnode hn;
1081 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001082
1083
1084 if ( name == 0 || *name == 0 )
1085 return 0;
1086
1087 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1088 return 0;
1089
suzuki toshiya704f4d72009-09-13 00:50:14 +09001090 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001091 if ( propid >= _num_bdf_properties )
1092 return font->user_props + ( propid - _num_bdf_properties );
1093
Werner Lemberg233302a2002-05-22 05:41:06 +00001094 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001095 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001096
1097
1098 /*************************************************************************/
1099 /* */
1100 /* BDF font file parsing flags and functions. */
1101 /* */
1102 /*************************************************************************/
1103
1104
1105 /* Parse flags. */
1106
1107#define _BDF_START 0x0001
1108#define _BDF_FONT_NAME 0x0002
1109#define _BDF_SIZE 0x0004
1110#define _BDF_FONT_BBX 0x0008
1111#define _BDF_PROPS 0x0010
1112#define _BDF_GLYPHS 0x0020
1113#define _BDF_GLYPH 0x0040
1114#define _BDF_ENCODING 0x0080
1115#define _BDF_SWIDTH 0x0100
1116#define _BDF_DWIDTH 0x0200
1117#define _BDF_BBX 0x0400
1118#define _BDF_BITMAP 0x0800
1119
1120#define _BDF_SWIDTH_ADJ 0x1000
1121
1122#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1123 _BDF_ENCODING | \
1124 _BDF_SWIDTH | \
1125 _BDF_DWIDTH | \
1126 _BDF_BBX | \
1127 _BDF_BITMAP )
1128
Werner Lembergf1c2b912006-01-13 14:53:28 +00001129#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1130#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001131
1132
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001133 static FT_Error
1134 _bdf_add_comment( bdf_font_t* font,
1135 char* comment,
1136 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001137 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001138 char* cp;
1139 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001140 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001141
1142
David Turner68df4f72005-03-15 18:18:57 +00001143 if ( FT_RENEW_ARRAY( font->comments,
1144 font->comments_len,
1145 font->comments_len + len + 1 ) )
1146 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001147
1148 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001149
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001150 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001151 cp[len] = '\n';
1152
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001153 font->comments_len += len + 1;
1154
1155 Exit:
1156 return error;
David Turner993a8d02002-05-18 12:03:43 +00001157 }
1158
David Turner993a8d02002-05-18 12:03:43 +00001159
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001160 /* Set the spacing from the font name if it exists, or set it to the */
1161 /* default specified in the options. */
1162 static FT_Error
1163 _bdf_set_default_spacing( bdf_font_t* font,
Werner Lemberge01406b2011-11-25 09:44:28 +01001164 bdf_options_t* opts,
1165 unsigned long lineno )
David Turner993a8d02002-05-18 12:03:43 +00001166 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001167 size_t len;
1168 char name[256];
1169 _bdf_list_t list;
1170 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001171 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001172
David Turner993a8d02002-05-18 12:03:43 +00001173
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001174 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1175 {
Werner Lemberg059bc332013-03-14 10:27:35 +01001176 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001177 goto Exit;
1178 }
David Turner993a8d02002-05-18 12:03:43 +00001179
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001180 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001181
David Turner68df4f72005-03-15 18:18:57 +00001182 _bdf_list_init( &list, memory );
1183
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001184 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001185
suzuki toshiya704f4d72009-09-13 00:50:14 +09001186 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +00001187 /* Limit ourselves to 256 characters in the font name. */
1188 if ( len >= 256 )
1189 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001190 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001191 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001192 goto Exit;
1193 }
1194
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001195 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001196
David Turner68df4f72005-03-15 18:18:57 +00001197 error = _bdf_list_split( &list, (char *)"-", name, len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001198 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001199 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001200
1201 if ( list.used == 15 )
1202 {
1203 switch ( list.field[11][0] )
1204 {
1205 case 'C':
1206 case 'c':
1207 font->spacing = BDF_CHARCELL;
1208 break;
1209 case 'M':
1210 case 'm':
1211 font->spacing = BDF_MONOWIDTH;
1212 break;
1213 case 'P':
1214 case 'p':
1215 font->spacing = BDF_PROPORTIONAL;
1216 break;
David Turner993a8d02002-05-18 12:03:43 +00001217 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001218 }
1219
David Turner68df4f72005-03-15 18:18:57 +00001220 Fail:
1221 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001222
1223 Exit:
1224 return error;
David Turner993a8d02002-05-18 12:03:43 +00001225 }
David Turner993a8d02002-05-18 12:03:43 +00001226
1227
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001228 /* Determine whether the property is an atom or not. If it is, then */
1229 /* clean it up so the double quotes are removed if they exist. */
1230 static int
1231 _bdf_is_atom( char* line,
1232 unsigned long linelen,
1233 char** name,
1234 char** value,
1235 bdf_font_t* font )
1236 {
1237 int hold;
1238 char *sp, *ep;
1239 bdf_property_t* p;
1240
David Turner993a8d02002-05-18 12:03:43 +00001241
1242 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001243
1244 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001245 ep++;
1246
1247 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001248 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001249 {
1250 hold = *ep;
1251 *ep = 0;
1252 }
1253
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001254 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001255
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001256 /* Restore the character that was saved before any return can happen. */
1257 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001258 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001259
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001260 /* If the property exists and is not an atom, just return here. */
1261 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001262 return 0;
1263
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001264 /* The property is an atom. Trim all leading and trailing whitespace */
1265 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001266 sp = ep;
1267 ep = line + linelen;
1268
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001269 /* Trim the leading whitespace if it exists. */
Werner Lemberg320d4972012-02-24 18:06:46 +01001270 if ( *sp )
1271 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001272 while ( *sp &&
1273 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001274 sp++;
1275
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001276 /* Trim the leading double quote if it exists. */
1277 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001278 sp++;
1279 *value = sp;
1280
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001281 /* Trim the trailing whitespace if it exists. */
1282 while ( ep > sp &&
1283 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001284 *--ep = 0;
1285
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001286 /* Trim the trailing double quote if it exists. */
1287 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001288 *--ep = 0;
1289
1290 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001291 }
David Turner993a8d02002-05-18 12:03:43 +00001292
1293
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001294 static FT_Error
Werner Lemberge01406b2011-11-25 09:44:28 +01001295 _bdf_add_property( bdf_font_t* font,
1296 char* name,
1297 char* value,
1298 unsigned long lineno )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001299 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001300 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001301 hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001302 bdf_property_t *prop, *fp;
1303 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001304 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001305
David Turner993a8d02002-05-18 12:03:43 +00001306
Werner Lemberg96ddc672011-06-29 09:15:54 +02001307 /* First, check whether the property already exists in the font. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001308 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001309 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001310 /* The property already exists in the font, so simply replace */
1311 /* the value of the property with the current value. */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001312 fp = font->props + hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001313
David Turnerb1b47622002-05-21 21:17:43 +00001314 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001315 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001316 case BDF_ATOM:
1317 /* Delete the current atom if it exists. */
1318 FT_FREE( fp->value.atom );
1319
David Turnerc0f9c4a2007-02-12 14:55:03 +00001320 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001321 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001322 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001323 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001324 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001325 break;
1326
1327 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001328 fp->value.l = _bdf_atol( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001329 break;
1330
1331 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001332 fp->value.ul = _bdf_atoul( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001333 break;
David Turnerd490e372002-05-28 23:40:37 +00001334
David Turnerb1b47622002-05-21 21:17:43 +00001335 default:
1336 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001337 }
David Turnerd490e372002-05-28 23:40:37 +00001338
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001339 goto Exit;
1340 }
1341
1342 /* See whether this property type exists yet or not. */
1343 /* If not, create it. */
1344 hn = hash_lookup( name, &(font->proptbl) );
1345 if ( hn == 0 )
1346 {
1347 error = bdf_create_property( name, BDF_ATOM, font );
1348 if ( error )
1349 goto Exit;
1350 hn = hash_lookup( name, &(font->proptbl) );
1351 }
1352
1353 /* Allocate another property if this is overflow. */
1354 if ( font->props_used == font->props_size )
1355 {
1356 if ( font->props_size == 0 )
1357 {
1358 if ( FT_NEW_ARRAY( font->props, 1 ) )
1359 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001360 }
1361 else
1362 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001363 if ( FT_RENEW_ARRAY( font->props,
1364 font->props_size,
1365 font->props_size + 1 ) )
1366 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001367 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001368
David Turner993a8d02002-05-18 12:03:43 +00001369 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001370 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001371 font->props_size++;
1372 }
1373
suzuki toshiya704f4d72009-09-13 00:50:14 +09001374 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001375 if ( propid >= _num_bdf_properties )
1376 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001377 else
David Turnerb1b47622002-05-21 21:17:43 +00001378 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001379
1380 fp = font->props + font->props_used;
1381
1382 fp->name = prop->name;
1383 fp->format = prop->format;
1384 fp->builtin = prop->builtin;
1385
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001386 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001387 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001388 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001389 fp->value.atom = 0;
1390 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001391 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001392 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001393 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001394 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001395 break;
David Turner993a8d02002-05-18 12:03:43 +00001396
1397 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001398 fp->value.l = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001399 break;
1400
1401 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001402 fp->value.ul = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001403 break;
David Turner993a8d02002-05-18 12:03:43 +00001404 }
1405
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001406 /* If the property happens to be a comment, then it doesn't need */
1407 /* to be added to the internal hash table. */
Werner Lemberg370aea82010-06-08 08:37:11 +02001408 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 )
1409 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001410 /* Add the property to the font property table. */
1411 error = hash_insert( fp->name,
suzuki toshiya704f4d72009-09-13 00:50:14 +09001412 font->props_used,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001413 (hashtable *)font->internal,
1414 memory );
1415 if ( error )
1416 goto Exit;
1417 }
David Turner993a8d02002-05-18 12:03:43 +00001418
1419 font->props_used++;
1420
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001421 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1422 /* property needs to be located if it exists in the property list, the */
1423 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1424 /* present, and the SPACING property should override the default */
1425 /* spacing. */
1426 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001427 font->default_char = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001428 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001429 font->font_ascent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001430 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001431 font->font_descent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001432 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001433 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001434 if ( !fp->value.atom )
1435 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001436 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001437 error = FT_THROW( Invalid_File_Format );
Werner Lembergb66efef2009-03-12 08:07:49 +00001438 goto Exit;
1439 }
1440
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001441 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001442 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001443 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001444 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001445 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001446 font->spacing = BDF_CHARCELL;
1447 }
1448
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001449 Exit:
1450 return error;
David Turner993a8d02002-05-18 12:03:43 +00001451 }
1452
David Turner993a8d02002-05-18 12:03:43 +00001453
David Turnerb1b47622002-05-21 21:17:43 +00001454 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001455 {
1456 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1457 };
1458
1459
1460 /* Actually parse the glyph info and bitmaps. */
1461 static FT_Error
1462 _bdf_parse_glyphs( char* line,
1463 unsigned long linelen,
1464 unsigned long lineno,
1465 void* call_data,
1466 void* client_data )
1467 {
1468 int c, mask_index;
1469 char* s;
1470 unsigned char* bp;
1471 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001472
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001473 _bdf_parse_t* p;
1474 bdf_glyph_t* glyph;
1475 bdf_font_t* font;
1476
1477 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001478 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001479
Werner Lemberg319c00d2003-04-23 19:48:24 +00001480 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001481 FT_UNUSED( lineno ); /* only used in debug mode */
1482
1483
Werner Lemberg319c00d2003-04-23 19:48:24 +00001484 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001485
1486 font = p->font;
1487 memory = font->memory;
1488
1489 /* Check for a comment. */
1490 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1491 {
1492 linelen -= 7;
1493
1494 s = line + 7;
1495 if ( *s != 0 )
1496 {
1497 s++;
1498 linelen--;
1499 }
1500 error = _bdf_add_comment( p->font, s, linelen );
1501 goto Exit;
1502 }
1503
1504 /* The very first thing expected is the number of glyphs. */
1505 if ( !( p->flags & _BDF_GLYPHS ) )
1506 {
1507 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1508 {
1509 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001510 error = FT_THROW( Missing_Chars_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001511 goto Exit;
1512 }
1513
David Turner68df4f72005-03-15 18:18:57 +00001514 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001515 if ( error )
1516 goto Exit;
1517 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1518
1519 /* Make sure the number of glyphs is non-zero. */
1520 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001521 font->glyphs_size = 64;
1522
Werner Lemberga08b2172007-03-28 07:17:17 +00001523 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1524 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001525 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001526 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001527 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001528 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001529 goto Exit;
1530 }
1531
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001532 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1533 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001534
David Turner993a8d02002-05-18 12:03:43 +00001535 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001536
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001537 goto Exit;
1538 }
1539
1540 /* Check for the ENDFONT field. */
1541 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1542 {
1543 /* Sort the glyphs by encoding. */
1544 ft_qsort( (char *)font->glyphs,
1545 font->glyphs_used,
1546 sizeof ( bdf_glyph_t ),
1547 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001548
1549 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001550
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001551 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001552 }
1553
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001554 /* Check for the ENDCHAR field. */
1555 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1556 {
1557 p->glyph_enc = 0;
1558 p->flags &= ~_BDF_GLYPH_BITS;
1559
1560 goto Exit;
1561 }
1562
Werner Lemberg96ddc672011-06-29 09:15:54 +02001563 /* Check whether a glyph is being scanned but should be */
1564 /* ignored because it is an unencoded glyph. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001565 if ( ( p->flags & _BDF_GLYPH ) &&
1566 p->glyph_enc == -1 &&
1567 p->opts->keep_unencoded == 0 )
1568 goto Exit;
1569
1570 /* Check for the STARTCHAR field. */
1571 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1572 {
1573 /* Set the character name in the parse info first until the */
1574 /* encoding can be checked for an unencoded character. */
1575 FT_FREE( p->glyph_name );
1576
David Turner68df4f72005-03-15 18:18:57 +00001577 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001578 if ( error )
1579 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001580
David Turner68df4f72005-03-15 18:18:57 +00001581 _bdf_list_shift( &p->list, 1 );
1582
1583 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001584
Werner Lembergba03af62007-05-30 13:57:02 +00001585 if ( !s )
1586 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001587 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001588 error = FT_THROW( Invalid_File_Format );
Werner Lembergba03af62007-05-30 13:57:02 +00001589 goto Exit;
1590 }
1591
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001592 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1593 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001594
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001595 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1596
1597 p->flags |= _BDF_GLYPH;
1598
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001599 FT_TRACE4(( DBGMSG1, lineno, s ));
1600
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001601 goto Exit;
1602 }
1603
1604 /* Check for the ENCODING field. */
1605 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1606 {
1607 if ( !( p->flags & _BDF_GLYPH ) )
1608 {
1609 /* Missing STARTCHAR field. */
1610 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001611 error = FT_THROW( Missing_Startchar_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001612 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001613 }
1614
David Turner68df4f72005-03-15 18:18:57 +00001615 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001616 if ( error )
1617 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001618
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001619 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001620
Werner Lemberg28dd2c42012-02-26 06:18:58 +01001621 /* Normalize negative encoding values. The specification only */
1622 /* allows -1, but we can be more generous here. */
1623 if ( p->glyph_enc < -1 )
1624 p->glyph_enc = -1;
1625
Werner Lemberg03242f52012-02-26 06:52:56 +01001626 /* Check for alternative encoding format. */
1627 if ( p->glyph_enc == -1 && p->list.used > 2 )
1628 p->glyph_enc = _bdf_atol( p->list.field[2], 0, 10 );
1629
Werner Lemberg7f2e4f42012-12-15 09:39:41 +01001630 if ( p->glyph_enc < -1 )
1631 p->glyph_enc = -1;
1632
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001633 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1634
Werner Lemberged54e432011-11-27 16:39:53 +01001635 /* Check that the encoding is in the Unicode range because */
1636 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lemberg07bdb6e2012-12-15 02:02:23 +01001637 if ( p->glyph_enc > 0 &&
1638 (size_t)p->glyph_enc >= sizeof ( p->have ) /
1639 sizeof ( unsigned long ) * 32 )
David Turner481838e2006-02-23 12:40:14 +00001640 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001641 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001642 error = FT_THROW( Invalid_File_Format );
David Turner481838e2006-02-23 12:40:14 +00001643 goto Exit;
1644 }
1645
Werner Lemberg96ddc672011-06-29 09:15:54 +02001646 /* Check whether this encoding has already been encountered. */
1647 /* If it has then change it to unencoded so it gets added if */
1648 /* indicated. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001649 if ( p->glyph_enc >= 0 )
1650 {
1651 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1652 {
1653 /* Emit a message saying a glyph has been moved to the */
1654 /* unencoded area. */
1655 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1656 p->glyph_enc, p->glyph_name ));
1657 p->glyph_enc = -1;
1658 font->modified = 1;
1659 }
1660 else
1661 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1662 }
1663
1664 if ( p->glyph_enc >= 0 )
1665 {
1666 /* Make sure there are enough glyphs allocated in case the */
1667 /* number of characters happen to be wrong. */
1668 if ( font->glyphs_used == font->glyphs_size )
1669 {
1670 if ( FT_RENEW_ARRAY( font->glyphs,
1671 font->glyphs_size,
1672 font->glyphs_size + 64 ) )
1673 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001674
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001675 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001676 }
1677
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001678 glyph = font->glyphs + font->glyphs_used++;
1679 glyph->name = p->glyph_name;
1680 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001681
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001682 /* Reset the initial glyph info. */
1683 p->glyph_name = 0;
1684 }
1685 else
1686 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001687 /* Unencoded glyph. Check whether it should */
1688 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001689 if ( p->opts->keep_unencoded != 0 )
1690 {
1691 /* Allocate the next unencoded glyph. */
1692 if ( font->unencoded_used == font->unencoded_size )
1693 {
David Turner68df4f72005-03-15 18:18:57 +00001694 if ( FT_RENEW_ARRAY( font->unencoded ,
1695 font->unencoded_size,
1696 font->unencoded_size + 4 ) )
1697 goto Exit;
1698
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001699 font->unencoded_size += 4;
1700 }
1701
1702 glyph = font->unencoded + font->unencoded_used;
1703 glyph->name = p->glyph_name;
1704 glyph->encoding = font->unencoded_used++;
1705 }
1706 else
1707 /* Free up the glyph name if the unencoded shouldn't be */
1708 /* kept. */
1709 FT_FREE( p->glyph_name );
1710
1711 p->glyph_name = 0;
1712 }
1713
1714 /* Clear the flags that might be added when width and height are */
1715 /* checked for consistency. */
1716 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1717
1718 p->flags |= _BDF_ENCODING;
1719
1720 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001721 }
1722
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001723 /* Point at the glyph being constructed. */
1724 if ( p->glyph_enc == -1 )
1725 glyph = font->unencoded + ( font->unencoded_used - 1 );
1726 else
1727 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001728
Werner Lemberg96ddc672011-06-29 09:15:54 +02001729 /* Check whether a bitmap is being constructed. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001730 if ( p->flags & _BDF_BITMAP )
1731 {
1732 /* If there are more rows than are specified in the glyph metrics, */
1733 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001734 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001735 {
1736 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1737 {
1738 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1739 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001740 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001741 }
1742
1743 goto Exit;
1744 }
1745
1746 /* Only collect the number of nibbles indicated by the glyph */
1747 /* metrics. If there are more columns, they are simply ignored. */
1748 nibbles = glyph->bpr << 1;
1749 bp = glyph->bitmap + p->row * glyph->bpr;
1750
David Turnerb698eed2006-02-23 14:50:13 +00001751 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001752 {
1753 c = line[i];
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001754 if ( !sbitset( hdigits, c ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001755 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001756 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001757 if ( i + 1 < nibbles && ( i & 1 ) )
1758 *++bp = 0;
1759 }
1760
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001761 /* If any line has not enough columns, */
1762 /* indicate they have been padded with zero bits. */
1763 if ( i < nibbles &&
1764 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1765 {
1766 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
1767 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1768 font->modified = 1;
1769 }
1770
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001771 /* Remove possible garbage at the right. */
1772 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001773 if ( glyph->bbx.width )
1774 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001775
1776 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001777 if ( i == nibbles &&
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001778 sbitset( hdigits, line[nibbles] ) &&
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001779 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001780 {
1781 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1782 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1783 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001784 }
1785
1786 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001787 goto Exit;
1788 }
David Turner993a8d02002-05-18 12:03:43 +00001789
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001790 /* Expect the SWIDTH (scalable width) field next. */
1791 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1792 {
1793 if ( !( p->flags & _BDF_ENCODING ) )
Werner Lemberg4086fb72012-03-01 08:55:40 +01001794 goto Missing_Encoding;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001795
David Turner68df4f72005-03-15 18:18:57 +00001796 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001797 if ( error )
1798 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001799
David Turnerb1b47622002-05-21 21:17:43 +00001800 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001801 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001802
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001803 goto Exit;
1804 }
David Turner993a8d02002-05-18 12:03:43 +00001805
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001806 /* Expect the DWIDTH (scalable width) field next. */
1807 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1808 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001809 if ( !( p->flags & _BDF_ENCODING ) )
1810 goto Missing_Encoding;
1811
David Turner68df4f72005-03-15 18:18:57 +00001812 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001813 if ( error )
1814 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001815
David Turnerb1b47622002-05-21 21:17:43 +00001816 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001817
1818 if ( !( p->flags & _BDF_SWIDTH ) )
1819 {
1820 /* Missing SWIDTH field. Emit an auto correction message and set */
1821 /* the scalable width from the device width. */
1822 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1823
Werner Lemberg02d4d592002-05-28 22:38:05 +00001824 glyph->swidth = (unsigned short)FT_MulDiv(
1825 glyph->dwidth, 72000L,
1826 (FT_Long)( font->point_size *
1827 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001828 }
1829
1830 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001831 goto Exit;
1832 }
David Turner993a8d02002-05-18 12:03:43 +00001833
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001834 /* Expect the BBX field next. */
1835 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1836 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001837 if ( !( p->flags & _BDF_ENCODING ) )
1838 goto Missing_Encoding;
1839
David Turner68df4f72005-03-15 18:18:57 +00001840 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001841 if ( error )
1842 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001843
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001844 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1845 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1846 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1847 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1848
1849 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001850 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1851 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001852
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001853 /* Determine the overall font bounding box as the characters are */
1854 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001855 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1856 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001857
David Turnerb1b47622002-05-21 21:17:43 +00001858 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001859
Werner Lembergdfa46192004-03-05 09:26:24 +00001860 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1861 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1862 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001863
1864 if ( !( p->flags & _BDF_DWIDTH ) )
1865 {
1866 /* Missing DWIDTH field. Emit an auto correction message and set */
1867 /* the device width to the glyph width. */
1868 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1869 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001870 }
1871
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001872 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1873 /* value if necessary. */
1874 if ( p->opts->correct_metrics != 0 )
1875 {
1876 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001877 unsigned short sw = (unsigned short)FT_MulDiv(
1878 glyph->dwidth, 72000L,
1879 (FT_Long)( font->point_size *
1880 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001881
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001882
1883 if ( sw != glyph->swidth )
1884 {
1885 glyph->swidth = sw;
1886
1887 if ( p->glyph_enc == -1 )
1888 _bdf_set_glyph_modified( font->umod,
1889 font->unencoded_used - 1 );
1890 else
1891 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1892
1893 p->flags |= _BDF_SWIDTH_ADJ;
1894 font->modified = 1;
1895 }
David Turner993a8d02002-05-18 12:03:43 +00001896 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001897
David Turner993a8d02002-05-18 12:03:43 +00001898 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001899 goto Exit;
1900 }
David Turner993a8d02002-05-18 12:03:43 +00001901
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001902 /* And finally, gather up the bitmap. */
1903 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1904 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001905 unsigned long bitmap_size;
1906
1907
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001908 if ( !( p->flags & _BDF_BBX ) )
1909 {
1910 /* Missing BBX field. */
1911 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001912 error = FT_THROW( Missing_Bbx_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001913 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001914 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001915
1916 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001917 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001918
1919 bitmap_size = glyph->bpr * glyph->bbx.height;
Werner Lembergc4cad302012-03-08 20:11:37 +01001920 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
Werner Lemberg26170df2006-03-26 07:19:07 +00001921 {
1922 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001923 error = FT_THROW( Bbx_Too_Big );
Werner Lemberg26170df2006-03-26 07:19:07 +00001924 goto Exit;
1925 }
1926 else
1927 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001928
1929 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1930 goto Exit;
1931
1932 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001933 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001934
1935 goto Exit;
1936 }
1937
Werner Lemberge01406b2011-11-25 09:44:28 +01001938 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001939 error = FT_THROW( Invalid_File_Format );
Werner Lemberg4086fb72012-03-01 08:55:40 +01001940 goto Exit;
1941
1942 Missing_Encoding:
1943 /* Missing ENCODING field. */
1944 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001945 error = FT_THROW( Missing_Encoding_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001946
1947 Exit:
Werner Lembergf4c94d42010-06-19 16:08:31 +02001948 if ( error && ( p->flags & _BDF_GLYPH ) )
1949 FT_FREE( p->glyph_name );
1950
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001951 return error;
David Turner993a8d02002-05-18 12:03:43 +00001952 }
1953
David Turner993a8d02002-05-18 12:03:43 +00001954
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001955 /* Load the font properties. */
1956 static FT_Error
1957 _bdf_parse_properties( char* line,
1958 unsigned long linelen,
1959 unsigned long lineno,
1960 void* call_data,
1961 void* client_data )
1962 {
1963 unsigned long vlen;
1964 _bdf_line_func_t* next;
1965 _bdf_parse_t* p;
1966 char* name;
1967 char* value;
1968 char nbuf[128];
Werner Lemberge3c93012013-03-14 11:21:17 +01001969 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001970
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001971 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001972
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001973
1974 next = (_bdf_line_func_t *)call_data;
1975 p = (_bdf_parse_t *) client_data;
1976
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001977 /* Check for the end of the properties. */
1978 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1979 {
1980 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1981 /* encountered yet, then make sure they are added as properties and */
1982 /* make sure they are set from the font bounding box info. */
1983 /* */
1984 /* This is *always* done regardless of the options, because X11 */
1985 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001986 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001987 {
1988 p->font->font_ascent = p->font->bbx.ascent;
1989 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001990 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
1991 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001992 if ( error )
1993 goto Exit;
1994
1995 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1996 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001997 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001998
Werner Lemberg428c2e42003-04-25 05:35:04 +00001999 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002000 {
2001 p->font->font_descent = p->font->bbx.descent;
2002 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002003 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2004 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002005 if ( error )
2006 goto Exit;
2007
2008 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2009 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002010 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002011
David Turner993a8d02002-05-18 12:03:43 +00002012 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002013 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00002014
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002015 goto Exit;
2016 }
David Turner993a8d02002-05-18 12:03:43 +00002017
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002018 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
2019 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
2020 goto Exit;
2021
2022 /* Handle COMMENT fields and properties in a special way to preserve */
2023 /* the spacing. */
2024 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2025 {
David Turner993a8d02002-05-18 12:03:43 +00002026 name = value = line;
2027 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002028 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00002029 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01002030 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002031 if ( error )
2032 goto Exit;
2033 }
2034 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
2035 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002036 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002037 if ( error )
2038 goto Exit;
2039 }
2040 else
2041 {
David Turner68df4f72005-03-15 18:18:57 +00002042 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002043 if ( error )
2044 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002045 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002046
David Turner68df4f72005-03-15 18:18:57 +00002047 _bdf_list_shift( &p->list, 1 );
2048 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002049
Werner Lemberge01406b2011-11-25 09:44:28 +01002050 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002051 if ( error )
2052 goto Exit;
2053 }
2054
2055 Exit:
2056 return error;
David Turner993a8d02002-05-18 12:03:43 +00002057 }
2058
David Turner993a8d02002-05-18 12:03:43 +00002059
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002060 /* Load the font header. */
2061 static FT_Error
2062 _bdf_parse_start( char* line,
2063 unsigned long linelen,
2064 unsigned long lineno,
2065 void* call_data,
2066 void* client_data )
2067 {
2068 unsigned long slen;
2069 _bdf_line_func_t* next;
2070 _bdf_parse_t* p;
2071 bdf_font_t* font;
2072 char *s;
David Turner993a8d02002-05-18 12:03:43 +00002073
David Turnerd490e372002-05-28 23:40:37 +00002074 FT_Memory memory = NULL;
Werner Lemberge3c93012013-03-14 11:21:17 +01002075 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002076
2077 FT_UNUSED( lineno ); /* only used in debug mode */
2078
2079
2080 next = (_bdf_line_func_t *)call_data;
2081 p = (_bdf_parse_t *) client_data;
2082
2083 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00002084 memory = p->font->memory;
2085
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002086 /* Check for a comment. This is done to handle those fonts that have */
2087 /* comments before the STARTFONT line for some reason. */
2088 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2089 {
2090 if ( p->opts->keep_comments != 0 && p->font != 0 )
2091 {
2092 linelen -= 7;
2093
2094 s = line + 7;
2095 if ( *s != 0 )
2096 {
2097 s++;
2098 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002099 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002100
2101 error = _bdf_add_comment( p->font, s, linelen );
2102 if ( error )
2103 goto Exit;
2104 /* here font is not defined! */
2105 }
2106
2107 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002108 }
2109
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002110 if ( !( p->flags & _BDF_START ) )
2111 {
2112 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002113
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002114 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2115 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01002116 /* we don't emit an error message since this code gets */
2117 /* explicitly caught one level higher */
Werner Lemberg059bc332013-03-14 10:27:35 +01002118 error = FT_THROW( Missing_Startfont_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002119 goto Exit;
2120 }
David Turner993a8d02002-05-18 12:03:43 +00002121
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002122 p->flags = _BDF_START;
2123 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002124
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002125 if ( FT_NEW( font ) )
2126 goto Exit;
2127 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002128
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002129 font->memory = p->memory;
2130 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002131
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002132 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09002133 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002134 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002135
David Turner993a8d02002-05-18 12:03:43 +00002136
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002137 error = hash_init( &(font->proptbl), memory );
2138 if ( error )
2139 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002140 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002141 i < _num_bdf_properties; i++, prop++ )
2142 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09002143 error = hash_insert( prop->name, i,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002144 &(font->proptbl), memory );
2145 if ( error )
2146 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002147 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002148 }
2149
2150 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2151 goto Exit;
2152 error = hash_init( (hashtable *)p->font->internal,memory );
2153 if ( error )
2154 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002155 p->font->spacing = p->opts->font_spacing;
2156 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002157
2158 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002159 }
2160
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002161 /* Check for the start of the properties. */
2162 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2163 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002164 if ( !( p->flags & _BDF_FONT_BBX ) )
Werner Lembergfb690292010-06-23 10:00:52 +02002165 {
2166 /* Missing the FONTBOUNDINGBOX field. */
2167 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002168 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergfb690292010-06-23 10:00:52 +02002169 goto Exit;
2170 }
2171
David Turner68df4f72005-03-15 18:18:57 +00002172 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002173 if ( error )
2174 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00002175 /* at this point, `p->font' can't be NULL */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002176 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2177
2178 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
Werner Lemberg9b6b5752012-12-15 01:34:41 +01002179 {
2180 p->font->props_size = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002181 goto Exit;
Werner Lemberg9b6b5752012-12-15 01:34:41 +01002182 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002183
2184 p->flags |= _BDF_PROPS;
2185 *next = _bdf_parse_properties;
2186
2187 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002188 }
2189
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002190 /* Check for the FONTBOUNDINGBOX field. */
2191 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2192 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002193 if ( !( p->flags & _BDF_SIZE ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002194 {
2195 /* Missing the SIZE field. */
2196 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002197 error = FT_THROW( Missing_Size_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002198 goto Exit;
2199 }
2200
David Turner68df4f72005-03-15 18:18:57 +00002201 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002202 if ( error )
2203 goto Exit;
2204
2205 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2206 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2207
2208 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2209 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2210
David Turnerd490e372002-05-28 23:40:37 +00002211 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002212 p->font->bbx.y_offset );
2213
2214 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002215
2216 p->flags |= _BDF_FONT_BBX;
2217
2218 goto Exit;
2219 }
2220
2221 /* The next thing to check for is the FONT field. */
2222 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2223 {
David Turner68df4f72005-03-15 18:18:57 +00002224 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002225 if ( error )
2226 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002227 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002228
David Turner68df4f72005-03-15 18:18:57 +00002229 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002230
2231 if ( !s )
2232 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002233 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002234 error = FT_THROW( Invalid_File_Format );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002235 goto Exit;
2236 }
2237
Werner Lembergfb690292010-06-23 10:00:52 +02002238 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2239 FT_FREE( p->font->name );
2240
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002241 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2242 goto Exit;
2243 FT_MEM_COPY( p->font->name, s, slen + 1 );
2244
2245 /* If the font name is an XLFD name, set the spacing to the one in */
2246 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002247 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002248 if ( error )
2249 goto Exit;
2250
2251 p->flags |= _BDF_FONT_NAME;
2252
2253 goto Exit;
2254 }
2255
2256 /* Check for the SIZE field. */
2257 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2258 {
2259 if ( !( p->flags & _BDF_FONT_NAME ) )
2260 {
2261 /* Missing the FONT field. */
2262 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002263 error = FT_THROW( Missing_Font_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002264 goto Exit;
2265 }
2266
David Turner68df4f72005-03-15 18:18:57 +00002267 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002268 if ( error )
2269 goto Exit;
2270
2271 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2272 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2273 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2274
2275 /* Check for the bits per pixel field. */
2276 if ( p->list.used == 5 )
2277 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002278 unsigned short bitcount, i, shift;
2279
2280
2281 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2282
2283 /* Only values 1, 2, 4, 8 are allowed. */
2284 shift = p->font->bpp;
2285 bitcount = 0;
2286 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002287 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002288 if ( shift & 1 )
2289 bitcount = i;
2290 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002291 }
David Turner993a8d02002-05-18 12:03:43 +00002292
Werner Lembergbd8e3242002-06-12 08:43:58 +00002293 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002294
2295 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002296 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002297 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002298 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002299 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002300 }
2301 }
2302 else
2303 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002304
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002305 p->flags |= _BDF_SIZE;
2306
2307 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002308 }
2309
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002310 /* Check for the CHARS field -- font properties are optional */
2311 if ( ft_memcmp( line, "CHARS", 5 ) == 0 )
2312 {
2313 char nbuf[128];
2314
2315
2316 if ( !( p->flags & _BDF_FONT_BBX ) )
2317 {
2318 /* Missing the FONTBOUNDINGBOX field. */
2319 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002320 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002321 goto Exit;
2322 }
2323
2324 /* Add the two standard X11 properties which are required */
2325 /* for compiling fonts. */
2326 p->font->font_ascent = p->font->bbx.ascent;
2327 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002328 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2329 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002330 if ( error )
2331 goto Exit;
2332 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2333
2334 p->font->font_descent = p->font->bbx.descent;
2335 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002336 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2337 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002338 if ( error )
2339 goto Exit;
2340 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2341
2342 p->font->modified = 1;
2343
2344 *next = _bdf_parse_glyphs;
2345
2346 /* A special return value. */
2347 error = -1;
2348 goto Exit;
2349 }
2350
Werner Lemberge01406b2011-11-25 09:44:28 +01002351 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002352 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002353
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002354 Exit:
2355 return error;
2356 }
David Turner993a8d02002-05-18 12:03:43 +00002357
2358
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002359 /*************************************************************************/
2360 /* */
2361 /* API. */
2362 /* */
2363 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002364
David Turner993a8d02002-05-18 12:03:43 +00002365
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002366 FT_LOCAL_DEF( FT_Error )
2367 bdf_load_font( FT_Stream stream,
2368 FT_Memory extmemory,
2369 bdf_options_t* opts,
2370 bdf_font_t* *font )
2371 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002372 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002373 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002374
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002375 FT_Memory memory = extmemory;
Werner Lemberge3c93012013-03-14 11:21:17 +01002376 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002377
2378
David Turner68df4f72005-03-15 18:18:57 +00002379 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002380 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002381
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002382 memory = NULL;
2383 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2384 p->minlb = 32767;
2385 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002386
David Turner68df4f72005-03-15 18:18:57 +00002387 _bdf_list_init( &p->list, extmemory );
2388
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002389 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002390 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002391 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002392 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002393
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002394 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002395 {
2396 /* If the font is not proportional, set the font's monowidth */
2397 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002398 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002399
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002400 if ( p->font->spacing != BDF_PROPORTIONAL )
2401 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002402
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002403 /* If the number of glyphs loaded is not that of the original count, */
2404 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002405 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002406 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002407 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2408 p->font->glyphs_used + p->font->unencoded_used ));
2409 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002410 }
2411
2412 /* Once the font has been loaded, adjust the overall font metrics if */
2413 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002414 if ( p->opts->correct_metrics != 0 &&
2415 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002416 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002417 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002418 {
2419 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002420 p->font->bbx.width, p->maxrb - p->minlb ));
2421 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2422 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002423 }
2424
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002425 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002426 {
2427 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002428 p->font->bbx.x_offset, p->minlb ));
2429 p->font->bbx.x_offset = p->minlb;
2430 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002431 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002432
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002433 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002434 {
2435 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002436 p->font->bbx.ascent, p->maxas ));
2437 p->font->bbx.ascent = p->maxas;
2438 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002439 }
2440
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002441 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002442 {
2443 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002444 p->font->bbx.descent, p->maxds ));
2445 p->font->bbx.descent = p->maxds;
2446 p->font->bbx.y_offset = (short)( -p->maxds );
2447 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002448 }
2449
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002450 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002451 {
2452 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002453 p->font->bbx.height, p->maxas + p->maxds ));
2454 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002455 }
2456
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002457 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002458 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2459 }
David Turner993a8d02002-05-18 12:03:43 +00002460 }
2461
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002462 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002463 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002464 /* The ENDFONT field was never reached or did not exist. */
2465 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002466 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002467 /* Error happened while parsing header. */
2468 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002469 error = FT_THROW( Corrupted_Font_Header );
Werner Lemberge01406b2011-11-25 09:44:28 +01002470 goto Exit;
2471 }
2472 else
2473 {
2474 /* Error happened when parsing glyphs. */
2475 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002476 error = FT_THROW( Corrupted_Font_Glyphs );
Werner Lemberge01406b2011-11-25 09:44:28 +01002477 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002478 }
David Turner993a8d02002-05-18 12:03:43 +00002479 }
2480
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002481 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002482 {
2483 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002484 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002485
Werner Lemberg370aea82010-06-08 08:37:11 +02002486 if ( p->font->comments_len > 0 )
2487 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002488 if ( FT_RENEW_ARRAY( p->font->comments,
2489 p->font->comments_len,
2490 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002491 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002492
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002493 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002494 }
David Turner993a8d02002-05-18 12:03:43 +00002495 }
Werner Lemberge3c93012013-03-14 11:21:17 +01002496 else if ( error == FT_Err_Ok )
Werner Lemberg059bc332013-03-14 10:27:35 +01002497 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002498
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002499 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002500
2501 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002502 if ( p )
2503 {
David Turner68df4f72005-03-15 18:18:57 +00002504 _bdf_list_done( &p->list );
2505
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002506 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002507
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002508 FT_FREE( p );
2509 }
2510
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002511 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002512
2513 Fail:
2514 bdf_free_font( p->font );
2515
2516 memory = extmemory;
2517
2518 FT_FREE( p->font );
2519
2520 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002521 }
David Turner993a8d02002-05-18 12:03:43 +00002522
2523
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002524 FT_LOCAL_DEF( void )
2525 bdf_free_font( bdf_font_t* font )
2526 {
2527 bdf_property_t* prop;
2528 unsigned long i;
2529 bdf_glyph_t* glyphs;
2530 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002531
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002532
2533 if ( font == 0 )
2534 return;
David Turner993a8d02002-05-18 12:03:43 +00002535
2536 memory = font->memory;
2537
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002538 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002539
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002540 /* Free up the internal hash table of property names. */
2541 if ( font->internal )
2542 {
2543 hash_free( (hashtable *)font->internal, memory );
2544 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002545 }
2546
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002547 /* Free up the comment info. */
2548 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002549
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002550 /* Free up the properties. */
2551 for ( i = 0; i < font->props_size; i++ )
2552 {
2553 if ( font->props[i].format == BDF_ATOM )
2554 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002555 }
2556
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002557 FT_FREE( font->props );
2558
2559 /* Free up the character info. */
2560 for ( i = 0, glyphs = font->glyphs;
2561 i < font->glyphs_used; i++, glyphs++ )
2562 {
2563 FT_FREE( glyphs->name );
2564 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002565 }
2566
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002567 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2568 i++, glyphs++ )
2569 {
2570 FT_FREE( glyphs->name );
2571 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002572 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002573
2574 FT_FREE( font->glyphs );
2575 FT_FREE( font->unencoded );
2576
2577 /* Free up the overflow storage if it was used. */
2578 for ( i = 0, glyphs = font->overflow.glyphs;
2579 i < font->overflow.glyphs_used; i++, glyphs++ )
2580 {
2581 FT_FREE( glyphs->name );
2582 FT_FREE( glyphs->bitmap );
2583 }
2584
2585 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002586
2587 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002588 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002589
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002590 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002591 for ( prop = font->user_props, i = 0;
2592 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002593 {
2594 FT_FREE( prop->name );
2595 if ( prop->format == BDF_ATOM )
2596 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002597 }
David Turner993a8d02002-05-18 12:03:43 +00002598
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002599 FT_FREE( font->user_props );
2600
2601 /* FREE( font ); */ /* XXX Fixme */
2602 }
David Turner993a8d02002-05-18 12:03:43 +00002603
2604
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002605 FT_LOCAL_DEF( bdf_property_t * )
2606 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002607 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002608 {
2609 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002610
David Turner993a8d02002-05-18 12:03:43 +00002611
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002612 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002613 return 0;
2614
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002615 hn = hash_lookup( name, (hashtable *)font->internal );
2616
suzuki toshiya704f4d72009-09-13 00:50:14 +09002617 return hn ? ( font->props + hn->data ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002618 }
2619
2620
2621/* END */