blob: 9ac50beabe16bdd8deb10eb3ef23eb0046eb462f [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 Lemberg7cf4d372002-05-21 14:13:01 +0000227
228 for ( i = 0, bp = obp; i < sz; i++, bp++ )
David Turner993a8d02002-05-18 12:03:43 +0000229 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000230 if ( *bp )
231 {
232 nbp = hash_bucket( (*bp)->key, ht );
233 *nbp = *bp;
234 }
David Turner993a8d02002-05-18 12:03:43 +0000235 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000236 FT_FREE( obp );
237
238 Exit:
239 return error;
David Turner993a8d02002-05-18 12:03:43 +0000240 }
David Turner993a8d02002-05-18 12:03:43 +0000241
242
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000243 static FT_Error
244 hash_init( hashtable* ht,
245 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000246 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000247 int sz = INITIAL_HT_SIZE;
248 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000249
David Turner993a8d02002-05-18 12:03:43 +0000250
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000251 ht->size = sz;
252 ht->limit = sz / 3;
253 ht->used = 0;
David Turner993a8d02002-05-18 12:03:43 +0000254
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000255 if ( FT_NEW_ARRAY( ht->table, sz ) )
256 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000257
258 Exit:
259 return error;
David Turner993a8d02002-05-18 12:03:43 +0000260 }
David Turner993a8d02002-05-18 12:03:43 +0000261
262
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000263 static void
264 hash_free( hashtable* ht,
265 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000266 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000267 if ( ht != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000268 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000269 int i, sz = ht->size;
270 hashnode* bp = ht->table;
David Turner993a8d02002-05-18 12:03:43 +0000271
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000272
273 for ( i = 0; i < sz; i++, bp++ )
274 FT_FREE( *bp );
275
276 FT_FREE( ht->table );
277 }
David Turner993a8d02002-05-18 12:03:43 +0000278 }
279
David Turner993a8d02002-05-18 12:03:43 +0000280
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000281 static FT_Error
282 hash_insert( char* key,
283 void* data,
284 hashtable* ht,
285 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000286 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000287 hashnode nn, *bp = hash_bucket( key, ht );
288 FT_Error error = BDF_Err_Ok;
289
290
291 nn = *bp;
292 if ( !nn )
293 {
294 if ( FT_NEW( nn ) )
295 goto Exit;
296 *bp = nn;
297
298 nn->key = key;
299 nn->data = data;
300
301 if ( ht->used >= ht->limit )
302 {
303 error = hash_rehash( ht, memory );
304 if ( error )
305 goto Exit;
306 }
307 ht->used++;
308 }
David Turner993a8d02002-05-18 12:03:43 +0000309 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000310 nn->data = data;
311
312 Exit:
313 return error;
David Turner993a8d02002-05-18 12:03:43 +0000314 }
315
David Turner993a8d02002-05-18 12:03:43 +0000316
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000317 static hashnode
Werner Lemberg428c2e42003-04-25 05:35:04 +0000318 hash_lookup( const char* key,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000319 hashtable* ht )
320 {
321 hashnode *np = hash_bucket( key, ht );
322
323
324 return *np;
325 }
326
327
328 /*************************************************************************/
329 /* */
330 /* Utility types and functions. */
331 /* */
332 /*************************************************************************/
333
334
335 /* Function type for parsing lines of a BDF font. */
336
337 typedef FT_Error
338 (*_bdf_line_func_t)( char* line,
339 unsigned long linelen,
340 unsigned long lineno,
341 void* call_data,
342 void* client_data );
343
344
345 /* List structure for splitting lines into fields. */
346
347 typedef struct _bdf_list_t_
348 {
349 char** field;
350 unsigned long size;
351 unsigned long used;
David Turner68df4f72005-03-15 18:18:57 +0000352 FT_Memory memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000353
354 } _bdf_list_t;
355
356
357 /* Structure used while loading BDF fonts. */
358
359 typedef struct _bdf_parse_t_
360 {
361 unsigned long flags;
362 unsigned long cnt;
363 unsigned long row;
364
365 short minlb;
366 short maxlb;
367 short maxrb;
368 short maxas;
369 short maxds;
370
371 short rbearing;
372
373 char* glyph_name;
374 long glyph_enc;
375
376 bdf_font_t* font;
377 bdf_options_t* opts;
378
379 unsigned long have[2048];
380 _bdf_list_t list;
381
382 FT_Memory memory;
383
384 } _bdf_parse_t;
385
386
David Turnerb1b47622002-05-21 21:17:43 +0000387#define setsbit( m, cc ) ( m[(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000388#define sbitset( m, cc ) ( m[(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
389
390
David Turner68df4f72005-03-15 18:18:57 +0000391 static void
392 _bdf_list_init( _bdf_list_t* list,
393 FT_Memory memory )
394 {
395 FT_ZERO(list);
396 list->memory = memory;
397 }
398
399 static void
400 _bdf_list_done( _bdf_list_t* list )
401 {
402 FT_Memory memory = list->memory;
403
404 if ( memory )
405 {
406 FT_FREE( list->field );
407 FT_ZERO(list);
408 }
409 }
410
411
412 static FT_Error
413 _bdf_list_ensure( _bdf_list_t* list,
414 int num_items )
415 {
416 FT_Error error = 0;
417
418 if ( num_items > list->size )
419 {
420 int oldsize = list->size;
421 int newsize = oldsize + (oldsize >> 1) + 4;
422 int bigsize = FT_INT_MAX / sizeof(char*);
423 FT_Memory memory = list->memory;
424
425 if ( oldsize == bigsize )
426 {
427 error = FT_Err_Out_Of_Memory;
428 goto Exit;
429 }
430 else if ( newsize < oldsize || newsize > bigsize )
431 newsize = bigsize;
432
433 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
434 goto Exit;
435
436 list->size = newsize;
437 }
438 Exit:
439 return error;
440 }
441
442
443 static void
444 _bdf_list_shift( _bdf_list_t* list,
445 unsigned long n )
446 {
447 unsigned long i, u;
448
449
450 if ( list == 0 || list->used == 0 || n == 0 )
451 return;
452
453 if ( n >= list->used )
454 {
455 list->used = 0;
456 return;
457 }
458
459 for ( u = n, i = 0; u < list->used; i++, u++ )
460 list->field[i] = list->field[u];
461 list->used -= n;
462 }
463
464
465 static char *
466 _bdf_list_join( _bdf_list_t* list,
467 int c,
468 unsigned long *alen )
469 {
470 unsigned long i, j;
471 char *fp, *dp;
472
473
474 *alen = 0;
475
476 if ( list == 0 || list->used == 0 )
477 return 0;
478
479 dp = list->field[0];
480 for ( i = j = 0; i < list->used; i++ )
481 {
482 fp = list->field[i];
483 while ( *fp )
484 dp[j++] = *fp++;
485
486 if ( i + 1 < list->used )
487 dp[j++] = (char)c;
488 }
489 dp[j] = 0;
490
491 *alen = j;
492 return dp;
493 }
494
495
496
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000497 /* An empty string for empty fields. */
498
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000499 static const char empty[1] = { 0 }; /* XXX eliminate this */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000500
501
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000502
503 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000504 _bdf_list_split( _bdf_list_t* list,
505 char* separators,
506 char* line,
507 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000508 {
509 int mult, final_empty;
510 char *sp, *ep, *end;
511 char seps[32];
512 FT_Error error = BDF_Err_Ok;
513
514
515 /* Initialize the list. */
516 list->used = 0;
517
518 /* If the line is empty, then simply return. */
519 if ( linelen == 0 || line[0] == 0 )
520 goto Exit;
521
522 /* In the original code, if the `separators' parameter is NULL or */
523 /* empty, the list is split into individual bytes. We don't need */
524 /* this, so an error is signaled. */
525 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000526 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000527 error = BDF_Err_Invalid_Argument;
528 goto Exit;
529 }
530
531 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000532 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000533
534 /* If the very last character of the separator string is a plus, then */
535 /* set the `mult' flag to indicate that multiple separators should be */
536 /* collapsed into one. */
537 for ( mult = 0, sp = separators; sp && *sp; sp++ )
538 {
539 if ( *sp == '+' && *( sp + 1 ) == 0 )
540 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000541 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000542 setsbit( seps, *sp );
543 }
544
545 /* Break the line up into fields. */
546 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
547 sp < end && *sp; )
548 {
549 /* Collect everything that is not a separator. */
550 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
551 ;
552
553 /* Resize the list if necessary. */
554 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000555 {
David Turner68df4f72005-03-15 18:18:57 +0000556 error = _bdf_list_ensure( list, list->used+1 );
557 if ( error )
558 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000559 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000560
561 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000562 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000563
564 sp = ep;
565
566 if ( mult )
567 {
568 /* If multiple separators should be collapsed, do it now by */
569 /* setting all the separator characters to 0. */
570 for ( ; *ep && sbitset( seps, *ep ); ep++ )
571 *ep = 0;
572 }
573 else if ( *ep != 0 )
574 /* Don't collapse multiple separators by making them 0, so just */
575 /* make the one encountered 0. */
576 *ep++ = 0;
577
578 final_empty = ( ep > sp && *ep == 0 );
579 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000580 }
581
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000582 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000583 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000584 {
David Turner68df4f72005-03-15 18:18:57 +0000585 error = _bdf_list_ensure( list, list->used+final_empty+1 );
586 if ( error )
587 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000588 }
589
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000590 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000591 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000592
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000593 list->field[list->used] = 0;
594
595 Exit:
596 return error;
David Turner993a8d02002-05-18 12:03:43 +0000597 }
598
David Turner993a8d02002-05-18 12:03:43 +0000599
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000600
David Turner68df4f72005-03-15 18:18:57 +0000601#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000602
603 static FT_Error
604 _bdf_readstream( FT_Stream stream,
605 _bdf_line_func_t callback,
606 void* client_data,
607 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000608 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000609 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000610 unsigned long lineno, buf_size;
611 int refill, bytes, hold, to_skip;
612 int start, end, cursor, avail;
613 char* buf = 0;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000614 FT_Memory memory = stream->memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000615 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000616
David Turner993a8d02002-05-18 12:03:43 +0000617
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000618 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000619 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000620 error = BDF_Err_Invalid_Argument;
621 goto Exit;
622 }
David Turner993a8d02002-05-18 12:03:43 +0000623
David Turner68df4f72005-03-15 18:18:57 +0000624 /* initial size and allocation of the input buffer
625 */
626 buf_size = 1024;
627
628 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000629 goto Exit;
630
David Turner68df4f72005-03-15 18:18:57 +0000631 cb = callback;
632 lineno = 1;
633 buf[0] = 0;
634 start = 0;
635 end = 0;
636 avail = 0;
637 cursor = 0;
638 refill = 1;
639 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000640
David Turner68df4f72005-03-15 18:18:57 +0000641 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000642 {
David Turner68df4f72005-03-15 18:18:57 +0000643 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000644 {
David Turner68df4f72005-03-15 18:18:57 +0000645 bytes = (int) FT_Stream_TryRead( stream, buf + cursor,
646 (FT_ULong)(buf_size - cursor) );
647 avail = cursor + bytes;
648 cursor = 0;
649 refill = 0;
650 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000651
David Turner68df4f72005-03-15 18:18:57 +0000652 end = start;
653
654 /* should we skip an optional character like \n or \r ? */
655 if ( start < avail && buf[start] == to_skip )
656 {
657 start += 1;
658 to_skip = NO_SKIP;
659 continue;
660 }
661
662 /* try to find the end of the line */
663 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
664 end++;
665
666 /* if we hit the end of the buffer, try shifting its content
667 * or even resizing it
668 */
669 if ( end >= avail )
670 {
671 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
672 break; /* ignore it then exit */
673
674 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000675 {
David Turner68df4f72005-03-15 18:18:57 +0000676 /* this line is definitely too long, try resizing the input buffer
677 * a bit to handle it.
678 */
679 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000680
David Turner68df4f72005-03-15 18:18:57 +0000681 if ( buf_size >= 65536UL ) /* limit ourselves to 64 Kb */
682 {
683 error = BDF_Err_Invalid_Argument;
684 goto Exit;
685 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000686
David Turner68df4f72005-03-15 18:18:57 +0000687 new_size = buf_size*2;
688 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
689 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000690
David Turner68df4f72005-03-15 18:18:57 +0000691 cursor = buf_size;
692 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000693 }
694 else
695 {
David Turner68df4f72005-03-15 18:18:57 +0000696 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000697
David Turner68df4f72005-03-15 18:18:57 +0000698 FT_MEM_COPY( buf, buf+start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000699
David Turner68df4f72005-03-15 18:18:57 +0000700 cursor = bytes;
701 avail -= bytes;
702 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000703 }
David Turner68df4f72005-03-15 18:18:57 +0000704 refill = 1;
705 continue;
David Turner993a8d02002-05-18 12:03:43 +0000706 }
David Turner68df4f72005-03-15 18:18:57 +0000707
708 /* Temporarily NUL-terminate the line. */
709 hold = buf[end];
710 buf[end] = 0;
711
712 /* XXX: Use encoding independent value for 0x1a */
713 if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
714 {
715 error = (*cb)( buf+start, end-start, lineno, (void*)&cb, client_data );
716 if ( error )
717 break;
718 }
719
720 lineno += 1;
721 buf[end] = (char)hold;
722 start = end+1;
723
724 if ( hold == '\n' )
725 to_skip = '\r';
726 else if ( hold == '\r' )
727 to_skip = '\n';
728 else
729 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000730 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000731
David Turner68df4f72005-03-15 18:18:57 +0000732 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000733
734 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000735 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000736 return error;
David Turner993a8d02002-05-18 12:03:43 +0000737 }
David Turner993a8d02002-05-18 12:03:43 +0000738
739
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000740 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000741
David Turnerb1b47622002-05-21 21:17:43 +0000742 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000743 {
David Turner993a8d02002-05-18 12:03:43 +0000744 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
745 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
746 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
747 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
748 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
749 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
750 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
751 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
752 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
753 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
754 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000755 };
David Turner993a8d02002-05-18 12:03:43 +0000756
David Turnerb1b47622002-05-21 21:17:43 +0000757 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000758 {
David Turner993a8d02002-05-18 12:03:43 +0000759 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
760 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
761 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
762 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000763 };
David Turner993a8d02002-05-18 12:03:43 +0000764
David Turnerb1b47622002-05-21 21:17:43 +0000765 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000766 {
David Turner993a8d02002-05-18 12:03:43 +0000767 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
768 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
769 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
770 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000771 };
David Turner993a8d02002-05-18 12:03:43 +0000772
David Turnerb1b47622002-05-21 21:17:43 +0000773 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000774 {
David Turner993a8d02002-05-18 12:03:43 +0000775 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
776 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
777 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
778 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000779 };
David Turner993a8d02002-05-18 12:03:43 +0000780
David Turner993a8d02002-05-18 12:03:43 +0000781
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000782#define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
David Turner993a8d02002-05-18 12:03:43 +0000783
David Turner993a8d02002-05-18 12:03:43 +0000784
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000785 /* Routine to convert an ASCII string into an unsigned long integer. */
786 static unsigned long
787 _bdf_atoul( char* s,
788 char** end,
789 int base )
David Turner993a8d02002-05-18 12:03:43 +0000790 {
David Turnerb1b47622002-05-21 21:17:43 +0000791 unsigned long v;
792 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000793
794
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000795 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000796 return 0;
797
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000798 /* Make sure the radix is something recognizable. Default to 10. */
799 switch ( base )
800 {
801 case 8:
802 dmap = odigits;
803 break;
804 case 16:
805 dmap = hdigits;
806 break;
807 default:
808 base = 10;
809 dmap = ddigits;
810 break;
David Turner993a8d02002-05-18 12:03:43 +0000811 }
812
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000813 /* Check for the special hex prefix. */
814 if ( *s == '0' &&
815 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
816 {
817 base = 16;
818 dmap = hdigits;
819 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000820 }
821
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000822 for ( v = 0; isdigok( dmap, *s ); s++ )
823 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000824
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000825 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000826 *end = s;
827
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000828 return v;
829 }
David Turner993a8d02002-05-18 12:03:43 +0000830
David Turner993a8d02002-05-18 12:03:43 +0000831
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000832 /* Routine to convert an ASCII string into an signed long integer. */
833 static long
834 _bdf_atol( char* s,
835 char** end,
836 int base )
837 {
David Turnerb1b47622002-05-21 21:17:43 +0000838 long v, neg;
839 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000840
841
842 if ( s == 0 || *s == 0 )
843 return 0;
844
845 /* Make sure the radix is something recognizable. Default to 10. */
846 switch ( base )
847 {
848 case 8:
849 dmap = odigits;
850 break;
851 case 16:
852 dmap = hdigits;
853 break;
854 default:
855 base = 10;
856 dmap = ddigits;
857 break;
858 }
859
860 /* Check for a minus sign. */
861 neg = 0;
862 if ( *s == '-' )
863 {
864 s++;
865 neg = 1;
866 }
867
868 /* Check for the special hex prefix. */
869 if ( *s == '0' &&
870 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
871 {
872 base = 16;
873 dmap = hdigits;
874 s += 2;
875 }
876
877 for ( v = 0; isdigok( dmap, *s ); s++ )
878 v = v * base + a2i[(int)*s];
879
880 if ( end != 0 )
881 *end = s;
882
883 return ( !neg ) ? v : -v;
884 }
885
886
887 /* Routine to convert an ASCII string into an signed short integer. */
888 static short
889 _bdf_atos( char* s,
890 char** end,
891 int base )
892 {
David Turnerb1b47622002-05-21 21:17:43 +0000893 short v, neg;
894 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000895
896
897 if ( s == 0 || *s == 0 )
898 return 0;
899
900 /* Make sure the radix is something recognizable. Default to 10. */
901 switch ( base )
902 {
903 case 8:
904 dmap = odigits;
905 break;
906 case 16:
907 dmap = hdigits;
908 break;
909 default:
910 base = 10;
911 dmap = ddigits;
912 break;
913 }
914
915 /* Check for a minus. */
916 neg = 0;
917 if ( *s == '-' )
918 {
919 s++;
920 neg = 1;
921 }
922
923 /* Check for the special hex prefix. */
924 if ( *s == '0' &&
925 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
926 {
927 base = 16;
928 dmap = hdigits;
929 s += 2;
930 }
931
932 for ( v = 0; isdigok( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +0000933 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000934
935 if ( end != 0 )
936 *end = s;
937
Werner Lemberg233302a2002-05-22 05:41:06 +0000938 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000939 }
940
941
942 /* Routine to compare two glyphs by encoding so they can be sorted. */
943 static int
944 by_encoding( const void* a,
945 const void* b )
946 {
947 bdf_glyph_t *c1, *c2;
948
949
950 c1 = (bdf_glyph_t *)a;
951 c2 = (bdf_glyph_t *)b;
952
953 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000954 return -1;
David Turner68df4f72005-03-15 18:18:57 +0000955
956 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000957 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000958
David Turner993a8d02002-05-18 12:03:43 +0000959 return 0;
David Turner993a8d02002-05-18 12:03:43 +0000960 }
961
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000962
963 static FT_Error
964 bdf_create_property( char* name,
965 int format,
966 bdf_font_t* font )
967 {
968 unsigned long n;
969 bdf_property_t* p;
970 FT_Memory memory = font->memory;
971 FT_Error error = BDF_Err_Ok;
972
973
974 /* First check to see if the property has */
975 /* already been added or not. If it has, then */
976 /* simply ignore it. */
977 if ( hash_lookup( name, &(font->proptbl) ) )
978 goto Exit;
979
David Turner68df4f72005-03-15 18:18:57 +0000980 if ( FT_RENEW_ARRAY( font->user_props,
981 font->nuser_props,
982 font->nuser_props + 1 ) )
983 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000984
985 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +0000986 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000987
988 n = (unsigned long)( ft_strlen( name ) + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000989
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000990 if ( FT_NEW_ARRAY( p->name, n ) )
991 goto Exit;
992
993 FT_MEM_COPY( (char *)p->name, name, n );
994
995 p->format = format;
996 p->builtin = 0;
997
998 n = _num_bdf_properties + font->nuser_props;
999
1000 error = hash_insert( p->name, (void *)n, &(font->proptbl), memory );
1001 if ( error )
1002 goto Exit;
1003
1004 font->nuser_props++;
1005
1006 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001007 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001008 }
David Turner993a8d02002-05-18 12:03:43 +00001009
1010
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001011 FT_LOCAL_DEF( bdf_property_t * )
1012 bdf_get_property( char* name,
1013 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001014 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001015 hashnode hn;
1016 unsigned long propid;
1017
1018
1019 if ( name == 0 || *name == 0 )
1020 return 0;
1021
1022 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1023 return 0;
1024
1025 propid = (unsigned long)hn->data;
1026 if ( propid >= _num_bdf_properties )
1027 return font->user_props + ( propid - _num_bdf_properties );
1028
Werner Lemberg233302a2002-05-22 05:41:06 +00001029 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001030 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001031
1032
1033 /*************************************************************************/
1034 /* */
1035 /* BDF font file parsing flags and functions. */
1036 /* */
1037 /*************************************************************************/
1038
1039
1040 /* Parse flags. */
1041
1042#define _BDF_START 0x0001
1043#define _BDF_FONT_NAME 0x0002
1044#define _BDF_SIZE 0x0004
1045#define _BDF_FONT_BBX 0x0008
1046#define _BDF_PROPS 0x0010
1047#define _BDF_GLYPHS 0x0020
1048#define _BDF_GLYPH 0x0040
1049#define _BDF_ENCODING 0x0080
1050#define _BDF_SWIDTH 0x0100
1051#define _BDF_DWIDTH 0x0200
1052#define _BDF_BBX 0x0400
1053#define _BDF_BITMAP 0x0800
1054
1055#define _BDF_SWIDTH_ADJ 0x1000
1056
1057#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1058 _BDF_ENCODING | \
1059 _BDF_SWIDTH | \
1060 _BDF_DWIDTH | \
1061 _BDF_BBX | \
1062 _BDF_BITMAP )
1063
1064#define _BDF_GLYPH_WIDTH_CHECK 0x40000000L
1065#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000L
1066
1067
1068 /* Auto correction messages. */
1069#define ACMSG1 "FONT_ASCENT property missing. " \
1070 "Added \"FONT_ASCENT %hd\".\n"
1071#define ACMSG2 "FONT_DESCENT property missing. " \
1072 "Added \"FONT_DESCENT %hd\".\n"
1073#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
1074#define ACMSG4 "Font left bearing != actual left bearing. " \
1075 "Old: %hd New: %hd.\n"
1076#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
1077#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
1078#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
1079#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
1080#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
1081#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
1082#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
1083#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
1084#define ACMSG13 "Glyph %ld extra rows removed.\n"
1085#define ACMSG14 "Glyph %ld extra columns removed.\n"
1086#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
1087
1088 /* Error messages. */
1089#define ERRMSG1 "[line %ld] Missing \"%s\" line.\n"
1090#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
1091#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
1092
1093
1094 static FT_Error
1095 _bdf_add_comment( bdf_font_t* font,
1096 char* comment,
1097 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001098 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001099 char* cp;
1100 FT_Memory memory = font->memory;
1101 FT_Error error = BDF_Err_Ok;
1102
1103
David Turner68df4f72005-03-15 18:18:57 +00001104 if ( FT_RENEW_ARRAY( font->comments,
1105 font->comments_len,
1106 font->comments_len + len + 1 ) )
1107 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001108
1109 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001110
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001111 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001112 cp[len] = '\n';
1113
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001114 font->comments_len += len + 1;
1115
1116 Exit:
1117 return error;
David Turner993a8d02002-05-18 12:03:43 +00001118 }
1119
David Turner993a8d02002-05-18 12:03:43 +00001120
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001121 /* Set the spacing from the font name if it exists, or set it to the */
1122 /* default specified in the options. */
1123 static FT_Error
1124 _bdf_set_default_spacing( bdf_font_t* font,
1125 bdf_options_t* opts )
David Turner993a8d02002-05-18 12:03:43 +00001126 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001127 unsigned long len;
1128 char name[128];
1129 _bdf_list_t list;
1130 FT_Memory memory;
1131 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001132
David Turner993a8d02002-05-18 12:03:43 +00001133
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001134 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1135 {
1136 error = BDF_Err_Invalid_Argument;
1137 goto Exit;
1138 }
David Turner993a8d02002-05-18 12:03:43 +00001139
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001140 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001141
David Turner68df4f72005-03-15 18:18:57 +00001142 _bdf_list_init( &list, memory );
1143
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001144 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001145
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001146 len = (unsigned long)( ft_strlen( font->name ) + 1 );
1147 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001148
David Turner68df4f72005-03-15 18:18:57 +00001149 error = _bdf_list_split( &list, (char *)"-", name, len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001150 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001151 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001152
1153 if ( list.used == 15 )
1154 {
1155 switch ( list.field[11][0] )
1156 {
1157 case 'C':
1158 case 'c':
1159 font->spacing = BDF_CHARCELL;
1160 break;
1161 case 'M':
1162 case 'm':
1163 font->spacing = BDF_MONOWIDTH;
1164 break;
1165 case 'P':
1166 case 'p':
1167 font->spacing = BDF_PROPORTIONAL;
1168 break;
David Turner993a8d02002-05-18 12:03:43 +00001169 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001170 }
1171
David Turner68df4f72005-03-15 18:18:57 +00001172 Fail:
1173 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001174
1175 Exit:
1176 return error;
David Turner993a8d02002-05-18 12:03:43 +00001177 }
David Turner993a8d02002-05-18 12:03:43 +00001178
1179
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001180 /* Determine whether the property is an atom or not. If it is, then */
1181 /* clean it up so the double quotes are removed if they exist. */
1182 static int
1183 _bdf_is_atom( char* line,
1184 unsigned long linelen,
1185 char** name,
1186 char** value,
1187 bdf_font_t* font )
1188 {
1189 int hold;
1190 char *sp, *ep;
1191 bdf_property_t* p;
1192
David Turner993a8d02002-05-18 12:03:43 +00001193
1194 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001195
1196 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001197 ep++;
1198
1199 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001200 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001201 {
1202 hold = *ep;
1203 *ep = 0;
1204 }
1205
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001206 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001207
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001208 /* Restore the character that was saved before any return can happen. */
1209 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001210 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001211
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001212 /* If the property exists and is not an atom, just return here. */
1213 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001214 return 0;
1215
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001216 /* The property is an atom. Trim all leading and trailing whitespace */
1217 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001218 sp = ep;
1219 ep = line + linelen;
1220
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001221 /* Trim the leading whitespace if it exists. */
David Turner993a8d02002-05-18 12:03:43 +00001222 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001223 while ( *sp &&
1224 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001225 sp++;
1226
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001227 /* Trim the leading double quote if it exists. */
1228 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001229 sp++;
1230 *value = sp;
1231
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001232 /* Trim the trailing whitespace if it exists. */
1233 while ( ep > sp &&
1234 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001235 *--ep = 0;
1236
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001237 /* Trim the trailing double quote if it exists. */
1238 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001239 *--ep = 0;
1240
1241 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001242 }
David Turner993a8d02002-05-18 12:03:43 +00001243
1244
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001245 static FT_Error
1246 _bdf_add_property( bdf_font_t* font,
1247 char* name,
1248 char* value )
1249 {
1250 unsigned long propid;
1251 hashnode hn;
1252 int len;
1253 bdf_property_t *prop, *fp;
1254 FT_Memory memory = font->memory;
1255 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001256
David Turner993a8d02002-05-18 12:03:43 +00001257
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001258 /* First, check to see if the property already exists in the font. */
1259 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001260 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001261 /* The property already exists in the font, so simply replace */
1262 /* the value of the property with the current value. */
1263 fp = font->props + (unsigned long)hn->data;
1264
David Turnerb1b47622002-05-21 21:17:43 +00001265 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001266 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001267 case BDF_ATOM:
1268 /* Delete the current atom if it exists. */
1269 FT_FREE( fp->value.atom );
1270
1271 if ( value == 0 )
1272 len = 1;
1273 else
1274 len = ft_strlen( value ) + 1;
1275
1276 if ( len > 1 )
1277 {
1278 if ( FT_NEW_ARRAY( fp->value.atom, len ) )
1279 goto Exit;
1280 FT_MEM_COPY( fp->value.atom, value, len );
1281 }
1282 else
1283 fp->value.atom = 0;
1284 break;
1285
1286 case BDF_INTEGER:
1287 fp->value.int32 = _bdf_atol( value, 0, 10 );
1288 break;
1289
1290 case BDF_CARDINAL:
1291 fp->value.card32 = _bdf_atoul( value, 0, 10 );
1292 break;
David Turnerd490e372002-05-28 23:40:37 +00001293
David Turnerb1b47622002-05-21 21:17:43 +00001294 default:
1295 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001296 }
David Turnerd490e372002-05-28 23:40:37 +00001297
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001298 goto Exit;
1299 }
1300
1301 /* See whether this property type exists yet or not. */
1302 /* If not, create it. */
1303 hn = hash_lookup( name, &(font->proptbl) );
1304 if ( hn == 0 )
1305 {
1306 error = bdf_create_property( name, BDF_ATOM, font );
1307 if ( error )
1308 goto Exit;
1309 hn = hash_lookup( name, &(font->proptbl) );
1310 }
1311
1312 /* Allocate another property if this is overflow. */
1313 if ( font->props_used == font->props_size )
1314 {
1315 if ( font->props_size == 0 )
1316 {
1317 if ( FT_NEW_ARRAY( font->props, 1 ) )
1318 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001319 }
1320 else
1321 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001322 if ( FT_RENEW_ARRAY( font->props,
1323 font->props_size,
1324 font->props_size + 1 ) )
1325 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001326 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001327
David Turner993a8d02002-05-18 12:03:43 +00001328 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001329 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001330 font->props_size++;
1331 }
1332
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001333 propid = (unsigned long)hn->data;
1334 if ( propid >= _num_bdf_properties )
1335 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001336 else
David Turnerb1b47622002-05-21 21:17:43 +00001337 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001338
1339 fp = font->props + font->props_used;
1340
1341 fp->name = prop->name;
1342 fp->format = prop->format;
1343 fp->builtin = prop->builtin;
1344
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001345 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001346 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001347 case BDF_ATOM:
1348 if ( value == 0 )
1349 len = 1;
1350 else
1351 len = ft_strlen( value ) + 1;
David Turner993a8d02002-05-18 12:03:43 +00001352
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001353 if ( len > 1 )
1354 {
1355 if ( FT_NEW_ARRAY( fp->value.atom, len ) )
1356 goto Exit;
1357 FT_MEM_COPY( fp->value.atom, value, len );
1358 }
1359 else
1360 fp->value.atom = 0;
1361 break;
David Turner993a8d02002-05-18 12:03:43 +00001362
1363 case BDF_INTEGER:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001364 fp->value.int32 = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001365 break;
1366
1367 case BDF_CARDINAL:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001368 fp->value.card32 = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001369 break;
David Turner993a8d02002-05-18 12:03:43 +00001370 }
1371
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001372 /* If the property happens to be a comment, then it doesn't need */
1373 /* to be added to the internal hash table. */
1374 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) {
1375 /* Add the property to the font property table. */
1376 error = hash_insert( fp->name,
1377 (void *)font->props_used,
1378 (hashtable *)font->internal,
1379 memory );
1380 if ( error )
1381 goto Exit;
1382 }
David Turner993a8d02002-05-18 12:03:43 +00001383
1384 font->props_used++;
1385
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001386 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1387 /* property needs to be located if it exists in the property list, the */
1388 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1389 /* present, and the SPACING property should override the default */
1390 /* spacing. */
1391 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
Werner Lemberg8ef41832004-06-22 12:28:17 +00001392 font->default_char = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001393 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001394 font->font_ascent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001395 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001396 font->font_descent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001397 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001398 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001399 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001400 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001401 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001402 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001403 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001404 font->spacing = BDF_CHARCELL;
1405 }
1406
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001407 Exit:
1408 return error;
David Turner993a8d02002-05-18 12:03:43 +00001409 }
1410
David Turner993a8d02002-05-18 12:03:43 +00001411
David Turnerb1b47622002-05-21 21:17:43 +00001412 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001413 {
1414 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1415 };
1416
1417
1418 /* Actually parse the glyph info and bitmaps. */
1419 static FT_Error
1420 _bdf_parse_glyphs( char* line,
1421 unsigned long linelen,
1422 unsigned long lineno,
1423 void* call_data,
1424 void* client_data )
1425 {
1426 int c, mask_index;
1427 char* s;
1428 unsigned char* bp;
1429 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001430
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001431 _bdf_parse_t* p;
1432 bdf_glyph_t* glyph;
1433 bdf_font_t* font;
1434
1435 FT_Memory memory;
1436 FT_Error error = BDF_Err_Ok;
1437
Werner Lemberg319c00d2003-04-23 19:48:24 +00001438 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001439 FT_UNUSED( lineno ); /* only used in debug mode */
1440
1441
Werner Lemberg319c00d2003-04-23 19:48:24 +00001442 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001443
1444 font = p->font;
1445 memory = font->memory;
1446
1447 /* Check for a comment. */
1448 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1449 {
1450 linelen -= 7;
1451
1452 s = line + 7;
1453 if ( *s != 0 )
1454 {
1455 s++;
1456 linelen--;
1457 }
1458 error = _bdf_add_comment( p->font, s, linelen );
1459 goto Exit;
1460 }
1461
1462 /* The very first thing expected is the number of glyphs. */
1463 if ( !( p->flags & _BDF_GLYPHS ) )
1464 {
1465 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1466 {
1467 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1468 error = BDF_Err_Missing_Chars_Field;
1469 goto Exit;
1470 }
1471
David Turner68df4f72005-03-15 18:18:57 +00001472 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001473 if ( error )
1474 goto Exit;
1475 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1476
1477 /* Make sure the number of glyphs is non-zero. */
1478 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001479 font->glyphs_size = 64;
1480
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001481 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1482 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001483
David Turner993a8d02002-05-18 12:03:43 +00001484 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001485
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001486 goto Exit;
1487 }
1488
1489 /* Check for the ENDFONT field. */
1490 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1491 {
1492 /* Sort the glyphs by encoding. */
1493 ft_qsort( (char *)font->glyphs,
1494 font->glyphs_used,
1495 sizeof ( bdf_glyph_t ),
1496 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001497
1498 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001499
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001500 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001501 }
1502
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001503 /* Check for the ENDCHAR field. */
1504 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1505 {
1506 p->glyph_enc = 0;
1507 p->flags &= ~_BDF_GLYPH_BITS;
1508
1509 goto Exit;
1510 }
1511
1512 /* Check to see whether a glyph is being scanned but should be */
1513 /* ignored because it is an unencoded glyph. */
1514 if ( ( p->flags & _BDF_GLYPH ) &&
1515 p->glyph_enc == -1 &&
1516 p->opts->keep_unencoded == 0 )
1517 goto Exit;
1518
1519 /* Check for the STARTCHAR field. */
1520 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1521 {
1522 /* Set the character name in the parse info first until the */
1523 /* encoding can be checked for an unencoded character. */
1524 FT_FREE( p->glyph_name );
1525
David Turner68df4f72005-03-15 18:18:57 +00001526 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001527 if ( error )
1528 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001529
David Turner68df4f72005-03-15 18:18:57 +00001530 _bdf_list_shift( &p->list, 1 );
1531
1532 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001533
1534 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1535 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001536
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001537 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1538
1539 p->flags |= _BDF_GLYPH;
1540
1541 goto Exit;
1542 }
1543
1544 /* Check for the ENCODING field. */
1545 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1546 {
1547 if ( !( p->flags & _BDF_GLYPH ) )
1548 {
1549 /* Missing STARTCHAR field. */
1550 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1551 error = BDF_Err_Missing_Startchar_Field;
1552 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001553 }
1554
David Turner68df4f72005-03-15 18:18:57 +00001555 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001556 if ( error )
1557 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001558
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001559 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001560
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001561 /* Check to see whether this encoding has already been encountered. */
1562 /* If it has then change it to unencoded so it gets added if */
1563 /* indicated. */
1564 if ( p->glyph_enc >= 0 )
1565 {
1566 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1567 {
1568 /* Emit a message saying a glyph has been moved to the */
1569 /* unencoded area. */
1570 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1571 p->glyph_enc, p->glyph_name ));
1572 p->glyph_enc = -1;
1573 font->modified = 1;
1574 }
1575 else
1576 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1577 }
1578
1579 if ( p->glyph_enc >= 0 )
1580 {
1581 /* Make sure there are enough glyphs allocated in case the */
1582 /* number of characters happen to be wrong. */
1583 if ( font->glyphs_used == font->glyphs_size )
1584 {
1585 if ( FT_RENEW_ARRAY( font->glyphs,
1586 font->glyphs_size,
1587 font->glyphs_size + 64 ) )
1588 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001589
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001590 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001591 }
1592
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001593 glyph = font->glyphs + font->glyphs_used++;
1594 glyph->name = p->glyph_name;
1595 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001596
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001597 /* Reset the initial glyph info. */
1598 p->glyph_name = 0;
1599 }
1600 else
1601 {
1602 /* Unencoded glyph. Check to see whether it should */
1603 /* be added or not. */
1604 if ( p->opts->keep_unencoded != 0 )
1605 {
1606 /* Allocate the next unencoded glyph. */
1607 if ( font->unencoded_used == font->unencoded_size )
1608 {
David Turner68df4f72005-03-15 18:18:57 +00001609 if ( FT_RENEW_ARRAY( font->unencoded ,
1610 font->unencoded_size,
1611 font->unencoded_size + 4 ) )
1612 goto Exit;
1613
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001614 font->unencoded_size += 4;
1615 }
1616
1617 glyph = font->unencoded + font->unencoded_used;
1618 glyph->name = p->glyph_name;
1619 glyph->encoding = font->unencoded_used++;
1620 }
1621 else
1622 /* Free up the glyph name if the unencoded shouldn't be */
1623 /* kept. */
1624 FT_FREE( p->glyph_name );
1625
1626 p->glyph_name = 0;
1627 }
1628
1629 /* Clear the flags that might be added when width and height are */
1630 /* checked for consistency. */
1631 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1632
1633 p->flags |= _BDF_ENCODING;
1634
1635 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001636 }
1637
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001638 /* Point at the glyph being constructed. */
1639 if ( p->glyph_enc == -1 )
1640 glyph = font->unencoded + ( font->unencoded_used - 1 );
1641 else
1642 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001643
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001644 /* Check to see whether a bitmap is being constructed. */
1645 if ( p->flags & _BDF_BITMAP )
1646 {
1647 /* If there are more rows than are specified in the glyph metrics, */
1648 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001649 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001650 {
1651 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1652 {
1653 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1654 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001655 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001656 }
1657
1658 goto Exit;
1659 }
1660
1661 /* Only collect the number of nibbles indicated by the glyph */
1662 /* metrics. If there are more columns, they are simply ignored. */
1663 nibbles = glyph->bpr << 1;
1664 bp = glyph->bitmap + p->row * glyph->bpr;
1665
1666 for ( i = 0, *bp = 0; i < nibbles; i++ )
1667 {
1668 c = line[i];
Werner Lemberg233302a2002-05-22 05:41:06 +00001669 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001670 if ( i + 1 < nibbles && ( i & 1 ) )
1671 *++bp = 0;
1672 }
1673
1674 /* Remove possible garbage at the right. */
1675 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
1676 *bp &= nibble_mask[mask_index];
1677
1678 /* If any line has extra columns, indicate they have been removed. */
1679 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1680 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1681 {
1682 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1683 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1684 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001685 }
1686
1687 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001688 goto Exit;
1689 }
David Turner993a8d02002-05-18 12:03:43 +00001690
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001691 /* Expect the SWIDTH (scalable width) field next. */
1692 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1693 {
1694 if ( !( p->flags & _BDF_ENCODING ) )
1695 {
1696 /* Missing ENCODING field. */
1697 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1698 error = BDF_Err_Missing_Encoding_Field;
1699 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001700 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001701
David Turner68df4f72005-03-15 18:18:57 +00001702 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001703 if ( error )
1704 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001705
David Turnerb1b47622002-05-21 21:17:43 +00001706 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001707 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001708
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001709 goto Exit;
1710 }
David Turner993a8d02002-05-18 12:03:43 +00001711
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001712 /* Expect the DWIDTH (scalable width) field next. */
1713 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1714 {
David Turner68df4f72005-03-15 18:18:57 +00001715 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001716 if ( error )
1717 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001718
David Turnerb1b47622002-05-21 21:17:43 +00001719 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001720
1721 if ( !( p->flags & _BDF_SWIDTH ) )
1722 {
1723 /* Missing SWIDTH field. Emit an auto correction message and set */
1724 /* the scalable width from the device width. */
1725 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1726
Werner Lemberg02d4d592002-05-28 22:38:05 +00001727 glyph->swidth = (unsigned short)FT_MulDiv(
1728 glyph->dwidth, 72000L,
1729 (FT_Long)( font->point_size *
1730 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001731 }
1732
1733 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001734 goto Exit;
1735 }
David Turner993a8d02002-05-18 12:03:43 +00001736
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001737 /* Expect the BBX field next. */
1738 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1739 {
David Turner68df4f72005-03-15 18:18:57 +00001740 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001741 if ( error )
1742 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001743
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001744 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1745 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1746 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1747 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1748
1749 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001750 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1751 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001752
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001753 /* Determine the overall font bounding box as the characters are */
1754 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001755 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1756 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001757
David Turnerb1b47622002-05-21 21:17:43 +00001758 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001759
Werner Lembergdfa46192004-03-05 09:26:24 +00001760 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1761 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1762 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001763
1764 if ( !( p->flags & _BDF_DWIDTH ) )
1765 {
1766 /* Missing DWIDTH field. Emit an auto correction message and set */
1767 /* the device width to the glyph width. */
1768 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1769 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001770 }
1771
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001772 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1773 /* value if necessary. */
1774 if ( p->opts->correct_metrics != 0 )
1775 {
1776 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001777 unsigned short sw = (unsigned short)FT_MulDiv(
1778 glyph->dwidth, 72000L,
1779 (FT_Long)( font->point_size *
1780 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001781
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001782
1783 if ( sw != glyph->swidth )
1784 {
1785 glyph->swidth = sw;
1786
1787 if ( p->glyph_enc == -1 )
1788 _bdf_set_glyph_modified( font->umod,
1789 font->unencoded_used - 1 );
1790 else
1791 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1792
1793 p->flags |= _BDF_SWIDTH_ADJ;
1794 font->modified = 1;
1795 }
David Turner993a8d02002-05-18 12:03:43 +00001796 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001797
David Turner993a8d02002-05-18 12:03:43 +00001798 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001799 goto Exit;
1800 }
David Turner993a8d02002-05-18 12:03:43 +00001801
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001802 /* And finally, gather up the bitmap. */
1803 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1804 {
1805 if ( !( p->flags & _BDF_BBX ) )
1806 {
1807 /* Missing BBX field. */
1808 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1809 error = BDF_Err_Missing_Bbx_Field;
1810 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001811 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001812
1813 /* Allocate enough space for the bitmap. */
1814 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg233302a2002-05-22 05:41:06 +00001815 glyph->bytes = (unsigned short)( glyph->bpr * glyph->bbx.height );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001816
1817 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1818 goto Exit;
1819
1820 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001821 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001822
1823 goto Exit;
1824 }
1825
1826 error = BDF_Err_Invalid_File_Format;
1827
1828 Exit:
1829 return error;
David Turner993a8d02002-05-18 12:03:43 +00001830 }
1831
David Turner993a8d02002-05-18 12:03:43 +00001832
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001833 /* Load the font properties. */
1834 static FT_Error
1835 _bdf_parse_properties( char* line,
1836 unsigned long linelen,
1837 unsigned long lineno,
1838 void* call_data,
1839 void* client_data )
1840 {
1841 unsigned long vlen;
1842 _bdf_line_func_t* next;
1843 _bdf_parse_t* p;
1844 char* name;
1845 char* value;
1846 char nbuf[128];
1847 FT_Memory memory;
1848 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001849
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001850 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001851
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001852
1853 next = (_bdf_line_func_t *)call_data;
1854 p = (_bdf_parse_t *) client_data;
1855
1856 memory = p->font->memory;
1857
1858 /* Check for the end of the properties. */
1859 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1860 {
1861 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1862 /* encountered yet, then make sure they are added as properties and */
1863 /* make sure they are set from the font bounding box info. */
1864 /* */
1865 /* This is *always* done regardless of the options, because X11 */
1866 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001867 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001868 {
1869 p->font->font_ascent = p->font->bbx.ascent;
1870 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1871 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
1872 if ( error )
1873 goto Exit;
1874
1875 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1876 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001877 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001878
Werner Lemberg428c2e42003-04-25 05:35:04 +00001879 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001880 {
1881 p->font->font_descent = p->font->bbx.descent;
1882 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1883 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
1884 if ( error )
1885 goto Exit;
1886
1887 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1888 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001889 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001890
David Turner993a8d02002-05-18 12:03:43 +00001891 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001892 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001893
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001894 goto Exit;
1895 }
David Turner993a8d02002-05-18 12:03:43 +00001896
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001897 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1898 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1899 goto Exit;
1900
1901 /* Handle COMMENT fields and properties in a special way to preserve */
1902 /* the spacing. */
1903 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1904 {
David Turner993a8d02002-05-18 12:03:43 +00001905 name = value = line;
1906 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001907 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001908 *value++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001909 error = _bdf_add_property( p->font, name, value );
1910 if ( error )
1911 goto Exit;
1912 }
1913 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1914 {
1915 error = _bdf_add_property( p->font, name, value );
1916 if ( error )
1917 goto Exit;
1918 }
1919 else
1920 {
David Turner68df4f72005-03-15 18:18:57 +00001921 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001922 if ( error )
1923 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001924 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001925
David Turner68df4f72005-03-15 18:18:57 +00001926 _bdf_list_shift( &p->list, 1 );
1927 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001928
1929 error = _bdf_add_property( p->font, name, value );
1930 if ( error )
1931 goto Exit;
1932 }
1933
1934 Exit:
1935 return error;
David Turner993a8d02002-05-18 12:03:43 +00001936 }
1937
David Turner993a8d02002-05-18 12:03:43 +00001938
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001939 /* Load the font header. */
1940 static FT_Error
1941 _bdf_parse_start( char* line,
1942 unsigned long linelen,
1943 unsigned long lineno,
1944 void* call_data,
1945 void* client_data )
1946 {
1947 unsigned long slen;
1948 _bdf_line_func_t* next;
1949 _bdf_parse_t* p;
1950 bdf_font_t* font;
1951 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001952
David Turnerd490e372002-05-28 23:40:37 +00001953 FT_Memory memory = NULL;
1954 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001955
1956 FT_UNUSED( lineno ); /* only used in debug mode */
1957
1958
1959 next = (_bdf_line_func_t *)call_data;
1960 p = (_bdf_parse_t *) client_data;
1961
1962 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00001963 memory = p->font->memory;
1964
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001965 /* Check for a comment. This is done to handle those fonts that have */
1966 /* comments before the STARTFONT line for some reason. */
1967 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1968 {
1969 if ( p->opts->keep_comments != 0 && p->font != 0 )
1970 {
1971 linelen -= 7;
1972
1973 s = line + 7;
1974 if ( *s != 0 )
1975 {
1976 s++;
1977 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00001978 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001979
1980 error = _bdf_add_comment( p->font, s, linelen );
1981 if ( error )
1982 goto Exit;
1983 /* here font is not defined! */
1984 }
1985
1986 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001987 }
1988
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001989 if ( !( p->flags & _BDF_START ) )
1990 {
1991 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00001992
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001993 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
1994 {
1995 /* No STARTFONT field is a good indication of a problem. */
1996 error = BDF_Err_Missing_Startfont_Field;
1997 goto Exit;
1998 }
David Turner993a8d02002-05-18 12:03:43 +00001999
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002000 p->flags = _BDF_START;
2001 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002002
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002003 if ( FT_NEW( font ) )
2004 goto Exit;
2005 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002006
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002007 font->memory = p->memory;
2008 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002009
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002010 { /* setup */
2011 unsigned long i;
2012 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002013
David Turner993a8d02002-05-18 12:03:43 +00002014
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002015 error = hash_init( &(font->proptbl), memory );
2016 if ( error )
2017 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002018 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002019 i < _num_bdf_properties; i++, prop++ )
2020 {
2021 error = hash_insert( prop->name, (void *)i,
2022 &(font->proptbl), memory );
2023 if ( error )
2024 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002025 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002026 }
2027
2028 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2029 goto Exit;
2030 error = hash_init( (hashtable *)p->font->internal,memory );
2031 if ( error )
2032 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002033 p->font->spacing = p->opts->font_spacing;
2034 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002035
2036 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002037 }
2038
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002039 /* Check for the start of the properties. */
2040 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2041 {
David Turner68df4f72005-03-15 18:18:57 +00002042 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002043 if ( error )
2044 goto Exit;
2045 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2046
2047 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2048 goto Exit;
2049
2050 p->flags |= _BDF_PROPS;
2051 *next = _bdf_parse_properties;
2052
2053 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002054 }
2055
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002056 /* Check for the FONTBOUNDINGBOX field. */
2057 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2058 {
2059 if ( !(p->flags & _BDF_SIZE ) )
2060 {
2061 /* Missing the SIZE field. */
2062 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2063 error = BDF_Err_Missing_Size_Field;
2064 goto Exit;
2065 }
2066
David Turner68df4f72005-03-15 18:18:57 +00002067 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002068 if ( error )
2069 goto Exit;
2070
2071 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2072 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2073
2074 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2075 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2076
David Turnerd490e372002-05-28 23:40:37 +00002077 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002078 p->font->bbx.y_offset );
2079
2080 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002081
2082 p->flags |= _BDF_FONT_BBX;
2083
2084 goto Exit;
2085 }
2086
2087 /* The next thing to check for is the FONT field. */
2088 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2089 {
David Turner68df4f72005-03-15 18:18:57 +00002090 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002091 if ( error )
2092 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002093 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002094
David Turner68df4f72005-03-15 18:18:57 +00002095 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002096 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2097 goto Exit;
2098 FT_MEM_COPY( p->font->name, s, slen + 1 );
2099
2100 /* If the font name is an XLFD name, set the spacing to the one in */
2101 /* the font name. If there is no spacing fall back on the default. */
2102 error = _bdf_set_default_spacing( p->font, p->opts );
2103 if ( error )
2104 goto Exit;
2105
2106 p->flags |= _BDF_FONT_NAME;
2107
2108 goto Exit;
2109 }
2110
2111 /* Check for the SIZE field. */
2112 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2113 {
2114 if ( !( p->flags & _BDF_FONT_NAME ) )
2115 {
2116 /* Missing the FONT field. */
2117 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2118 error = BDF_Err_Missing_Font_Field;
2119 goto Exit;
2120 }
2121
David Turner68df4f72005-03-15 18:18:57 +00002122 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002123 if ( error )
2124 goto Exit;
2125
2126 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2127 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2128 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2129
2130 /* Check for the bits per pixel field. */
2131 if ( p->list.used == 5 )
2132 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002133 unsigned short bitcount, i, shift;
2134
2135
2136 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2137
2138 /* Only values 1, 2, 4, 8 are allowed. */
2139 shift = p->font->bpp;
2140 bitcount = 0;
2141 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002142 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002143 if ( shift & 1 )
2144 bitcount = i;
2145 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002146 }
David Turner993a8d02002-05-18 12:03:43 +00002147
Werner Lembergbd8e3242002-06-12 08:43:58 +00002148 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002149
2150 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002151 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002152 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002153 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002154 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002155 }
2156 }
2157 else
2158 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002159
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002160 p->flags |= _BDF_SIZE;
2161
2162 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002163 }
2164
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002165 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002166
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002167 Exit:
2168 return error;
2169 }
David Turner993a8d02002-05-18 12:03:43 +00002170
2171
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002172 /*************************************************************************/
2173 /* */
2174 /* API. */
2175 /* */
2176 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002177
David Turner993a8d02002-05-18 12:03:43 +00002178
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002179 FT_LOCAL_DEF( FT_Error )
2180 bdf_load_font( FT_Stream stream,
2181 FT_Memory extmemory,
2182 bdf_options_t* opts,
2183 bdf_font_t* *font )
2184 {
2185 unsigned long lineno;
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002186 _bdf_parse_t *p;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002187
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002188 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002189 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002190
2191
David Turner68df4f72005-03-15 18:18:57 +00002192 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002193 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002194
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002195 memory = NULL;
2196 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2197 p->minlb = 32767;
2198 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002199
David Turner68df4f72005-03-15 18:18:57 +00002200 _bdf_list_init( &p->list, extmemory );
2201
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002202 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002203 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002204 if ( error )
2205 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002206
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002207 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002208 {
2209 /* If the font is not proportional, set the font's monowidth */
2210 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002211 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002212
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002213 if ( p->font->spacing != BDF_PROPORTIONAL )
2214 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002215
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002216 /* If the number of glyphs loaded is not that of the original count, */
2217 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002218 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002219 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002220 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2221 p->font->glyphs_used + p->font->unencoded_used ));
2222 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002223 }
2224
2225 /* Once the font has been loaded, adjust the overall font metrics if */
2226 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002227 if ( p->opts->correct_metrics != 0 &&
2228 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002229 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002230 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002231 {
2232 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002233 p->font->bbx.width, p->maxrb - p->minlb ));
2234 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2235 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002236 }
2237
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002238 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002239 {
2240 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002241 p->font->bbx.x_offset, p->minlb ));
2242 p->font->bbx.x_offset = p->minlb;
2243 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002244 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002245
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002246 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002247 {
2248 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002249 p->font->bbx.ascent, p->maxas ));
2250 p->font->bbx.ascent = p->maxas;
2251 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002252 }
2253
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002254 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002255 {
2256 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002257 p->font->bbx.descent, p->maxds ));
2258 p->font->bbx.descent = p->maxds;
2259 p->font->bbx.y_offset = (short)( -p->maxds );
2260 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002261 }
2262
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002263 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002264 {
2265 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002266 p->font->bbx.height, p->maxas + p->maxds ));
2267 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002268 }
2269
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002270 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002271 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2272 }
David Turner993a8d02002-05-18 12:03:43 +00002273 }
2274
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002275 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002276 {
2277 {
2278 /* The ENDFONT field was never reached or did not exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002279 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002280 /* Error happened while parsing header. */
2281 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2282 else
2283 /* Error happened when parsing glyphs. */
2284 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2285 }
David Turner993a8d02002-05-18 12:03:43 +00002286 }
2287
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002288 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002289 {
2290 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002291 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002292
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002293 if ( p->font->comments_len > 0 ) {
2294 if ( FT_RENEW_ARRAY( p->font->comments,
2295 p->font->comments_len,
2296 p->font->comments_len + 1 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002297 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002298
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002299 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002300 }
David Turner993a8d02002-05-18 12:03:43 +00002301 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002302 else if ( error == BDF_Err_Ok )
2303 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002304
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002305 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002306
2307 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002308 if ( p )
2309 {
David Turner68df4f72005-03-15 18:18:57 +00002310 _bdf_list_done( &p->list );
2311
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002312 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002313
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002314 FT_FREE( p );
2315 }
2316
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002317 return error;
2318 }
David Turner993a8d02002-05-18 12:03:43 +00002319
2320
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002321 FT_LOCAL_DEF( void )
2322 bdf_free_font( bdf_font_t* font )
2323 {
2324 bdf_property_t* prop;
2325 unsigned long i;
2326 bdf_glyph_t* glyphs;
2327 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002328
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002329
2330 if ( font == 0 )
2331 return;
David Turner993a8d02002-05-18 12:03:43 +00002332
2333 memory = font->memory;
2334
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002335 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002336
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002337 /* Free up the internal hash table of property names. */
2338 if ( font->internal )
2339 {
2340 hash_free( (hashtable *)font->internal, memory );
2341 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002342 }
2343
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002344 /* Free up the comment info. */
2345 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002346
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002347 /* Free up the properties. */
2348 for ( i = 0; i < font->props_size; i++ )
2349 {
2350 if ( font->props[i].format == BDF_ATOM )
2351 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002352 }
2353
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002354 FT_FREE( font->props );
2355
2356 /* Free up the character info. */
2357 for ( i = 0, glyphs = font->glyphs;
2358 i < font->glyphs_used; i++, glyphs++ )
2359 {
2360 FT_FREE( glyphs->name );
2361 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002362 }
2363
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002364 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2365 i++, glyphs++ )
2366 {
2367 FT_FREE( glyphs->name );
2368 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002369 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002370
2371 FT_FREE( font->glyphs );
2372 FT_FREE( font->unencoded );
2373
2374 /* Free up the overflow storage if it was used. */
2375 for ( i = 0, glyphs = font->overflow.glyphs;
2376 i < font->overflow.glyphs_used; i++, glyphs++ )
2377 {
2378 FT_FREE( glyphs->name );
2379 FT_FREE( glyphs->bitmap );
2380 }
2381
2382 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002383
2384 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002385 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002386
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002387 /* Free up the user defined properties. */
2388 for (prop = font->user_props, i = 0;
2389 i < font->nuser_props; i++, prop++ )
2390 {
2391 FT_FREE( prop->name );
2392 if ( prop->format == BDF_ATOM )
2393 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002394 }
David Turner993a8d02002-05-18 12:03:43 +00002395
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002396 FT_FREE( font->user_props );
2397
2398 /* FREE( font ); */ /* XXX Fixme */
2399 }
David Turner993a8d02002-05-18 12:03:43 +00002400
2401
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002402 FT_LOCAL_DEF( bdf_property_t * )
2403 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002404 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002405 {
2406 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002407
David Turner993a8d02002-05-18 12:03:43 +00002408
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002409 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002410 return 0;
2411
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002412 hn = hash_lookup( name, (hashtable *)font->internal );
2413
2414 return hn ? ( font->props + (unsigned long)hn->data ) : 0;
2415 }
2416
2417
2418/* END */