blob: 0429f7de1cdf2f98e6f4ab6524ce6cecf3bb8724 [file] [log] [blame]
David Turner993a8d02002-05-18 12:03:43 +00001/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
Werner Lemberg7cf4d372002-05-21 14:13:01 +00003 * Copyright 2001, 2002 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
35#include FT_INTERNAL_DEBUG_H
36#include FT_INTERNAL_STREAM_H
37#include FT_INTERNAL_OBJECTS_H
38
39#include "bdf.h"
David Turner993a8d02002-05-18 12:03:43 +000040#include "bdferror.h"
41
David Turner993a8d02002-05-18 12:03:43 +000042
Werner Lemberg7cf4d372002-05-21 14:13:01 +000043 /*************************************************************************/
44 /* */
45 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
46 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
47 /* messages during execution. */
48 /* */
49#undef FT_COMPONENT
50#define FT_COMPONENT trace_bdflib
David Turner993a8d02002-05-18 12:03:43 +000051
David Turner993a8d02002-05-18 12:03:43 +000052
Werner Lemberg7cf4d372002-05-21 14:13:01 +000053 /*************************************************************************/
54 /* */
55 /* Default BDF font options. */
56 /* */
57 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000058
David Turner993a8d02002-05-18 12:03:43 +000059
David Turnerb1b47622002-05-21 21:17:43 +000060 static const bdf_options_t _bdf_opts =
Werner Lemberg7cf4d372002-05-21 14:13:01 +000061 {
David Turner993a8d02002-05-18 12:03:43 +000062 1, /* Correct metrics. */
63 1, /* Preserve unencoded glyphs. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000064 0, /* Preserve comments. */
65 BDF_PROPORTIONAL /* Default spacing. */
66 };
David Turner993a8d02002-05-18 12:03:43 +000067
David Turner993a8d02002-05-18 12:03:43 +000068
Werner Lemberg7cf4d372002-05-21 14:13:01 +000069 /*************************************************************************/
70 /* */
71 /* Builtin BDF font properties. */
72 /* */
73 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000074
Werner Lemberg7cf4d372002-05-21 14:13:01 +000075 /* List of most properties that might appear in a font. Doesn't include */
76 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
David Turner993a8d02002-05-18 12:03:43 +000077
David Turnerb1b47622002-05-21 21:17:43 +000078 static const bdf_property_t _bdf_properties[] =
David Turner993a8d02002-05-18 12:03:43 +000079 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +000080 { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
81 { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
82 { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
83 { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
84 { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
85 { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
86 { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
87 { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
88 { (char *)"COMMENT", BDF_ATOM, 1, { 0 } },
89 { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } },
90 { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
91 { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } },
92 { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
93 { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } },
94 { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } },
95 { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } },
96 { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
97 { (char *)"FONT", BDF_ATOM, 1, { 0 } },
98 { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
99 { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
100 { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
101 { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } },
102 { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } },
103 { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
104 { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } },
105 { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } },
106 { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } },
107 { (char *)"NOTICE", BDF_ATOM, 1, { 0 } },
108 { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
109 { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } },
110 { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
111 { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
112 { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
113 { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
114 { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
115 { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
116 { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
117 { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
118 { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
119 { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
120 { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
121 { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
122 { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
123 { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
124 { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
125 { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
126 { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
127 { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
128 { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
129 { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
130 { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
131 { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
132 { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
133 { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
134 { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
135 { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
136 { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
137 { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
138 { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
139 { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
140 { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
141 { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } },
142 { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
143 { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
144 { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
145 { (char *)"SLANT", BDF_ATOM, 1, { 0 } },
146 { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
147 { (char *)"SPACING", BDF_ATOM, 1, { 0 } },
148 { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
149 { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
150 { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
151 { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
152 { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
153 { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
154 { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
155 { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
156 { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
157 { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
158 { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } },
159 { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
160 { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } },
161 { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
162 { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
163 };
David Turner993a8d02002-05-18 12:03:43 +0000164
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000165 static unsigned long
166 _num_bdf_properties = sizeof ( _bdf_properties ) /
167 sizeof ( _bdf_properties[0] );
David Turner993a8d02002-05-18 12:03:43 +0000168
169
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000170 /*************************************************************************/
171 /* */
172 /* Hash table utilities for the properties. */
173 /* */
174 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +0000175
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000176 /* XXX: Replace this with FreeType's hash functions */
David Turner993a8d02002-05-18 12:03:43 +0000177
David Turner993a8d02002-05-18 12:03:43 +0000178
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000179#define INITIAL_HT_SIZE 241
180
181 typedef void
182 (*hash_free_func)( hashnode node );
183
184 static hashnode*
185 hash_bucket( char* key,
186 hashtable* ht )
David Turner993a8d02002-05-18 12:03:43 +0000187 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000188 char* kp = key;
189 unsigned long res = 0;
190 hashnode* bp = ht->table, *ndp;
191
192
193 /* Mocklisp hash function. */
194 while ( *kp )
195 res = ( res << 5 ) - res + *kp++;
196
197 ndp = bp + ( res % ht->size );
198 while ( *ndp )
David Turner993a8d02002-05-18 12:03:43 +0000199 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000200 kp = (*ndp)->key;
201 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
202 break;
203 ndp--;
204 if ( ndp < bp )
205 ndp = bp + ( ht->size - 1 );
David Turner993a8d02002-05-18 12:03:43 +0000206 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000207
208 return ndp;
David Turner993a8d02002-05-18 12:03:43 +0000209 }
David Turner993a8d02002-05-18 12:03:43 +0000210
211
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000212 static FT_Error
213 hash_rehash( hashtable* ht,
214 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000215 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000216 hashnode* obp = ht->table, *bp, *nbp;
David Turner993a8d02002-05-18 12:03:43 +0000217 int i, sz = ht->size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000218 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000219
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000220
221 ht->size <<= 1;
222 ht->limit = ht->size / 3;
223
224 if ( FT_NEW_ARRAY( ht->table, ht->size ) )
225 goto Exit;
226 FT_MEM_SET( ht->table, 0, sizeof ( hashnode ) * ht->size );
227
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;
257 FT_MEM_SET( ht->table, 0, sizeof ( hashnode ) * sz );
258
259 Exit:
260 return error;
David Turner993a8d02002-05-18 12:03:43 +0000261 }
David Turner993a8d02002-05-18 12:03:43 +0000262
263
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000264 static void
265 hash_free( hashtable* ht,
266 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000267 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000268 if ( ht != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000269 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000270 int i, sz = ht->size;
271 hashnode* bp = ht->table;
David Turner993a8d02002-05-18 12:03:43 +0000272
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000273
274 for ( i = 0; i < sz; i++, bp++ )
275 FT_FREE( *bp );
276
277 FT_FREE( ht->table );
278 }
David Turner993a8d02002-05-18 12:03:43 +0000279 }
280
David Turner993a8d02002-05-18 12:03:43 +0000281
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000282 static FT_Error
283 hash_insert( char* key,
284 void* data,
285 hashtable* ht,
286 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000287 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000288 hashnode nn, *bp = hash_bucket( key, ht );
289 FT_Error error = BDF_Err_Ok;
290
291
292 nn = *bp;
293 if ( !nn )
294 {
295 if ( FT_NEW( nn ) )
296 goto Exit;
297 *bp = nn;
298
299 nn->key = key;
300 nn->data = data;
301
302 if ( ht->used >= ht->limit )
303 {
304 error = hash_rehash( ht, memory );
305 if ( error )
306 goto Exit;
307 }
308 ht->used++;
309 }
David Turner993a8d02002-05-18 12:03:43 +0000310 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000311 nn->data = data;
312
313 Exit:
314 return error;
David Turner993a8d02002-05-18 12:03:43 +0000315 }
316
David Turner993a8d02002-05-18 12:03:43 +0000317
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000318 static hashnode
319 hash_lookup( char* key,
320 hashtable* ht )
321 {
322 hashnode *np = hash_bucket( key, ht );
323
324
325 return *np;
326 }
327
328
329 /*************************************************************************/
330 /* */
331 /* Utility types and functions. */
332 /* */
333 /*************************************************************************/
334
335
336 /* Function type for parsing lines of a BDF font. */
337
338 typedef FT_Error
339 (*_bdf_line_func_t)( char* line,
340 unsigned long linelen,
341 unsigned long lineno,
342 void* call_data,
343 void* client_data );
344
345
346 /* List structure for splitting lines into fields. */
347
348 typedef struct _bdf_list_t_
349 {
350 char** field;
351 unsigned long size;
352 unsigned long used;
353
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
391 /* An empty string for empty fields. */
392
393 static char empty[1] = { 0 }; /* XXX eliminate this */
394
395
396 /* Assume the line is NULL-terminated and that the `list' parameter */
397 /* was initialized the first time it was used. */
398
399 static FT_Error
400 _bdf_split( char* separators,
401 char* line,
402 unsigned long linelen,
403 _bdf_list_t* list,
404 FT_Memory memory )
405 {
406 int mult, final_empty;
407 char *sp, *ep, *end;
408 char seps[32];
409 FT_Error error = BDF_Err_Ok;
410
411
412 /* Initialize the list. */
413 list->used = 0;
414
415 /* If the line is empty, then simply return. */
416 if ( linelen == 0 || line[0] == 0 )
417 goto Exit;
418
419 /* In the original code, if the `separators' parameter is NULL or */
420 /* empty, the list is split into individual bytes. We don't need */
421 /* this, so an error is signaled. */
422 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000423 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000424 error = BDF_Err_Invalid_Argument;
425 goto Exit;
426 }
427
428 /* Prepare the separator bitmap. */
429 FT_MEM_SET( seps, 0, 32 );
430
431 /* If the very last character of the separator string is a plus, then */
432 /* set the `mult' flag to indicate that multiple separators should be */
433 /* collapsed into one. */
434 for ( mult = 0, sp = separators; sp && *sp; sp++ )
435 {
436 if ( *sp == '+' && *( sp + 1 ) == 0 )
437 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000438 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000439 setsbit( seps, *sp );
440 }
441
442 /* Break the line up into fields. */
443 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
444 sp < end && *sp; )
445 {
446 /* Collect everything that is not a separator. */
447 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
448 ;
449
450 /* Resize the list if necessary. */
451 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000452 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000453 if ( list->size == 0 )
454 {
455 if ( FT_NEW_ARRAY( list->field, 5 ) )
456 goto Exit;
457 }
458 else
459 {
460 if ( FT_RENEW_ARRAY ( list->field ,
461 list->size,
462 list->size + 5 ) )
463 goto Exit;
464 }
465
466 list->size += 5;
David Turner993a8d02002-05-18 12:03:43 +0000467 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000468
469 /* Assign the field appropriately. */
470 list->field[list->used++] = ( ep > sp ) ? sp : empty;
471
472 sp = ep;
473
474 if ( mult )
475 {
476 /* If multiple separators should be collapsed, do it now by */
477 /* setting all the separator characters to 0. */
478 for ( ; *ep && sbitset( seps, *ep ); ep++ )
479 *ep = 0;
480 }
481 else if ( *ep != 0 )
482 /* Don't collapse multiple separators by making them 0, so just */
483 /* make the one encountered 0. */
484 *ep++ = 0;
485
486 final_empty = ( ep > sp && *ep == 0 );
487 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000488 }
489
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000490 /* Finally, NULL-terminate the list. */
491 if ( list->used + final_empty + 1 >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000492 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000493 if ( list->used == list->size )
494 {
495 if ( list->size == 0 )
496 {
497 if ( FT_NEW_ARRAY( list->field, 5 ) )
498 goto Exit;
499 }
500 else
501 {
502 if ( FT_RENEW_ARRAY( list->field,
503 list->size,
504 list->size + 5 ) )
505 goto Exit;
506 }
David Turner993a8d02002-05-18 12:03:43 +0000507
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000508 list->size += 5;
509 }
David Turner993a8d02002-05-18 12:03:43 +0000510 }
511
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000512 if ( final_empty )
513 list->field[list->used++] = empty;
David Turner993a8d02002-05-18 12:03:43 +0000514
David Turner993a8d02002-05-18 12:03:43 +0000515 if ( list->used == list->size )
516 {
517 if ( list->size == 0 )
518 {
519 if ( FT_NEW_ARRAY( list->field, 5 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000520 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000521 }
522 else
523 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000524 if ( FT_RENEW_ARRAY( list->field,
525 list->size,
526 list->size + 5 ) )
527 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000528 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000529
David Turner993a8d02002-05-18 12:03:43 +0000530 list->size += 5;
531 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000532
533 list->field[list->used] = 0;
534
535 Exit:
536 return error;
David Turner993a8d02002-05-18 12:03:43 +0000537 }
538
David Turner993a8d02002-05-18 12:03:43 +0000539
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000540 static void
541 _bdf_shift( unsigned long n,
542 _bdf_list_t* list )
David Turner993a8d02002-05-18 12:03:43 +0000543 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000544 unsigned long i, u;
545
546
547 if ( list == 0 || list->used == 0 || n == 0 )
548 return;
549
550 if ( n >= list->used )
David Turner993a8d02002-05-18 12:03:43 +0000551 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000552 list->used = 0;
553 return;
David Turner993a8d02002-05-18 12:03:43 +0000554 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000555
556 for ( u = n, i = 0; u < list->used; i++, u++ )
557 list->field[i] = list->field[u];
558 list->used -= n;
559 }
560
561
562 static char *
563 _bdf_join( int c,
564 unsigned long* len,
565 _bdf_list_t* list )
566 {
567 unsigned long i, j;
568 char *fp, *dp;
569
570
571 if ( list == 0 || list->used == 0 )
572 return 0;
573
574 *len = 0;
575
576 dp = list->field[0];
577 for ( i = j = 0; i < list->used; i++ )
578 {
579 fp = list->field[i];
580 while ( *fp )
581 dp[j++] = *fp++;
582
583 if ( i + 1 < list->used )
David Turnerb1b47622002-05-21 21:17:43 +0000584 dp[j++] = (char)c;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000585 }
586 dp[j] = 0;
587
588 *len = j;
589 return dp;
590 }
591
592
593 /* High speed file reader that passes each line to a callback. */
594 static FT_Error
595 bdf_internal_readstream( FT_Stream stream,
596 char* buffer,
597 int count,
598 int *read_bytes )
599 {
600 int rbytes;
601 unsigned long pos = stream->pos;
602 FT_Error error = BDF_Err_Ok;
603
604
605 if ( pos > stream->size )
606 {
607 FT_ERROR(( "bdf_internal_readstream:" ));
608 FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
609 pos, stream->size ));
610 error = BDF_Err_Invalid_Stream_Operation;
611 goto Exit;
612 }
613
614 if ( stream->read )
615 rbytes = stream->read( stream, pos,
616 (unsigned char *)buffer, count );
David Turner993a8d02002-05-18 12:03:43 +0000617 else
618 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000619 rbytes = stream->size - pos;
620 if ( rbytes > count )
621 rbytes = count;
622
623 FT_MEM_COPY( buffer, stream->base + pos, rbytes );
David Turner993a8d02002-05-18 12:03:43 +0000624 }
David Turner993a8d02002-05-18 12:03:43 +0000625
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000626 stream->pos = pos + rbytes;
David Turner993a8d02002-05-18 12:03:43 +0000627
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000628 *read_bytes = rbytes;
David Turner993a8d02002-05-18 12:03:43 +0000629
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000630 Exit:
631 return error;
David Turner993a8d02002-05-18 12:03:43 +0000632 }
633
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000634
635 static FT_Error
636 _bdf_readstream( FT_Stream stream,
637 _bdf_line_func_t callback,
638 void* client_data,
639 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000640 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000641 _bdf_line_func_t cb;
642 unsigned long lineno;
643 int n, res, done, refill, bytes, hold;
644 char *ls, *le, *pp, *pe, *hp;
645 /* XXX: Use a dynamic buffer */
646 char buf[65536L];
647 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000648
David Turner993a8d02002-05-18 12:03:43 +0000649
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000650 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000651 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000652 error = BDF_Err_Invalid_Argument;
653 goto Exit;
654 }
David Turner993a8d02002-05-18 12:03:43 +0000655
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000656 cb = callback;
657 lineno = 1;
658 buf[0] = 0;
David Turner993a8d02002-05-18 12:03:43 +0000659
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000660 res = done = 0;
661 pp = ls = le = buf;
662
663 bytes = 65536L;
664
665 while ( !done )
666 {
667 error = bdf_internal_readstream( stream, pp, bytes, &n );
668 if ( error )
669 goto Exit;
670
671 if ( n == 0 )
672 break;
673
674 /* Determine the new end of the buffer pages. */
675 pe = pp + n;
676
677 for ( refill = 0; done == 0 && refill == 0; )
678 {
679 while ( le < pe && *le != '\n' && *le != '\r' )
680 le++;
681
682 if ( le == pe )
683 {
684 /* Hit the end of the last page in the buffer. Need to find */
685 /* out how many pages to shift and how many pages need to be */
686 /* read in. Adjust the line start and end pointers down to */
687 /* point to the right places in the pages. */
688
689 pp = buf + ( ( ( ls - buf ) >> 13 ) << 13 );
690 n = pp - buf;
691 ls -= n;
692 le -= n;
693 n = pe - pp;
694
695 FT_MEM_COPY( buf, pp, n );
696
697 pp = buf + n;
698 bytes = 65536L - n;
699 refill = 1;
700 }
701 else
702 {
703 /* Temporarily NULL-terminate the line. */
704 hp = le;
705 hold = *le;
706 *le = 0;
707
708 /* XXX: Use encoding independent value for 0x1a */
709 if ( *ls != '#' && *ls != 0x1a &&
710 le > ls &&
711 ( error = (*cb)( ls, le - ls, lineno, (void *)&cb,
712 client_data ) ) != BDF_Err_Ok )
713 done = 1;
714 else
715 {
David Turner993a8d02002-05-18 12:03:43 +0000716 ls = ++le;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000717 /* Handle the case of DOS crlf sequences. */
718 if ( le < pe && hold == '\n' && *le =='\r' )
David Turner993a8d02002-05-18 12:03:43 +0000719 ls = ++le;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000720 }
721
722 /* Increment the line number. */
723 lineno++;
724
725 /* Restore the character at the end of the line. */
David Turnerb1b47622002-05-21 21:17:43 +0000726 *hp = (char)hold;
727 }
David Turner993a8d02002-05-18 12:03:43 +0000728 }
729 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000730
731 *lno = lineno;
732
733 Exit:
734 return error;
David Turner993a8d02002-05-18 12:03:43 +0000735 }
David Turner993a8d02002-05-18 12:03:43 +0000736
737
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000738 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000739
David Turnerb1b47622002-05-21 21:17:43 +0000740 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000741 {
David Turner993a8d02002-05-18 12:03:43 +0000742 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
743 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
744 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, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
747 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
748 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
749 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
750 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
751 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
752 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000753 };
David Turner993a8d02002-05-18 12:03:43 +0000754
David Turnerb1b47622002-05-21 21:17:43 +0000755 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000756 {
David Turner993a8d02002-05-18 12:03:43 +0000757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
758 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
759 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
760 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000761 };
David Turner993a8d02002-05-18 12:03:43 +0000762
David Turnerb1b47622002-05-21 21:17:43 +0000763 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000764 {
David Turner993a8d02002-05-18 12:03:43 +0000765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
767 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
768 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000769 };
David Turner993a8d02002-05-18 12:03:43 +0000770
David Turnerb1b47622002-05-21 21:17:43 +0000771 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000772 {
David Turner993a8d02002-05-18 12:03:43 +0000773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
774 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
775 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
776 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000777 };
David Turner993a8d02002-05-18 12:03:43 +0000778
David Turner993a8d02002-05-18 12:03:43 +0000779
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000780#define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
David Turner993a8d02002-05-18 12:03:43 +0000781
David Turner993a8d02002-05-18 12:03:43 +0000782
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000783 /* Routine to convert an ASCII string into an unsigned long integer. */
784 static unsigned long
785 _bdf_atoul( char* s,
786 char** end,
787 int base )
David Turner993a8d02002-05-18 12:03:43 +0000788 {
David Turnerb1b47622002-05-21 21:17:43 +0000789 unsigned long v;
790 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000791
792
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000793 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000794 return 0;
795
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000796 /* Make sure the radix is something recognizable. Default to 10. */
797 switch ( base )
798 {
799 case 8:
800 dmap = odigits;
801 break;
802 case 16:
803 dmap = hdigits;
804 break;
805 default:
806 base = 10;
807 dmap = ddigits;
808 break;
David Turner993a8d02002-05-18 12:03:43 +0000809 }
810
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000811 /* Check for the special hex prefix. */
812 if ( *s == '0' &&
813 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
814 {
815 base = 16;
816 dmap = hdigits;
817 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000818 }
819
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000820 for ( v = 0; isdigok( dmap, *s ); s++ )
821 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000822
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000823 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000824 *end = s;
825
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000826 return v;
827 }
David Turner993a8d02002-05-18 12:03:43 +0000828
David Turner993a8d02002-05-18 12:03:43 +0000829
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000830 /* Routine to convert an ASCII string into an signed long integer. */
831 static long
832 _bdf_atol( char* s,
833 char** end,
834 int base )
835 {
David Turnerb1b47622002-05-21 21:17:43 +0000836 long v, neg;
837 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000838
839
840 if ( s == 0 || *s == 0 )
841 return 0;
842
843 /* Make sure the radix is something recognizable. Default to 10. */
844 switch ( base )
845 {
846 case 8:
847 dmap = odigits;
848 break;
849 case 16:
850 dmap = hdigits;
851 break;
852 default:
853 base = 10;
854 dmap = ddigits;
855 break;
856 }
857
858 /* Check for a minus sign. */
859 neg = 0;
860 if ( *s == '-' )
861 {
862 s++;
863 neg = 1;
864 }
865
866 /* Check for the special hex prefix. */
867 if ( *s == '0' &&
868 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
869 {
870 base = 16;
871 dmap = hdigits;
872 s += 2;
873 }
874
875 for ( v = 0; isdigok( dmap, *s ); s++ )
876 v = v * base + a2i[(int)*s];
877
878 if ( end != 0 )
879 *end = s;
880
881 return ( !neg ) ? v : -v;
882 }
883
884
885 /* Routine to convert an ASCII string into an signed short integer. */
886 static short
887 _bdf_atos( char* s,
888 char** end,
889 int base )
890 {
David Turnerb1b47622002-05-21 21:17:43 +0000891 short v, neg;
892 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000893
894
895 if ( s == 0 || *s == 0 )
896 return 0;
897
898 /* Make sure the radix is something recognizable. Default to 10. */
899 switch ( base )
900 {
901 case 8:
902 dmap = odigits;
903 break;
904 case 16:
905 dmap = hdigits;
906 break;
907 default:
908 base = 10;
909 dmap = ddigits;
910 break;
911 }
912
913 /* Check for a minus. */
914 neg = 0;
915 if ( *s == '-' )
916 {
917 s++;
918 neg = 1;
919 }
920
921 /* Check for the special hex prefix. */
922 if ( *s == '0' &&
923 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
924 {
925 base = 16;
926 dmap = hdigits;
927 s += 2;
928 }
929
930 for ( v = 0; isdigok( dmap, *s ); s++ )
David Turnerb1b47622002-05-21 21:17:43 +0000931 v = (short)(v * base + a2i[(int)*s]);
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000932
933 if ( end != 0 )
934 *end = s;
935
David Turnerb1b47622002-05-21 21:17:43 +0000936 return (short)(( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000937 }
938
939
940 /* Routine to compare two glyphs by encoding so they can be sorted. */
941 static int
942 by_encoding( const void* a,
943 const void* b )
944 {
945 bdf_glyph_t *c1, *c2;
946
947
948 c1 = (bdf_glyph_t *)a;
949 c2 = (bdf_glyph_t *)b;
950
951 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000952 return -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000953 else if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000954 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000955
David Turner993a8d02002-05-18 12:03:43 +0000956 return 0;
David Turner993a8d02002-05-18 12:03:43 +0000957 }
958
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000959
960 static FT_Error
961 bdf_create_property( char* name,
962 int format,
963 bdf_font_t* font )
964 {
965 unsigned long n;
966 bdf_property_t* p;
967 FT_Memory memory = font->memory;
968 FT_Error error = BDF_Err_Ok;
969
970
971 /* First check to see if the property has */
972 /* already been added or not. If it has, then */
973 /* simply ignore it. */
974 if ( hash_lookup( name, &(font->proptbl) ) )
975 goto Exit;
976
977 if ( font->nuser_props == 0 )
978 {
979 if ( FT_NEW_ARRAY( font->user_props, 1 ) )
980 goto Exit;
981 }
982 else
983 {
984 if ( FT_RENEW_ARRAY( font->user_props,
985 font->nuser_props,
986 font->nuser_props + 1 ) )
987 goto Exit;
988 }
989
990 p = font->user_props + font->nuser_props;
991 FT_MEM_SET( p, 0, sizeof ( bdf_property_t ) );
992
993 n = (unsigned long)( ft_strlen( name ) + 1 );
994 if ( FT_NEW_ARRAY( p->name, n ) )
995 goto Exit;
996
997 FT_MEM_COPY( (char *)p->name, name, n );
998
999 p->format = format;
1000 p->builtin = 0;
1001
1002 n = _num_bdf_properties + font->nuser_props;
1003
1004 error = hash_insert( p->name, (void *)n, &(font->proptbl), memory );
1005 if ( error )
1006 goto Exit;
1007
1008 font->nuser_props++;
1009
1010 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001011 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001012 }
David Turner993a8d02002-05-18 12:03:43 +00001013
1014
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001015 FT_LOCAL_DEF( bdf_property_t * )
1016 bdf_get_property( char* name,
1017 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001018 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001019 hashnode hn;
1020 unsigned long propid;
1021
1022
1023 if ( name == 0 || *name == 0 )
1024 return 0;
1025
1026 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1027 return 0;
1028
1029 propid = (unsigned long)hn->data;
1030 if ( propid >= _num_bdf_properties )
1031 return font->user_props + ( propid - _num_bdf_properties );
1032
David Turnerb1b47622002-05-21 21:17:43 +00001033 return (bdf_property_t*) _bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001034 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001035
1036
1037 /*************************************************************************/
1038 /* */
1039 /* BDF font file parsing flags and functions. */
1040 /* */
1041 /*************************************************************************/
1042
1043
1044 /* Parse flags. */
1045
1046#define _BDF_START 0x0001
1047#define _BDF_FONT_NAME 0x0002
1048#define _BDF_SIZE 0x0004
1049#define _BDF_FONT_BBX 0x0008
1050#define _BDF_PROPS 0x0010
1051#define _BDF_GLYPHS 0x0020
1052#define _BDF_GLYPH 0x0040
1053#define _BDF_ENCODING 0x0080
1054#define _BDF_SWIDTH 0x0100
1055#define _BDF_DWIDTH 0x0200
1056#define _BDF_BBX 0x0400
1057#define _BDF_BITMAP 0x0800
1058
1059#define _BDF_SWIDTH_ADJ 0x1000
1060
1061#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1062 _BDF_ENCODING | \
1063 _BDF_SWIDTH | \
1064 _BDF_DWIDTH | \
1065 _BDF_BBX | \
1066 _BDF_BITMAP )
1067
1068#define _BDF_GLYPH_WIDTH_CHECK 0x40000000L
1069#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000L
1070
1071
1072 /* Auto correction messages. */
1073#define ACMSG1 "FONT_ASCENT property missing. " \
1074 "Added \"FONT_ASCENT %hd\".\n"
1075#define ACMSG2 "FONT_DESCENT property missing. " \
1076 "Added \"FONT_DESCENT %hd\".\n"
1077#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
1078#define ACMSG4 "Font left bearing != actual left bearing. " \
1079 "Old: %hd New: %hd.\n"
1080#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
1081#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
1082#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
1083#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
1084#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
1085#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
1086#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
1087#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
1088#define ACMSG13 "Glyph %ld extra rows removed.\n"
1089#define ACMSG14 "Glyph %ld extra columns removed.\n"
1090#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
1091
1092 /* Error messages. */
1093#define ERRMSG1 "[line %ld] Missing \"%s\" line.\n"
1094#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
1095#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
1096
1097
1098 static FT_Error
1099 _bdf_add_comment( bdf_font_t* font,
1100 char* comment,
1101 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001102 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001103 char* cp;
1104 FT_Memory memory = font->memory;
1105 FT_Error error = BDF_Err_Ok;
1106
1107
1108 if ( font->comments_len == 0 )
1109 {
1110 if ( FT_NEW_ARRAY( font->comments, len + 1 ) )
1111 goto Exit;
1112 }
1113 else
1114 {
1115 if ( FT_RENEW_ARRAY( font->comments,
1116 font->comments_len,
1117 font->comments_len + len + 1 ) )
1118 goto Exit;
1119 }
1120
1121 cp = font->comments + font->comments_len;
1122 FT_MEM_COPY( cp, comment, len );
1123 cp += len;
1124 *cp++ = '\n';
1125 font->comments_len += len + 1;
1126
1127 Exit:
1128 return error;
David Turner993a8d02002-05-18 12:03:43 +00001129 }
1130
David Turner993a8d02002-05-18 12:03:43 +00001131
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001132 /* Set the spacing from the font name if it exists, or set it to the */
1133 /* default specified in the options. */
1134 static FT_Error
1135 _bdf_set_default_spacing( bdf_font_t* font,
1136 bdf_options_t* opts )
David Turner993a8d02002-05-18 12:03:43 +00001137 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001138 unsigned long len;
1139 char name[128];
1140 _bdf_list_t list;
1141 FT_Memory memory;
1142 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001143
David Turner993a8d02002-05-18 12:03:43 +00001144
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001145 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1146 {
1147 error = BDF_Err_Invalid_Argument;
1148 goto Exit;
1149 }
David Turner993a8d02002-05-18 12:03:43 +00001150
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001151 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001152
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001153 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001154
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001155 len = (unsigned long)( ft_strlen( font->name ) + 1 );
1156 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001157
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001158 list.size = list.used = 0;
David Turner993a8d02002-05-18 12:03:43 +00001159
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001160 error = _bdf_split( (char *)"-", name, len, &list, memory );
1161 if ( error )
1162 goto Exit;
1163
1164 if ( list.used == 15 )
1165 {
1166 switch ( list.field[11][0] )
1167 {
1168 case 'C':
1169 case 'c':
1170 font->spacing = BDF_CHARCELL;
1171 break;
1172 case 'M':
1173 case 'm':
1174 font->spacing = BDF_MONOWIDTH;
1175 break;
1176 case 'P':
1177 case 'p':
1178 font->spacing = BDF_PROPORTIONAL;
1179 break;
David Turner993a8d02002-05-18 12:03:43 +00001180 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001181 }
1182
1183 FT_FREE( list.field );
1184
1185 Exit:
1186 return error;
David Turner993a8d02002-05-18 12:03:43 +00001187 }
David Turner993a8d02002-05-18 12:03:43 +00001188
1189
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001190 /* Determine whether the property is an atom or not. If it is, then */
1191 /* clean it up so the double quotes are removed if they exist. */
1192 static int
1193 _bdf_is_atom( char* line,
1194 unsigned long linelen,
1195 char** name,
1196 char** value,
1197 bdf_font_t* font )
1198 {
1199 int hold;
1200 char *sp, *ep;
1201 bdf_property_t* p;
1202
David Turner993a8d02002-05-18 12:03:43 +00001203
1204 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001205
1206 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001207 ep++;
1208
1209 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001210 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001211 {
1212 hold = *ep;
1213 *ep = 0;
1214 }
1215
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001216 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001217
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001218 /* Restore the character that was saved before any return can happen. */
1219 if ( hold != -1 )
David Turnerb1b47622002-05-21 21:17:43 +00001220 *ep = (char) hold;
David Turner993a8d02002-05-18 12:03:43 +00001221
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001222 /* If the property exists and is not an atom, just return here. */
1223 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001224 return 0;
1225
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001226 /* The property is an atom. Trim all leading and trailing whitespace */
1227 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001228 sp = ep;
1229 ep = line + linelen;
1230
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001231 /* Trim the leading whitespace if it exists. */
David Turner993a8d02002-05-18 12:03:43 +00001232 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001233 while ( *sp &&
1234 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001235 sp++;
1236
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001237 /* Trim the leading double quote if it exists. */
1238 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001239 sp++;
1240 *value = sp;
1241
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001242 /* Trim the trailing whitespace if it exists. */
1243 while ( ep > sp &&
1244 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001245 *--ep = 0;
1246
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001247 /* Trim the trailing double quote if it exists. */
1248 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001249 *--ep = 0;
1250
1251 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001252 }
David Turner993a8d02002-05-18 12:03:43 +00001253
1254
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001255 static FT_Error
1256 _bdf_add_property( bdf_font_t* font,
1257 char* name,
1258 char* value )
1259 {
1260 unsigned long propid;
1261 hashnode hn;
1262 int len;
1263 bdf_property_t *prop, *fp;
1264 FT_Memory memory = font->memory;
1265 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001266
David Turner993a8d02002-05-18 12:03:43 +00001267
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001268 /* First, check to see if the property already exists in the font. */
1269 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001270 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001271 /* The property already exists in the font, so simply replace */
1272 /* the value of the property with the current value. */
1273 fp = font->props + (unsigned long)hn->data;
1274
David Turnerb1b47622002-05-21 21:17:43 +00001275 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001276 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001277 case BDF_ATOM:
1278 /* Delete the current atom if it exists. */
1279 FT_FREE( fp->value.atom );
1280
1281 if ( value == 0 )
1282 len = 1;
1283 else
1284 len = ft_strlen( value ) + 1;
1285
1286 if ( len > 1 )
1287 {
1288 if ( FT_NEW_ARRAY( fp->value.atom, len ) )
1289 goto Exit;
1290 FT_MEM_COPY( fp->value.atom, value, len );
1291 }
1292 else
1293 fp->value.atom = 0;
1294 break;
1295
1296 case BDF_INTEGER:
1297 fp->value.int32 = _bdf_atol( value, 0, 10 );
1298 break;
1299
1300 case BDF_CARDINAL:
1301 fp->value.card32 = _bdf_atoul( value, 0, 10 );
1302 break;
David Turnerb1b47622002-05-21 21:17:43 +00001303
1304 default:
1305 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001306 }
David Turnerb1b47622002-05-21 21:17:43 +00001307
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001308 goto Exit;
1309 }
1310
1311 /* See whether this property type exists yet or not. */
1312 /* If not, create it. */
1313 hn = hash_lookup( name, &(font->proptbl) );
1314 if ( hn == 0 )
1315 {
1316 error = bdf_create_property( name, BDF_ATOM, font );
1317 if ( error )
1318 goto Exit;
1319 hn = hash_lookup( name, &(font->proptbl) );
1320 }
1321
1322 /* Allocate another property if this is overflow. */
1323 if ( font->props_used == font->props_size )
1324 {
1325 if ( font->props_size == 0 )
1326 {
1327 if ( FT_NEW_ARRAY( font->props, 1 ) )
1328 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001329 }
1330 else
1331 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001332 if ( FT_RENEW_ARRAY( font->props,
1333 font->props_size,
1334 font->props_size + 1 ) )
1335 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001336 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001337
David Turner993a8d02002-05-18 12:03:43 +00001338 fp = font->props + font->props_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001339 FT_MEM_SET( fp, 0, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001340 font->props_size++;
1341 }
1342
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001343 propid = (unsigned long)hn->data;
1344 if ( propid >= _num_bdf_properties )
1345 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001346 else
David Turnerb1b47622002-05-21 21:17:43 +00001347 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001348
1349 fp = font->props + font->props_used;
1350
1351 fp->name = prop->name;
1352 fp->format = prop->format;
1353 fp->builtin = prop->builtin;
1354
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001355 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001356 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001357 case BDF_ATOM:
1358 if ( value == 0 )
1359 len = 1;
1360 else
1361 len = ft_strlen( value ) + 1;
David Turner993a8d02002-05-18 12:03:43 +00001362
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001363 if ( len > 1 )
1364 {
1365 if ( FT_NEW_ARRAY( fp->value.atom, len ) )
1366 goto Exit;
1367 FT_MEM_COPY( fp->value.atom, value, len );
1368 }
1369 else
1370 fp->value.atom = 0;
1371 break;
David Turner993a8d02002-05-18 12:03:43 +00001372
1373 case BDF_INTEGER:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001374 fp->value.int32 = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001375 break;
1376
1377 case BDF_CARDINAL:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001378 fp->value.card32 = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001379 break;
David Turner993a8d02002-05-18 12:03:43 +00001380 }
1381
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001382 /* If the property happens to be a comment, then it doesn't need */
1383 /* to be added to the internal hash table. */
1384 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) {
1385 /* Add the property to the font property table. */
1386 error = hash_insert( fp->name,
1387 (void *)font->props_used,
1388 (hashtable *)font->internal,
1389 memory );
1390 if ( error )
1391 goto Exit;
1392 }
David Turner993a8d02002-05-18 12:03:43 +00001393
1394 font->props_used++;
1395
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001396 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1397 /* property needs to be located if it exists in the property list, the */
1398 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1399 /* present, and the SPACING property should override the default */
1400 /* spacing. */
1401 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001402 font->default_glyph = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001403 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001404 font->font_ascent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001405 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001406 font->font_descent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001407 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001408 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001409 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001410 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001411 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001412 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001413 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001414 font->spacing = BDF_CHARCELL;
1415 }
1416
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001417 Exit:
1418 return error;
David Turner993a8d02002-05-18 12:03:43 +00001419 }
1420
David Turner993a8d02002-05-18 12:03:43 +00001421
David Turnerb1b47622002-05-21 21:17:43 +00001422 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001423 {
1424 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1425 };
1426
1427
1428 /* Actually parse the glyph info and bitmaps. */
1429 static FT_Error
1430 _bdf_parse_glyphs( char* line,
1431 unsigned long linelen,
1432 unsigned long lineno,
1433 void* call_data,
1434 void* client_data )
1435 {
1436 int c, mask_index;
1437 char* s;
1438 unsigned char* bp;
1439 unsigned long i, slen, nibbles;
1440 double ps, rx, dw, sw;
1441
1442 _bdf_line_func_t* next;
1443 _bdf_parse_t* p;
1444 bdf_glyph_t* glyph;
1445 bdf_font_t* font;
1446
1447 FT_Memory memory;
1448 FT_Error error = BDF_Err_Ok;
1449
1450 FT_UNUSED( lineno ); /* only used in debug mode */
1451
1452
1453 next = (_bdf_line_func_t *)call_data;
1454 p = (_bdf_parse_t *) client_data;
1455
1456 font = p->font;
1457 memory = font->memory;
1458
1459 /* Check for a comment. */
1460 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1461 {
1462 linelen -= 7;
1463
1464 s = line + 7;
1465 if ( *s != 0 )
1466 {
1467 s++;
1468 linelen--;
1469 }
1470 error = _bdf_add_comment( p->font, s, linelen );
1471 goto Exit;
1472 }
1473
1474 /* The very first thing expected is the number of glyphs. */
1475 if ( !( p->flags & _BDF_GLYPHS ) )
1476 {
1477 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1478 {
1479 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1480 error = BDF_Err_Missing_Chars_Field;
1481 goto Exit;
1482 }
1483
1484 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1485 if ( error )
1486 goto Exit;
1487 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1488
1489 /* Make sure the number of glyphs is non-zero. */
1490 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001491 font->glyphs_size = 64;
1492
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001493 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1494 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001495
David Turner993a8d02002-05-18 12:03:43 +00001496 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001497
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001498 goto Exit;
1499 }
1500
1501 /* Check for the ENDFONT field. */
1502 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1503 {
1504 /* Sort the glyphs by encoding. */
1505 ft_qsort( (char *)font->glyphs,
1506 font->glyphs_used,
1507 sizeof ( bdf_glyph_t ),
1508 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001509
1510 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001511
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001512 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001513 }
1514
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001515 /* Check for the ENDCHAR field. */
1516 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1517 {
1518 p->glyph_enc = 0;
1519 p->flags &= ~_BDF_GLYPH_BITS;
1520
1521 goto Exit;
1522 }
1523
1524 /* Check to see whether a glyph is being scanned but should be */
1525 /* ignored because it is an unencoded glyph. */
1526 if ( ( p->flags & _BDF_GLYPH ) &&
1527 p->glyph_enc == -1 &&
1528 p->opts->keep_unencoded == 0 )
1529 goto Exit;
1530
1531 /* Check for the STARTCHAR field. */
1532 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1533 {
1534 /* Set the character name in the parse info first until the */
1535 /* encoding can be checked for an unencoded character. */
1536 FT_FREE( p->glyph_name );
1537
1538 error = _bdf_split( (char *)" +", line, linelen, &p->list,memory );
1539 if ( error )
1540 goto Exit;
1541 _bdf_shift( 1, &p->list );
1542
1543 s = _bdf_join( ' ', &slen, &p->list );
1544
1545 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1546 goto Exit;
1547 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1548
1549 p->flags |= _BDF_GLYPH;
1550
1551 goto Exit;
1552 }
1553
1554 /* Check for the ENCODING field. */
1555 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1556 {
1557 if ( !( p->flags & _BDF_GLYPH ) )
1558 {
1559 /* Missing STARTCHAR field. */
1560 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1561 error = BDF_Err_Missing_Startchar_Field;
1562 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001563 }
1564
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001565 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1566 if ( error )
1567 goto Exit;
1568 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001569
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001570 /* Check to see whether this encoding has already been encountered. */
1571 /* If it has then change it to unencoded so it gets added if */
1572 /* indicated. */
1573 if ( p->glyph_enc >= 0 )
1574 {
1575 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1576 {
1577 /* Emit a message saying a glyph has been moved to the */
1578 /* unencoded area. */
1579 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1580 p->glyph_enc, p->glyph_name ));
1581 p->glyph_enc = -1;
1582 font->modified = 1;
1583 }
1584 else
1585 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1586 }
1587
1588 if ( p->glyph_enc >= 0 )
1589 {
1590 /* Make sure there are enough glyphs allocated in case the */
1591 /* number of characters happen to be wrong. */
1592 if ( font->glyphs_used == font->glyphs_size )
1593 {
1594 if ( FT_RENEW_ARRAY( font->glyphs,
1595 font->glyphs_size,
1596 font->glyphs_size + 64 ) )
1597 goto Exit;
1598 FT_MEM_SET( font->glyphs + font->glyphs_size,
1599 0,
1600 sizeof ( bdf_glyph_t ) * 64 ); /* FZ inutile */
1601 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001602 }
1603
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001604 glyph = font->glyphs + font->glyphs_used++;
1605 glyph->name = p->glyph_name;
1606 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001607
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001608 /* Reset the initial glyph info. */
1609 p->glyph_name = 0;
1610 }
1611 else
1612 {
1613 /* Unencoded glyph. Check to see whether it should */
1614 /* be added or not. */
1615 if ( p->opts->keep_unencoded != 0 )
1616 {
1617 /* Allocate the next unencoded glyph. */
1618 if ( font->unencoded_used == font->unencoded_size )
1619 {
1620 if ( font->unencoded_size == 0 )
1621 {
1622 if ( FT_NEW_ARRAY( font->unencoded, 2 ) )
1623 goto Exit;
1624 }
1625 else
1626 {
1627 if ( FT_RENEW_ARRAY( font->unencoded ,
1628 font->unencoded_size,
1629 font->unencoded_size + 4 ) )
1630 goto Exit;
1631 }
1632 font->unencoded_size += 4;
1633 }
1634
1635 glyph = font->unencoded + font->unencoded_used;
1636 glyph->name = p->glyph_name;
1637 glyph->encoding = font->unencoded_used++;
1638 }
1639 else
1640 /* Free up the glyph name if the unencoded shouldn't be */
1641 /* kept. */
1642 FT_FREE( p->glyph_name );
1643
1644 p->glyph_name = 0;
1645 }
1646
1647 /* Clear the flags that might be added when width and height are */
1648 /* checked for consistency. */
1649 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1650
1651 p->flags |= _BDF_ENCODING;
1652
1653 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001654 }
1655
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001656 /* Point at the glyph being constructed. */
1657 if ( p->glyph_enc == -1 )
1658 glyph = font->unencoded + ( font->unencoded_used - 1 );
1659 else
1660 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001661
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001662 /* Check to see whether a bitmap is being constructed. */
1663 if ( p->flags & _BDF_BITMAP )
1664 {
1665 /* If there are more rows than are specified in the glyph metrics, */
1666 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001667 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001668 {
1669 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1670 {
1671 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1672 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001673 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001674 }
1675
1676 goto Exit;
1677 }
1678
1679 /* Only collect the number of nibbles indicated by the glyph */
1680 /* metrics. If there are more columns, they are simply ignored. */
1681 nibbles = glyph->bpr << 1;
1682 bp = glyph->bitmap + p->row * glyph->bpr;
1683
1684 for ( i = 0, *bp = 0; i < nibbles; i++ )
1685 {
1686 c = line[i];
David Turnerb1b47622002-05-21 21:17:43 +00001687 *bp = (FT_Byte)(( *bp << 4 ) + a2i[c]);
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001688 if ( i + 1 < nibbles && ( i & 1 ) )
1689 *++bp = 0;
1690 }
1691
1692 /* Remove possible garbage at the right. */
1693 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
1694 *bp &= nibble_mask[mask_index];
1695
1696 /* If any line has extra columns, indicate they have been removed. */
1697 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1698 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1699 {
1700 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1701 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1702 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001703 }
1704
1705 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001706 goto Exit;
1707 }
David Turner993a8d02002-05-18 12:03:43 +00001708
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001709 /* Expect the SWIDTH (scalable width) field next. */
1710 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1711 {
1712 if ( !( p->flags & _BDF_ENCODING ) )
1713 {
1714 /* Missing ENCODING field. */
1715 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1716 error = BDF_Err_Missing_Encoding_Field;
1717 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001718 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001719
1720 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1721 if ( error )
1722 goto Exit;
David Turnerb1b47622002-05-21 21:17:43 +00001723 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001724 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001725
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001726 goto Exit;
1727 }
David Turner993a8d02002-05-18 12:03:43 +00001728
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001729 /* Expect the DWIDTH (scalable width) field next. */
1730 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1731 {
1732 error = _bdf_split( (char *)" +", line, linelen, &p->list,memory );
1733 if ( error )
1734 goto Exit;
David Turnerb1b47622002-05-21 21:17:43 +00001735 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001736
1737 if ( !( p->flags & _BDF_SWIDTH ) )
1738 {
1739 /* Missing SWIDTH field. Emit an auto correction message and set */
1740 /* the scalable width from the device width. */
1741 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1742
1743 ps = (double)font->point_size;
1744 rx = (double)font->resolution_x;
1745 dw = (double)glyph->dwidth;
1746
1747 glyph->swidth = (unsigned short)( ( dw * 72000.0 ) / ( ps * rx ) );
David Turner993a8d02002-05-18 12:03:43 +00001748 }
1749
1750 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001751 goto Exit;
1752 }
David Turner993a8d02002-05-18 12:03:43 +00001753
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001754 /* Expect the BBX field next. */
1755 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1756 {
1757 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1758 if ( error )
1759 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001760
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001761 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1762 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1763 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1764 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1765
1766 /* Generate the ascent and descent of the character. */
David Turnerb1b47622002-05-21 21:17:43 +00001767 glyph->bbx.ascent = (short)(glyph->bbx.height + glyph->bbx.y_offset);
1768 glyph->bbx.descent = (short)(-glyph->bbx.y_offset);
David Turner993a8d02002-05-18 12:03:43 +00001769
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001770 /* Determine the overall font bounding box as the characters are */
1771 /* loaded so corrections can be done later if indicated. */
1772 p->maxas = MAX( glyph->bbx.ascent, p->maxas );
1773 p->maxds = MAX( glyph->bbx.descent, p->maxds );
1774
David Turnerb1b47622002-05-21 21:17:43 +00001775 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001776
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001777 p->maxrb = MAX( p->rbearing, p->maxrb );
1778 p->minlb = MIN( glyph->bbx.x_offset, p->minlb );
1779 p->maxlb = MAX( glyph->bbx.x_offset, p->maxlb );
1780
1781 if ( !( p->flags & _BDF_DWIDTH ) )
1782 {
1783 /* Missing DWIDTH field. Emit an auto correction message and set */
1784 /* the device width to the glyph width. */
1785 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1786 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001787 }
1788
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001789 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1790 /* value if necessary. */
1791 if ( p->opts->correct_metrics != 0 )
1792 {
1793 /* Determine the point size of the glyph. */
1794 ps = (double)font->point_size;
1795 rx = (double)font->resolution_x;
1796 dw = (double)glyph->dwidth;
David Turner993a8d02002-05-18 12:03:43 +00001797
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001798 sw = (unsigned short)( ( dw * 72000.0 ) / ( ps * rx ) );
1799
1800 if ( sw != glyph->swidth )
1801 {
1802 glyph->swidth = sw;
1803
1804 if ( p->glyph_enc == -1 )
1805 _bdf_set_glyph_modified( font->umod,
1806 font->unencoded_used - 1 );
1807 else
1808 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1809
1810 p->flags |= _BDF_SWIDTH_ADJ;
1811 font->modified = 1;
1812 }
David Turner993a8d02002-05-18 12:03:43 +00001813 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001814
David Turner993a8d02002-05-18 12:03:43 +00001815 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001816 goto Exit;
1817 }
David Turner993a8d02002-05-18 12:03:43 +00001818
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001819 /* And finally, gather up the bitmap. */
1820 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1821 {
1822 if ( !( p->flags & _BDF_BBX ) )
1823 {
1824 /* Missing BBX field. */
1825 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1826 error = BDF_Err_Missing_Bbx_Field;
1827 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001828 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001829
1830 /* Allocate enough space for the bitmap. */
1831 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
David Turnerb1b47622002-05-21 21:17:43 +00001832 glyph->bytes = (unsigned short)(glyph->bpr * glyph->bbx.height);
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001833
1834 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1835 goto Exit;
1836
1837 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001838 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001839
1840 goto Exit;
1841 }
1842
1843 error = BDF_Err_Invalid_File_Format;
1844
1845 Exit:
1846 return error;
David Turner993a8d02002-05-18 12:03:43 +00001847 }
1848
David Turner993a8d02002-05-18 12:03:43 +00001849
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001850 /* Load the font properties. */
1851 static FT_Error
1852 _bdf_parse_properties( char* line,
1853 unsigned long linelen,
1854 unsigned long lineno,
1855 void* call_data,
1856 void* client_data )
1857 {
1858 unsigned long vlen;
1859 _bdf_line_func_t* next;
1860 _bdf_parse_t* p;
1861 char* name;
1862 char* value;
1863 char nbuf[128];
1864 FT_Memory memory;
1865 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001866
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001867 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001868
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001869
1870 next = (_bdf_line_func_t *)call_data;
1871 p = (_bdf_parse_t *) client_data;
1872
1873 memory = p->font->memory;
1874
1875 /* Check for the end of the properties. */
1876 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1877 {
1878 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1879 /* encountered yet, then make sure they are added as properties and */
1880 /* make sure they are set from the font bounding box info. */
1881 /* */
1882 /* This is *always* done regardless of the options, because X11 */
1883 /* requires these two fields to compile fonts. */
1884 if ( bdf_get_font_property( p->font, (char *)"FONT_ASCENT" ) == 0 )
1885 {
1886 p->font->font_ascent = p->font->bbx.ascent;
1887 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1888 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
1889 if ( error )
1890 goto Exit;
1891
1892 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1893 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001894 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001895
1896 if ( bdf_get_font_property( p->font, (char *)"FONT_DESCENT" ) == 0 )
1897 {
1898 p->font->font_descent = p->font->bbx.descent;
1899 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1900 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
1901 if ( error )
1902 goto Exit;
1903
1904 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1905 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001906 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001907
David Turner993a8d02002-05-18 12:03:43 +00001908 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001909 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001910
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001911 goto Exit;
1912 }
David Turner993a8d02002-05-18 12:03:43 +00001913
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001914 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1915 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1916 goto Exit;
1917
1918 /* Handle COMMENT fields and properties in a special way to preserve */
1919 /* the spacing. */
1920 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1921 {
David Turner993a8d02002-05-18 12:03:43 +00001922 name = value = line;
1923 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001924 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001925 *value++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001926 error = _bdf_add_property( p->font, name, value );
1927 if ( error )
1928 goto Exit;
1929 }
1930 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1931 {
1932 error = _bdf_add_property( p->font, name, value );
1933 if ( error )
1934 goto Exit;
1935 }
1936 else
1937 {
1938 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1939 if ( error )
1940 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001941 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001942
1943 _bdf_shift( 1, &p->list );
1944 value = _bdf_join( ' ', &vlen, &p->list );
1945
1946 error = _bdf_add_property( p->font, name, value );
1947 if ( error )
1948 goto Exit;
1949 }
1950
1951 Exit:
1952 return error;
David Turner993a8d02002-05-18 12:03:43 +00001953 }
1954
David Turner993a8d02002-05-18 12:03:43 +00001955
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001956 /* Load the font header. */
1957 static FT_Error
1958 _bdf_parse_start( char* line,
1959 unsigned long linelen,
1960 unsigned long lineno,
1961 void* call_data,
1962 void* client_data )
1963 {
1964 unsigned long slen;
1965 _bdf_line_func_t* next;
1966 _bdf_parse_t* p;
1967 bdf_font_t* font;
1968 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001969
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001970 FT_Memory memory;
1971 FT_Error error = BDF_Err_Ok;
1972
1973 FT_UNUSED( lineno ); /* only used in debug mode */
1974
1975
1976 next = (_bdf_line_func_t *)call_data;
1977 p = (_bdf_parse_t *) client_data;
1978
1979 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00001980 memory = p->font->memory;
1981
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001982 /* Check for a comment. This is done to handle those fonts that have */
1983 /* comments before the STARTFONT line for some reason. */
1984 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1985 {
1986 if ( p->opts->keep_comments != 0 && p->font != 0 )
1987 {
1988 linelen -= 7;
1989
1990 s = line + 7;
1991 if ( *s != 0 )
1992 {
1993 s++;
1994 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00001995 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001996
1997 error = _bdf_add_comment( p->font, s, linelen );
1998 if ( error )
1999 goto Exit;
2000 /* here font is not defined! */
2001 }
2002
2003 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002004 }
2005
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002006 if ( !( p->flags & _BDF_START ) )
2007 {
2008 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002009
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002010 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2011 {
2012 /* No STARTFONT field is a good indication of a problem. */
2013 error = BDF_Err_Missing_Startfont_Field;
2014 goto Exit;
2015 }
David Turner993a8d02002-05-18 12:03:43 +00002016
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002017 p->flags = _BDF_START;
2018 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002019
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002020 if ( FT_NEW( font ) )
2021 goto Exit;
2022 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002023
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002024 font->memory = p->memory;
2025 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002026
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002027 { /* setup */
2028 unsigned long i;
2029 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002030
David Turner993a8d02002-05-18 12:03:43 +00002031
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002032 error = hash_init( &(font->proptbl), memory );
2033 if ( error )
2034 goto Exit;
David Turnerb1b47622002-05-21 21:17:43 +00002035 for ( i = 0, prop = (bdf_property_t*) _bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002036 i < _num_bdf_properties; i++, prop++ )
2037 {
2038 error = hash_insert( prop->name, (void *)i,
2039 &(font->proptbl), memory );
2040 if ( error )
2041 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002042 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002043 }
2044
2045 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2046 goto Exit;
2047 error = hash_init( (hashtable *)p->font->internal,memory );
2048 if ( error )
2049 goto Exit;
2050 p->font->spacing = p->opts->font_spacing;
2051 p->font->default_glyph = -1;
2052
2053 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002054 }
2055
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002056 /* Check for the start of the properties. */
2057 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2058 {
2059 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
2060 if ( error )
2061 goto Exit;
2062 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2063
2064 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2065 goto Exit;
2066
2067 p->flags |= _BDF_PROPS;
2068 *next = _bdf_parse_properties;
2069
2070 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002071 }
2072
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002073 /* Check for the FONTBOUNDINGBOX field. */
2074 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2075 {
2076 if ( !(p->flags & _BDF_SIZE ) )
2077 {
2078 /* Missing the SIZE field. */
2079 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2080 error = BDF_Err_Missing_Size_Field;
2081 goto Exit;
2082 }
2083
2084 error = _bdf_split( (char *)" +", line, linelen, &p->list , memory );
2085 if ( error )
2086 goto Exit;
2087
2088 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2089 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2090
2091 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2092 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2093
David Turnerb1b47622002-05-21 21:17:43 +00002094 p->font->bbx.ascent = (short)( p->font->bbx.height +
2095 p->font->bbx.y_offset );
2096
2097 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002098
2099 p->flags |= _BDF_FONT_BBX;
2100
2101 goto Exit;
2102 }
2103
2104 /* The next thing to check for is the FONT field. */
2105 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2106 {
2107 error = _bdf_split( (char *)" +", line, linelen, &p->list , memory );
2108 if ( error )
2109 goto Exit;
2110 _bdf_shift( 1, &p->list );
2111
2112 s = _bdf_join( ' ', &slen, &p->list );
2113 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2114 goto Exit;
2115 FT_MEM_COPY( p->font->name, s, slen + 1 );
2116
2117 /* If the font name is an XLFD name, set the spacing to the one in */
2118 /* the font name. If there is no spacing fall back on the default. */
2119 error = _bdf_set_default_spacing( p->font, p->opts );
2120 if ( error )
2121 goto Exit;
2122
2123 p->flags |= _BDF_FONT_NAME;
2124
2125 goto Exit;
2126 }
2127
2128 /* Check for the SIZE field. */
2129 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2130 {
2131 if ( !( p->flags & _BDF_FONT_NAME ) )
2132 {
2133 /* Missing the FONT field. */
2134 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2135 error = BDF_Err_Missing_Font_Field;
2136 goto Exit;
2137 }
2138
2139 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
2140 if ( error )
2141 goto Exit;
2142
2143 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2144 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2145 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2146
2147 /* Check for the bits per pixel field. */
2148 if ( p->list.used == 5 )
2149 {
2150 p->font->bpp = _bdf_atos( p->list.field[4], 0, 10 );
2151 if ( p->font->bpp > 1 && ( p->font->bpp & 1 ) )
2152 {
2153 /* Move up to the next bits per pixel value if an odd number */
2154 /* is encountered. */
2155 p->font->bpp++;
2156 if ( p->font->bpp <= 4 )
2157 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
David Turner993a8d02002-05-18 12:03:43 +00002158 }
David Turner993a8d02002-05-18 12:03:43 +00002159
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002160 if ( p->font->bpp > 4 )
2161 {
2162 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
2163 p->font->bpp = 4;
2164 }
2165 }
2166 else
2167 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002168
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002169 p->flags |= _BDF_SIZE;
2170
2171 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002172 }
2173
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002174 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002175
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002176 Exit:
2177 return error;
2178 }
David Turner993a8d02002-05-18 12:03:43 +00002179
2180
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002181 /*************************************************************************/
2182 /* */
2183 /* API. */
2184 /* */
2185 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002186
David Turner993a8d02002-05-18 12:03:43 +00002187
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002188 FT_LOCAL_DEF( FT_Error )
2189 bdf_load_font( FT_Stream stream,
2190 FT_Memory extmemory,
2191 bdf_options_t* opts,
2192 bdf_font_t* *font )
2193 {
2194 unsigned long lineno;
2195 _bdf_parse_t p;
2196
2197 FT_Memory memory;
2198 FT_Error error = BDF_Err_Ok;
2199
2200
2201 FT_MEM_SET( &p, 0, sizeof ( _bdf_parse_t ) );
2202
David Turnerb1b47622002-05-21 21:17:43 +00002203 p.opts = (bdf_options_t*)(( opts != 0 ) ? opts : &_bdf_opts);
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002204 p.minlb = 32767;
David Turner993a8d02002-05-18 12:03:43 +00002205 p.memory = extmemory; /* only during font creation */
2206
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002207 error = _bdf_readstream( stream, _bdf_parse_start,
2208 (void *)&p, &lineno );
2209 if ( error )
2210 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002211
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002212 if ( p.font != 0 )
2213 {
2214 /* If the font is not proportional, set the font's monowidth */
2215 /* field to the width of the font bounding box. */
David Turner993a8d02002-05-18 12:03:43 +00002216 memory = p.font->memory;
2217
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002218 if ( p.font->spacing != BDF_PROPORTIONAL )
2219 p.font->monowidth = p.font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002220
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002221 /* If the number of glyphs loaded is not that of the original count, */
2222 /* indicate the difference. */
2223 if ( p.cnt != p.font->glyphs_used + p.font->unencoded_used )
2224 {
2225 FT_TRACE2(( "bdf_load_font: " ACMSG15, p.cnt,
2226 p.font->glyphs_used + p.font->unencoded_used ));
2227 p.font->modified = 1;
2228 }
2229
2230 /* Once the font has been loaded, adjust the overall font metrics if */
2231 /* necessary. */
2232 if ( p.opts->correct_metrics != 0 &&
2233 ( p.font->glyphs_used > 0 || p.font->unencoded_used > 0 ) )
2234 {
2235 if ( p.maxrb - p.minlb != p.font->bbx.width )
2236 {
2237 FT_TRACE2(( "bdf_load_font: " ACMSG3,
2238 p.font->bbx.width, p.maxrb - p.minlb ));
David Turnerb1b47622002-05-21 21:17:43 +00002239 p.font->bbx.width = (unsigned short)(p.maxrb - p.minlb);
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002240 p.font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002241 }
2242
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002243 if ( p.font->bbx.x_offset != p.minlb )
2244 {
2245 FT_TRACE2(( "bdf_load_font: " ACMSG4,
2246 p.font->bbx.x_offset, p.minlb ));
2247 p.font->bbx.x_offset = p.minlb;
2248 p.font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002249 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002250
2251 if ( p.font->bbx.ascent != p.maxas )
2252 {
2253 FT_TRACE2(( "bdf_load_font: " ACMSG5,
2254 p.font->bbx.ascent, p.maxas ));
2255 p.font->bbx.ascent = p.maxas;
2256 p.font->modified = 1;
2257 }
2258
2259 if ( p.font->bbx.descent != p.maxds )
2260 {
2261 FT_TRACE2(( "bdf_load_font: " ACMSG6,
2262 p.font->bbx.descent, p.maxds ));
2263 p.font->bbx.descent = p.maxds;
David Turnerb1b47622002-05-21 21:17:43 +00002264 p.font->bbx.y_offset = (short)(-p.maxds);
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002265 p.font->modified = 1;
2266 }
2267
2268 if ( p.maxas + p.maxds != p.font->bbx.height )
2269 {
2270 FT_TRACE2(( "bdf_load_font: " ACMSG7,
2271 p.font->bbx.height, p.maxas + p.maxds ));
David Turnerb1b47622002-05-21 21:17:43 +00002272 p.font->bbx.height = (unsigned short)(p.maxas + p.maxds);
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002273 }
2274
2275 if ( p.flags & _BDF_SWIDTH_ADJ )
2276 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2277 }
David Turner993a8d02002-05-18 12:03:43 +00002278 }
2279
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002280 if ( p.flags & _BDF_START )
2281 {
2282 {
2283 /* The ENDFONT field was never reached or did not exist. */
2284 if ( !( p.flags & _BDF_GLYPHS ) )
2285 /* Error happened while parsing header. */
2286 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2287 else
2288 /* Error happened when parsing glyphs. */
2289 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2290 }
David Turner993a8d02002-05-18 12:03:43 +00002291 }
2292
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002293 /* Free up the list used during the parsing. */
2294 FT_FREE( p.list.field );
David Turner993a8d02002-05-18 12:03:43 +00002295
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002296 if ( p.font != 0 )
2297 {
2298 /* Make sure the comments are NULL terminated if they exist. */
2299 memory = p.font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002300
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002301 if ( p.font->comments_len > 0 ) {
2302 if ( FT_RENEW_ARRAY( p.font->comments,
2303 p.font->comments_len,
2304 p.font->comments_len + 1 ) )
2305 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002306
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002307 p.font->comments[p.font->comments_len] = 0;
2308 }
David Turner993a8d02002-05-18 12:03:43 +00002309 }
2310
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002311 *font = p.font;
2312
2313 Exit:
2314 return error;
2315 }
David Turner993a8d02002-05-18 12:03:43 +00002316
2317
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002318 FT_LOCAL_DEF( void )
2319 bdf_free_font( bdf_font_t* font )
2320 {
2321 bdf_property_t* prop;
2322 unsigned long i;
2323 bdf_glyph_t* glyphs;
2324 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002325
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002326
2327 if ( font == 0 )
2328 return;
David Turner993a8d02002-05-18 12:03:43 +00002329
2330 memory = font->memory;
2331
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002332 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002333
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002334 /* Free up the internal hash table of property names. */
2335 if ( font->internal )
2336 {
2337 hash_free( (hashtable *)font->internal, memory );
2338 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002339 }
2340
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002341 /* Free up the comment info. */
2342 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002343
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002344 /* Free up the properties. */
2345 for ( i = 0; i < font->props_size; i++ )
2346 {
2347 if ( font->props[i].format == BDF_ATOM )
2348 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002349 }
2350
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002351 FT_FREE( font->props );
2352
2353 /* Free up the character info. */
2354 for ( i = 0, glyphs = font->glyphs;
2355 i < font->glyphs_used; i++, glyphs++ )
2356 {
2357 FT_FREE( glyphs->name );
2358 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002359 }
2360
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002361 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2362 i++, glyphs++ )
2363 {
2364 FT_FREE( glyphs->name );
2365 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002366 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002367
2368 FT_FREE( font->glyphs );
2369 FT_FREE( font->unencoded );
2370
2371 /* Free up the overflow storage if it was used. */
2372 for ( i = 0, glyphs = font->overflow.glyphs;
2373 i < font->overflow.glyphs_used; i++, glyphs++ )
2374 {
2375 FT_FREE( glyphs->name );
2376 FT_FREE( glyphs->bitmap );
2377 }
2378
2379 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002380
2381 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002382 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002383
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002384 /* Free up the user defined properties. */
2385 for (prop = font->user_props, i = 0;
2386 i < font->nuser_props; i++, prop++ )
2387 {
2388 FT_FREE( prop->name );
2389 if ( prop->format == BDF_ATOM )
2390 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002391 }
David Turner993a8d02002-05-18 12:03:43 +00002392
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002393 FT_FREE( font->user_props );
2394
2395 /* FREE( font ); */ /* XXX Fixme */
2396 }
David Turner993a8d02002-05-18 12:03:43 +00002397
2398
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002399 FT_LOCAL_DEF( bdf_property_t * )
2400 bdf_get_font_property( bdf_font_t* font,
2401 char* name )
2402 {
2403 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002404
David Turner993a8d02002-05-18 12:03:43 +00002405
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002406 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002407 return 0;
2408
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002409 hn = hash_lookup( name, (hashtable *)font->internal );
2410
2411 return hn ? ( font->props + (unsigned long)hn->data ) : 0;
2412 }
2413
2414
2415/* END */