blob: a9ee1db1534ef98349788cf4ce70627463f60a55 [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
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 Lemberg7cf4d372002-05-21 14:13:01 +0000166 static unsigned long
167 _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*
186 hash_bucket( char* key,
187 hashtable* ht )
David Turner993a8d02002-05-18 12:03:43 +0000188 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000189 char* kp = key;
190 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;
227 FT_MEM_SET( ht->table, 0, sizeof ( hashnode ) * ht->size );
228
229 for ( i = 0, bp = obp; i < sz; i++, bp++ )
David Turner993a8d02002-05-18 12:03:43 +0000230 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000231 if ( *bp )
232 {
233 nbp = hash_bucket( (*bp)->key, ht );
234 *nbp = *bp;
235 }
David Turner993a8d02002-05-18 12:03:43 +0000236 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000237 FT_FREE( obp );
238
239 Exit:
240 return error;
David Turner993a8d02002-05-18 12:03:43 +0000241 }
David Turner993a8d02002-05-18 12:03:43 +0000242
243
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000244 static FT_Error
245 hash_init( hashtable* ht,
246 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000247 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000248 int sz = INITIAL_HT_SIZE;
249 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000250
David Turner993a8d02002-05-18 12:03:43 +0000251
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000252 ht->size = sz;
253 ht->limit = sz / 3;
254 ht->used = 0;
David Turner993a8d02002-05-18 12:03:43 +0000255
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000256 if ( FT_NEW_ARRAY( ht->table, sz ) )
257 goto Exit;
258 FT_MEM_SET( ht->table, 0, sizeof ( hashnode ) * sz );
259
260 Exit:
261 return error;
David Turner993a8d02002-05-18 12:03:43 +0000262 }
David Turner993a8d02002-05-18 12:03:43 +0000263
264
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000265 static void
266 hash_free( hashtable* ht,
267 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000268 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000269 if ( ht != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000270 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000271 int i, sz = ht->size;
272 hashnode* bp = ht->table;
David Turner993a8d02002-05-18 12:03:43 +0000273
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000274
275 for ( i = 0; i < sz; i++, bp++ )
276 FT_FREE( *bp );
277
278 FT_FREE( ht->table );
279 }
David Turner993a8d02002-05-18 12:03:43 +0000280 }
281
David Turner993a8d02002-05-18 12:03:43 +0000282
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000283 static FT_Error
284 hash_insert( char* key,
285 void* data,
286 hashtable* ht,
287 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000288 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000289 hashnode nn, *bp = hash_bucket( key, ht );
290 FT_Error error = BDF_Err_Ok;
291
292
293 nn = *bp;
294 if ( !nn )
295 {
296 if ( FT_NEW( nn ) )
297 goto Exit;
298 *bp = nn;
299
300 nn->key = key;
301 nn->data = data;
302
303 if ( ht->used >= ht->limit )
304 {
305 error = hash_rehash( ht, memory );
306 if ( error )
307 goto Exit;
308 }
309 ht->used++;
310 }
David Turner993a8d02002-05-18 12:03:43 +0000311 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000312 nn->data = data;
313
314 Exit:
315 return error;
David Turner993a8d02002-05-18 12:03:43 +0000316 }
317
David Turner993a8d02002-05-18 12:03:43 +0000318
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000319 static hashnode
320 hash_lookup( char* key,
321 hashtable* ht )
322 {
323 hashnode *np = hash_bucket( key, ht );
324
325
326 return *np;
327 }
328
329
330 /*************************************************************************/
331 /* */
332 /* Utility types and functions. */
333 /* */
334 /*************************************************************************/
335
336
337 /* Function type for parsing lines of a BDF font. */
338
339 typedef FT_Error
340 (*_bdf_line_func_t)( char* line,
341 unsigned long linelen,
342 unsigned long lineno,
343 void* call_data,
344 void* client_data );
345
346
347 /* List structure for splitting lines into fields. */
348
349 typedef struct _bdf_list_t_
350 {
351 char** field;
352 unsigned long size;
353 unsigned long used;
354
355 } _bdf_list_t;
356
357
358 /* Structure used while loading BDF fonts. */
359
360 typedef struct _bdf_parse_t_
361 {
362 unsigned long flags;
363 unsigned long cnt;
364 unsigned long row;
365
366 short minlb;
367 short maxlb;
368 short maxrb;
369 short maxas;
370 short maxds;
371
372 short rbearing;
373
374 char* glyph_name;
375 long glyph_enc;
376
377 bdf_font_t* font;
378 bdf_options_t* opts;
379
380 unsigned long have[2048];
381 _bdf_list_t list;
382
383 FT_Memory memory;
384
385 } _bdf_parse_t;
386
387
David Turnerb1b47622002-05-21 21:17:43 +0000388#define setsbit( m, cc ) ( m[(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000389#define sbitset( m, cc ) ( m[(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
390
391
392 /* An empty string for empty fields. */
393
394 static char empty[1] = { 0 }; /* XXX eliminate this */
395
396
397 /* Assume the line is NULL-terminated and that the `list' parameter */
398 /* was initialized the first time it was used. */
399
400 static FT_Error
401 _bdf_split( char* separators,
402 char* line,
403 unsigned long linelen,
404 _bdf_list_t* list,
405 FT_Memory memory )
406 {
407 int mult, final_empty;
408 char *sp, *ep, *end;
409 char seps[32];
410 FT_Error error = BDF_Err_Ok;
411
412
413 /* Initialize the list. */
414 list->used = 0;
415
416 /* If the line is empty, then simply return. */
417 if ( linelen == 0 || line[0] == 0 )
418 goto Exit;
419
420 /* In the original code, if the `separators' parameter is NULL or */
421 /* empty, the list is split into individual bytes. We don't need */
422 /* this, so an error is signaled. */
423 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000424 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000425 error = BDF_Err_Invalid_Argument;
426 goto Exit;
427 }
428
429 /* Prepare the separator bitmap. */
430 FT_MEM_SET( seps, 0, 32 );
431
432 /* If the very last character of the separator string is a plus, then */
433 /* set the `mult' flag to indicate that multiple separators should be */
434 /* collapsed into one. */
435 for ( mult = 0, sp = separators; sp && *sp; sp++ )
436 {
437 if ( *sp == '+' && *( sp + 1 ) == 0 )
438 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000439 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000440 setsbit( seps, *sp );
441 }
442
443 /* Break the line up into fields. */
444 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
445 sp < end && *sp; )
446 {
447 /* Collect everything that is not a separator. */
448 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
449 ;
450
451 /* Resize the list if necessary. */
452 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000453 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000454 if ( list->size == 0 )
455 {
456 if ( FT_NEW_ARRAY( list->field, 5 ) )
457 goto Exit;
458 }
459 else
460 {
461 if ( FT_RENEW_ARRAY ( list->field ,
462 list->size,
463 list->size + 5 ) )
464 goto Exit;
465 }
466
467 list->size += 5;
David Turner993a8d02002-05-18 12:03:43 +0000468 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000469
470 /* Assign the field appropriately. */
471 list->field[list->used++] = ( ep > sp ) ? sp : empty;
472
473 sp = ep;
474
475 if ( mult )
476 {
477 /* If multiple separators should be collapsed, do it now by */
478 /* setting all the separator characters to 0. */
479 for ( ; *ep && sbitset( seps, *ep ); ep++ )
480 *ep = 0;
481 }
482 else if ( *ep != 0 )
483 /* Don't collapse multiple separators by making them 0, so just */
484 /* make the one encountered 0. */
485 *ep++ = 0;
486
487 final_empty = ( ep > sp && *ep == 0 );
488 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000489 }
490
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000491 /* Finally, NULL-terminate the list. */
492 if ( list->used + final_empty + 1 >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000493 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000494 if ( list->used == list->size )
495 {
496 if ( list->size == 0 )
497 {
498 if ( FT_NEW_ARRAY( list->field, 5 ) )
499 goto Exit;
500 }
501 else
502 {
503 if ( FT_RENEW_ARRAY( list->field,
504 list->size,
505 list->size + 5 ) )
506 goto Exit;
507 }
David Turner993a8d02002-05-18 12:03:43 +0000508
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000509 list->size += 5;
510 }
David Turner993a8d02002-05-18 12:03:43 +0000511 }
512
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000513 if ( final_empty )
514 list->field[list->used++] = empty;
David Turner993a8d02002-05-18 12:03:43 +0000515
David Turner993a8d02002-05-18 12:03:43 +0000516 if ( list->used == list->size )
517 {
518 if ( list->size == 0 )
519 {
520 if ( FT_NEW_ARRAY( list->field, 5 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000521 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000522 }
523 else
524 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000525 if ( FT_RENEW_ARRAY( list->field,
526 list->size,
527 list->size + 5 ) )
528 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000529 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000530
David Turner993a8d02002-05-18 12:03:43 +0000531 list->size += 5;
532 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000533
534 list->field[list->used] = 0;
535
536 Exit:
537 return error;
David Turner993a8d02002-05-18 12:03:43 +0000538 }
539
David Turner993a8d02002-05-18 12:03:43 +0000540
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000541 static void
542 _bdf_shift( unsigned long n,
543 _bdf_list_t* list )
David Turner993a8d02002-05-18 12:03:43 +0000544 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000545 unsigned long i, u;
546
547
548 if ( list == 0 || list->used == 0 || n == 0 )
549 return;
550
551 if ( n >= list->used )
David Turner993a8d02002-05-18 12:03:43 +0000552 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000553 list->used = 0;
554 return;
David Turner993a8d02002-05-18 12:03:43 +0000555 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000556
557 for ( u = n, i = 0; u < list->used; i++, u++ )
558 list->field[i] = list->field[u];
559 list->used -= n;
560 }
561
562
563 static char *
564 _bdf_join( int c,
565 unsigned long* len,
566 _bdf_list_t* list )
567 {
568 unsigned long i, j;
569 char *fp, *dp;
570
571
572 if ( list == 0 || list->used == 0 )
573 return 0;
574
575 *len = 0;
576
577 dp = list->field[0];
578 for ( i = j = 0; i < list->used; i++ )
579 {
580 fp = list->field[i];
581 while ( *fp )
582 dp[j++] = *fp++;
583
584 if ( i + 1 < list->used )
David Turnerb1b47622002-05-21 21:17:43 +0000585 dp[j++] = (char)c;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000586 }
587 dp[j] = 0;
588
589 *len = j;
590 return dp;
591 }
592
593
594 /* High speed file reader that passes each line to a callback. */
595 static FT_Error
596 bdf_internal_readstream( FT_Stream stream,
597 char* buffer,
598 int count,
599 int *read_bytes )
600 {
601 int rbytes;
602 unsigned long pos = stream->pos;
603 FT_Error error = BDF_Err_Ok;
604
605
606 if ( pos > stream->size )
607 {
608 FT_ERROR(( "bdf_internal_readstream:" ));
609 FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
610 pos, stream->size ));
611 error = BDF_Err_Invalid_Stream_Operation;
612 goto Exit;
613 }
614
615 if ( stream->read )
616 rbytes = stream->read( stream, pos,
617 (unsigned char *)buffer, count );
David Turner993a8d02002-05-18 12:03:43 +0000618 else
619 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000620 rbytes = stream->size - pos;
621 if ( rbytes > count )
622 rbytes = count;
623
624 FT_MEM_COPY( buffer, stream->base + pos, rbytes );
David Turner993a8d02002-05-18 12:03:43 +0000625 }
David Turner993a8d02002-05-18 12:03:43 +0000626
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000627 stream->pos = pos + rbytes;
David Turner993a8d02002-05-18 12:03:43 +0000628
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000629 *read_bytes = rbytes;
David Turner993a8d02002-05-18 12:03:43 +0000630
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000631 Exit:
632 return error;
David Turner993a8d02002-05-18 12:03:43 +0000633 }
634
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000635
636 static FT_Error
637 _bdf_readstream( FT_Stream stream,
638 _bdf_line_func_t callback,
639 void* client_data,
640 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000641 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000642 _bdf_line_func_t cb;
643 unsigned long lineno;
644 int n, res, done, refill, bytes, hold;
645 char *ls, *le, *pp, *pe, *hp;
646 /* XXX: Use a dynamic buffer */
647 char buf[65536L];
648 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000649
David Turner993a8d02002-05-18 12:03:43 +0000650
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000651 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000652 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000653 error = BDF_Err_Invalid_Argument;
654 goto Exit;
655 }
David Turner993a8d02002-05-18 12:03:43 +0000656
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000657 cb = callback;
658 lineno = 1;
659 buf[0] = 0;
David Turner993a8d02002-05-18 12:03:43 +0000660
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000661 res = done = 0;
662 pp = ls = le = buf;
663
664 bytes = 65536L;
665
666 while ( !done )
667 {
668 error = bdf_internal_readstream( stream, pp, bytes, &n );
669 if ( error )
670 goto Exit;
671
672 if ( n == 0 )
673 break;
674
675 /* Determine the new end of the buffer pages. */
676 pe = pp + n;
677
678 for ( refill = 0; done == 0 && refill == 0; )
679 {
680 while ( le < pe && *le != '\n' && *le != '\r' )
681 le++;
682
683 if ( le == pe )
684 {
685 /* Hit the end of the last page in the buffer. Need to find */
686 /* out how many pages to shift and how many pages need to be */
687 /* read in. Adjust the line start and end pointers down to */
688 /* point to the right places in the pages. */
689
690 pp = buf + ( ( ( ls - buf ) >> 13 ) << 13 );
691 n = pp - buf;
692 ls -= n;
693 le -= n;
694 n = pe - pp;
695
696 FT_MEM_COPY( buf, pp, n );
697
698 pp = buf + n;
699 bytes = 65536L - n;
700 refill = 1;
701 }
702 else
703 {
704 /* Temporarily NULL-terminate the line. */
705 hp = le;
706 hold = *le;
707 *le = 0;
708
709 /* XXX: Use encoding independent value for 0x1a */
710 if ( *ls != '#' && *ls != 0x1a &&
711 le > ls &&
712 ( error = (*cb)( ls, le - ls, lineno, (void *)&cb,
713 client_data ) ) != BDF_Err_Ok )
714 done = 1;
715 else
716 {
David Turner993a8d02002-05-18 12:03:43 +0000717 ls = ++le;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000718 /* Handle the case of DOS crlf sequences. */
719 if ( le < pe && hold == '\n' && *le =='\r' )
David Turner993a8d02002-05-18 12:03:43 +0000720 ls = ++le;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000721 }
722
723 /* Increment the line number. */
724 lineno++;
725
726 /* Restore the character at the end of the line. */
David Turnerb1b47622002-05-21 21:17:43 +0000727 *hp = (char)hold;
David Turnerd490e372002-05-28 23:40:37 +0000728 }
David Turner993a8d02002-05-18 12:03:43 +0000729 }
730 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000731
732 *lno = lineno;
733
734 Exit:
735 return error;
David Turner993a8d02002-05-18 12:03:43 +0000736 }
David Turner993a8d02002-05-18 12:03:43 +0000737
738
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000739 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000740
David Turnerb1b47622002-05-21 21:17:43 +0000741 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000742 {
David Turner993a8d02002-05-18 12:03:43 +0000743 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
747 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
748 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
749 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
750 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
751 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
752 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
753 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000754 };
David Turner993a8d02002-05-18 12:03:43 +0000755
David Turnerb1b47622002-05-21 21:17:43 +0000756 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000757 {
David Turner993a8d02002-05-18 12:03:43 +0000758 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
759 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
760 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
761 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000762 };
David Turner993a8d02002-05-18 12:03:43 +0000763
David Turnerb1b47622002-05-21 21:17:43 +0000764 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000765 {
David Turner993a8d02002-05-18 12:03:43 +0000766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
767 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
768 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
769 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000770 };
David Turner993a8d02002-05-18 12:03:43 +0000771
David Turnerb1b47622002-05-21 21:17:43 +0000772 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000773 {
David Turner993a8d02002-05-18 12:03:43 +0000774 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
775 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
776 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
777 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000778 };
David Turner993a8d02002-05-18 12:03:43 +0000779
David Turner993a8d02002-05-18 12:03:43 +0000780
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000781#define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
David Turner993a8d02002-05-18 12:03:43 +0000782
David Turner993a8d02002-05-18 12:03:43 +0000783
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000784 /* Routine to convert an ASCII string into an unsigned long integer. */
785 static unsigned long
786 _bdf_atoul( char* s,
787 char** end,
788 int base )
David Turner993a8d02002-05-18 12:03:43 +0000789 {
David Turnerb1b47622002-05-21 21:17:43 +0000790 unsigned long v;
791 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000792
793
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000794 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000795 return 0;
796
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000797 /* Make sure the radix is something recognizable. Default to 10. */
798 switch ( base )
799 {
800 case 8:
801 dmap = odigits;
802 break;
803 case 16:
804 dmap = hdigits;
805 break;
806 default:
807 base = 10;
808 dmap = ddigits;
809 break;
David Turner993a8d02002-05-18 12:03:43 +0000810 }
811
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000812 /* Check for the special hex prefix. */
813 if ( *s == '0' &&
814 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
815 {
816 base = 16;
817 dmap = hdigits;
818 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000819 }
820
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000821 for ( v = 0; isdigok( dmap, *s ); s++ )
822 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000823
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000824 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000825 *end = s;
826
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000827 return v;
828 }
David Turner993a8d02002-05-18 12:03:43 +0000829
David Turner993a8d02002-05-18 12:03:43 +0000830
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000831 /* Routine to convert an ASCII string into an signed long integer. */
832 static long
833 _bdf_atol( char* s,
834 char** end,
835 int base )
836 {
David Turnerb1b47622002-05-21 21:17:43 +0000837 long v, neg;
838 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000839
840
841 if ( s == 0 || *s == 0 )
842 return 0;
843
844 /* Make sure the radix is something recognizable. Default to 10. */
845 switch ( base )
846 {
847 case 8:
848 dmap = odigits;
849 break;
850 case 16:
851 dmap = hdigits;
852 break;
853 default:
854 base = 10;
855 dmap = ddigits;
856 break;
857 }
858
859 /* Check for a minus sign. */
860 neg = 0;
861 if ( *s == '-' )
862 {
863 s++;
864 neg = 1;
865 }
866
867 /* Check for the special hex prefix. */
868 if ( *s == '0' &&
869 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
870 {
871 base = 16;
872 dmap = hdigits;
873 s += 2;
874 }
875
876 for ( v = 0; isdigok( dmap, *s ); s++ )
877 v = v * base + a2i[(int)*s];
878
879 if ( end != 0 )
880 *end = s;
881
882 return ( !neg ) ? v : -v;
883 }
884
885
886 /* Routine to convert an ASCII string into an signed short integer. */
887 static short
888 _bdf_atos( char* s,
889 char** end,
890 int base )
891 {
David Turnerb1b47622002-05-21 21:17:43 +0000892 short v, neg;
893 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000894
895
896 if ( s == 0 || *s == 0 )
897 return 0;
898
899 /* Make sure the radix is something recognizable. Default to 10. */
900 switch ( base )
901 {
902 case 8:
903 dmap = odigits;
904 break;
905 case 16:
906 dmap = hdigits;
907 break;
908 default:
909 base = 10;
910 dmap = ddigits;
911 break;
912 }
913
914 /* Check for a minus. */
915 neg = 0;
916 if ( *s == '-' )
917 {
918 s++;
919 neg = 1;
920 }
921
922 /* Check for the special hex prefix. */
923 if ( *s == '0' &&
924 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
925 {
926 base = 16;
927 dmap = hdigits;
928 s += 2;
929 }
930
931 for ( v = 0; isdigok( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +0000932 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000933
934 if ( end != 0 )
935 *end = s;
936
Werner Lemberg233302a2002-05-22 05:41:06 +0000937 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000938 }
939
940
941 /* Routine to compare two glyphs by encoding so they can be sorted. */
942 static int
943 by_encoding( const void* a,
944 const void* b )
945 {
946 bdf_glyph_t *c1, *c2;
947
948
949 c1 = (bdf_glyph_t *)a;
950 c2 = (bdf_glyph_t *)b;
951
952 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000953 return -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000954 else if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000955 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000956
David Turner993a8d02002-05-18 12:03:43 +0000957 return 0;
David Turner993a8d02002-05-18 12:03:43 +0000958 }
959
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000960
961 static FT_Error
962 bdf_create_property( char* name,
963 int format,
964 bdf_font_t* font )
965 {
966 unsigned long n;
967 bdf_property_t* p;
968 FT_Memory memory = font->memory;
969 FT_Error error = BDF_Err_Ok;
970
971
972 /* First check to see if the property has */
973 /* already been added or not. If it has, then */
974 /* simply ignore it. */
975 if ( hash_lookup( name, &(font->proptbl) ) )
976 goto Exit;
977
978 if ( font->nuser_props == 0 )
979 {
980 if ( FT_NEW_ARRAY( font->user_props, 1 ) )
981 goto Exit;
982 }
983 else
984 {
985 if ( FT_RENEW_ARRAY( font->user_props,
986 font->nuser_props,
987 font->nuser_props + 1 ) )
988 goto Exit;
989 }
990
991 p = font->user_props + font->nuser_props;
992 FT_MEM_SET( p, 0, sizeof ( bdf_property_t ) );
993
994 n = (unsigned long)( ft_strlen( name ) + 1 );
995 if ( FT_NEW_ARRAY( p->name, n ) )
996 goto Exit;
997
998 FT_MEM_COPY( (char *)p->name, name, n );
999
1000 p->format = format;
1001 p->builtin = 0;
1002
1003 n = _num_bdf_properties + font->nuser_props;
1004
1005 error = hash_insert( p->name, (void *)n, &(font->proptbl), memory );
1006 if ( error )
1007 goto Exit;
1008
1009 font->nuser_props++;
1010
1011 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001012 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001013 }
David Turner993a8d02002-05-18 12:03:43 +00001014
1015
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001016 FT_LOCAL_DEF( bdf_property_t * )
1017 bdf_get_property( char* name,
1018 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001019 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001020 hashnode hn;
1021 unsigned long propid;
1022
1023
1024 if ( name == 0 || *name == 0 )
1025 return 0;
1026
1027 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1028 return 0;
1029
1030 propid = (unsigned long)hn->data;
1031 if ( propid >= _num_bdf_properties )
1032 return font->user_props + ( propid - _num_bdf_properties );
1033
Werner Lemberg233302a2002-05-22 05:41:06 +00001034 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001035 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001036
1037
1038 /*************************************************************************/
1039 /* */
1040 /* BDF font file parsing flags and functions. */
1041 /* */
1042 /*************************************************************************/
1043
1044
1045 /* Parse flags. */
1046
1047#define _BDF_START 0x0001
1048#define _BDF_FONT_NAME 0x0002
1049#define _BDF_SIZE 0x0004
1050#define _BDF_FONT_BBX 0x0008
1051#define _BDF_PROPS 0x0010
1052#define _BDF_GLYPHS 0x0020
1053#define _BDF_GLYPH 0x0040
1054#define _BDF_ENCODING 0x0080
1055#define _BDF_SWIDTH 0x0100
1056#define _BDF_DWIDTH 0x0200
1057#define _BDF_BBX 0x0400
1058#define _BDF_BITMAP 0x0800
1059
1060#define _BDF_SWIDTH_ADJ 0x1000
1061
1062#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1063 _BDF_ENCODING | \
1064 _BDF_SWIDTH | \
1065 _BDF_DWIDTH | \
1066 _BDF_BBX | \
1067 _BDF_BITMAP )
1068
1069#define _BDF_GLYPH_WIDTH_CHECK 0x40000000L
1070#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000L
1071
1072
1073 /* Auto correction messages. */
1074#define ACMSG1 "FONT_ASCENT property missing. " \
1075 "Added \"FONT_ASCENT %hd\".\n"
1076#define ACMSG2 "FONT_DESCENT property missing. " \
1077 "Added \"FONT_DESCENT %hd\".\n"
1078#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
1079#define ACMSG4 "Font left bearing != actual left bearing. " \
1080 "Old: %hd New: %hd.\n"
1081#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
1082#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
1083#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
1084#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
1085#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
1086#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
1087#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
1088#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
1089#define ACMSG13 "Glyph %ld extra rows removed.\n"
1090#define ACMSG14 "Glyph %ld extra columns removed.\n"
1091#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
1092
1093 /* Error messages. */
1094#define ERRMSG1 "[line %ld] Missing \"%s\" line.\n"
1095#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
1096#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
1097
1098
1099 static FT_Error
1100 _bdf_add_comment( bdf_font_t* font,
1101 char* comment,
1102 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001103 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001104 char* cp;
1105 FT_Memory memory = font->memory;
1106 FT_Error error = BDF_Err_Ok;
1107
1108
1109 if ( font->comments_len == 0 )
1110 {
1111 if ( FT_NEW_ARRAY( font->comments, len + 1 ) )
1112 goto Exit;
1113 }
1114 else
1115 {
1116 if ( FT_RENEW_ARRAY( font->comments,
1117 font->comments_len,
1118 font->comments_len + len + 1 ) )
1119 goto Exit;
1120 }
1121
1122 cp = font->comments + font->comments_len;
1123 FT_MEM_COPY( cp, comment, len );
1124 cp += len;
1125 *cp++ = '\n';
1126 font->comments_len += len + 1;
1127
1128 Exit:
1129 return error;
David Turner993a8d02002-05-18 12:03:43 +00001130 }
1131
David Turner993a8d02002-05-18 12:03:43 +00001132
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001133 /* Set the spacing from the font name if it exists, or set it to the */
1134 /* default specified in the options. */
1135 static FT_Error
1136 _bdf_set_default_spacing( bdf_font_t* font,
1137 bdf_options_t* opts )
David Turner993a8d02002-05-18 12:03:43 +00001138 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001139 unsigned long len;
1140 char name[128];
1141 _bdf_list_t list;
1142 FT_Memory memory;
1143 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001144
David Turner993a8d02002-05-18 12:03:43 +00001145
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001146 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1147 {
1148 error = BDF_Err_Invalid_Argument;
1149 goto Exit;
1150 }
David Turner993a8d02002-05-18 12:03:43 +00001151
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001152 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001153
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001154 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001155
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001156 len = (unsigned long)( ft_strlen( font->name ) + 1 );
1157 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001158
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001159 list.size = list.used = 0;
David Turner993a8d02002-05-18 12:03:43 +00001160
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001161 error = _bdf_split( (char *)"-", name, len, &list, memory );
1162 if ( error )
1163 goto Exit;
1164
1165 if ( list.used == 15 )
1166 {
1167 switch ( list.field[11][0] )
1168 {
1169 case 'C':
1170 case 'c':
1171 font->spacing = BDF_CHARCELL;
1172 break;
1173 case 'M':
1174 case 'm':
1175 font->spacing = BDF_MONOWIDTH;
1176 break;
1177 case 'P':
1178 case 'p':
1179 font->spacing = BDF_PROPORTIONAL;
1180 break;
David Turner993a8d02002-05-18 12:03:43 +00001181 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001182 }
1183
1184 FT_FREE( list.field );
1185
1186 Exit:
1187 return error;
David Turner993a8d02002-05-18 12:03:43 +00001188 }
David Turner993a8d02002-05-18 12:03:43 +00001189
1190
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001191 /* Determine whether the property is an atom or not. If it is, then */
1192 /* clean it up so the double quotes are removed if they exist. */
1193 static int
1194 _bdf_is_atom( char* line,
1195 unsigned long linelen,
1196 char** name,
1197 char** value,
1198 bdf_font_t* font )
1199 {
1200 int hold;
1201 char *sp, *ep;
1202 bdf_property_t* p;
1203
David Turner993a8d02002-05-18 12:03:43 +00001204
1205 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001206
1207 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001208 ep++;
1209
1210 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001211 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001212 {
1213 hold = *ep;
1214 *ep = 0;
1215 }
1216
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001217 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001218
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001219 /* Restore the character that was saved before any return can happen. */
1220 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001221 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001222
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001223 /* If the property exists and is not an atom, just return here. */
1224 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001225 return 0;
1226
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001227 /* The property is an atom. Trim all leading and trailing whitespace */
1228 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001229 sp = ep;
1230 ep = line + linelen;
1231
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001232 /* Trim the leading whitespace if it exists. */
David Turner993a8d02002-05-18 12:03:43 +00001233 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001234 while ( *sp &&
1235 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001236 sp++;
1237
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001238 /* Trim the leading double quote if it exists. */
1239 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001240 sp++;
1241 *value = sp;
1242
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001243 /* Trim the trailing whitespace if it exists. */
1244 while ( ep > sp &&
1245 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001246 *--ep = 0;
1247
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001248 /* Trim the trailing double quote if it exists. */
1249 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001250 *--ep = 0;
1251
1252 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001253 }
David Turner993a8d02002-05-18 12:03:43 +00001254
1255
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001256 static FT_Error
1257 _bdf_add_property( bdf_font_t* font,
1258 char* name,
1259 char* value )
1260 {
1261 unsigned long propid;
1262 hashnode hn;
1263 int len;
1264 bdf_property_t *prop, *fp;
1265 FT_Memory memory = font->memory;
1266 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001267
David Turner993a8d02002-05-18 12:03:43 +00001268
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001269 /* First, check to see if the property already exists in the font. */
1270 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001271 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001272 /* The property already exists in the font, so simply replace */
1273 /* the value of the property with the current value. */
1274 fp = font->props + (unsigned long)hn->data;
1275
David Turnerb1b47622002-05-21 21:17:43 +00001276 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001277 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001278 case BDF_ATOM:
1279 /* Delete the current atom if it exists. */
1280 FT_FREE( fp->value.atom );
1281
1282 if ( value == 0 )
1283 len = 1;
1284 else
1285 len = ft_strlen( value ) + 1;
1286
1287 if ( len > 1 )
1288 {
1289 if ( FT_NEW_ARRAY( fp->value.atom, len ) )
1290 goto Exit;
1291 FT_MEM_COPY( fp->value.atom, value, len );
1292 }
1293 else
1294 fp->value.atom = 0;
1295 break;
1296
1297 case BDF_INTEGER:
1298 fp->value.int32 = _bdf_atol( value, 0, 10 );
1299 break;
1300
1301 case BDF_CARDINAL:
1302 fp->value.card32 = _bdf_atoul( value, 0, 10 );
1303 break;
David Turnerd490e372002-05-28 23:40:37 +00001304
David Turnerb1b47622002-05-21 21:17:43 +00001305 default:
1306 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001307 }
David Turnerd490e372002-05-28 23:40:37 +00001308
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001309 goto Exit;
1310 }
1311
1312 /* See whether this property type exists yet or not. */
1313 /* If not, create it. */
1314 hn = hash_lookup( name, &(font->proptbl) );
1315 if ( hn == 0 )
1316 {
1317 error = bdf_create_property( name, BDF_ATOM, font );
1318 if ( error )
1319 goto Exit;
1320 hn = hash_lookup( name, &(font->proptbl) );
1321 }
1322
1323 /* Allocate another property if this is overflow. */
1324 if ( font->props_used == font->props_size )
1325 {
1326 if ( font->props_size == 0 )
1327 {
1328 if ( FT_NEW_ARRAY( font->props, 1 ) )
1329 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001330 }
1331 else
1332 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001333 if ( FT_RENEW_ARRAY( font->props,
1334 font->props_size,
1335 font->props_size + 1 ) )
1336 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001337 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001338
David Turner993a8d02002-05-18 12:03:43 +00001339 fp = font->props + font->props_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001340 FT_MEM_SET( fp, 0, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001341 font->props_size++;
1342 }
1343
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001344 propid = (unsigned long)hn->data;
1345 if ( propid >= _num_bdf_properties )
1346 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001347 else
David Turnerb1b47622002-05-21 21:17:43 +00001348 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001349
1350 fp = font->props + font->props_used;
1351
1352 fp->name = prop->name;
1353 fp->format = prop->format;
1354 fp->builtin = prop->builtin;
1355
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001356 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001357 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001358 case BDF_ATOM:
1359 if ( value == 0 )
1360 len = 1;
1361 else
1362 len = ft_strlen( value ) + 1;
David Turner993a8d02002-05-18 12:03:43 +00001363
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001364 if ( len > 1 )
1365 {
1366 if ( FT_NEW_ARRAY( fp->value.atom, len ) )
1367 goto Exit;
1368 FT_MEM_COPY( fp->value.atom, value, len );
1369 }
1370 else
1371 fp->value.atom = 0;
1372 break;
David Turner993a8d02002-05-18 12:03:43 +00001373
1374 case BDF_INTEGER:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001375 fp->value.int32 = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001376 break;
1377
1378 case BDF_CARDINAL:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001379 fp->value.card32 = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001380 break;
David Turner993a8d02002-05-18 12:03:43 +00001381 }
1382
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001383 /* If the property happens to be a comment, then it doesn't need */
1384 /* to be added to the internal hash table. */
1385 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) {
1386 /* Add the property to the font property table. */
1387 error = hash_insert( fp->name,
1388 (void *)font->props_used,
1389 (hashtable *)font->internal,
1390 memory );
1391 if ( error )
1392 goto Exit;
1393 }
David Turner993a8d02002-05-18 12:03:43 +00001394
1395 font->props_used++;
1396
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001397 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1398 /* property needs to be located if it exists in the property list, the */
1399 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1400 /* present, and the SPACING property should override the default */
1401 /* spacing. */
1402 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001403 font->default_glyph = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001404 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001405 font->font_ascent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001406 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001407 font->font_descent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001408 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001409 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001410 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001411 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001412 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001413 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001414 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001415 font->spacing = BDF_CHARCELL;
1416 }
1417
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001418 Exit:
1419 return error;
David Turner993a8d02002-05-18 12:03:43 +00001420 }
1421
David Turner993a8d02002-05-18 12:03:43 +00001422
David Turnerb1b47622002-05-21 21:17:43 +00001423 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001424 {
1425 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1426 };
1427
1428
1429 /* Actually parse the glyph info and bitmaps. */
1430 static FT_Error
1431 _bdf_parse_glyphs( char* line,
1432 unsigned long linelen,
1433 unsigned long lineno,
1434 void* call_data,
1435 void* client_data )
1436 {
1437 int c, mask_index;
1438 char* s;
1439 unsigned char* bp;
1440 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001441
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];
Werner Lemberg233302a2002-05-22 05:41:06 +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
David Turnerd490e372002-05-28 23:40:37 +00001743 ps = (double)font->point_size;
1744 rx = (double)font->resolution_x;
1745 dw = (double)glyph->dwidth;
1746
Werner Lemberg02d4d592002-05-28 22:38:05 +00001747 glyph->swidth = (unsigned short)FT_MulDiv(
1748 glyph->dwidth, 72000L,
1749 (FT_Long)( font->point_size *
1750 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001751 }
1752
1753 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001754 goto Exit;
1755 }
David Turner993a8d02002-05-18 12:03:43 +00001756
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001757 /* Expect the BBX field next. */
1758 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1759 {
1760 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1761 if ( error )
1762 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001763
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001764 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1765 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1766 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1767 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1768
1769 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001770 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1771 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001772
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001773 /* Determine the overall font bounding box as the characters are */
1774 /* loaded so corrections can be done later if indicated. */
1775 p->maxas = MAX( glyph->bbx.ascent, p->maxas );
1776 p->maxds = MAX( glyph->bbx.descent, p->maxds );
1777
David Turnerb1b47622002-05-21 21:17:43 +00001778 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001779
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001780 p->maxrb = MAX( p->rbearing, p->maxrb );
1781 p->minlb = MIN( glyph->bbx.x_offset, p->minlb );
1782 p->maxlb = MAX( glyph->bbx.x_offset, p->maxlb );
1783
1784 if ( !( p->flags & _BDF_DWIDTH ) )
1785 {
1786 /* Missing DWIDTH field. Emit an auto correction message and set */
1787 /* the device width to the glyph width. */
1788 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1789 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001790 }
1791
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001792 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1793 /* value if necessary. */
1794 if ( p->opts->correct_metrics != 0 )
1795 {
1796 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001797 unsigned short sw = (unsigned short)FT_MulDiv(
1798 glyph->dwidth, 72000L,
1799 (FT_Long)( font->point_size *
1800 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001801
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001802
1803 if ( sw != glyph->swidth )
1804 {
1805 glyph->swidth = sw;
1806
1807 if ( p->glyph_enc == -1 )
1808 _bdf_set_glyph_modified( font->umod,
1809 font->unencoded_used - 1 );
1810 else
1811 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1812
1813 p->flags |= _BDF_SWIDTH_ADJ;
1814 font->modified = 1;
1815 }
David Turner993a8d02002-05-18 12:03:43 +00001816 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001817
David Turner993a8d02002-05-18 12:03:43 +00001818 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001819 goto Exit;
1820 }
David Turner993a8d02002-05-18 12:03:43 +00001821
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001822 /* And finally, gather up the bitmap. */
1823 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1824 {
1825 if ( !( p->flags & _BDF_BBX ) )
1826 {
1827 /* Missing BBX field. */
1828 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1829 error = BDF_Err_Missing_Bbx_Field;
1830 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001831 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001832
1833 /* Allocate enough space for the bitmap. */
1834 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg233302a2002-05-22 05:41:06 +00001835 glyph->bytes = (unsigned short)( glyph->bpr * glyph->bbx.height );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001836
1837 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1838 goto Exit;
1839
1840 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001841 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001842
1843 goto Exit;
1844 }
1845
1846 error = BDF_Err_Invalid_File_Format;
1847
1848 Exit:
1849 return error;
David Turner993a8d02002-05-18 12:03:43 +00001850 }
1851
David Turner993a8d02002-05-18 12:03:43 +00001852
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001853 /* Load the font properties. */
1854 static FT_Error
1855 _bdf_parse_properties( char* line,
1856 unsigned long linelen,
1857 unsigned long lineno,
1858 void* call_data,
1859 void* client_data )
1860 {
1861 unsigned long vlen;
1862 _bdf_line_func_t* next;
1863 _bdf_parse_t* p;
1864 char* name;
1865 char* value;
1866 char nbuf[128];
1867 FT_Memory memory;
1868 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001869
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001870 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001871
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001872
1873 next = (_bdf_line_func_t *)call_data;
1874 p = (_bdf_parse_t *) client_data;
1875
1876 memory = p->font->memory;
1877
1878 /* Check for the end of the properties. */
1879 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1880 {
1881 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1882 /* encountered yet, then make sure they are added as properties and */
1883 /* make sure they are set from the font bounding box info. */
1884 /* */
1885 /* This is *always* done regardless of the options, because X11 */
1886 /* requires these two fields to compile fonts. */
1887 if ( bdf_get_font_property( p->font, (char *)"FONT_ASCENT" ) == 0 )
1888 {
1889 p->font->font_ascent = p->font->bbx.ascent;
1890 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1891 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
1892 if ( error )
1893 goto Exit;
1894
1895 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1896 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001897 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001898
1899 if ( bdf_get_font_property( p->font, (char *)"FONT_DESCENT" ) == 0 )
1900 {
1901 p->font->font_descent = p->font->bbx.descent;
1902 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1903 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
1904 if ( error )
1905 goto Exit;
1906
1907 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1908 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001909 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001910
David Turner993a8d02002-05-18 12:03:43 +00001911 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001912 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001913
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001914 goto Exit;
1915 }
David Turner993a8d02002-05-18 12:03:43 +00001916
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001917 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1918 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1919 goto Exit;
1920
1921 /* Handle COMMENT fields and properties in a special way to preserve */
1922 /* the spacing. */
1923 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1924 {
David Turner993a8d02002-05-18 12:03:43 +00001925 name = value = line;
1926 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001927 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001928 *value++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001929 error = _bdf_add_property( p->font, name, value );
1930 if ( error )
1931 goto Exit;
1932 }
1933 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1934 {
1935 error = _bdf_add_property( p->font, name, value );
1936 if ( error )
1937 goto Exit;
1938 }
1939 else
1940 {
1941 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1942 if ( error )
1943 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001944 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001945
1946 _bdf_shift( 1, &p->list );
1947 value = _bdf_join( ' ', &vlen, &p->list );
1948
1949 error = _bdf_add_property( p->font, name, value );
1950 if ( error )
1951 goto Exit;
1952 }
1953
1954 Exit:
1955 return error;
David Turner993a8d02002-05-18 12:03:43 +00001956 }
1957
David Turner993a8d02002-05-18 12:03:43 +00001958
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001959 /* Load the font header. */
1960 static FT_Error
1961 _bdf_parse_start( char* line,
1962 unsigned long linelen,
1963 unsigned long lineno,
1964 void* call_data,
1965 void* client_data )
1966 {
1967 unsigned long slen;
1968 _bdf_line_func_t* next;
1969 _bdf_parse_t* p;
1970 bdf_font_t* font;
1971 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001972
David Turnerd490e372002-05-28 23:40:37 +00001973 FT_Memory memory = NULL;
1974 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001975
1976 FT_UNUSED( lineno ); /* only used in debug mode */
1977
1978
1979 next = (_bdf_line_func_t *)call_data;
1980 p = (_bdf_parse_t *) client_data;
1981
1982 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00001983 memory = p->font->memory;
1984
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001985 /* Check for a comment. This is done to handle those fonts that have */
1986 /* comments before the STARTFONT line for some reason. */
1987 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1988 {
1989 if ( p->opts->keep_comments != 0 && p->font != 0 )
1990 {
1991 linelen -= 7;
1992
1993 s = line + 7;
1994 if ( *s != 0 )
1995 {
1996 s++;
1997 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00001998 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001999
2000 error = _bdf_add_comment( p->font, s, linelen );
2001 if ( error )
2002 goto Exit;
2003 /* here font is not defined! */
2004 }
2005
2006 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002007 }
2008
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002009 if ( !( p->flags & _BDF_START ) )
2010 {
2011 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002012
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002013 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2014 {
2015 /* No STARTFONT field is a good indication of a problem. */
2016 error = BDF_Err_Missing_Startfont_Field;
2017 goto Exit;
2018 }
David Turner993a8d02002-05-18 12:03:43 +00002019
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002020 p->flags = _BDF_START;
2021 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002022
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002023 if ( FT_NEW( font ) )
2024 goto Exit;
2025 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002026
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002027 font->memory = p->memory;
2028 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002029
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002030 { /* setup */
2031 unsigned long i;
2032 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002033
David Turner993a8d02002-05-18 12:03:43 +00002034
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002035 error = hash_init( &(font->proptbl), memory );
2036 if ( error )
2037 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002038 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002039 i < _num_bdf_properties; i++, prop++ )
2040 {
2041 error = hash_insert( prop->name, (void *)i,
2042 &(font->proptbl), memory );
2043 if ( error )
2044 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002045 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002046 }
2047
2048 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2049 goto Exit;
2050 error = hash_init( (hashtable *)p->font->internal,memory );
2051 if ( error )
2052 goto Exit;
2053 p->font->spacing = p->opts->font_spacing;
2054 p->font->default_glyph = -1;
2055
2056 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002057 }
2058
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002059 /* Check for the start of the properties. */
2060 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2061 {
2062 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
2063 if ( error )
2064 goto Exit;
2065 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2066
2067 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2068 goto Exit;
2069
2070 p->flags |= _BDF_PROPS;
2071 *next = _bdf_parse_properties;
2072
2073 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002074 }
2075
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002076 /* Check for the FONTBOUNDINGBOX field. */
2077 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2078 {
2079 if ( !(p->flags & _BDF_SIZE ) )
2080 {
2081 /* Missing the SIZE field. */
2082 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2083 error = BDF_Err_Missing_Size_Field;
2084 goto Exit;
2085 }
2086
2087 error = _bdf_split( (char *)" +", line, linelen, &p->list , memory );
2088 if ( error )
2089 goto Exit;
2090
2091 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2092 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2093
2094 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2095 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2096
David Turnerd490e372002-05-28 23:40:37 +00002097 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002098 p->font->bbx.y_offset );
2099
2100 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002101
2102 p->flags |= _BDF_FONT_BBX;
2103
2104 goto Exit;
2105 }
2106
2107 /* The next thing to check for is the FONT field. */
2108 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2109 {
2110 error = _bdf_split( (char *)" +", line, linelen, &p->list , memory );
2111 if ( error )
2112 goto Exit;
2113 _bdf_shift( 1, &p->list );
2114
2115 s = _bdf_join( ' ', &slen, &p->list );
2116 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2117 goto Exit;
2118 FT_MEM_COPY( p->font->name, s, slen + 1 );
2119
2120 /* If the font name is an XLFD name, set the spacing to the one in */
2121 /* the font name. If there is no spacing fall back on the default. */
2122 error = _bdf_set_default_spacing( p->font, p->opts );
2123 if ( error )
2124 goto Exit;
2125
2126 p->flags |= _BDF_FONT_NAME;
2127
2128 goto Exit;
2129 }
2130
2131 /* Check for the SIZE field. */
2132 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2133 {
2134 if ( !( p->flags & _BDF_FONT_NAME ) )
2135 {
2136 /* Missing the FONT field. */
2137 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2138 error = BDF_Err_Missing_Font_Field;
2139 goto Exit;
2140 }
2141
2142 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
2143 if ( error )
2144 goto Exit;
2145
2146 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2147 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2148 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2149
2150 /* Check for the bits per pixel field. */
2151 if ( p->list.used == 5 )
2152 {
2153 p->font->bpp = _bdf_atos( p->list.field[4], 0, 10 );
2154 if ( p->font->bpp > 1 && ( p->font->bpp & 1 ) )
2155 {
2156 /* Move up to the next bits per pixel value if an odd number */
2157 /* is encountered. */
2158 p->font->bpp++;
2159 if ( p->font->bpp <= 4 )
2160 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
David Turner993a8d02002-05-18 12:03:43 +00002161 }
David Turner993a8d02002-05-18 12:03:43 +00002162
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002163 if ( p->font->bpp > 4 )
2164 {
2165 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
2166 p->font->bpp = 4;
2167 }
2168 }
2169 else
2170 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002171
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002172 p->flags |= _BDF_SIZE;
2173
2174 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002175 }
2176
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002177 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002178
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002179 Exit:
2180 return error;
2181 }
David Turner993a8d02002-05-18 12:03:43 +00002182
2183
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002184 /*************************************************************************/
2185 /* */
2186 /* API. */
2187 /* */
2188 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002189
David Turner993a8d02002-05-18 12:03:43 +00002190
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002191 FT_LOCAL_DEF( FT_Error )
2192 bdf_load_font( FT_Stream stream,
2193 FT_Memory extmemory,
2194 bdf_options_t* opts,
2195 bdf_font_t* *font )
2196 {
2197 unsigned long lineno;
2198 _bdf_parse_t p;
2199
David Turnerd490e372002-05-28 23:40:37 +00002200 FT_Memory memory = NULL;
2201 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002202
2203
2204 FT_MEM_SET( &p, 0, sizeof ( _bdf_parse_t ) );
2205
Werner Lemberg233302a2002-05-22 05:41:06 +00002206 p.opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002207 p.minlb = 32767;
David Turner993a8d02002-05-18 12:03:43 +00002208 p.memory = extmemory; /* only during font creation */
2209
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002210 error = _bdf_readstream( stream, _bdf_parse_start,
2211 (void *)&p, &lineno );
2212 if ( error )
2213 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002214
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002215 if ( p.font != 0 )
2216 {
2217 /* If the font is not proportional, set the font's monowidth */
2218 /* field to the width of the font bounding box. */
David Turner993a8d02002-05-18 12:03:43 +00002219 memory = p.font->memory;
2220
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002221 if ( p.font->spacing != BDF_PROPORTIONAL )
2222 p.font->monowidth = p.font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002223
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002224 /* If the number of glyphs loaded is not that of the original count, */
2225 /* indicate the difference. */
2226 if ( p.cnt != p.font->glyphs_used + p.font->unencoded_used )
2227 {
2228 FT_TRACE2(( "bdf_load_font: " ACMSG15, p.cnt,
2229 p.font->glyphs_used + p.font->unencoded_used ));
2230 p.font->modified = 1;
2231 }
2232
2233 /* Once the font has been loaded, adjust the overall font metrics if */
2234 /* necessary. */
2235 if ( p.opts->correct_metrics != 0 &&
2236 ( p.font->glyphs_used > 0 || p.font->unencoded_used > 0 ) )
2237 {
2238 if ( p.maxrb - p.minlb != p.font->bbx.width )
2239 {
2240 FT_TRACE2(( "bdf_load_font: " ACMSG3,
2241 p.font->bbx.width, p.maxrb - p.minlb ));
Werner Lemberg233302a2002-05-22 05:41:06 +00002242 p.font->bbx.width = (unsigned short)( p.maxrb - p.minlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002243 p.font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002244 }
2245
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002246 if ( p.font->bbx.x_offset != p.minlb )
2247 {
2248 FT_TRACE2(( "bdf_load_font: " ACMSG4,
2249 p.font->bbx.x_offset, p.minlb ));
2250 p.font->bbx.x_offset = p.minlb;
2251 p.font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002252 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002253
2254 if ( p.font->bbx.ascent != p.maxas )
2255 {
2256 FT_TRACE2(( "bdf_load_font: " ACMSG5,
2257 p.font->bbx.ascent, p.maxas ));
2258 p.font->bbx.ascent = p.maxas;
2259 p.font->modified = 1;
2260 }
2261
2262 if ( p.font->bbx.descent != p.maxds )
2263 {
2264 FT_TRACE2(( "bdf_load_font: " ACMSG6,
2265 p.font->bbx.descent, p.maxds ));
2266 p.font->bbx.descent = p.maxds;
Werner Lemberg233302a2002-05-22 05:41:06 +00002267 p.font->bbx.y_offset = (short)( -p.maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002268 p.font->modified = 1;
2269 }
2270
2271 if ( p.maxas + p.maxds != p.font->bbx.height )
2272 {
2273 FT_TRACE2(( "bdf_load_font: " ACMSG7,
2274 p.font->bbx.height, p.maxas + p.maxds ));
Werner Lemberg233302a2002-05-22 05:41:06 +00002275 p.font->bbx.height = (unsigned short)( p.maxas + p.maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002276 }
2277
2278 if ( p.flags & _BDF_SWIDTH_ADJ )
2279 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2280 }
David Turner993a8d02002-05-18 12:03:43 +00002281 }
2282
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002283 if ( p.flags & _BDF_START )
2284 {
2285 {
2286 /* The ENDFONT field was never reached or did not exist. */
2287 if ( !( p.flags & _BDF_GLYPHS ) )
2288 /* Error happened while parsing header. */
2289 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2290 else
2291 /* Error happened when parsing glyphs. */
2292 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2293 }
David Turner993a8d02002-05-18 12:03:43 +00002294 }
2295
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002296 /* Free up the list used during the parsing. */
2297 FT_FREE( p.list.field );
David Turner993a8d02002-05-18 12:03:43 +00002298
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002299 if ( p.font != 0 )
2300 {
2301 /* Make sure the comments are NULL terminated if they exist. */
2302 memory = p.font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002303
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002304 if ( p.font->comments_len > 0 ) {
2305 if ( FT_RENEW_ARRAY( p.font->comments,
2306 p.font->comments_len,
2307 p.font->comments_len + 1 ) )
2308 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002309
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002310 p.font->comments[p.font->comments_len] = 0;
2311 }
David Turner993a8d02002-05-18 12:03:43 +00002312 }
2313
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002314 *font = p.font;
2315
2316 Exit:
2317 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,
2404 char* name )
2405 {
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 */