blob: dde4e854f6c9d84e82a62897fc252eb62842b434 [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;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000646 char *buf = 0;
647 FT_Memory memory = stream->memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000648 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000649
David Turner993a8d02002-05-18 12:03:43 +0000650
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000651 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000652 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000653 error = BDF_Err_Invalid_Argument;
654 goto Exit;
655 }
David Turner993a8d02002-05-18 12:03:43 +0000656
Werner Lemberg7925edc2002-05-30 19:29:41 +0000657 if ( FT_NEW_ARRAY( buf, 65536L ) )
658 goto Exit;
659
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000660 cb = callback;
661 lineno = 1;
662 buf[0] = 0;
David Turner993a8d02002-05-18 12:03:43 +0000663
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000664 res = done = 0;
665 pp = ls = le = buf;
666
667 bytes = 65536L;
668
669 while ( !done )
670 {
671 error = bdf_internal_readstream( stream, pp, bytes, &n );
672 if ( error )
673 goto Exit;
674
675 if ( n == 0 )
676 break;
677
678 /* Determine the new end of the buffer pages. */
679 pe = pp + n;
680
681 for ( refill = 0; done == 0 && refill == 0; )
682 {
683 while ( le < pe && *le != '\n' && *le != '\r' )
684 le++;
685
686 if ( le == pe )
687 {
688 /* Hit the end of the last page in the buffer. Need to find */
689 /* out how many pages to shift and how many pages need to be */
690 /* read in. Adjust the line start and end pointers down to */
691 /* point to the right places in the pages. */
692
693 pp = buf + ( ( ( ls - buf ) >> 13 ) << 13 );
694 n = pp - buf;
695 ls -= n;
696 le -= n;
697 n = pe - pp;
698
699 FT_MEM_COPY( buf, pp, n );
700
701 pp = buf + n;
702 bytes = 65536L - n;
703 refill = 1;
704 }
705 else
706 {
707 /* Temporarily NULL-terminate the line. */
708 hp = le;
709 hold = *le;
710 *le = 0;
711
712 /* XXX: Use encoding independent value for 0x1a */
713 if ( *ls != '#' && *ls != 0x1a &&
714 le > ls &&
715 ( error = (*cb)( ls, le - ls, lineno, (void *)&cb,
716 client_data ) ) != BDF_Err_Ok )
717 done = 1;
718 else
719 {
David Turner993a8d02002-05-18 12:03:43 +0000720 ls = ++le;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000721 /* Handle the case of DOS crlf sequences. */
722 if ( le < pe && hold == '\n' && *le =='\r' )
David Turner993a8d02002-05-18 12:03:43 +0000723 ls = ++le;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000724 }
725
726 /* Increment the line number. */
727 lineno++;
728
729 /* Restore the character at the end of the line. */
David Turnerb1b47622002-05-21 21:17:43 +0000730 *hp = (char)hold;
David Turnerd490e372002-05-28 23:40:37 +0000731 }
David Turner993a8d02002-05-18 12:03:43 +0000732 }
733 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000734
735 *lno = lineno;
736
737 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000738 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000739 return error;
David Turner993a8d02002-05-18 12:03:43 +0000740 }
David Turner993a8d02002-05-18 12:03:43 +0000741
742
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000743 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000744
David Turnerb1b47622002-05-21 21:17:43 +0000745 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000746 {
David Turner993a8d02002-05-18 12:03:43 +0000747 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
748 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
749 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
750 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
751 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
752 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
753 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
754 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
755 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
756 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000758 };
David Turner993a8d02002-05-18 12:03:43 +0000759
David Turnerb1b47622002-05-21 21:17:43 +0000760 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000761 {
David Turner993a8d02002-05-18 12:03:43 +0000762 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
764 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000766 };
David Turner993a8d02002-05-18 12:03:43 +0000767
David Turnerb1b47622002-05-21 21:17:43 +0000768 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000769 {
David Turner993a8d02002-05-18 12:03:43 +0000770 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
771 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000774 };
David Turner993a8d02002-05-18 12:03:43 +0000775
David Turnerb1b47622002-05-21 21:17:43 +0000776 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000777 {
David Turner993a8d02002-05-18 12:03:43 +0000778 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
779 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
780 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000782 };
David Turner993a8d02002-05-18 12:03:43 +0000783
David Turner993a8d02002-05-18 12:03:43 +0000784
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000785#define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
David Turner993a8d02002-05-18 12:03:43 +0000786
David Turner993a8d02002-05-18 12:03:43 +0000787
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000788 /* Routine to convert an ASCII string into an unsigned long integer. */
789 static unsigned long
790 _bdf_atoul( char* s,
791 char** end,
792 int base )
David Turner993a8d02002-05-18 12:03:43 +0000793 {
David Turnerb1b47622002-05-21 21:17:43 +0000794 unsigned long v;
795 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000796
797
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000798 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000799 return 0;
800
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000801 /* Make sure the radix is something recognizable. Default to 10. */
802 switch ( base )
803 {
804 case 8:
805 dmap = odigits;
806 break;
807 case 16:
808 dmap = hdigits;
809 break;
810 default:
811 base = 10;
812 dmap = ddigits;
813 break;
David Turner993a8d02002-05-18 12:03:43 +0000814 }
815
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000816 /* Check for the special hex prefix. */
817 if ( *s == '0' &&
818 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
819 {
820 base = 16;
821 dmap = hdigits;
822 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000823 }
824
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000825 for ( v = 0; isdigok( dmap, *s ); s++ )
826 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000827
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000828 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000829 *end = s;
830
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000831 return v;
832 }
David Turner993a8d02002-05-18 12:03:43 +0000833
David Turner993a8d02002-05-18 12:03:43 +0000834
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000835 /* Routine to convert an ASCII string into an signed long integer. */
836 static long
837 _bdf_atol( char* s,
838 char** end,
839 int base )
840 {
David Turnerb1b47622002-05-21 21:17:43 +0000841 long v, neg;
842 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000843
844
845 if ( s == 0 || *s == 0 )
846 return 0;
847
848 /* Make sure the radix is something recognizable. Default to 10. */
849 switch ( base )
850 {
851 case 8:
852 dmap = odigits;
853 break;
854 case 16:
855 dmap = hdigits;
856 break;
857 default:
858 base = 10;
859 dmap = ddigits;
860 break;
861 }
862
863 /* Check for a minus sign. */
864 neg = 0;
865 if ( *s == '-' )
866 {
867 s++;
868 neg = 1;
869 }
870
871 /* Check for the special hex prefix. */
872 if ( *s == '0' &&
873 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
874 {
875 base = 16;
876 dmap = hdigits;
877 s += 2;
878 }
879
880 for ( v = 0; isdigok( dmap, *s ); s++ )
881 v = v * base + a2i[(int)*s];
882
883 if ( end != 0 )
884 *end = s;
885
886 return ( !neg ) ? v : -v;
887 }
888
889
890 /* Routine to convert an ASCII string into an signed short integer. */
891 static short
892 _bdf_atos( char* s,
893 char** end,
894 int base )
895 {
David Turnerb1b47622002-05-21 21:17:43 +0000896 short v, neg;
897 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000898
899
900 if ( s == 0 || *s == 0 )
901 return 0;
902
903 /* Make sure the radix is something recognizable. Default to 10. */
904 switch ( base )
905 {
906 case 8:
907 dmap = odigits;
908 break;
909 case 16:
910 dmap = hdigits;
911 break;
912 default:
913 base = 10;
914 dmap = ddigits;
915 break;
916 }
917
918 /* Check for a minus. */
919 neg = 0;
920 if ( *s == '-' )
921 {
922 s++;
923 neg = 1;
924 }
925
926 /* Check for the special hex prefix. */
927 if ( *s == '0' &&
928 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
929 {
930 base = 16;
931 dmap = hdigits;
932 s += 2;
933 }
934
935 for ( v = 0; isdigok( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +0000936 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000937
938 if ( end != 0 )
939 *end = s;
940
Werner Lemberg233302a2002-05-22 05:41:06 +0000941 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000942 }
943
944
945 /* Routine to compare two glyphs by encoding so they can be sorted. */
946 static int
947 by_encoding( const void* a,
948 const void* b )
949 {
950 bdf_glyph_t *c1, *c2;
951
952
953 c1 = (bdf_glyph_t *)a;
954 c2 = (bdf_glyph_t *)b;
955
956 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000957 return -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000958 else if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000959 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000960
David Turner993a8d02002-05-18 12:03:43 +0000961 return 0;
David Turner993a8d02002-05-18 12:03:43 +0000962 }
963
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000964
965 static FT_Error
966 bdf_create_property( char* name,
967 int format,
968 bdf_font_t* font )
969 {
970 unsigned long n;
971 bdf_property_t* p;
972 FT_Memory memory = font->memory;
973 FT_Error error = BDF_Err_Ok;
974
975
976 /* First check to see if the property has */
977 /* already been added or not. If it has, then */
978 /* simply ignore it. */
979 if ( hash_lookup( name, &(font->proptbl) ) )
980 goto Exit;
981
982 if ( font->nuser_props == 0 )
983 {
984 if ( FT_NEW_ARRAY( font->user_props, 1 ) )
985 goto Exit;
986 }
987 else
988 {
989 if ( FT_RENEW_ARRAY( font->user_props,
990 font->nuser_props,
991 font->nuser_props + 1 ) )
992 goto Exit;
993 }
994
995 p = font->user_props + font->nuser_props;
996 FT_MEM_SET( p, 0, sizeof ( bdf_property_t ) );
997
998 n = (unsigned long)( ft_strlen( name ) + 1 );
999 if ( FT_NEW_ARRAY( p->name, n ) )
1000 goto Exit;
1001
1002 FT_MEM_COPY( (char *)p->name, name, n );
1003
1004 p->format = format;
1005 p->builtin = 0;
1006
1007 n = _num_bdf_properties + font->nuser_props;
1008
1009 error = hash_insert( p->name, (void *)n, &(font->proptbl), memory );
1010 if ( error )
1011 goto Exit;
1012
1013 font->nuser_props++;
1014
1015 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001016 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001017 }
David Turner993a8d02002-05-18 12:03:43 +00001018
1019
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001020 FT_LOCAL_DEF( bdf_property_t * )
1021 bdf_get_property( char* name,
1022 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001023 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001024 hashnode hn;
1025 unsigned long propid;
1026
1027
1028 if ( name == 0 || *name == 0 )
1029 return 0;
1030
1031 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1032 return 0;
1033
1034 propid = (unsigned long)hn->data;
1035 if ( propid >= _num_bdf_properties )
1036 return font->user_props + ( propid - _num_bdf_properties );
1037
Werner Lemberg233302a2002-05-22 05:41:06 +00001038 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001039 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001040
1041
1042 /*************************************************************************/
1043 /* */
1044 /* BDF font file parsing flags and functions. */
1045 /* */
1046 /*************************************************************************/
1047
1048
1049 /* Parse flags. */
1050
1051#define _BDF_START 0x0001
1052#define _BDF_FONT_NAME 0x0002
1053#define _BDF_SIZE 0x0004
1054#define _BDF_FONT_BBX 0x0008
1055#define _BDF_PROPS 0x0010
1056#define _BDF_GLYPHS 0x0020
1057#define _BDF_GLYPH 0x0040
1058#define _BDF_ENCODING 0x0080
1059#define _BDF_SWIDTH 0x0100
1060#define _BDF_DWIDTH 0x0200
1061#define _BDF_BBX 0x0400
1062#define _BDF_BITMAP 0x0800
1063
1064#define _BDF_SWIDTH_ADJ 0x1000
1065
1066#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1067 _BDF_ENCODING | \
1068 _BDF_SWIDTH | \
1069 _BDF_DWIDTH | \
1070 _BDF_BBX | \
1071 _BDF_BITMAP )
1072
1073#define _BDF_GLYPH_WIDTH_CHECK 0x40000000L
1074#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000L
1075
1076
1077 /* Auto correction messages. */
1078#define ACMSG1 "FONT_ASCENT property missing. " \
1079 "Added \"FONT_ASCENT %hd\".\n"
1080#define ACMSG2 "FONT_DESCENT property missing. " \
1081 "Added \"FONT_DESCENT %hd\".\n"
1082#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
1083#define ACMSG4 "Font left bearing != actual left bearing. " \
1084 "Old: %hd New: %hd.\n"
1085#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
1086#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
1087#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
1088#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
1089#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
1090#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
1091#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
1092#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
1093#define ACMSG13 "Glyph %ld extra rows removed.\n"
1094#define ACMSG14 "Glyph %ld extra columns removed.\n"
1095#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
1096
1097 /* Error messages. */
1098#define ERRMSG1 "[line %ld] Missing \"%s\" line.\n"
1099#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
1100#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
1101
1102
1103 static FT_Error
1104 _bdf_add_comment( bdf_font_t* font,
1105 char* comment,
1106 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001107 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001108 char* cp;
1109 FT_Memory memory = font->memory;
1110 FT_Error error = BDF_Err_Ok;
1111
1112
1113 if ( font->comments_len == 0 )
1114 {
1115 if ( FT_NEW_ARRAY( font->comments, len + 1 ) )
1116 goto Exit;
1117 }
1118 else
1119 {
1120 if ( FT_RENEW_ARRAY( font->comments,
1121 font->comments_len,
1122 font->comments_len + len + 1 ) )
1123 goto Exit;
1124 }
1125
1126 cp = font->comments + font->comments_len;
1127 FT_MEM_COPY( cp, comment, len );
1128 cp += len;
1129 *cp++ = '\n';
1130 font->comments_len += len + 1;
1131
1132 Exit:
1133 return error;
David Turner993a8d02002-05-18 12:03:43 +00001134 }
1135
David Turner993a8d02002-05-18 12:03:43 +00001136
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001137 /* Set the spacing from the font name if it exists, or set it to the */
1138 /* default specified in the options. */
1139 static FT_Error
1140 _bdf_set_default_spacing( bdf_font_t* font,
1141 bdf_options_t* opts )
David Turner993a8d02002-05-18 12:03:43 +00001142 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001143 unsigned long len;
1144 char name[128];
1145 _bdf_list_t list;
1146 FT_Memory memory;
1147 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001148
David Turner993a8d02002-05-18 12:03:43 +00001149
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001150 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1151 {
1152 error = BDF_Err_Invalid_Argument;
1153 goto Exit;
1154 }
David Turner993a8d02002-05-18 12:03:43 +00001155
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001156 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001157
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001158 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001159
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001160 len = (unsigned long)( ft_strlen( font->name ) + 1 );
1161 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001162
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001163 list.size = list.used = 0;
David Turner993a8d02002-05-18 12:03:43 +00001164
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001165 error = _bdf_split( (char *)"-", name, len, &list, memory );
1166 if ( error )
1167 goto Exit;
1168
1169 if ( list.used == 15 )
1170 {
1171 switch ( list.field[11][0] )
1172 {
1173 case 'C':
1174 case 'c':
1175 font->spacing = BDF_CHARCELL;
1176 break;
1177 case 'M':
1178 case 'm':
1179 font->spacing = BDF_MONOWIDTH;
1180 break;
1181 case 'P':
1182 case 'p':
1183 font->spacing = BDF_PROPORTIONAL;
1184 break;
David Turner993a8d02002-05-18 12:03:43 +00001185 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001186 }
1187
1188 FT_FREE( list.field );
1189
1190 Exit:
1191 return error;
David Turner993a8d02002-05-18 12:03:43 +00001192 }
David Turner993a8d02002-05-18 12:03:43 +00001193
1194
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001195 /* Determine whether the property is an atom or not. If it is, then */
1196 /* clean it up so the double quotes are removed if they exist. */
1197 static int
1198 _bdf_is_atom( char* line,
1199 unsigned long linelen,
1200 char** name,
1201 char** value,
1202 bdf_font_t* font )
1203 {
1204 int hold;
1205 char *sp, *ep;
1206 bdf_property_t* p;
1207
David Turner993a8d02002-05-18 12:03:43 +00001208
1209 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001210
1211 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001212 ep++;
1213
1214 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001215 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001216 {
1217 hold = *ep;
1218 *ep = 0;
1219 }
1220
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001221 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001222
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001223 /* Restore the character that was saved before any return can happen. */
1224 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001225 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001226
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001227 /* If the property exists and is not an atom, just return here. */
1228 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001229 return 0;
1230
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001231 /* The property is an atom. Trim all leading and trailing whitespace */
1232 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001233 sp = ep;
1234 ep = line + linelen;
1235
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001236 /* Trim the leading whitespace if it exists. */
David Turner993a8d02002-05-18 12:03:43 +00001237 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001238 while ( *sp &&
1239 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001240 sp++;
1241
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001242 /* Trim the leading double quote if it exists. */
1243 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001244 sp++;
1245 *value = sp;
1246
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001247 /* Trim the trailing whitespace if it exists. */
1248 while ( ep > sp &&
1249 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001250 *--ep = 0;
1251
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001252 /* Trim the trailing double quote if it exists. */
1253 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001254 *--ep = 0;
1255
1256 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001257 }
David Turner993a8d02002-05-18 12:03:43 +00001258
1259
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001260 static FT_Error
1261 _bdf_add_property( bdf_font_t* font,
1262 char* name,
1263 char* value )
1264 {
1265 unsigned long propid;
1266 hashnode hn;
1267 int len;
1268 bdf_property_t *prop, *fp;
1269 FT_Memory memory = font->memory;
1270 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001271
David Turner993a8d02002-05-18 12:03:43 +00001272
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001273 /* First, check to see if the property already exists in the font. */
1274 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001275 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001276 /* The property already exists in the font, so simply replace */
1277 /* the value of the property with the current value. */
1278 fp = font->props + (unsigned long)hn->data;
1279
David Turnerb1b47622002-05-21 21:17:43 +00001280 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001281 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001282 case BDF_ATOM:
1283 /* Delete the current atom if it exists. */
1284 FT_FREE( fp->value.atom );
1285
1286 if ( value == 0 )
1287 len = 1;
1288 else
1289 len = ft_strlen( value ) + 1;
1290
1291 if ( len > 1 )
1292 {
1293 if ( FT_NEW_ARRAY( fp->value.atom, len ) )
1294 goto Exit;
1295 FT_MEM_COPY( fp->value.atom, value, len );
1296 }
1297 else
1298 fp->value.atom = 0;
1299 break;
1300
1301 case BDF_INTEGER:
1302 fp->value.int32 = _bdf_atol( value, 0, 10 );
1303 break;
1304
1305 case BDF_CARDINAL:
1306 fp->value.card32 = _bdf_atoul( value, 0, 10 );
1307 break;
David Turnerd490e372002-05-28 23:40:37 +00001308
David Turnerb1b47622002-05-21 21:17:43 +00001309 default:
1310 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001311 }
David Turnerd490e372002-05-28 23:40:37 +00001312
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001313 goto Exit;
1314 }
1315
1316 /* See whether this property type exists yet or not. */
1317 /* If not, create it. */
1318 hn = hash_lookup( name, &(font->proptbl) );
1319 if ( hn == 0 )
1320 {
1321 error = bdf_create_property( name, BDF_ATOM, font );
1322 if ( error )
1323 goto Exit;
1324 hn = hash_lookup( name, &(font->proptbl) );
1325 }
1326
1327 /* Allocate another property if this is overflow. */
1328 if ( font->props_used == font->props_size )
1329 {
1330 if ( font->props_size == 0 )
1331 {
1332 if ( FT_NEW_ARRAY( font->props, 1 ) )
1333 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001334 }
1335 else
1336 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001337 if ( FT_RENEW_ARRAY( font->props,
1338 font->props_size,
1339 font->props_size + 1 ) )
1340 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001341 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001342
David Turner993a8d02002-05-18 12:03:43 +00001343 fp = font->props + font->props_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001344 FT_MEM_SET( fp, 0, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001345 font->props_size++;
1346 }
1347
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001348 propid = (unsigned long)hn->data;
1349 if ( propid >= _num_bdf_properties )
1350 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001351 else
David Turnerb1b47622002-05-21 21:17:43 +00001352 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001353
1354 fp = font->props + font->props_used;
1355
1356 fp->name = prop->name;
1357 fp->format = prop->format;
1358 fp->builtin = prop->builtin;
1359
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001360 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001361 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001362 case BDF_ATOM:
1363 if ( value == 0 )
1364 len = 1;
1365 else
1366 len = ft_strlen( value ) + 1;
David Turner993a8d02002-05-18 12:03:43 +00001367
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001368 if ( len > 1 )
1369 {
1370 if ( FT_NEW_ARRAY( fp->value.atom, len ) )
1371 goto Exit;
1372 FT_MEM_COPY( fp->value.atom, value, len );
1373 }
1374 else
1375 fp->value.atom = 0;
1376 break;
David Turner993a8d02002-05-18 12:03:43 +00001377
1378 case BDF_INTEGER:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001379 fp->value.int32 = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001380 break;
1381
1382 case BDF_CARDINAL:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001383 fp->value.card32 = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001384 break;
David Turner993a8d02002-05-18 12:03:43 +00001385 }
1386
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001387 /* If the property happens to be a comment, then it doesn't need */
1388 /* to be added to the internal hash table. */
1389 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) {
1390 /* Add the property to the font property table. */
1391 error = hash_insert( fp->name,
1392 (void *)font->props_used,
1393 (hashtable *)font->internal,
1394 memory );
1395 if ( error )
1396 goto Exit;
1397 }
David Turner993a8d02002-05-18 12:03:43 +00001398
1399 font->props_used++;
1400
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001401 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1402 /* property needs to be located if it exists in the property list, the */
1403 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1404 /* present, and the SPACING property should override the default */
1405 /* spacing. */
1406 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001407 font->default_glyph = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001408 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001409 font->font_ascent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001410 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001411 font->font_descent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001412 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001413 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001414 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001415 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001416 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001417 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001418 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001419 font->spacing = BDF_CHARCELL;
1420 }
1421
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001422 Exit:
1423 return error;
David Turner993a8d02002-05-18 12:03:43 +00001424 }
1425
David Turner993a8d02002-05-18 12:03:43 +00001426
David Turnerb1b47622002-05-21 21:17:43 +00001427 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001428 {
1429 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1430 };
1431
1432
1433 /* Actually parse the glyph info and bitmaps. */
1434 static FT_Error
1435 _bdf_parse_glyphs( char* line,
1436 unsigned long linelen,
1437 unsigned long lineno,
1438 void* call_data,
1439 void* client_data )
1440 {
1441 int c, mask_index;
1442 char* s;
1443 unsigned char* bp;
1444 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001445
1446 _bdf_line_func_t* next;
1447 _bdf_parse_t* p;
1448 bdf_glyph_t* glyph;
1449 bdf_font_t* font;
1450
1451 FT_Memory memory;
1452 FT_Error error = BDF_Err_Ok;
1453
1454 FT_UNUSED( lineno ); /* only used in debug mode */
1455
1456
1457 next = (_bdf_line_func_t *)call_data;
1458 p = (_bdf_parse_t *) client_data;
1459
1460 font = p->font;
1461 memory = font->memory;
1462
1463 /* Check for a comment. */
1464 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1465 {
1466 linelen -= 7;
1467
1468 s = line + 7;
1469 if ( *s != 0 )
1470 {
1471 s++;
1472 linelen--;
1473 }
1474 error = _bdf_add_comment( p->font, s, linelen );
1475 goto Exit;
1476 }
1477
1478 /* The very first thing expected is the number of glyphs. */
1479 if ( !( p->flags & _BDF_GLYPHS ) )
1480 {
1481 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1482 {
1483 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1484 error = BDF_Err_Missing_Chars_Field;
1485 goto Exit;
1486 }
1487
1488 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1489 if ( error )
1490 goto Exit;
1491 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1492
1493 /* Make sure the number of glyphs is non-zero. */
1494 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001495 font->glyphs_size = 64;
1496
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001497 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1498 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001499
David Turner993a8d02002-05-18 12:03:43 +00001500 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001501
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001502 goto Exit;
1503 }
1504
1505 /* Check for the ENDFONT field. */
1506 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1507 {
1508 /* Sort the glyphs by encoding. */
1509 ft_qsort( (char *)font->glyphs,
1510 font->glyphs_used,
1511 sizeof ( bdf_glyph_t ),
1512 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001513
1514 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001515
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001516 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001517 }
1518
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001519 /* Check for the ENDCHAR field. */
1520 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1521 {
1522 p->glyph_enc = 0;
1523 p->flags &= ~_BDF_GLYPH_BITS;
1524
1525 goto Exit;
1526 }
1527
1528 /* Check to see whether a glyph is being scanned but should be */
1529 /* ignored because it is an unencoded glyph. */
1530 if ( ( p->flags & _BDF_GLYPH ) &&
1531 p->glyph_enc == -1 &&
1532 p->opts->keep_unencoded == 0 )
1533 goto Exit;
1534
1535 /* Check for the STARTCHAR field. */
1536 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1537 {
1538 /* Set the character name in the parse info first until the */
1539 /* encoding can be checked for an unencoded character. */
1540 FT_FREE( p->glyph_name );
1541
1542 error = _bdf_split( (char *)" +", line, linelen, &p->list,memory );
1543 if ( error )
1544 goto Exit;
1545 _bdf_shift( 1, &p->list );
1546
1547 s = _bdf_join( ' ', &slen, &p->list );
1548
1549 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1550 goto Exit;
1551 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1552
1553 p->flags |= _BDF_GLYPH;
1554
1555 goto Exit;
1556 }
1557
1558 /* Check for the ENCODING field. */
1559 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1560 {
1561 if ( !( p->flags & _BDF_GLYPH ) )
1562 {
1563 /* Missing STARTCHAR field. */
1564 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1565 error = BDF_Err_Missing_Startchar_Field;
1566 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001567 }
1568
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001569 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1570 if ( error )
1571 goto Exit;
1572 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001573
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001574 /* Check to see whether this encoding has already been encountered. */
1575 /* If it has then change it to unencoded so it gets added if */
1576 /* indicated. */
1577 if ( p->glyph_enc >= 0 )
1578 {
1579 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1580 {
1581 /* Emit a message saying a glyph has been moved to the */
1582 /* unencoded area. */
1583 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1584 p->glyph_enc, p->glyph_name ));
1585 p->glyph_enc = -1;
1586 font->modified = 1;
1587 }
1588 else
1589 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1590 }
1591
1592 if ( p->glyph_enc >= 0 )
1593 {
1594 /* Make sure there are enough glyphs allocated in case the */
1595 /* number of characters happen to be wrong. */
1596 if ( font->glyphs_used == font->glyphs_size )
1597 {
1598 if ( FT_RENEW_ARRAY( font->glyphs,
1599 font->glyphs_size,
1600 font->glyphs_size + 64 ) )
1601 goto Exit;
1602 FT_MEM_SET( font->glyphs + font->glyphs_size,
1603 0,
1604 sizeof ( bdf_glyph_t ) * 64 ); /* FZ inutile */
1605 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001606 }
1607
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001608 glyph = font->glyphs + font->glyphs_used++;
1609 glyph->name = p->glyph_name;
1610 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001611
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001612 /* Reset the initial glyph info. */
1613 p->glyph_name = 0;
1614 }
1615 else
1616 {
1617 /* Unencoded glyph. Check to see whether it should */
1618 /* be added or not. */
1619 if ( p->opts->keep_unencoded != 0 )
1620 {
1621 /* Allocate the next unencoded glyph. */
1622 if ( font->unencoded_used == font->unencoded_size )
1623 {
1624 if ( font->unencoded_size == 0 )
1625 {
Werner Lemberg7925edc2002-05-30 19:29:41 +00001626 if ( FT_NEW_ARRAY( font->unencoded, 4 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001627 goto Exit;
1628 }
1629 else
1630 {
1631 if ( FT_RENEW_ARRAY( font->unencoded ,
1632 font->unencoded_size,
1633 font->unencoded_size + 4 ) )
1634 goto Exit;
1635 }
1636 font->unencoded_size += 4;
1637 }
1638
1639 glyph = font->unencoded + font->unencoded_used;
1640 glyph->name = p->glyph_name;
1641 glyph->encoding = font->unencoded_used++;
1642 }
1643 else
1644 /* Free up the glyph name if the unencoded shouldn't be */
1645 /* kept. */
1646 FT_FREE( p->glyph_name );
1647
1648 p->glyph_name = 0;
1649 }
1650
1651 /* Clear the flags that might be added when width and height are */
1652 /* checked for consistency. */
1653 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1654
1655 p->flags |= _BDF_ENCODING;
1656
1657 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001658 }
1659
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001660 /* Point at the glyph being constructed. */
1661 if ( p->glyph_enc == -1 )
1662 glyph = font->unencoded + ( font->unencoded_used - 1 );
1663 else
1664 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001665
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001666 /* Check to see whether a bitmap is being constructed. */
1667 if ( p->flags & _BDF_BITMAP )
1668 {
1669 /* If there are more rows than are specified in the glyph metrics, */
1670 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001671 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001672 {
1673 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1674 {
1675 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1676 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001677 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001678 }
1679
1680 goto Exit;
1681 }
1682
1683 /* Only collect the number of nibbles indicated by the glyph */
1684 /* metrics. If there are more columns, they are simply ignored. */
1685 nibbles = glyph->bpr << 1;
1686 bp = glyph->bitmap + p->row * glyph->bpr;
1687
1688 for ( i = 0, *bp = 0; i < nibbles; i++ )
1689 {
1690 c = line[i];
Werner Lemberg233302a2002-05-22 05:41:06 +00001691 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001692 if ( i + 1 < nibbles && ( i & 1 ) )
1693 *++bp = 0;
1694 }
1695
1696 /* Remove possible garbage at the right. */
1697 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
1698 *bp &= nibble_mask[mask_index];
1699
1700 /* If any line has extra columns, indicate they have been removed. */
1701 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1702 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1703 {
1704 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1705 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1706 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001707 }
1708
1709 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001710 goto Exit;
1711 }
David Turner993a8d02002-05-18 12:03:43 +00001712
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001713 /* Expect the SWIDTH (scalable width) field next. */
1714 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1715 {
1716 if ( !( p->flags & _BDF_ENCODING ) )
1717 {
1718 /* Missing ENCODING field. */
1719 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1720 error = BDF_Err_Missing_Encoding_Field;
1721 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001722 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001723
1724 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1725 if ( error )
1726 goto Exit;
David Turnerb1b47622002-05-21 21:17:43 +00001727 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001728 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001729
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001730 goto Exit;
1731 }
David Turner993a8d02002-05-18 12:03:43 +00001732
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001733 /* Expect the DWIDTH (scalable width) field next. */
1734 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1735 {
1736 error = _bdf_split( (char *)" +", line, linelen, &p->list,memory );
1737 if ( error )
1738 goto Exit;
David Turnerb1b47622002-05-21 21:17:43 +00001739 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001740
1741 if ( !( p->flags & _BDF_SWIDTH ) )
1742 {
1743 /* Missing SWIDTH field. Emit an auto correction message and set */
1744 /* the scalable width from the device width. */
1745 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
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. */
Werner Lemberg7925edc2002-05-30 19:29:41 +00002297 if ( memory != NULL )
2298 FT_FREE( p.list.field );
David Turner993a8d02002-05-18 12:03:43 +00002299
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002300 if ( p.font != 0 )
2301 {
2302 /* Make sure the comments are NULL terminated if they exist. */
2303 memory = p.font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002304
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002305 if ( p.font->comments_len > 0 ) {
2306 if ( FT_RENEW_ARRAY( p.font->comments,
2307 p.font->comments_len,
2308 p.font->comments_len + 1 ) )
2309 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002310
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002311 p.font->comments[p.font->comments_len] = 0;
2312 }
David Turner993a8d02002-05-18 12:03:43 +00002313 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002314 else if ( error == BDF_Err_Ok )
2315 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002316
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002317 *font = p.font;
2318
2319 Exit:
2320 return error;
2321 }
David Turner993a8d02002-05-18 12:03:43 +00002322
2323
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002324 FT_LOCAL_DEF( void )
2325 bdf_free_font( bdf_font_t* font )
2326 {
2327 bdf_property_t* prop;
2328 unsigned long i;
2329 bdf_glyph_t* glyphs;
2330 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002331
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002332
2333 if ( font == 0 )
2334 return;
David Turner993a8d02002-05-18 12:03:43 +00002335
2336 memory = font->memory;
2337
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002338 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002339
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002340 /* Free up the internal hash table of property names. */
2341 if ( font->internal )
2342 {
2343 hash_free( (hashtable *)font->internal, memory );
2344 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002345 }
2346
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002347 /* Free up the comment info. */
2348 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002349
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002350 /* Free up the properties. */
2351 for ( i = 0; i < font->props_size; i++ )
2352 {
2353 if ( font->props[i].format == BDF_ATOM )
2354 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002355 }
2356
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002357 FT_FREE( font->props );
2358
2359 /* Free up the character info. */
2360 for ( i = 0, glyphs = font->glyphs;
2361 i < font->glyphs_used; i++, glyphs++ )
2362 {
2363 FT_FREE( glyphs->name );
2364 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002365 }
2366
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002367 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2368 i++, glyphs++ )
2369 {
2370 FT_FREE( glyphs->name );
2371 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002372 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002373
2374 FT_FREE( font->glyphs );
2375 FT_FREE( font->unencoded );
2376
2377 /* Free up the overflow storage if it was used. */
2378 for ( i = 0, glyphs = font->overflow.glyphs;
2379 i < font->overflow.glyphs_used; i++, glyphs++ )
2380 {
2381 FT_FREE( glyphs->name );
2382 FT_FREE( glyphs->bitmap );
2383 }
2384
2385 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002386
2387 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002388 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002389
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002390 /* Free up the user defined properties. */
2391 for (prop = font->user_props, i = 0;
2392 i < font->nuser_props; i++, prop++ )
2393 {
2394 FT_FREE( prop->name );
2395 if ( prop->format == BDF_ATOM )
2396 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002397 }
David Turner993a8d02002-05-18 12:03:43 +00002398
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002399 FT_FREE( font->user_props );
2400
2401 /* FREE( font ); */ /* XXX Fixme */
2402 }
David Turner993a8d02002-05-18 12:03:43 +00002403
2404
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002405 FT_LOCAL_DEF( bdf_property_t * )
2406 bdf_get_font_property( bdf_font_t* font,
2407 char* name )
2408 {
2409 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002410
David Turner993a8d02002-05-18 12:03:43 +00002411
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002412 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002413 return 0;
2414
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002415 hn = hash_lookup( name, (hashtable *)font->internal );
2416
2417 return hn ? ( font->props + (unsigned long)hn->data ) : 0;
2418 }
2419
2420
2421/* END */