blob: be0e3987e4fa9e43463fad2c70334264ed1d4eca [file] [log] [blame]
David Turner993a8d02002-05-18 12:03:43 +00001/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
Werner Lembergdfa46192004-03-05 09:26:24 +00003 * Copyright 2001, 2002, 2003, 2004 Francesco Zappa Nardelli
David Turner993a8d02002-05-18 12:03:43 +00004 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
20 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
Werner Lemberg7cf4d372002-05-21 14:13:01 +000024 /*************************************************************************/
25 /* */
26 /* This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 */
27 /* */
28 /* taken from Mark Leisher's xmbdfed package */
29 /* */
30 /*************************************************************************/
31
David Turner993a8d02002-05-18 12:03:43 +000032
33#include <ft2build.h>
34
Werner Lemberg02d4d592002-05-28 22:38:05 +000035#include FT_FREETYPE_H
David Turner993a8d02002-05-18 12:03:43 +000036#include FT_INTERNAL_DEBUG_H
37#include FT_INTERNAL_STREAM_H
38#include FT_INTERNAL_OBJECTS_H
39
40#include "bdf.h"
David Turner993a8d02002-05-18 12:03:43 +000041#include "bdferror.h"
42
David Turner993a8d02002-05-18 12:03:43 +000043
Werner Lemberg7cf4d372002-05-21 14:13:01 +000044 /*************************************************************************/
45 /* */
46 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
47 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
48 /* messages during execution. */
49 /* */
50#undef FT_COMPONENT
51#define FT_COMPONENT trace_bdflib
David Turner993a8d02002-05-18 12:03:43 +000052
David Turner993a8d02002-05-18 12:03:43 +000053
Werner Lemberg7cf4d372002-05-21 14:13:01 +000054 /*************************************************************************/
55 /* */
56 /* Default BDF font options. */
57 /* */
58 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000059
David Turner993a8d02002-05-18 12:03:43 +000060
David Turnerb1b47622002-05-21 21:17:43 +000061 static const bdf_options_t _bdf_opts =
Werner Lemberg7cf4d372002-05-21 14:13:01 +000062 {
David Turner993a8d02002-05-18 12:03:43 +000063 1, /* Correct metrics. */
64 1, /* Preserve unencoded glyphs. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000065 0, /* Preserve comments. */
66 BDF_PROPORTIONAL /* Default spacing. */
67 };
David Turner993a8d02002-05-18 12:03:43 +000068
David Turner993a8d02002-05-18 12:03:43 +000069
Werner Lemberg7cf4d372002-05-21 14:13:01 +000070 /*************************************************************************/
71 /* */
72 /* Builtin BDF font properties. */
73 /* */
74 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000075
Werner Lemberg7cf4d372002-05-21 14:13:01 +000076 /* List of most properties that might appear in a font. Doesn't include */
77 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
David Turner993a8d02002-05-18 12:03:43 +000078
David Turnerb1b47622002-05-21 21:17:43 +000079 static const bdf_property_t _bdf_properties[] =
David Turner993a8d02002-05-18 12:03:43 +000080 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +000081 { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
82 { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
83 { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
84 { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
85 { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
86 { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
87 { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
88 { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
89 { (char *)"COMMENT", BDF_ATOM, 1, { 0 } },
90 { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } },
91 { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
92 { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } },
93 { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
94 { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } },
95 { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } },
96 { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } },
97 { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
98 { (char *)"FONT", BDF_ATOM, 1, { 0 } },
99 { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
100 { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
101 { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
102 { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } },
103 { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } },
104 { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
105 { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } },
106 { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } },
107 { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } },
108 { (char *)"NOTICE", BDF_ATOM, 1, { 0 } },
109 { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
110 { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } },
111 { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
112 { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
113 { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
114 { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
115 { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
116 { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
117 { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
118 { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
119 { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
120 { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
121 { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
122 { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
123 { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
124 { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
125 { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
126 { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
127 { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
128 { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
129 { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
130 { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
131 { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
132 { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
133 { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
134 { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
135 { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
136 { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
137 { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
138 { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
139 { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
140 { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
141 { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
142 { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } },
143 { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
144 { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
145 { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
146 { (char *)"SLANT", BDF_ATOM, 1, { 0 } },
147 { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
148 { (char *)"SPACING", BDF_ATOM, 1, { 0 } },
149 { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
150 { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
151 { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
152 { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
153 { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
154 { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
155 { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
156 { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
157 { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
158 { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
159 { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } },
160 { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
161 { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } },
162 { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
163 { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
164 };
David Turner993a8d02002-05-18 12:03:43 +0000165
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000166 static const unsigned long
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000167 _num_bdf_properties = sizeof ( _bdf_properties ) /
168 sizeof ( _bdf_properties[0] );
David Turner993a8d02002-05-18 12:03:43 +0000169
170
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000171 /*************************************************************************/
172 /* */
173 /* Hash table utilities for the properties. */
174 /* */
175 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +0000176
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000177 /* XXX: Replace this with FreeType's hash functions */
David Turner993a8d02002-05-18 12:03:43 +0000178
David Turner993a8d02002-05-18 12:03:43 +0000179
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000180#define INITIAL_HT_SIZE 241
181
182 typedef void
183 (*hash_free_func)( hashnode node );
184
185 static hashnode*
Werner Lemberg428c2e42003-04-25 05:35:04 +0000186 hash_bucket( const char* key,
187 hashtable* ht )
David Turner993a8d02002-05-18 12:03:43 +0000188 {
Werner Lemberg428c2e42003-04-25 05:35:04 +0000189 const char* kp = key;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000190 unsigned long res = 0;
191 hashnode* bp = ht->table, *ndp;
192
193
194 /* Mocklisp hash function. */
195 while ( *kp )
196 res = ( res << 5 ) - res + *kp++;
197
198 ndp = bp + ( res % ht->size );
199 while ( *ndp )
David Turner993a8d02002-05-18 12:03:43 +0000200 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000201 kp = (*ndp)->key;
202 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
203 break;
204 ndp--;
205 if ( ndp < bp )
206 ndp = bp + ( ht->size - 1 );
David Turner993a8d02002-05-18 12:03:43 +0000207 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000208
209 return ndp;
David Turner993a8d02002-05-18 12:03:43 +0000210 }
David Turner993a8d02002-05-18 12:03:43 +0000211
212
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000213 static FT_Error
214 hash_rehash( hashtable* ht,
215 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000216 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000217 hashnode* obp = ht->table, *bp, *nbp;
David Turner993a8d02002-05-18 12:03:43 +0000218 int i, sz = ht->size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000219 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000220
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000221
222 ht->size <<= 1;
223 ht->limit = ht->size / 3;
224
225 if ( FT_NEW_ARRAY( ht->table, ht->size ) )
226 goto Exit;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000227 FT_MEM_ZERO( ht->table, sizeof ( hashnode ) * ht->size );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000228
229 for ( i = 0, bp = obp; i < sz; i++, bp++ )
David Turner993a8d02002-05-18 12:03:43 +0000230 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000231 if ( *bp )
232 {
233 nbp = hash_bucket( (*bp)->key, ht );
234 *nbp = *bp;
235 }
David Turner993a8d02002-05-18 12:03:43 +0000236 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000237 FT_FREE( obp );
238
239 Exit:
240 return error;
David Turner993a8d02002-05-18 12:03:43 +0000241 }
David Turner993a8d02002-05-18 12:03:43 +0000242
243
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000244 static FT_Error
245 hash_init( hashtable* ht,
246 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000247 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000248 int sz = INITIAL_HT_SIZE;
249 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000250
David Turner993a8d02002-05-18 12:03:43 +0000251
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000252 ht->size = sz;
253 ht->limit = sz / 3;
254 ht->used = 0;
David Turner993a8d02002-05-18 12:03:43 +0000255
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000256 if ( FT_NEW_ARRAY( ht->table, sz ) )
257 goto Exit;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000258 FT_MEM_ZERO( ht->table, sizeof ( hashnode ) * sz );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000259
260 Exit:
261 return error;
David Turner993a8d02002-05-18 12:03:43 +0000262 }
David Turner993a8d02002-05-18 12:03:43 +0000263
264
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000265 static void
266 hash_free( hashtable* ht,
267 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000268 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000269 if ( ht != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000270 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000271 int i, sz = ht->size;
272 hashnode* bp = ht->table;
David Turner993a8d02002-05-18 12:03:43 +0000273
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000274
275 for ( i = 0; i < sz; i++, bp++ )
276 FT_FREE( *bp );
277
278 FT_FREE( ht->table );
279 }
David Turner993a8d02002-05-18 12:03:43 +0000280 }
281
David Turner993a8d02002-05-18 12:03:43 +0000282
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000283 static FT_Error
284 hash_insert( char* key,
285 void* data,
286 hashtable* ht,
287 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000288 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000289 hashnode nn, *bp = hash_bucket( key, ht );
290 FT_Error error = BDF_Err_Ok;
291
292
293 nn = *bp;
294 if ( !nn )
295 {
296 if ( FT_NEW( nn ) )
297 goto Exit;
298 *bp = nn;
299
300 nn->key = key;
301 nn->data = data;
302
303 if ( ht->used >= ht->limit )
304 {
305 error = hash_rehash( ht, memory );
306 if ( error )
307 goto Exit;
308 }
309 ht->used++;
310 }
David Turner993a8d02002-05-18 12:03:43 +0000311 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000312 nn->data = data;
313
314 Exit:
315 return error;
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 hashnode
Werner Lemberg428c2e42003-04-25 05:35:04 +0000320 hash_lookup( const char* key,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000321 hashtable* ht )
322 {
323 hashnode *np = hash_bucket( key, ht );
324
325
326 return *np;
327 }
328
329
330 /*************************************************************************/
331 /* */
332 /* Utility types and functions. */
333 /* */
334 /*************************************************************************/
335
336
337 /* Function type for parsing lines of a BDF font. */
338
339 typedef FT_Error
340 (*_bdf_line_func_t)( char* line,
341 unsigned long linelen,
342 unsigned long lineno,
343 void* call_data,
344 void* client_data );
345
346
347 /* List structure for splitting lines into fields. */
348
349 typedef struct _bdf_list_t_
350 {
351 char** field;
352 unsigned long size;
353 unsigned long used;
354
355 } _bdf_list_t;
356
357
358 /* Structure used while loading BDF fonts. */
359
360 typedef struct _bdf_parse_t_
361 {
362 unsigned long flags;
363 unsigned long cnt;
364 unsigned long row;
365
366 short minlb;
367 short maxlb;
368 short maxrb;
369 short maxas;
370 short maxds;
371
372 short rbearing;
373
374 char* glyph_name;
375 long glyph_enc;
376
377 bdf_font_t* font;
378 bdf_options_t* opts;
379
380 unsigned long have[2048];
381 _bdf_list_t list;
382
383 FT_Memory memory;
384
385 } _bdf_parse_t;
386
387
David Turnerb1b47622002-05-21 21:17:43 +0000388#define setsbit( m, cc ) ( m[(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000389#define sbitset( m, cc ) ( m[(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
390
391
392 /* An empty string for empty fields. */
393
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000394 static const char empty[1] = { 0 }; /* XXX eliminate this */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000395
396
397 /* Assume the line is NULL-terminated and that the `list' parameter */
398 /* was initialized the first time it was used. */
399
400 static FT_Error
401 _bdf_split( char* separators,
402 char* line,
403 unsigned long linelen,
404 _bdf_list_t* list,
405 FT_Memory memory )
406 {
407 int mult, final_empty;
408 char *sp, *ep, *end;
409 char seps[32];
410 FT_Error error = BDF_Err_Ok;
411
412
413 /* Initialize the list. */
414 list->used = 0;
415
416 /* If the line is empty, then simply return. */
417 if ( linelen == 0 || line[0] == 0 )
418 goto Exit;
419
420 /* In the original code, if the `separators' parameter is NULL or */
421 /* empty, the list is split into individual bytes. We don't need */
422 /* this, so an error is signaled. */
423 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000424 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000425 error = BDF_Err_Invalid_Argument;
426 goto Exit;
427 }
428
429 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000430 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000431
432 /* If the very last character of the separator string is a plus, then */
433 /* set the `mult' flag to indicate that multiple separators should be */
434 /* collapsed into one. */
435 for ( mult = 0, sp = separators; sp && *sp; sp++ )
436 {
437 if ( *sp == '+' && *( sp + 1 ) == 0 )
438 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000439 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000440 setsbit( seps, *sp );
441 }
442
443 /* Break the line up into fields. */
444 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
445 sp < end && *sp; )
446 {
447 /* Collect everything that is not a separator. */
448 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
449 ;
450
451 /* Resize the list if necessary. */
452 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000453 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000454 if ( list->size == 0 )
455 {
456 if ( FT_NEW_ARRAY( list->field, 5 ) )
457 goto Exit;
458 }
459 else
460 {
461 if ( FT_RENEW_ARRAY ( list->field ,
462 list->size,
463 list->size + 5 ) )
464 goto Exit;
465 }
466
467 list->size += 5;
David Turner993a8d02002-05-18 12:03:43 +0000468 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000469
470 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000471 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000472
473 sp = ep;
474
475 if ( mult )
476 {
477 /* If multiple separators should be collapsed, do it now by */
478 /* setting all the separator characters to 0. */
479 for ( ; *ep && sbitset( seps, *ep ); ep++ )
480 *ep = 0;
481 }
482 else if ( *ep != 0 )
483 /* Don't collapse multiple separators by making them 0, so just */
484 /* make the one encountered 0. */
485 *ep++ = 0;
486
487 final_empty = ( ep > sp && *ep == 0 );
488 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000489 }
490
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000491 /* Finally, NULL-terminate the list. */
492 if ( list->used + final_empty + 1 >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000493 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000494 if ( list->used == list->size )
495 {
496 if ( list->size == 0 )
497 {
498 if ( FT_NEW_ARRAY( list->field, 5 ) )
499 goto Exit;
500 }
501 else
502 {
503 if ( FT_RENEW_ARRAY( list->field,
504 list->size,
505 list->size + 5 ) )
506 goto Exit;
507 }
David Turner993a8d02002-05-18 12:03:43 +0000508
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000509 list->size += 5;
510 }
David Turner993a8d02002-05-18 12:03:43 +0000511 }
512
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000513 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000514 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000515
David Turner993a8d02002-05-18 12:03:43 +0000516 if ( list->used == list->size )
517 {
518 if ( list->size == 0 )
519 {
520 if ( FT_NEW_ARRAY( list->field, 5 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000521 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000522 }
523 else
524 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000525 if ( FT_RENEW_ARRAY( list->field,
526 list->size,
527 list->size + 5 ) )
528 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000529 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000530
David Turner993a8d02002-05-18 12:03:43 +0000531 list->size += 5;
532 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000533
534 list->field[list->used] = 0;
535
536 Exit:
537 return error;
David Turner993a8d02002-05-18 12:03:43 +0000538 }
539
David Turner993a8d02002-05-18 12:03:43 +0000540
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000541 static void
542 _bdf_shift( unsigned long n,
543 _bdf_list_t* list )
David Turner993a8d02002-05-18 12:03:43 +0000544 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000545 unsigned long i, u;
546
547
548 if ( list == 0 || list->used == 0 || n == 0 )
549 return;
550
551 if ( n >= list->used )
David Turner993a8d02002-05-18 12:03:43 +0000552 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000553 list->used = 0;
554 return;
David Turner993a8d02002-05-18 12:03:43 +0000555 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000556
557 for ( u = n, i = 0; u < list->used; i++, u++ )
558 list->field[i] = list->field[u];
559 list->used -= n;
560 }
561
562
563 static char *
564 _bdf_join( int c,
565 unsigned long* len,
566 _bdf_list_t* list )
567 {
568 unsigned long i, j;
569 char *fp, *dp;
570
571
572 if ( list == 0 || list->used == 0 )
573 return 0;
574
575 *len = 0;
576
577 dp = list->field[0];
578 for ( i = j = 0; i < list->used; i++ )
579 {
580 fp = list->field[i];
581 while ( *fp )
582 dp[j++] = *fp++;
583
584 if ( i + 1 < list->used )
David Turnerb1b47622002-05-21 21:17:43 +0000585 dp[j++] = (char)c;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000586 }
587 dp[j] = 0;
588
589 *len = j;
590 return dp;
591 }
592
593
594 /* High speed file reader that passes each line to a callback. */
595 static FT_Error
596 bdf_internal_readstream( FT_Stream stream,
597 char* buffer,
598 int count,
599 int *read_bytes )
600 {
601 int rbytes;
602 unsigned long pos = stream->pos;
603 FT_Error error = BDF_Err_Ok;
604
605
606 if ( pos > stream->size )
607 {
608 FT_ERROR(( "bdf_internal_readstream:" ));
609 FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
610 pos, stream->size ));
611 error = BDF_Err_Invalid_Stream_Operation;
612 goto Exit;
613 }
614
615 if ( stream->read )
616 rbytes = stream->read( stream, pos,
617 (unsigned char *)buffer, count );
David Turner993a8d02002-05-18 12:03:43 +0000618 else
619 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000620 rbytes = stream->size - pos;
621 if ( rbytes > count )
622 rbytes = count;
623
624 FT_MEM_COPY( buffer, stream->base + pos, rbytes );
David Turner993a8d02002-05-18 12:03:43 +0000625 }
David Turner993a8d02002-05-18 12:03:43 +0000626
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000627 stream->pos = pos + rbytes;
David Turner993a8d02002-05-18 12:03:43 +0000628
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000629 *read_bytes = rbytes;
David Turner993a8d02002-05-18 12:03:43 +0000630
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000631 Exit:
632 return error;
David Turner993a8d02002-05-18 12:03:43 +0000633 }
634
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000635
636 static FT_Error
637 _bdf_readstream( FT_Stream stream,
638 _bdf_line_func_t callback,
639 void* client_data,
640 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000641 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000642 _bdf_line_func_t cb;
643 unsigned long lineno;
Werner Lemberg319c00d2003-04-23 19:48:24 +0000644 int n, done, refill, bytes, hold;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000645 char *ls, *le, *pp, *pe, *hp;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000646 char *buf = 0;
647 FT_Memory memory = stream->memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000648 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000649
David Turner993a8d02002-05-18 12:03:43 +0000650
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000651 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000652 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000653 error = BDF_Err_Invalid_Argument;
654 goto Exit;
655 }
David Turner993a8d02002-05-18 12:03:43 +0000656
Werner Lemberg7925edc2002-05-30 19:29:41 +0000657 if ( FT_NEW_ARRAY( buf, 65536L ) )
658 goto Exit;
659
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000660 cb = callback;
661 lineno = 1;
662 buf[0] = 0;
David Turner993a8d02002-05-18 12:03:43 +0000663
Werner Lemberg319c00d2003-04-23 19:48:24 +0000664 done = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000665 pp = ls = le = buf;
666
667 bytes = 65536L;
668
669 while ( !done )
670 {
671 error = bdf_internal_readstream( stream, pp, bytes, &n );
672 if ( error )
673 goto Exit;
674
675 if ( n == 0 )
676 break;
677
678 /* Determine the new end of the buffer pages. */
679 pe = pp + n;
680
681 for ( refill = 0; done == 0 && refill == 0; )
682 {
683 while ( le < pe && *le != '\n' && *le != '\r' )
684 le++;
685
686 if ( le == pe )
687 {
688 /* Hit the end of the last page in the buffer. Need to find */
689 /* out how many pages to shift and how many pages need to be */
690 /* read in. Adjust the line start and end pointers down to */
691 /* point to the right places in the pages. */
692
693 pp = buf + ( ( ( ls - buf ) >> 13 ) << 13 );
694 n = pp - buf;
695 ls -= n;
696 le -= n;
697 n = pe - pp;
698
Werner Lemberged2a8df2003-09-01 07:06:06 +0000699 FT_MEM_MOVE( buf, pp, n );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000700
701 pp = buf + n;
702 bytes = 65536L - n;
703 refill = 1;
704 }
705 else
706 {
707 /* Temporarily NULL-terminate the line. */
708 hp = le;
709 hold = *le;
710 *le = 0;
711
712 /* XXX: Use encoding independent value for 0x1a */
713 if ( *ls != '#' && *ls != 0x1a &&
714 le > ls &&
715 ( error = (*cb)( ls, le - ls, lineno, (void *)&cb,
716 client_data ) ) != BDF_Err_Ok )
717 done = 1;
718 else
719 {
David Turner993a8d02002-05-18 12:03:43 +0000720 ls = ++le;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000721 /* Handle the case of DOS crlf sequences. */
722 if ( le < pe && hold == '\n' && *le =='\r' )
David Turner993a8d02002-05-18 12:03:43 +0000723 ls = ++le;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000724 }
725
726 /* Increment the line number. */
727 lineno++;
728
729 /* Restore the character at the end of the line. */
David Turnerb1b47622002-05-21 21:17:43 +0000730 *hp = (char)hold;
David Turnerd490e372002-05-28 23:40:37 +0000731 }
David Turner993a8d02002-05-18 12:03:43 +0000732 }
733 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000734
735 *lno = lineno;
736
737 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000738 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000739 return error;
David Turner993a8d02002-05-18 12:03:43 +0000740 }
David Turner993a8d02002-05-18 12:03:43 +0000741
742
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000743 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000744
David Turnerb1b47622002-05-21 21:17:43 +0000745 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000746 {
David Turner993a8d02002-05-18 12:03:43 +0000747 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
748 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
749 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
750 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
751 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
752 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
753 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
754 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
755 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
756 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000758 };
David Turner993a8d02002-05-18 12:03:43 +0000759
David Turnerb1b47622002-05-21 21:17:43 +0000760 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000761 {
David Turner993a8d02002-05-18 12:03:43 +0000762 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
764 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000766 };
David Turner993a8d02002-05-18 12:03:43 +0000767
David Turnerb1b47622002-05-21 21:17:43 +0000768 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000769 {
David Turner993a8d02002-05-18 12:03:43 +0000770 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
771 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000774 };
David Turner993a8d02002-05-18 12:03:43 +0000775
David Turnerb1b47622002-05-21 21:17:43 +0000776 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000777 {
David Turner993a8d02002-05-18 12:03:43 +0000778 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
779 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
780 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000782 };
David Turner993a8d02002-05-18 12:03:43 +0000783
David Turner993a8d02002-05-18 12:03:43 +0000784
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000785#define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
David Turner993a8d02002-05-18 12:03:43 +0000786
David Turner993a8d02002-05-18 12:03:43 +0000787
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000788 /* Routine to convert an ASCII string into an unsigned long integer. */
789 static unsigned long
790 _bdf_atoul( char* s,
791 char** end,
792 int base )
David Turner993a8d02002-05-18 12:03:43 +0000793 {
David Turnerb1b47622002-05-21 21:17:43 +0000794 unsigned long v;
795 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000796
797
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000798 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000799 return 0;
800
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000801 /* Make sure the radix is something recognizable. Default to 10. */
802 switch ( base )
803 {
804 case 8:
805 dmap = odigits;
806 break;
807 case 16:
808 dmap = hdigits;
809 break;
810 default:
811 base = 10;
812 dmap = ddigits;
813 break;
David Turner993a8d02002-05-18 12:03:43 +0000814 }
815
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000816 /* Check for the special hex prefix. */
817 if ( *s == '0' &&
818 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
819 {
820 base = 16;
821 dmap = hdigits;
822 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000823 }
824
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000825 for ( v = 0; isdigok( dmap, *s ); s++ )
826 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000827
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000828 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000829 *end = s;
830
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000831 return v;
832 }
David Turner993a8d02002-05-18 12:03:43 +0000833
David Turner993a8d02002-05-18 12:03:43 +0000834
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000835 /* Routine to convert an ASCII string into an signed long integer. */
836 static long
837 _bdf_atol( char* s,
838 char** end,
839 int base )
840 {
David Turnerb1b47622002-05-21 21:17:43 +0000841 long v, neg;
842 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000843
844
845 if ( s == 0 || *s == 0 )
846 return 0;
847
848 /* Make sure the radix is something recognizable. Default to 10. */
849 switch ( base )
850 {
851 case 8:
852 dmap = odigits;
853 break;
854 case 16:
855 dmap = hdigits;
856 break;
857 default:
858 base = 10;
859 dmap = ddigits;
860 break;
861 }
862
863 /* Check for a minus sign. */
864 neg = 0;
865 if ( *s == '-' )
866 {
867 s++;
868 neg = 1;
869 }
870
871 /* Check for the special hex prefix. */
872 if ( *s == '0' &&
873 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
874 {
875 base = 16;
876 dmap = hdigits;
877 s += 2;
878 }
879
880 for ( v = 0; isdigok( dmap, *s ); s++ )
881 v = v * base + a2i[(int)*s];
882
883 if ( end != 0 )
884 *end = s;
885
886 return ( !neg ) ? v : -v;
887 }
888
889
890 /* Routine to convert an ASCII string into an signed short integer. */
891 static short
892 _bdf_atos( char* s,
893 char** end,
894 int base )
895 {
David Turnerb1b47622002-05-21 21:17:43 +0000896 short v, neg;
897 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000898
899
900 if ( s == 0 || *s == 0 )
901 return 0;
902
903 /* Make sure the radix is something recognizable. Default to 10. */
904 switch ( base )
905 {
906 case 8:
907 dmap = odigits;
908 break;
909 case 16:
910 dmap = hdigits;
911 break;
912 default:
913 base = 10;
914 dmap = ddigits;
915 break;
916 }
917
918 /* Check for a minus. */
919 neg = 0;
920 if ( *s == '-' )
921 {
922 s++;
923 neg = 1;
924 }
925
926 /* Check for the special hex prefix. */
927 if ( *s == '0' &&
928 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
929 {
930 base = 16;
931 dmap = hdigits;
932 s += 2;
933 }
934
935 for ( v = 0; isdigok( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +0000936 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000937
938 if ( end != 0 )
939 *end = s;
940
Werner Lemberg233302a2002-05-22 05:41:06 +0000941 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000942 }
943
944
945 /* Routine to compare two glyphs by encoding so they can be sorted. */
946 static int
947 by_encoding( const void* a,
948 const void* b )
949 {
950 bdf_glyph_t *c1, *c2;
951
952
953 c1 = (bdf_glyph_t *)a;
954 c2 = (bdf_glyph_t *)b;
955
956 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000957 return -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000958 else if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000959 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000960
David Turner993a8d02002-05-18 12:03:43 +0000961 return 0;
David Turner993a8d02002-05-18 12:03:43 +0000962 }
963
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000964
965 static FT_Error
966 bdf_create_property( char* name,
967 int format,
968 bdf_font_t* font )
969 {
970 unsigned long n;
971 bdf_property_t* p;
972 FT_Memory memory = font->memory;
973 FT_Error error = BDF_Err_Ok;
974
975
976 /* First check to see if the property has */
977 /* already been added or not. If it has, then */
978 /* simply ignore it. */
979 if ( hash_lookup( name, &(font->proptbl) ) )
980 goto Exit;
981
982 if ( font->nuser_props == 0 )
983 {
984 if ( FT_NEW_ARRAY( font->user_props, 1 ) )
985 goto Exit;
986 }
987 else
988 {
989 if ( FT_RENEW_ARRAY( font->user_props,
990 font->nuser_props,
991 font->nuser_props + 1 ) )
992 goto Exit;
993 }
994
995 p = font->user_props + font->nuser_props;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000996 FT_MEM_ZERO( p, sizeof ( bdf_property_t ) );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000997
998 n = (unsigned long)( ft_strlen( name ) + 1 );
999 if ( FT_NEW_ARRAY( p->name, n ) )
1000 goto Exit;
1001
1002 FT_MEM_COPY( (char *)p->name, name, n );
1003
1004 p->format = format;
1005 p->builtin = 0;
1006
1007 n = _num_bdf_properties + font->nuser_props;
1008
1009 error = hash_insert( p->name, (void *)n, &(font->proptbl), memory );
1010 if ( error )
1011 goto Exit;
1012
1013 font->nuser_props++;
1014
1015 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001016 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001017 }
David Turner993a8d02002-05-18 12:03:43 +00001018
1019
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001020 FT_LOCAL_DEF( bdf_property_t * )
1021 bdf_get_property( char* name,
1022 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001023 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001024 hashnode hn;
1025 unsigned long propid;
1026
1027
1028 if ( name == 0 || *name == 0 )
1029 return 0;
1030
1031 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1032 return 0;
1033
1034 propid = (unsigned long)hn->data;
1035 if ( propid >= _num_bdf_properties )
1036 return font->user_props + ( propid - _num_bdf_properties );
1037
Werner Lemberg233302a2002-05-22 05:41:06 +00001038 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001039 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001040
1041
1042 /*************************************************************************/
1043 /* */
1044 /* BDF font file parsing flags and functions. */
1045 /* */
1046 /*************************************************************************/
1047
1048
1049 /* Parse flags. */
1050
1051#define _BDF_START 0x0001
1052#define _BDF_FONT_NAME 0x0002
1053#define _BDF_SIZE 0x0004
1054#define _BDF_FONT_BBX 0x0008
1055#define _BDF_PROPS 0x0010
1056#define _BDF_GLYPHS 0x0020
1057#define _BDF_GLYPH 0x0040
1058#define _BDF_ENCODING 0x0080
1059#define _BDF_SWIDTH 0x0100
1060#define _BDF_DWIDTH 0x0200
1061#define _BDF_BBX 0x0400
1062#define _BDF_BITMAP 0x0800
1063
1064#define _BDF_SWIDTH_ADJ 0x1000
1065
1066#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1067 _BDF_ENCODING | \
1068 _BDF_SWIDTH | \
1069 _BDF_DWIDTH | \
1070 _BDF_BBX | \
1071 _BDF_BITMAP )
1072
1073#define _BDF_GLYPH_WIDTH_CHECK 0x40000000L
1074#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000L
1075
1076
1077 /* Auto correction messages. */
1078#define ACMSG1 "FONT_ASCENT property missing. " \
1079 "Added \"FONT_ASCENT %hd\".\n"
1080#define ACMSG2 "FONT_DESCENT property missing. " \
1081 "Added \"FONT_DESCENT %hd\".\n"
1082#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
1083#define ACMSG4 "Font left bearing != actual left bearing. " \
1084 "Old: %hd New: %hd.\n"
1085#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
1086#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
1087#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
1088#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
1089#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
1090#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
1091#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
1092#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
1093#define ACMSG13 "Glyph %ld extra rows removed.\n"
1094#define ACMSG14 "Glyph %ld extra columns removed.\n"
1095#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
1096
1097 /* Error messages. */
1098#define ERRMSG1 "[line %ld] Missing \"%s\" line.\n"
1099#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
1100#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
1101
1102
1103 static FT_Error
1104 _bdf_add_comment( bdf_font_t* font,
1105 char* comment,
1106 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001107 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001108 char* cp;
1109 FT_Memory memory = font->memory;
1110 FT_Error error = BDF_Err_Ok;
1111
1112
1113 if ( font->comments_len == 0 )
1114 {
1115 if ( FT_NEW_ARRAY( font->comments, len + 1 ) )
1116 goto Exit;
1117 }
1118 else
1119 {
1120 if ( FT_RENEW_ARRAY( font->comments,
1121 font->comments_len,
1122 font->comments_len + len + 1 ) )
1123 goto Exit;
1124 }
1125
1126 cp = font->comments + font->comments_len;
1127 FT_MEM_COPY( cp, comment, len );
1128 cp += len;
1129 *cp++ = '\n';
1130 font->comments_len += len + 1;
1131
1132 Exit:
1133 return error;
David Turner993a8d02002-05-18 12:03:43 +00001134 }
1135
David Turner993a8d02002-05-18 12:03:43 +00001136
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001137 /* Set the spacing from the font name if it exists, or set it to the */
1138 /* default specified in the options. */
1139 static FT_Error
1140 _bdf_set_default_spacing( bdf_font_t* font,
1141 bdf_options_t* opts )
David Turner993a8d02002-05-18 12:03:43 +00001142 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001143 unsigned long len;
1144 char name[128];
1145 _bdf_list_t list;
1146 FT_Memory memory;
1147 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001148
David Turner993a8d02002-05-18 12:03:43 +00001149
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001150 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1151 {
1152 error = BDF_Err_Invalid_Argument;
1153 goto Exit;
1154 }
David Turner993a8d02002-05-18 12:03:43 +00001155
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001156 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001157
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001158 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001159
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001160 len = (unsigned long)( ft_strlen( font->name ) + 1 );
1161 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001162
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001163 list.size = list.used = 0;
David Turner993a8d02002-05-18 12:03:43 +00001164
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001165 error = _bdf_split( (char *)"-", name, len, &list, memory );
1166 if ( error )
1167 goto Exit;
1168
1169 if ( list.used == 15 )
1170 {
1171 switch ( list.field[11][0] )
1172 {
1173 case 'C':
1174 case 'c':
1175 font->spacing = BDF_CHARCELL;
1176 break;
1177 case 'M':
1178 case 'm':
1179 font->spacing = BDF_MONOWIDTH;
1180 break;
1181 case 'P':
1182 case 'p':
1183 font->spacing = BDF_PROPORTIONAL;
1184 break;
David Turner993a8d02002-05-18 12:03:43 +00001185 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001186 }
1187
1188 FT_FREE( list.field );
1189
1190 Exit:
1191 return error;
David Turner993a8d02002-05-18 12:03:43 +00001192 }
David Turner993a8d02002-05-18 12:03:43 +00001193
1194
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001195 /* Determine whether the property is an atom or not. If it is, then */
1196 /* clean it up so the double quotes are removed if they exist. */
1197 static int
1198 _bdf_is_atom( char* line,
1199 unsigned long linelen,
1200 char** name,
1201 char** value,
1202 bdf_font_t* font )
1203 {
1204 int hold;
1205 char *sp, *ep;
1206 bdf_property_t* p;
1207
David Turner993a8d02002-05-18 12:03:43 +00001208
1209 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001210
1211 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001212 ep++;
1213
1214 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001215 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001216 {
1217 hold = *ep;
1218 *ep = 0;
1219 }
1220
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001221 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001222
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001223 /* Restore the character that was saved before any return can happen. */
1224 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001225 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001226
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001227 /* If the property exists and is not an atom, just return here. */
1228 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001229 return 0;
1230
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001231 /* The property is an atom. Trim all leading and trailing whitespace */
1232 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001233 sp = ep;
1234 ep = line + linelen;
1235
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001236 /* Trim the leading whitespace if it exists. */
David Turner993a8d02002-05-18 12:03:43 +00001237 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001238 while ( *sp &&
1239 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001240 sp++;
1241
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001242 /* Trim the leading double quote if it exists. */
1243 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001244 sp++;
1245 *value = sp;
1246
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001247 /* Trim the trailing whitespace if it exists. */
1248 while ( ep > sp &&
1249 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001250 *--ep = 0;
1251
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001252 /* Trim the trailing double quote if it exists. */
1253 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001254 *--ep = 0;
1255
1256 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001257 }
David Turner993a8d02002-05-18 12:03:43 +00001258
1259
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001260 static FT_Error
1261 _bdf_add_property( bdf_font_t* font,
1262 char* name,
1263 char* value )
1264 {
1265 unsigned long propid;
1266 hashnode hn;
1267 int len;
1268 bdf_property_t *prop, *fp;
1269 FT_Memory memory = font->memory;
1270 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001271
David Turner993a8d02002-05-18 12:03:43 +00001272
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001273 /* First, check to see if the property already exists in the font. */
1274 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001275 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001276 /* The property already exists in the font, so simply replace */
1277 /* the value of the property with the current value. */
1278 fp = font->props + (unsigned long)hn->data;
1279
David Turnerb1b47622002-05-21 21:17:43 +00001280 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001281 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001282 case BDF_ATOM:
1283 /* Delete the current atom if it exists. */
1284 FT_FREE( fp->value.atom );
1285
1286 if ( value == 0 )
1287 len = 1;
1288 else
1289 len = ft_strlen( value ) + 1;
1290
1291 if ( len > 1 )
1292 {
1293 if ( FT_NEW_ARRAY( fp->value.atom, len ) )
1294 goto Exit;
1295 FT_MEM_COPY( fp->value.atom, value, len );
1296 }
1297 else
1298 fp->value.atom = 0;
1299 break;
1300
1301 case BDF_INTEGER:
1302 fp->value.int32 = _bdf_atol( value, 0, 10 );
1303 break;
1304
1305 case BDF_CARDINAL:
1306 fp->value.card32 = _bdf_atoul( value, 0, 10 );
1307 break;
David Turnerd490e372002-05-28 23:40:37 +00001308
David Turnerb1b47622002-05-21 21:17:43 +00001309 default:
1310 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001311 }
David Turnerd490e372002-05-28 23:40:37 +00001312
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001313 goto Exit;
1314 }
1315
1316 /* See whether this property type exists yet or not. */
1317 /* If not, create it. */
1318 hn = hash_lookup( name, &(font->proptbl) );
1319 if ( hn == 0 )
1320 {
1321 error = bdf_create_property( name, BDF_ATOM, font );
1322 if ( error )
1323 goto Exit;
1324 hn = hash_lookup( name, &(font->proptbl) );
1325 }
1326
1327 /* Allocate another property if this is overflow. */
1328 if ( font->props_used == font->props_size )
1329 {
1330 if ( font->props_size == 0 )
1331 {
1332 if ( FT_NEW_ARRAY( font->props, 1 ) )
1333 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001334 }
1335 else
1336 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001337 if ( FT_RENEW_ARRAY( font->props,
1338 font->props_size,
1339 font->props_size + 1 ) )
1340 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001341 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001342
David Turner993a8d02002-05-18 12:03:43 +00001343 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001344 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001345 font->props_size++;
1346 }
1347
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001348 propid = (unsigned long)hn->data;
1349 if ( propid >= _num_bdf_properties )
1350 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001351 else
David Turnerb1b47622002-05-21 21:17:43 +00001352 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001353
1354 fp = font->props + font->props_used;
1355
1356 fp->name = prop->name;
1357 fp->format = prop->format;
1358 fp->builtin = prop->builtin;
1359
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001360 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001361 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001362 case BDF_ATOM:
1363 if ( value == 0 )
1364 len = 1;
1365 else
1366 len = ft_strlen( value ) + 1;
David Turner993a8d02002-05-18 12:03:43 +00001367
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001368 if ( len > 1 )
1369 {
1370 if ( FT_NEW_ARRAY( fp->value.atom, len ) )
1371 goto Exit;
1372 FT_MEM_COPY( fp->value.atom, value, len );
1373 }
1374 else
1375 fp->value.atom = 0;
1376 break;
David Turner993a8d02002-05-18 12:03:43 +00001377
1378 case BDF_INTEGER:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001379 fp->value.int32 = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001380 break;
1381
1382 case BDF_CARDINAL:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001383 fp->value.card32 = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001384 break;
David Turner993a8d02002-05-18 12:03:43 +00001385 }
1386
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001387 /* If the property happens to be a comment, then it doesn't need */
1388 /* to be added to the internal hash table. */
1389 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) {
1390 /* Add the property to the font property table. */
1391 error = hash_insert( fp->name,
1392 (void *)font->props_used,
1393 (hashtable *)font->internal,
1394 memory );
1395 if ( error )
1396 goto Exit;
1397 }
David Turner993a8d02002-05-18 12:03:43 +00001398
1399 font->props_used++;
1400
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001401 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1402 /* property needs to be located if it exists in the property list, the */
1403 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1404 /* present, and the SPACING property should override the default */
1405 /* spacing. */
1406 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001407 font->default_glyph = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001408 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001409 font->font_ascent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001410 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001411 font->font_descent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001412 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001413 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001414 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001415 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001416 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001417 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001418 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001419 font->spacing = BDF_CHARCELL;
1420 }
1421
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001422 Exit:
1423 return error;
David Turner993a8d02002-05-18 12:03:43 +00001424 }
1425
David Turner993a8d02002-05-18 12:03:43 +00001426
David Turnerb1b47622002-05-21 21:17:43 +00001427 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001428 {
1429 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1430 };
1431
1432
1433 /* Actually parse the glyph info and bitmaps. */
1434 static FT_Error
1435 _bdf_parse_glyphs( char* line,
1436 unsigned long linelen,
1437 unsigned long lineno,
1438 void* call_data,
1439 void* client_data )
1440 {
1441 int c, mask_index;
1442 char* s;
1443 unsigned char* bp;
1444 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001445
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001446 _bdf_parse_t* p;
1447 bdf_glyph_t* glyph;
1448 bdf_font_t* font;
1449
1450 FT_Memory memory;
1451 FT_Error error = BDF_Err_Ok;
1452
Werner Lemberg319c00d2003-04-23 19:48:24 +00001453 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001454 FT_UNUSED( lineno ); /* only used in debug mode */
1455
1456
Werner Lemberg319c00d2003-04-23 19:48:24 +00001457 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001458
1459 font = p->font;
1460 memory = font->memory;
1461
1462 /* Check for a comment. */
1463 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1464 {
1465 linelen -= 7;
1466
1467 s = line + 7;
1468 if ( *s != 0 )
1469 {
1470 s++;
1471 linelen--;
1472 }
1473 error = _bdf_add_comment( p->font, s, linelen );
1474 goto Exit;
1475 }
1476
1477 /* The very first thing expected is the number of glyphs. */
1478 if ( !( p->flags & _BDF_GLYPHS ) )
1479 {
1480 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1481 {
1482 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1483 error = BDF_Err_Missing_Chars_Field;
1484 goto Exit;
1485 }
1486
1487 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1488 if ( error )
1489 goto Exit;
1490 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1491
1492 /* Make sure the number of glyphs is non-zero. */
1493 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001494 font->glyphs_size = 64;
1495
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001496 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1497 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001498
David Turner993a8d02002-05-18 12:03:43 +00001499 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001500
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001501 goto Exit;
1502 }
1503
1504 /* Check for the ENDFONT field. */
1505 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1506 {
1507 /* Sort the glyphs by encoding. */
1508 ft_qsort( (char *)font->glyphs,
1509 font->glyphs_used,
1510 sizeof ( bdf_glyph_t ),
1511 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001512
1513 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001514
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001515 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001516 }
1517
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001518 /* Check for the ENDCHAR field. */
1519 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1520 {
1521 p->glyph_enc = 0;
1522 p->flags &= ~_BDF_GLYPH_BITS;
1523
1524 goto Exit;
1525 }
1526
1527 /* Check to see whether a glyph is being scanned but should be */
1528 /* ignored because it is an unencoded glyph. */
1529 if ( ( p->flags & _BDF_GLYPH ) &&
1530 p->glyph_enc == -1 &&
1531 p->opts->keep_unencoded == 0 )
1532 goto Exit;
1533
1534 /* Check for the STARTCHAR field. */
1535 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1536 {
1537 /* Set the character name in the parse info first until the */
1538 /* encoding can be checked for an unencoded character. */
1539 FT_FREE( p->glyph_name );
1540
1541 error = _bdf_split( (char *)" +", line, linelen, &p->list,memory );
1542 if ( error )
1543 goto Exit;
1544 _bdf_shift( 1, &p->list );
1545
1546 s = _bdf_join( ' ', &slen, &p->list );
1547
1548 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1549 goto Exit;
1550 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1551
1552 p->flags |= _BDF_GLYPH;
1553
1554 goto Exit;
1555 }
1556
1557 /* Check for the ENCODING field. */
1558 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1559 {
1560 if ( !( p->flags & _BDF_GLYPH ) )
1561 {
1562 /* Missing STARTCHAR field. */
1563 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1564 error = BDF_Err_Missing_Startchar_Field;
1565 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001566 }
1567
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001568 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1569 if ( error )
1570 goto Exit;
1571 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001572
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001573 /* Check to see whether this encoding has already been encountered. */
1574 /* If it has then change it to unencoded so it gets added if */
1575 /* indicated. */
1576 if ( p->glyph_enc >= 0 )
1577 {
1578 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1579 {
1580 /* Emit a message saying a glyph has been moved to the */
1581 /* unencoded area. */
1582 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1583 p->glyph_enc, p->glyph_name ));
1584 p->glyph_enc = -1;
1585 font->modified = 1;
1586 }
1587 else
1588 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1589 }
1590
1591 if ( p->glyph_enc >= 0 )
1592 {
1593 /* Make sure there are enough glyphs allocated in case the */
1594 /* number of characters happen to be wrong. */
1595 if ( font->glyphs_used == font->glyphs_size )
1596 {
1597 if ( FT_RENEW_ARRAY( font->glyphs,
1598 font->glyphs_size,
1599 font->glyphs_size + 64 ) )
1600 goto Exit;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001601 FT_MEM_ZERO( font->glyphs + font->glyphs_size,
1602 sizeof ( bdf_glyph_t ) * 64 ); /* FZ inutile */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001603 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001604 }
1605
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001606 glyph = font->glyphs + font->glyphs_used++;
1607 glyph->name = p->glyph_name;
1608 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001609
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001610 /* Reset the initial glyph info. */
1611 p->glyph_name = 0;
1612 }
1613 else
1614 {
1615 /* Unencoded glyph. Check to see whether it should */
1616 /* be added or not. */
1617 if ( p->opts->keep_unencoded != 0 )
1618 {
1619 /* Allocate the next unencoded glyph. */
1620 if ( font->unencoded_used == font->unencoded_size )
1621 {
1622 if ( font->unencoded_size == 0 )
1623 {
Werner Lemberg7925edc2002-05-30 19:29:41 +00001624 if ( FT_NEW_ARRAY( font->unencoded, 4 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001625 goto Exit;
1626 }
1627 else
1628 {
1629 if ( FT_RENEW_ARRAY( font->unencoded ,
1630 font->unencoded_size,
1631 font->unencoded_size + 4 ) )
1632 goto Exit;
1633 }
1634 font->unencoded_size += 4;
1635 }
1636
1637 glyph = font->unencoded + font->unencoded_used;
1638 glyph->name = p->glyph_name;
1639 glyph->encoding = font->unencoded_used++;
1640 }
1641 else
1642 /* Free up the glyph name if the unencoded shouldn't be */
1643 /* kept. */
1644 FT_FREE( p->glyph_name );
1645
1646 p->glyph_name = 0;
1647 }
1648
1649 /* Clear the flags that might be added when width and height are */
1650 /* checked for consistency. */
1651 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1652
1653 p->flags |= _BDF_ENCODING;
1654
1655 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001656 }
1657
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001658 /* Point at the glyph being constructed. */
1659 if ( p->glyph_enc == -1 )
1660 glyph = font->unencoded + ( font->unencoded_used - 1 );
1661 else
1662 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001663
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001664 /* Check to see whether a bitmap is being constructed. */
1665 if ( p->flags & _BDF_BITMAP )
1666 {
1667 /* If there are more rows than are specified in the glyph metrics, */
1668 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001669 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001670 {
1671 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1672 {
1673 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1674 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001675 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001676 }
1677
1678 goto Exit;
1679 }
1680
1681 /* Only collect the number of nibbles indicated by the glyph */
1682 /* metrics. If there are more columns, they are simply ignored. */
1683 nibbles = glyph->bpr << 1;
1684 bp = glyph->bitmap + p->row * glyph->bpr;
1685
1686 for ( i = 0, *bp = 0; i < nibbles; i++ )
1687 {
1688 c = line[i];
Werner Lemberg233302a2002-05-22 05:41:06 +00001689 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001690 if ( i + 1 < nibbles && ( i & 1 ) )
1691 *++bp = 0;
1692 }
1693
1694 /* Remove possible garbage at the right. */
1695 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
1696 *bp &= nibble_mask[mask_index];
1697
1698 /* If any line has extra columns, indicate they have been removed. */
1699 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1700 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1701 {
1702 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1703 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1704 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001705 }
1706
1707 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001708 goto Exit;
1709 }
David Turner993a8d02002-05-18 12:03:43 +00001710
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001711 /* Expect the SWIDTH (scalable width) field next. */
1712 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1713 {
1714 if ( !( p->flags & _BDF_ENCODING ) )
1715 {
1716 /* Missing ENCODING field. */
1717 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1718 error = BDF_Err_Missing_Encoding_Field;
1719 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001720 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001721
1722 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1723 if ( error )
1724 goto Exit;
David Turnerb1b47622002-05-21 21:17:43 +00001725 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001726 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001727
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001728 goto Exit;
1729 }
David Turner993a8d02002-05-18 12:03:43 +00001730
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001731 /* Expect the DWIDTH (scalable width) field next. */
1732 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1733 {
1734 error = _bdf_split( (char *)" +", line, linelen, &p->list,memory );
1735 if ( error )
1736 goto Exit;
David Turnerb1b47622002-05-21 21:17:43 +00001737 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001738
1739 if ( !( p->flags & _BDF_SWIDTH ) )
1740 {
1741 /* Missing SWIDTH field. Emit an auto correction message and set */
1742 /* the scalable width from the device width. */
1743 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1744
Werner Lemberg02d4d592002-05-28 22:38:05 +00001745 glyph->swidth = (unsigned short)FT_MulDiv(
1746 glyph->dwidth, 72000L,
1747 (FT_Long)( font->point_size *
1748 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001749 }
1750
1751 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001752 goto Exit;
1753 }
David Turner993a8d02002-05-18 12:03:43 +00001754
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001755 /* Expect the BBX field next. */
1756 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1757 {
1758 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1759 if ( error )
1760 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001761
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001762 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1763 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1764 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1765 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1766
1767 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001768 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1769 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001770
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001771 /* Determine the overall font bounding box as the characters are */
1772 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001773 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1774 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001775
David Turnerb1b47622002-05-21 21:17:43 +00001776 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001777
Werner Lembergdfa46192004-03-05 09:26:24 +00001778 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1779 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1780 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001781
1782 if ( !( p->flags & _BDF_DWIDTH ) )
1783 {
1784 /* Missing DWIDTH field. Emit an auto correction message and set */
1785 /* the device width to the glyph width. */
1786 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1787 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001788 }
1789
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001790 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1791 /* value if necessary. */
1792 if ( p->opts->correct_metrics != 0 )
1793 {
1794 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001795 unsigned short sw = (unsigned short)FT_MulDiv(
1796 glyph->dwidth, 72000L,
1797 (FT_Long)( font->point_size *
1798 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001799
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001800
1801 if ( sw != glyph->swidth )
1802 {
1803 glyph->swidth = sw;
1804
1805 if ( p->glyph_enc == -1 )
1806 _bdf_set_glyph_modified( font->umod,
1807 font->unencoded_used - 1 );
1808 else
1809 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1810
1811 p->flags |= _BDF_SWIDTH_ADJ;
1812 font->modified = 1;
1813 }
David Turner993a8d02002-05-18 12:03:43 +00001814 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001815
David Turner993a8d02002-05-18 12:03:43 +00001816 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001817 goto Exit;
1818 }
David Turner993a8d02002-05-18 12:03:43 +00001819
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001820 /* And finally, gather up the bitmap. */
1821 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1822 {
1823 if ( !( p->flags & _BDF_BBX ) )
1824 {
1825 /* Missing BBX field. */
1826 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1827 error = BDF_Err_Missing_Bbx_Field;
1828 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001829 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001830
1831 /* Allocate enough space for the bitmap. */
1832 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg233302a2002-05-22 05:41:06 +00001833 glyph->bytes = (unsigned short)( glyph->bpr * glyph->bbx.height );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001834
1835 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1836 goto Exit;
1837
1838 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001839 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001840
1841 goto Exit;
1842 }
1843
1844 error = BDF_Err_Invalid_File_Format;
1845
1846 Exit:
1847 return error;
David Turner993a8d02002-05-18 12:03:43 +00001848 }
1849
David Turner993a8d02002-05-18 12:03:43 +00001850
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001851 /* Load the font properties. */
1852 static FT_Error
1853 _bdf_parse_properties( char* line,
1854 unsigned long linelen,
1855 unsigned long lineno,
1856 void* call_data,
1857 void* client_data )
1858 {
1859 unsigned long vlen;
1860 _bdf_line_func_t* next;
1861 _bdf_parse_t* p;
1862 char* name;
1863 char* value;
1864 char nbuf[128];
1865 FT_Memory memory;
1866 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001867
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001868 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001869
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001870
1871 next = (_bdf_line_func_t *)call_data;
1872 p = (_bdf_parse_t *) client_data;
1873
1874 memory = p->font->memory;
1875
1876 /* Check for the end of the properties. */
1877 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1878 {
1879 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1880 /* encountered yet, then make sure they are added as properties and */
1881 /* make sure they are set from the font bounding box info. */
1882 /* */
1883 /* This is *always* done regardless of the options, because X11 */
1884 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001885 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001886 {
1887 p->font->font_ascent = p->font->bbx.ascent;
1888 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1889 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
1890 if ( error )
1891 goto Exit;
1892
1893 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1894 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001895 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001896
Werner Lemberg428c2e42003-04-25 05:35:04 +00001897 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001898 {
1899 p->font->font_descent = p->font->bbx.descent;
1900 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1901 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
1902 if ( error )
1903 goto Exit;
1904
1905 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1906 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001907 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001908
David Turner993a8d02002-05-18 12:03:43 +00001909 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001910 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001911
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001912 goto Exit;
1913 }
David Turner993a8d02002-05-18 12:03:43 +00001914
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001915 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1916 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1917 goto Exit;
1918
1919 /* Handle COMMENT fields and properties in a special way to preserve */
1920 /* the spacing. */
1921 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1922 {
David Turner993a8d02002-05-18 12:03:43 +00001923 name = value = line;
1924 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001925 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001926 *value++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001927 error = _bdf_add_property( p->font, name, value );
1928 if ( error )
1929 goto Exit;
1930 }
1931 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1932 {
1933 error = _bdf_add_property( p->font, name, value );
1934 if ( error )
1935 goto Exit;
1936 }
1937 else
1938 {
1939 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1940 if ( error )
1941 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001942 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001943
1944 _bdf_shift( 1, &p->list );
1945 value = _bdf_join( ' ', &vlen, &p->list );
1946
1947 error = _bdf_add_property( p->font, name, value );
1948 if ( error )
1949 goto Exit;
1950 }
1951
1952 Exit:
1953 return error;
David Turner993a8d02002-05-18 12:03:43 +00001954 }
1955
David Turner993a8d02002-05-18 12:03:43 +00001956
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001957 /* Load the font header. */
1958 static FT_Error
1959 _bdf_parse_start( char* line,
1960 unsigned long linelen,
1961 unsigned long lineno,
1962 void* call_data,
1963 void* client_data )
1964 {
1965 unsigned long slen;
1966 _bdf_line_func_t* next;
1967 _bdf_parse_t* p;
1968 bdf_font_t* font;
1969 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001970
David Turnerd490e372002-05-28 23:40:37 +00001971 FT_Memory memory = NULL;
1972 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001973
1974 FT_UNUSED( lineno ); /* only used in debug mode */
1975
1976
1977 next = (_bdf_line_func_t *)call_data;
1978 p = (_bdf_parse_t *) client_data;
1979
1980 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00001981 memory = p->font->memory;
1982
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001983 /* Check for a comment. This is done to handle those fonts that have */
1984 /* comments before the STARTFONT line for some reason. */
1985 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1986 {
1987 if ( p->opts->keep_comments != 0 && p->font != 0 )
1988 {
1989 linelen -= 7;
1990
1991 s = line + 7;
1992 if ( *s != 0 )
1993 {
1994 s++;
1995 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00001996 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001997
1998 error = _bdf_add_comment( p->font, s, linelen );
1999 if ( error )
2000 goto Exit;
2001 /* here font is not defined! */
2002 }
2003
2004 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002005 }
2006
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002007 if ( !( p->flags & _BDF_START ) )
2008 {
2009 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002010
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002011 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2012 {
2013 /* No STARTFONT field is a good indication of a problem. */
2014 error = BDF_Err_Missing_Startfont_Field;
2015 goto Exit;
2016 }
David Turner993a8d02002-05-18 12:03:43 +00002017
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002018 p->flags = _BDF_START;
2019 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002020
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002021 if ( FT_NEW( font ) )
2022 goto Exit;
2023 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002024
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002025 font->memory = p->memory;
2026 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002027
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002028 { /* setup */
2029 unsigned long i;
2030 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002031
David Turner993a8d02002-05-18 12:03:43 +00002032
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002033 error = hash_init( &(font->proptbl), memory );
2034 if ( error )
2035 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002036 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002037 i < _num_bdf_properties; i++, prop++ )
2038 {
2039 error = hash_insert( prop->name, (void *)i,
2040 &(font->proptbl), memory );
2041 if ( error )
2042 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002043 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002044 }
2045
2046 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2047 goto Exit;
2048 error = hash_init( (hashtable *)p->font->internal,memory );
2049 if ( error )
2050 goto Exit;
2051 p->font->spacing = p->opts->font_spacing;
2052 p->font->default_glyph = -1;
2053
2054 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002055 }
2056
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002057 /* Check for the start of the properties. */
2058 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2059 {
2060 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
2061 if ( error )
2062 goto Exit;
2063 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2064
2065 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2066 goto Exit;
2067
2068 p->flags |= _BDF_PROPS;
2069 *next = _bdf_parse_properties;
2070
2071 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002072 }
2073
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002074 /* Check for the FONTBOUNDINGBOX field. */
2075 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2076 {
2077 if ( !(p->flags & _BDF_SIZE ) )
2078 {
2079 /* Missing the SIZE field. */
2080 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2081 error = BDF_Err_Missing_Size_Field;
2082 goto Exit;
2083 }
2084
2085 error = _bdf_split( (char *)" +", line, linelen, &p->list , memory );
2086 if ( error )
2087 goto Exit;
2088
2089 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2090 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2091
2092 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2093 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2094
David Turnerd490e372002-05-28 23:40:37 +00002095 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002096 p->font->bbx.y_offset );
2097
2098 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002099
2100 p->flags |= _BDF_FONT_BBX;
2101
2102 goto Exit;
2103 }
2104
2105 /* The next thing to check for is the FONT field. */
2106 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2107 {
2108 error = _bdf_split( (char *)" +", line, linelen, &p->list , memory );
2109 if ( error )
2110 goto Exit;
2111 _bdf_shift( 1, &p->list );
2112
2113 s = _bdf_join( ' ', &slen, &p->list );
2114 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2115 goto Exit;
2116 FT_MEM_COPY( p->font->name, s, slen + 1 );
2117
2118 /* If the font name is an XLFD name, set the spacing to the one in */
2119 /* the font name. If there is no spacing fall back on the default. */
2120 error = _bdf_set_default_spacing( p->font, p->opts );
2121 if ( error )
2122 goto Exit;
2123
2124 p->flags |= _BDF_FONT_NAME;
2125
2126 goto Exit;
2127 }
2128
2129 /* Check for the SIZE field. */
2130 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2131 {
2132 if ( !( p->flags & _BDF_FONT_NAME ) )
2133 {
2134 /* Missing the FONT field. */
2135 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2136 error = BDF_Err_Missing_Font_Field;
2137 goto Exit;
2138 }
2139
2140 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
2141 if ( error )
2142 goto Exit;
2143
2144 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2145 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2146 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2147
2148 /* Check for the bits per pixel field. */
2149 if ( p->list.used == 5 )
2150 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002151 unsigned short bitcount, i, shift;
2152
2153
2154 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2155
2156 /* Only values 1, 2, 4, 8 are allowed. */
2157 shift = p->font->bpp;
2158 bitcount = 0;
2159 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002160 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002161 if ( shift & 1 )
2162 bitcount = i;
2163 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002164 }
David Turner993a8d02002-05-18 12:03:43 +00002165
Werner Lembergbd8e3242002-06-12 08:43:58 +00002166 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002167
2168 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002169 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002170 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002171 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002172 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002173 }
2174 }
2175 else
2176 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002177
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002178 p->flags |= _BDF_SIZE;
2179
2180 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002181 }
2182
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002183 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002184
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002185 Exit:
2186 return error;
2187 }
David Turner993a8d02002-05-18 12:03:43 +00002188
2189
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002190 /*************************************************************************/
2191 /* */
2192 /* API. */
2193 /* */
2194 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002195
David Turner993a8d02002-05-18 12:03:43 +00002196
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002197 FT_LOCAL_DEF( FT_Error )
2198 bdf_load_font( FT_Stream stream,
2199 FT_Memory extmemory,
2200 bdf_options_t* opts,
2201 bdf_font_t* *font )
2202 {
2203 unsigned long lineno;
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002204 _bdf_parse_t *p;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002205
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002206 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002207 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002208
2209
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002210 if ( FT_ALLOC( p, sizeof ( _bdf_parse_t ) ) )
2211 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002212
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002213 memory = NULL;
2214 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2215 p->minlb = 32767;
2216 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002217
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002218 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002219 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002220 if ( error )
2221 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002222
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002223 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002224 {
2225 /* If the font is not proportional, set the font's monowidth */
2226 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002227 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002228
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002229 if ( p->font->spacing != BDF_PROPORTIONAL )
2230 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002231
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002232 /* If the number of glyphs loaded is not that of the original count, */
2233 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002234 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002235 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002236 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2237 p->font->glyphs_used + p->font->unencoded_used ));
2238 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002239 }
2240
2241 /* Once the font has been loaded, adjust the overall font metrics if */
2242 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002243 if ( p->opts->correct_metrics != 0 &&
2244 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002245 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002246 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002247 {
2248 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002249 p->font->bbx.width, p->maxrb - p->minlb ));
2250 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2251 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002252 }
2253
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002254 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002255 {
2256 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002257 p->font->bbx.x_offset, p->minlb ));
2258 p->font->bbx.x_offset = p->minlb;
2259 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002260 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002261
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002262 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002263 {
2264 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002265 p->font->bbx.ascent, p->maxas ));
2266 p->font->bbx.ascent = p->maxas;
2267 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002268 }
2269
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002270 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002271 {
2272 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002273 p->font->bbx.descent, p->maxds ));
2274 p->font->bbx.descent = p->maxds;
2275 p->font->bbx.y_offset = (short)( -p->maxds );
2276 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002277 }
2278
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002279 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002280 {
2281 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002282 p->font->bbx.height, p->maxas + p->maxds ));
2283 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002284 }
2285
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002286 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002287 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2288 }
David Turner993a8d02002-05-18 12:03:43 +00002289 }
2290
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002291 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002292 {
2293 {
2294 /* The ENDFONT field was never reached or did not exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002295 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002296 /* Error happened while parsing header. */
2297 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2298 else
2299 /* Error happened when parsing glyphs. */
2300 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2301 }
David Turner993a8d02002-05-18 12:03:43 +00002302 }
2303
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002304 /* Free up the list used during the parsing. */
Werner Lemberg7925edc2002-05-30 19:29:41 +00002305 if ( memory != NULL )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002306 FT_FREE( p->list.field );
David Turner993a8d02002-05-18 12:03:43 +00002307
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002308 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002309 {
2310 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002311 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002312
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002313 if ( p->font->comments_len > 0 ) {
2314 if ( FT_RENEW_ARRAY( p->font->comments,
2315 p->font->comments_len,
2316 p->font->comments_len + 1 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002317 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002318
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002319 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002320 }
David Turner993a8d02002-05-18 12:03:43 +00002321 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002322 else if ( error == BDF_Err_Ok )
2323 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002324
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002325 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002326
2327 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002328 if ( p )
2329 {
2330 memory = extmemory;
2331 FT_FREE( p );
2332 }
2333
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002334 return error;
2335 }
David Turner993a8d02002-05-18 12:03:43 +00002336
2337
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002338 FT_LOCAL_DEF( void )
2339 bdf_free_font( bdf_font_t* font )
2340 {
2341 bdf_property_t* prop;
2342 unsigned long i;
2343 bdf_glyph_t* glyphs;
2344 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002345
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002346
2347 if ( font == 0 )
2348 return;
David Turner993a8d02002-05-18 12:03:43 +00002349
2350 memory = font->memory;
2351
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002352 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002353
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002354 /* Free up the internal hash table of property names. */
2355 if ( font->internal )
2356 {
2357 hash_free( (hashtable *)font->internal, memory );
2358 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002359 }
2360
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002361 /* Free up the comment info. */
2362 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002363
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002364 /* Free up the properties. */
2365 for ( i = 0; i < font->props_size; i++ )
2366 {
2367 if ( font->props[i].format == BDF_ATOM )
2368 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002369 }
2370
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002371 FT_FREE( font->props );
2372
2373 /* Free up the character info. */
2374 for ( i = 0, glyphs = font->glyphs;
2375 i < font->glyphs_used; i++, glyphs++ )
2376 {
2377 FT_FREE( glyphs->name );
2378 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002379 }
2380
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002381 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2382 i++, glyphs++ )
2383 {
2384 FT_FREE( glyphs->name );
2385 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002386 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002387
2388 FT_FREE( font->glyphs );
2389 FT_FREE( font->unencoded );
2390
2391 /* Free up the overflow storage if it was used. */
2392 for ( i = 0, glyphs = font->overflow.glyphs;
2393 i < font->overflow.glyphs_used; i++, glyphs++ )
2394 {
2395 FT_FREE( glyphs->name );
2396 FT_FREE( glyphs->bitmap );
2397 }
2398
2399 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002400
2401 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002402 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002403
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002404 /* Free up the user defined properties. */
2405 for (prop = font->user_props, i = 0;
2406 i < font->nuser_props; i++, prop++ )
2407 {
2408 FT_FREE( prop->name );
2409 if ( prop->format == BDF_ATOM )
2410 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002411 }
David Turner993a8d02002-05-18 12:03:43 +00002412
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002413 FT_FREE( font->user_props );
2414
2415 /* FREE( font ); */ /* XXX Fixme */
2416 }
David Turner993a8d02002-05-18 12:03:43 +00002417
2418
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002419 FT_LOCAL_DEF( bdf_property_t * )
2420 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002421 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002422 {
2423 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002424
David Turner993a8d02002-05-18 12:03:43 +00002425
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002426 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002427 return 0;
2428
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002429 hn = hash_lookup( name, (hashtable *)font->internal );
2430
2431 return hn ? ( font->props + (unsigned long)hn->data ) : 0;
2432 }
2433
2434
2435/* END */