blob: 6c931add38985c65fba9c3314feab111e1116cc7 [file] [log] [blame]
David Turner993a8d02002-05-18 12:03:43 +00001/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
Werner Lemberg442bfb82007-02-12 21:44:10 +00003 * Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007
4 * Francesco Zappa Nardelli
David Turner993a8d02002-05-18 12:03:43 +00005 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
Werner Lemberg7cf4d372002-05-21 14:13:01 +000025 /*************************************************************************/
26 /* */
27 /* This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 */
28 /* */
29 /* taken from Mark Leisher's xmbdfed package */
30 /* */
31 /*************************************************************************/
32
David Turner993a8d02002-05-18 12:03:43 +000033
34#include <ft2build.h>
35
Werner Lemberg02d4d592002-05-28 22:38:05 +000036#include FT_FREETYPE_H
David Turner993a8d02002-05-18 12:03:43 +000037#include FT_INTERNAL_DEBUG_H
38#include FT_INTERNAL_STREAM_H
39#include FT_INTERNAL_OBJECTS_H
40
41#include "bdf.h"
David Turner993a8d02002-05-18 12:03:43 +000042#include "bdferror.h"
43
David Turner993a8d02002-05-18 12:03:43 +000044
Werner Lemberg7cf4d372002-05-21 14:13:01 +000045 /*************************************************************************/
46 /* */
47 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
48 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
49 /* messages during execution. */
50 /* */
51#undef FT_COMPONENT
52#define FT_COMPONENT trace_bdflib
David Turner993a8d02002-05-18 12:03:43 +000053
David Turner993a8d02002-05-18 12:03:43 +000054
Werner Lemberg7cf4d372002-05-21 14:13:01 +000055 /*************************************************************************/
56 /* */
57 /* Default BDF font options. */
58 /* */
59 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000060
David Turner993a8d02002-05-18 12:03:43 +000061
David Turnerb1b47622002-05-21 21:17:43 +000062 static const bdf_options_t _bdf_opts =
Werner Lemberg7cf4d372002-05-21 14:13:01 +000063 {
David Turner993a8d02002-05-18 12:03:43 +000064 1, /* Correct metrics. */
65 1, /* Preserve unencoded glyphs. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000066 0, /* Preserve comments. */
67 BDF_PROPORTIONAL /* Default spacing. */
68 };
David Turner993a8d02002-05-18 12:03:43 +000069
David Turner993a8d02002-05-18 12:03:43 +000070
Werner Lemberg7cf4d372002-05-21 14:13:01 +000071 /*************************************************************************/
72 /* */
73 /* Builtin BDF font properties. */
74 /* */
75 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000076
Werner Lemberg7cf4d372002-05-21 14:13:01 +000077 /* List of most properties that might appear in a font. Doesn't include */
78 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
David Turner993a8d02002-05-18 12:03:43 +000079
David Turnerb1b47622002-05-21 21:17:43 +000080 static const bdf_property_t _bdf_properties[] =
David Turner993a8d02002-05-18 12:03:43 +000081 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +000082 { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
83 { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
84 { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
85 { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
86 { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
87 { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
88 { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
89 { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
90 { (char *)"COMMENT", BDF_ATOM, 1, { 0 } },
91 { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } },
92 { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
93 { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } },
94 { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
95 { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } },
96 { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } },
97 { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } },
98 { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
99 { (char *)"FONT", BDF_ATOM, 1, { 0 } },
100 { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
101 { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
102 { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
103 { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } },
104 { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } },
105 { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
106 { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } },
107 { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } },
108 { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } },
109 { (char *)"NOTICE", BDF_ATOM, 1, { 0 } },
110 { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
111 { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } },
112 { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
113 { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
114 { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
115 { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
116 { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
117 { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
118 { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
119 { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
120 { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
121 { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
122 { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
123 { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
124 { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
125 { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
126 { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
127 { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
128 { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
129 { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
130 { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
131 { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
132 { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
133 { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
134 { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
135 { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
136 { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
137 { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
138 { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
139 { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
140 { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
141 { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
142 { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
143 { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } },
144 { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
145 { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
146 { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
147 { (char *)"SLANT", BDF_ATOM, 1, { 0 } },
148 { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
149 { (char *)"SPACING", BDF_ATOM, 1, { 0 } },
150 { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
151 { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
152 { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
153 { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
154 { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
155 { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
156 { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
157 { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
158 { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
159 { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
160 { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } },
161 { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
162 { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } },
163 { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
164 { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
165 };
David Turner993a8d02002-05-18 12:03:43 +0000166
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000167 static const unsigned long
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000168 _num_bdf_properties = sizeof ( _bdf_properties ) /
169 sizeof ( _bdf_properties[0] );
David Turner993a8d02002-05-18 12:03:43 +0000170
171
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000172 /*************************************************************************/
173 /* */
174 /* Hash table utilities for the properties. */
175 /* */
176 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +0000177
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000178 /* XXX: Replace this with FreeType's hash functions */
David Turner993a8d02002-05-18 12:03:43 +0000179
David Turner993a8d02002-05-18 12:03:43 +0000180
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000181#define INITIAL_HT_SIZE 241
182
183 typedef void
184 (*hash_free_func)( hashnode node );
185
186 static hashnode*
Werner Lemberg428c2e42003-04-25 05:35:04 +0000187 hash_bucket( const char* key,
188 hashtable* ht )
David Turner993a8d02002-05-18 12:03:43 +0000189 {
Werner Lemberg428c2e42003-04-25 05:35:04 +0000190 const char* kp = key;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000191 unsigned long res = 0;
192 hashnode* bp = ht->table, *ndp;
193
194
195 /* Mocklisp hash function. */
196 while ( *kp )
197 res = ( res << 5 ) - res + *kp++;
198
199 ndp = bp + ( res % ht->size );
200 while ( *ndp )
David Turner993a8d02002-05-18 12:03:43 +0000201 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000202 kp = (*ndp)->key;
203 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
204 break;
205 ndp--;
206 if ( ndp < bp )
207 ndp = bp + ( ht->size - 1 );
David Turner993a8d02002-05-18 12:03:43 +0000208 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000209
210 return ndp;
David Turner993a8d02002-05-18 12:03:43 +0000211 }
David Turner993a8d02002-05-18 12:03:43 +0000212
213
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000214 static FT_Error
215 hash_rehash( hashtable* ht,
216 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000217 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000218 hashnode* obp = ht->table, *bp, *nbp;
David Turner993a8d02002-05-18 12:03:43 +0000219 int i, sz = ht->size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000220 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000221
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000222
223 ht->size <<= 1;
224 ht->limit = ht->size / 3;
225
226 if ( FT_NEW_ARRAY( ht->table, ht->size ) )
227 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000228
229 for ( i = 0, bp = obp; i < sz; i++, bp++ )
David Turner993a8d02002-05-18 12:03:43 +0000230 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000231 if ( *bp )
232 {
233 nbp = hash_bucket( (*bp)->key, ht );
234 *nbp = *bp;
235 }
David Turner993a8d02002-05-18 12:03:43 +0000236 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000237 FT_FREE( obp );
238
239 Exit:
240 return error;
David Turner993a8d02002-05-18 12:03:43 +0000241 }
David Turner993a8d02002-05-18 12:03:43 +0000242
243
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000244 static FT_Error
245 hash_init( hashtable* ht,
246 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000247 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000248 int sz = INITIAL_HT_SIZE;
249 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000250
David Turner993a8d02002-05-18 12:03:43 +0000251
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000252 ht->size = sz;
253 ht->limit = sz / 3;
254 ht->used = 0;
David Turner993a8d02002-05-18 12:03:43 +0000255
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000256 if ( FT_NEW_ARRAY( ht->table, sz ) )
257 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000258
259 Exit:
260 return error;
David Turner993a8d02002-05-18 12:03:43 +0000261 }
David Turner993a8d02002-05-18 12:03:43 +0000262
263
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000264 static void
265 hash_free( hashtable* ht,
266 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000267 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000268 if ( ht != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000269 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000270 int i, sz = ht->size;
271 hashnode* bp = ht->table;
David Turner993a8d02002-05-18 12:03:43 +0000272
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000273
274 for ( i = 0; i < sz; i++, bp++ )
275 FT_FREE( *bp );
276
277 FT_FREE( ht->table );
278 }
David Turner993a8d02002-05-18 12:03:43 +0000279 }
280
David Turner993a8d02002-05-18 12:03:43 +0000281
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000282 static FT_Error
283 hash_insert( char* key,
284 void* data,
285 hashtable* ht,
286 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000287 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000288 hashnode nn, *bp = hash_bucket( key, ht );
289 FT_Error error = BDF_Err_Ok;
290
291
292 nn = *bp;
293 if ( !nn )
294 {
295 if ( FT_NEW( nn ) )
296 goto Exit;
297 *bp = nn;
298
299 nn->key = key;
300 nn->data = data;
301
302 if ( ht->used >= ht->limit )
303 {
304 error = hash_rehash( ht, memory );
305 if ( error )
306 goto Exit;
307 }
308 ht->used++;
309 }
David Turner993a8d02002-05-18 12:03:43 +0000310 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000311 nn->data = data;
312
313 Exit:
314 return error;
David Turner993a8d02002-05-18 12:03:43 +0000315 }
316
David Turner993a8d02002-05-18 12:03:43 +0000317
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000318 static hashnode
Werner Lemberg428c2e42003-04-25 05:35:04 +0000319 hash_lookup( const char* key,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000320 hashtable* ht )
321 {
322 hashnode *np = hash_bucket( key, ht );
323
324
325 return *np;
326 }
327
328
329 /*************************************************************************/
330 /* */
331 /* Utility types and functions. */
332 /* */
333 /*************************************************************************/
334
335
336 /* Function type for parsing lines of a BDF font. */
337
338 typedef FT_Error
339 (*_bdf_line_func_t)( char* line,
340 unsigned long linelen,
341 unsigned long lineno,
342 void* call_data,
343 void* client_data );
344
345
346 /* List structure for splitting lines into fields. */
347
348 typedef struct _bdf_list_t_
349 {
350 char** field;
351 unsigned long size;
352 unsigned long used;
David Turner68df4f72005-03-15 18:18:57 +0000353 FT_Memory memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000354
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
David Turner68df4f72005-03-15 18:18:57 +0000392 static void
393 _bdf_list_init( _bdf_list_t* list,
394 FT_Memory memory )
395 {
Werner Lembergebf55852005-03-16 01:49:54 +0000396 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000397 list->memory = memory;
398 }
399
Werner Lembergebf55852005-03-16 01:49:54 +0000400
David Turner68df4f72005-03-15 18:18:57 +0000401 static void
402 _bdf_list_done( _bdf_list_t* list )
403 {
404 FT_Memory memory = list->memory;
405
Werner Lembergebf55852005-03-16 01:49:54 +0000406
David Turner68df4f72005-03-15 18:18:57 +0000407 if ( memory )
408 {
409 FT_FREE( list->field );
Werner Lembergebf55852005-03-16 01:49:54 +0000410 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000411 }
412 }
413
414
415 static FT_Error
416 _bdf_list_ensure( _bdf_list_t* list,
417 int num_items )
418 {
Werner Lembergebf55852005-03-16 01:49:54 +0000419 FT_Error error = BDF_Err_Ok;
420
David Turner68df4f72005-03-15 18:18:57 +0000421
David Turner5d02b8a2005-03-15 23:48:15 +0000422 if ( num_items > (int)list->size )
David Turner68df4f72005-03-15 18:18:57 +0000423 {
Werner Lembergebf55852005-03-16 01:49:54 +0000424 int oldsize = list->size;
425 int newsize = oldsize + ( oldsize >> 1 ) + 4;
426 int bigsize = FT_INT_MAX / sizeof ( char* );
David Turner68df4f72005-03-15 18:18:57 +0000427 FT_Memory memory = list->memory;
428
Werner Lembergebf55852005-03-16 01:49:54 +0000429
David Turner68df4f72005-03-15 18:18:57 +0000430 if ( oldsize == bigsize )
431 {
Werner Lembergebf55852005-03-16 01:49:54 +0000432 error = BDF_Err_Out_Of_Memory;
David Turner68df4f72005-03-15 18:18:57 +0000433 goto Exit;
434 }
435 else if ( newsize < oldsize || newsize > bigsize )
436 newsize = bigsize;
437
438 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
439 goto Exit;
440
441 list->size = newsize;
442 }
Werner Lembergebf55852005-03-16 01:49:54 +0000443
David Turner68df4f72005-03-15 18:18:57 +0000444 Exit:
445 return error;
446 }
447
448
449 static void
450 _bdf_list_shift( _bdf_list_t* list,
451 unsigned long n )
452 {
453 unsigned long i, u;
454
455
456 if ( list == 0 || list->used == 0 || n == 0 )
457 return;
458
459 if ( n >= list->used )
460 {
461 list->used = 0;
462 return;
463 }
464
465 for ( u = n, i = 0; u < list->used; i++, u++ )
466 list->field[i] = list->field[u];
467 list->used -= n;
468 }
469
470
471 static char *
472 _bdf_list_join( _bdf_list_t* list,
473 int c,
474 unsigned long *alen )
475 {
476 unsigned long i, j;
477 char *fp, *dp;
478
479
480 *alen = 0;
481
482 if ( list == 0 || list->used == 0 )
483 return 0;
484
485 dp = list->field[0];
486 for ( i = j = 0; i < list->used; i++ )
487 {
488 fp = list->field[i];
489 while ( *fp )
490 dp[j++] = *fp++;
491
492 if ( i + 1 < list->used )
493 dp[j++] = (char)c;
494 }
495 dp[j] = 0;
496
497 *alen = j;
498 return dp;
499 }
500
501
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000502 /* An empty string for empty fields. */
503
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000504 static const char empty[1] = { 0 }; /* XXX eliminate this */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000505
506
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000507 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000508 _bdf_list_split( _bdf_list_t* list,
509 char* separators,
510 char* line,
511 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000512 {
513 int mult, final_empty;
514 char *sp, *ep, *end;
515 char seps[32];
516 FT_Error error = BDF_Err_Ok;
517
518
519 /* Initialize the list. */
520 list->used = 0;
521
522 /* If the line is empty, then simply return. */
523 if ( linelen == 0 || line[0] == 0 )
524 goto Exit;
525
526 /* In the original code, if the `separators' parameter is NULL or */
527 /* empty, the list is split into individual bytes. We don't need */
528 /* this, so an error is signaled. */
529 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000530 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000531 error = BDF_Err_Invalid_Argument;
532 goto Exit;
533 }
534
535 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000536 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000537
538 /* If the very last character of the separator string is a plus, then */
539 /* set the `mult' flag to indicate that multiple separators should be */
540 /* collapsed into one. */
541 for ( mult = 0, sp = separators; sp && *sp; sp++ )
542 {
543 if ( *sp == '+' && *( sp + 1 ) == 0 )
544 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000545 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000546 setsbit( seps, *sp );
547 }
548
549 /* Break the line up into fields. */
550 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
551 sp < end && *sp; )
552 {
553 /* Collect everything that is not a separator. */
554 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
555 ;
556
557 /* Resize the list if necessary. */
558 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000559 {
Werner Lembergebf55852005-03-16 01:49:54 +0000560 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000561 if ( error )
562 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000563 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000564
565 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000566 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000567
568 sp = ep;
569
570 if ( mult )
571 {
572 /* If multiple separators should be collapsed, do it now by */
573 /* setting all the separator characters to 0. */
574 for ( ; *ep && sbitset( seps, *ep ); ep++ )
575 *ep = 0;
576 }
577 else if ( *ep != 0 )
578 /* Don't collapse multiple separators by making them 0, so just */
579 /* make the one encountered 0. */
580 *ep++ = 0;
581
582 final_empty = ( ep > sp && *ep == 0 );
583 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000584 }
585
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000586 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000587 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000588 {
Werner Lembergebf55852005-03-16 01:49:54 +0000589 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000590 if ( error )
591 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000592 }
593
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000594 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000595 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000596
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000597 list->field[list->used] = 0;
598
599 Exit:
600 return error;
David Turner993a8d02002-05-18 12:03:43 +0000601 }
602
David Turner993a8d02002-05-18 12:03:43 +0000603
David Turner68df4f72005-03-15 18:18:57 +0000604#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000605
Werner Lembergebf55852005-03-16 01:49:54 +0000606
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000607 static FT_Error
608 _bdf_readstream( FT_Stream stream,
609 _bdf_line_func_t callback,
610 void* client_data,
611 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000612 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000613 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000614 unsigned long lineno, buf_size;
615 int refill, bytes, hold, to_skip;
616 int start, end, cursor, avail;
617 char* buf = 0;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000618 FT_Memory memory = stream->memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000619 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000620
David Turner993a8d02002-05-18 12:03:43 +0000621
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000622 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000623 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000624 error = BDF_Err_Invalid_Argument;
625 goto Exit;
626 }
David Turner993a8d02002-05-18 12:03:43 +0000627
Werner Lembergebf55852005-03-16 01:49:54 +0000628 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000629 buf_size = 1024;
630
631 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000632 goto Exit;
633
Werner Lembergebf55852005-03-16 01:49:54 +0000634 cb = callback;
635 lineno = 1;
636 buf[0] = 0;
637 start = 0;
638 end = 0;
639 avail = 0;
640 cursor = 0;
641 refill = 1;
642 to_skip = NO_SKIP;
643 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000644
David Turner68df4f72005-03-15 18:18:57 +0000645 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000646 {
David Turner68df4f72005-03-15 18:18:57 +0000647 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000648 {
Werner Lembergebf55852005-03-16 01:49:54 +0000649 bytes = (int)FT_Stream_TryRead( stream, (FT_Byte*)buf + cursor,
David Turner68df4f72005-03-15 18:18:57 +0000650 (FT_ULong)(buf_size - cursor) );
651 avail = cursor + bytes;
652 cursor = 0;
653 refill = 0;
654 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000655
David Turner68df4f72005-03-15 18:18:57 +0000656 end = start;
657
Werner Lembergebf55852005-03-16 01:49:54 +0000658 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000659 if ( start < avail && buf[start] == to_skip )
660 {
661 start += 1;
662 to_skip = NO_SKIP;
663 continue;
664 }
665
666 /* try to find the end of the line */
667 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
668 end++;
669
Werner Lembergebf55852005-03-16 01:49:54 +0000670 /* if we hit the end of the buffer, try shifting its content */
671 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000672 if ( end >= avail )
673 {
674 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
675 break; /* ignore it then exit */
676
677 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000678 {
Werner Lembergebf55852005-03-16 01:49:54 +0000679 /* this line is definitely too long; try resizing the input */
680 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000681 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000682
Werner Lembergebf55852005-03-16 01:49:54 +0000683
684 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000685 {
686 error = BDF_Err_Invalid_Argument;
687 goto Exit;
688 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000689
Werner Lembergebf55852005-03-16 01:49:54 +0000690 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000691 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
692 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000693
David Turner68df4f72005-03-15 18:18:57 +0000694 cursor = buf_size;
695 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000696 }
697 else
698 {
David Turner68df4f72005-03-15 18:18:57 +0000699 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000700
Werner Lembergebf55852005-03-16 01:49:54 +0000701 FT_MEM_COPY( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000702
David Turner68df4f72005-03-15 18:18:57 +0000703 cursor = bytes;
704 avail -= bytes;
705 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000706 }
David Turner68df4f72005-03-15 18:18:57 +0000707 refill = 1;
708 continue;
David Turner993a8d02002-05-18 12:03:43 +0000709 }
David Turner68df4f72005-03-15 18:18:57 +0000710
711 /* Temporarily NUL-terminate the line. */
712 hold = buf[end];
713 buf[end] = 0;
714
715 /* XXX: Use encoding independent value for 0x1a */
716 if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
717 {
Werner Lembergebf55852005-03-16 01:49:54 +0000718 error = (*cb)( buf + start, end - start, lineno,
719 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000720 if ( error )
721 break;
722 }
723
724 lineno += 1;
725 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000726 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000727
728 if ( hold == '\n' )
729 to_skip = '\r';
730 else if ( hold == '\r' )
731 to_skip = '\n';
732 else
733 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000734 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000735
David Turner68df4f72005-03-15 18:18:57 +0000736 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000737
738 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000739 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000740 return error;
David Turner993a8d02002-05-18 12:03:43 +0000741 }
David Turner993a8d02002-05-18 12:03:43 +0000742
743
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000744 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000745
David Turnerb1b47622002-05-21 21:17:43 +0000746 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000747 {
David Turner993a8d02002-05-18 12:03:43 +0000748 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
752 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
753 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
754 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
755 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
756 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
758 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000759 };
David Turner993a8d02002-05-18 12:03:43 +0000760
David Turnerb1b47622002-05-21 21:17:43 +0000761 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000762 {
David Turner993a8d02002-05-18 12:03:43 +0000763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
764 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000767 };
David Turner993a8d02002-05-18 12:03:43 +0000768
David Turnerb1b47622002-05-21 21:17:43 +0000769 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000770 {
David Turner993a8d02002-05-18 12:03:43 +0000771 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
774 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000775 };
David Turner993a8d02002-05-18 12:03:43 +0000776
David Turnerb1b47622002-05-21 21:17:43 +0000777 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000778 {
David Turner993a8d02002-05-18 12:03:43 +0000779 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
780 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
782 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000783 };
David Turner993a8d02002-05-18 12:03:43 +0000784
David Turner993a8d02002-05-18 12:03:43 +0000785
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000786#define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
David Turner993a8d02002-05-18 12:03:43 +0000787
David Turner993a8d02002-05-18 12:03:43 +0000788
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000789 /* Routine to convert an ASCII string into an unsigned long integer. */
790 static unsigned long
791 _bdf_atoul( char* s,
792 char** end,
793 int base )
David Turner993a8d02002-05-18 12:03:43 +0000794 {
David Turnerb1b47622002-05-21 21:17:43 +0000795 unsigned long v;
796 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000797
798
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000799 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000800 return 0;
801
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000802 /* Make sure the radix is something recognizable. Default to 10. */
803 switch ( base )
804 {
805 case 8:
806 dmap = odigits;
807 break;
808 case 16:
809 dmap = hdigits;
810 break;
811 default:
812 base = 10;
813 dmap = ddigits;
814 break;
David Turner993a8d02002-05-18 12:03:43 +0000815 }
816
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000817 /* Check for the special hex prefix. */
818 if ( *s == '0' &&
819 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
820 {
821 base = 16;
822 dmap = hdigits;
823 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000824 }
825
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000826 for ( v = 0; isdigok( dmap, *s ); s++ )
827 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000828
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000829 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000830 *end = s;
831
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000832 return v;
833 }
David Turner993a8d02002-05-18 12:03:43 +0000834
David Turner993a8d02002-05-18 12:03:43 +0000835
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000836 /* Routine to convert an ASCII string into an signed long integer. */
837 static long
838 _bdf_atol( char* s,
839 char** end,
840 int base )
841 {
David Turnerb1b47622002-05-21 21:17:43 +0000842 long v, neg;
843 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000844
845
846 if ( s == 0 || *s == 0 )
847 return 0;
848
849 /* Make sure the radix is something recognizable. Default to 10. */
850 switch ( base )
851 {
852 case 8:
853 dmap = odigits;
854 break;
855 case 16:
856 dmap = hdigits;
857 break;
858 default:
859 base = 10;
860 dmap = ddigits;
861 break;
862 }
863
864 /* Check for a minus sign. */
865 neg = 0;
866 if ( *s == '-' )
867 {
868 s++;
869 neg = 1;
870 }
871
872 /* Check for the special hex prefix. */
873 if ( *s == '0' &&
874 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
875 {
876 base = 16;
877 dmap = hdigits;
878 s += 2;
879 }
880
881 for ( v = 0; isdigok( dmap, *s ); s++ )
882 v = v * base + a2i[(int)*s];
883
884 if ( end != 0 )
885 *end = s;
886
887 return ( !neg ) ? v : -v;
888 }
889
890
891 /* Routine to convert an ASCII string into an signed short integer. */
892 static short
893 _bdf_atos( char* s,
894 char** end,
895 int base )
896 {
David Turnerb1b47622002-05-21 21:17:43 +0000897 short v, neg;
898 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000899
900
901 if ( s == 0 || *s == 0 )
902 return 0;
903
904 /* Make sure the radix is something recognizable. Default to 10. */
905 switch ( base )
906 {
907 case 8:
908 dmap = odigits;
909 break;
910 case 16:
911 dmap = hdigits;
912 break;
913 default:
914 base = 10;
915 dmap = ddigits;
916 break;
917 }
918
919 /* Check for a minus. */
920 neg = 0;
921 if ( *s == '-' )
922 {
923 s++;
924 neg = 1;
925 }
926
927 /* Check for the special hex prefix. */
928 if ( *s == '0' &&
929 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
930 {
931 base = 16;
932 dmap = hdigits;
933 s += 2;
934 }
935
936 for ( v = 0; isdigok( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +0000937 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000938
939 if ( end != 0 )
940 *end = s;
941
Werner Lemberg233302a2002-05-22 05:41:06 +0000942 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000943 }
944
945
946 /* Routine to compare two glyphs by encoding so they can be sorted. */
947 static int
948 by_encoding( const void* a,
949 const void* b )
950 {
951 bdf_glyph_t *c1, *c2;
952
953
954 c1 = (bdf_glyph_t *)a;
955 c2 = (bdf_glyph_t *)b;
956
957 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000958 return -1;
David Turner68df4f72005-03-15 18:18:57 +0000959
960 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000961 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000962
David Turner993a8d02002-05-18 12:03:43 +0000963 return 0;
David Turner993a8d02002-05-18 12:03:43 +0000964 }
965
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000966
967 static FT_Error
968 bdf_create_property( char* name,
969 int format,
970 bdf_font_t* font )
971 {
972 unsigned long n;
973 bdf_property_t* p;
974 FT_Memory memory = font->memory;
975 FT_Error error = BDF_Err_Ok;
976
977
978 /* First check to see if the property has */
979 /* already been added or not. If it has, then */
980 /* simply ignore it. */
981 if ( hash_lookup( name, &(font->proptbl) ) )
982 goto Exit;
983
David Turner68df4f72005-03-15 18:18:57 +0000984 if ( FT_RENEW_ARRAY( font->user_props,
985 font->nuser_props,
986 font->nuser_props + 1 ) )
987 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000988
989 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +0000990 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000991
992 n = (unsigned long)( ft_strlen( name ) + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000993
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000994 if ( FT_NEW_ARRAY( p->name, n ) )
995 goto Exit;
996
997 FT_MEM_COPY( (char *)p->name, name, n );
998
999 p->format = format;
1000 p->builtin = 0;
1001
1002 n = _num_bdf_properties + font->nuser_props;
1003
1004 error = hash_insert( p->name, (void *)n, &(font->proptbl), memory );
1005 if ( error )
1006 goto Exit;
1007
1008 font->nuser_props++;
1009
1010 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001011 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001012 }
David Turner993a8d02002-05-18 12:03:43 +00001013
1014
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001015 FT_LOCAL_DEF( bdf_property_t * )
1016 bdf_get_property( char* name,
1017 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001018 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001019 hashnode hn;
1020 unsigned long propid;
1021
1022
1023 if ( name == 0 || *name == 0 )
1024 return 0;
1025
1026 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1027 return 0;
1028
1029 propid = (unsigned long)hn->data;
1030 if ( propid >= _num_bdf_properties )
1031 return font->user_props + ( propid - _num_bdf_properties );
1032
Werner Lemberg233302a2002-05-22 05:41:06 +00001033 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001034 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001035
1036
1037 /*************************************************************************/
1038 /* */
1039 /* BDF font file parsing flags and functions. */
1040 /* */
1041 /*************************************************************************/
1042
1043
1044 /* Parse flags. */
1045
1046#define _BDF_START 0x0001
1047#define _BDF_FONT_NAME 0x0002
1048#define _BDF_SIZE 0x0004
1049#define _BDF_FONT_BBX 0x0008
1050#define _BDF_PROPS 0x0010
1051#define _BDF_GLYPHS 0x0020
1052#define _BDF_GLYPH 0x0040
1053#define _BDF_ENCODING 0x0080
1054#define _BDF_SWIDTH 0x0100
1055#define _BDF_DWIDTH 0x0200
1056#define _BDF_BBX 0x0400
1057#define _BDF_BITMAP 0x0800
1058
1059#define _BDF_SWIDTH_ADJ 0x1000
1060
1061#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1062 _BDF_ENCODING | \
1063 _BDF_SWIDTH | \
1064 _BDF_DWIDTH | \
1065 _BDF_BBX | \
1066 _BDF_BITMAP )
1067
Werner Lembergf1c2b912006-01-13 14:53:28 +00001068#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1069#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001070
1071
1072 /* Auto correction messages. */
1073#define ACMSG1 "FONT_ASCENT property missing. " \
1074 "Added \"FONT_ASCENT %hd\".\n"
1075#define ACMSG2 "FONT_DESCENT property missing. " \
1076 "Added \"FONT_DESCENT %hd\".\n"
1077#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
1078#define ACMSG4 "Font left bearing != actual left bearing. " \
1079 "Old: %hd New: %hd.\n"
1080#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
1081#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
1082#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
1083#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
1084#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
1085#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
1086#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
1087#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
1088#define ACMSG13 "Glyph %ld extra rows removed.\n"
1089#define ACMSG14 "Glyph %ld extra columns removed.\n"
1090#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
1091
1092 /* Error messages. */
1093#define ERRMSG1 "[line %ld] Missing \"%s\" line.\n"
1094#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
1095#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
Werner Lemberg26170df2006-03-26 07:19:07 +00001096#define ERRMSG4 "[line %ld] BBX too big.\n"
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001097
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
David Turner68df4f72005-03-15 18:18:57 +00001109 if ( FT_RENEW_ARRAY( font->comments,
1110 font->comments_len,
1111 font->comments_len + len + 1 ) )
1112 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001113
1114 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001115
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001116 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001117 cp[len] = '\n';
1118
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001119 font->comments_len += len + 1;
1120
1121 Exit:
1122 return error;
David Turner993a8d02002-05-18 12:03:43 +00001123 }
1124
David Turner993a8d02002-05-18 12:03:43 +00001125
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001126 /* Set the spacing from the font name if it exists, or set it to the */
1127 /* default specified in the options. */
1128 static FT_Error
1129 _bdf_set_default_spacing( bdf_font_t* font,
1130 bdf_options_t* opts )
David Turner993a8d02002-05-18 12:03:43 +00001131 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001132 unsigned long len;
1133 char name[128];
1134 _bdf_list_t list;
1135 FT_Memory memory;
1136 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001137
David Turner993a8d02002-05-18 12:03:43 +00001138
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001139 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1140 {
1141 error = BDF_Err_Invalid_Argument;
1142 goto Exit;
1143 }
David Turner993a8d02002-05-18 12:03:43 +00001144
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001145 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001146
David Turner68df4f72005-03-15 18:18:57 +00001147 _bdf_list_init( &list, memory );
1148
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001149 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001150
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001151 len = (unsigned long)( ft_strlen( font->name ) + 1 );
1152 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001153
David Turner68df4f72005-03-15 18:18:57 +00001154 error = _bdf_list_split( &list, (char *)"-", name, len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001155 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001156 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001157
1158 if ( list.used == 15 )
1159 {
1160 switch ( list.field[11][0] )
1161 {
1162 case 'C':
1163 case 'c':
1164 font->spacing = BDF_CHARCELL;
1165 break;
1166 case 'M':
1167 case 'm':
1168 font->spacing = BDF_MONOWIDTH;
1169 break;
1170 case 'P':
1171 case 'p':
1172 font->spacing = BDF_PROPORTIONAL;
1173 break;
David Turner993a8d02002-05-18 12:03:43 +00001174 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001175 }
1176
David Turner68df4f72005-03-15 18:18:57 +00001177 Fail:
1178 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001179
1180 Exit:
1181 return error;
David Turner993a8d02002-05-18 12:03:43 +00001182 }
David Turner993a8d02002-05-18 12:03:43 +00001183
1184
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001185 /* Determine whether the property is an atom or not. If it is, then */
1186 /* clean it up so the double quotes are removed if they exist. */
1187 static int
1188 _bdf_is_atom( char* line,
1189 unsigned long linelen,
1190 char** name,
1191 char** value,
1192 bdf_font_t* font )
1193 {
1194 int hold;
1195 char *sp, *ep;
1196 bdf_property_t* p;
1197
David Turner993a8d02002-05-18 12:03:43 +00001198
1199 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001200
1201 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001202 ep++;
1203
1204 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001205 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001206 {
1207 hold = *ep;
1208 *ep = 0;
1209 }
1210
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001211 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001212
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001213 /* Restore the character that was saved before any return can happen. */
1214 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001215 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001216
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001217 /* If the property exists and is not an atom, just return here. */
1218 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001219 return 0;
1220
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001221 /* The property is an atom. Trim all leading and trailing whitespace */
1222 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001223 sp = ep;
1224 ep = line + linelen;
1225
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001226 /* Trim the leading whitespace if it exists. */
David Turner993a8d02002-05-18 12:03:43 +00001227 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001228 while ( *sp &&
1229 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001230 sp++;
1231
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001232 /* Trim the leading double quote if it exists. */
1233 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001234 sp++;
1235 *value = sp;
1236
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001237 /* Trim the trailing whitespace if it exists. */
1238 while ( ep > sp &&
1239 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001240 *--ep = 0;
1241
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001242 /* Trim the trailing double quote if it exists. */
1243 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001244 *--ep = 0;
1245
1246 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001247 }
David Turner993a8d02002-05-18 12:03:43 +00001248
1249
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001250 static FT_Error
1251 _bdf_add_property( bdf_font_t* font,
1252 char* name,
1253 char* value )
1254 {
1255 unsigned long propid;
1256 hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001257 bdf_property_t *prop, *fp;
1258 FT_Memory memory = font->memory;
1259 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001260
David Turner993a8d02002-05-18 12:03:43 +00001261
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001262 /* First, check to see if the property already exists in the font. */
1263 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001264 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001265 /* The property already exists in the font, so simply replace */
1266 /* the value of the property with the current value. */
1267 fp = font->props + (unsigned long)hn->data;
1268
David Turnerb1b47622002-05-21 21:17:43 +00001269 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001270 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001271 case BDF_ATOM:
1272 /* Delete the current atom if it exists. */
1273 FT_FREE( fp->value.atom );
1274
David Turnerc0f9c4a2007-02-12 14:55:03 +00001275 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001276 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001277 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001278 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001279 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001280 break;
1281
1282 case BDF_INTEGER:
1283 fp->value.int32 = _bdf_atol( value, 0, 10 );
1284 break;
1285
1286 case BDF_CARDINAL:
1287 fp->value.card32 = _bdf_atoul( value, 0, 10 );
1288 break;
David Turnerd490e372002-05-28 23:40:37 +00001289
David Turnerb1b47622002-05-21 21:17:43 +00001290 default:
1291 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001292 }
David Turnerd490e372002-05-28 23:40:37 +00001293
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001294 goto Exit;
1295 }
1296
1297 /* See whether this property type exists yet or not. */
1298 /* If not, create it. */
1299 hn = hash_lookup( name, &(font->proptbl) );
1300 if ( hn == 0 )
1301 {
1302 error = bdf_create_property( name, BDF_ATOM, font );
1303 if ( error )
1304 goto Exit;
1305 hn = hash_lookup( name, &(font->proptbl) );
1306 }
1307
1308 /* Allocate another property if this is overflow. */
1309 if ( font->props_used == font->props_size )
1310 {
1311 if ( font->props_size == 0 )
1312 {
1313 if ( FT_NEW_ARRAY( font->props, 1 ) )
1314 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001315 }
1316 else
1317 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001318 if ( FT_RENEW_ARRAY( font->props,
1319 font->props_size,
1320 font->props_size + 1 ) )
1321 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001322 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001323
David Turner993a8d02002-05-18 12:03:43 +00001324 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001325 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001326 font->props_size++;
1327 }
1328
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001329 propid = (unsigned long)hn->data;
1330 if ( propid >= _num_bdf_properties )
1331 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001332 else
David Turnerb1b47622002-05-21 21:17:43 +00001333 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001334
1335 fp = font->props + font->props_used;
1336
1337 fp->name = prop->name;
1338 fp->format = prop->format;
1339 fp->builtin = prop->builtin;
1340
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001341 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001342 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001343 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001344 fp->value.atom = 0;
1345 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001346 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001347 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001348 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001349 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001350 break;
David Turner993a8d02002-05-18 12:03:43 +00001351
1352 case BDF_INTEGER:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001353 fp->value.int32 = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001354 break;
1355
1356 case BDF_CARDINAL:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001357 fp->value.card32 = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001358 break;
David Turner993a8d02002-05-18 12:03:43 +00001359 }
1360
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001361 /* If the property happens to be a comment, then it doesn't need */
1362 /* to be added to the internal hash table. */
1363 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) {
1364 /* Add the property to the font property table. */
1365 error = hash_insert( fp->name,
1366 (void *)font->props_used,
1367 (hashtable *)font->internal,
1368 memory );
1369 if ( error )
1370 goto Exit;
1371 }
David Turner993a8d02002-05-18 12:03:43 +00001372
1373 font->props_used++;
1374
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001375 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1376 /* property needs to be located if it exists in the property list, the */
1377 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1378 /* present, and the SPACING property should override the default */
1379 /* spacing. */
1380 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
Werner Lemberg8ef41832004-06-22 12:28:17 +00001381 font->default_char = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001382 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001383 font->font_ascent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001384 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001385 font->font_descent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001386 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001387 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001388 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001389 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001390 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001391 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001392 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001393 font->spacing = BDF_CHARCELL;
1394 }
1395
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001396 Exit:
1397 return error;
David Turner993a8d02002-05-18 12:03:43 +00001398 }
1399
David Turner993a8d02002-05-18 12:03:43 +00001400
David Turnerb1b47622002-05-21 21:17:43 +00001401 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001402 {
1403 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1404 };
1405
1406
1407 /* Actually parse the glyph info and bitmaps. */
1408 static FT_Error
1409 _bdf_parse_glyphs( char* line,
1410 unsigned long linelen,
1411 unsigned long lineno,
1412 void* call_data,
1413 void* client_data )
1414 {
1415 int c, mask_index;
1416 char* s;
1417 unsigned char* bp;
1418 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001419
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001420 _bdf_parse_t* p;
1421 bdf_glyph_t* glyph;
1422 bdf_font_t* font;
1423
1424 FT_Memory memory;
1425 FT_Error error = BDF_Err_Ok;
1426
Werner Lemberg319c00d2003-04-23 19:48:24 +00001427 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001428 FT_UNUSED( lineno ); /* only used in debug mode */
1429
1430
Werner Lemberg319c00d2003-04-23 19:48:24 +00001431 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001432
1433 font = p->font;
1434 memory = font->memory;
1435
1436 /* Check for a comment. */
1437 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1438 {
1439 linelen -= 7;
1440
1441 s = line + 7;
1442 if ( *s != 0 )
1443 {
1444 s++;
1445 linelen--;
1446 }
1447 error = _bdf_add_comment( p->font, s, linelen );
1448 goto Exit;
1449 }
1450
1451 /* The very first thing expected is the number of glyphs. */
1452 if ( !( p->flags & _BDF_GLYPHS ) )
1453 {
1454 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1455 {
1456 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1457 error = BDF_Err_Missing_Chars_Field;
1458 goto Exit;
1459 }
1460
David Turner68df4f72005-03-15 18:18:57 +00001461 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001462 if ( error )
1463 goto Exit;
1464 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1465
1466 /* Make sure the number of glyphs is non-zero. */
1467 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001468 font->glyphs_size = 64;
1469
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001470 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1471 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001472
David Turner993a8d02002-05-18 12:03:43 +00001473 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001474
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001475 goto Exit;
1476 }
1477
1478 /* Check for the ENDFONT field. */
1479 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1480 {
1481 /* Sort the glyphs by encoding. */
1482 ft_qsort( (char *)font->glyphs,
1483 font->glyphs_used,
1484 sizeof ( bdf_glyph_t ),
1485 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001486
1487 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001488
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001489 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001490 }
1491
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001492 /* Check for the ENDCHAR field. */
1493 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1494 {
1495 p->glyph_enc = 0;
1496 p->flags &= ~_BDF_GLYPH_BITS;
1497
1498 goto Exit;
1499 }
1500
1501 /* Check to see whether a glyph is being scanned but should be */
1502 /* ignored because it is an unencoded glyph. */
1503 if ( ( p->flags & _BDF_GLYPH ) &&
1504 p->glyph_enc == -1 &&
1505 p->opts->keep_unencoded == 0 )
1506 goto Exit;
1507
1508 /* Check for the STARTCHAR field. */
1509 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1510 {
1511 /* Set the character name in the parse info first until the */
1512 /* encoding can be checked for an unencoded character. */
1513 FT_FREE( p->glyph_name );
1514
David Turner68df4f72005-03-15 18:18:57 +00001515 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001516 if ( error )
1517 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001518
David Turner68df4f72005-03-15 18:18:57 +00001519 _bdf_list_shift( &p->list, 1 );
1520
1521 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001522
1523 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1524 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001525
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001526 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1527
1528 p->flags |= _BDF_GLYPH;
1529
1530 goto Exit;
1531 }
1532
1533 /* Check for the ENCODING field. */
1534 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1535 {
1536 if ( !( p->flags & _BDF_GLYPH ) )
1537 {
1538 /* Missing STARTCHAR field. */
1539 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1540 error = BDF_Err_Missing_Startchar_Field;
1541 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001542 }
1543
David Turner68df4f72005-03-15 18:18:57 +00001544 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001545 if ( error )
1546 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001547
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001548 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001549
David Turner481838e2006-02-23 12:40:14 +00001550 /* Check that the encoding is in the range [0,65536] because */
1551 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lembergd4303da2006-02-23 21:01:34 +00001552 if ( (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
David Turner481838e2006-02-23 12:40:14 +00001553 {
1554 error = BDF_Err_Invalid_File_Format;
1555 goto Exit;
1556 }
1557
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001558 /* Check to see whether this encoding has already been encountered. */
1559 /* If it has then change it to unencoded so it gets added if */
1560 /* indicated. */
1561 if ( p->glyph_enc >= 0 )
1562 {
1563 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1564 {
1565 /* Emit a message saying a glyph has been moved to the */
1566 /* unencoded area. */
1567 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1568 p->glyph_enc, p->glyph_name ));
1569 p->glyph_enc = -1;
1570 font->modified = 1;
1571 }
1572 else
1573 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1574 }
1575
1576 if ( p->glyph_enc >= 0 )
1577 {
1578 /* Make sure there are enough glyphs allocated in case the */
1579 /* number of characters happen to be wrong. */
1580 if ( font->glyphs_used == font->glyphs_size )
1581 {
1582 if ( FT_RENEW_ARRAY( font->glyphs,
1583 font->glyphs_size,
1584 font->glyphs_size + 64 ) )
1585 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001586
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001587 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001588 }
1589
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001590 glyph = font->glyphs + font->glyphs_used++;
1591 glyph->name = p->glyph_name;
1592 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001593
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001594 /* Reset the initial glyph info. */
1595 p->glyph_name = 0;
1596 }
1597 else
1598 {
1599 /* Unencoded glyph. Check to see whether it should */
1600 /* be added or not. */
1601 if ( p->opts->keep_unencoded != 0 )
1602 {
1603 /* Allocate the next unencoded glyph. */
1604 if ( font->unencoded_used == font->unencoded_size )
1605 {
David Turner68df4f72005-03-15 18:18:57 +00001606 if ( FT_RENEW_ARRAY( font->unencoded ,
1607 font->unencoded_size,
1608 font->unencoded_size + 4 ) )
1609 goto Exit;
1610
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001611 font->unencoded_size += 4;
1612 }
1613
1614 glyph = font->unencoded + font->unencoded_used;
1615 glyph->name = p->glyph_name;
1616 glyph->encoding = font->unencoded_used++;
1617 }
1618 else
1619 /* Free up the glyph name if the unencoded shouldn't be */
1620 /* kept. */
1621 FT_FREE( p->glyph_name );
1622
1623 p->glyph_name = 0;
1624 }
1625
1626 /* Clear the flags that might be added when width and height are */
1627 /* checked for consistency. */
1628 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1629
1630 p->flags |= _BDF_ENCODING;
1631
1632 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001633 }
1634
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001635 /* Point at the glyph being constructed. */
1636 if ( p->glyph_enc == -1 )
1637 glyph = font->unencoded + ( font->unencoded_used - 1 );
1638 else
1639 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001640
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001641 /* Check to see whether a bitmap is being constructed. */
1642 if ( p->flags & _BDF_BITMAP )
1643 {
1644 /* If there are more rows than are specified in the glyph metrics, */
1645 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001646 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001647 {
1648 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1649 {
1650 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1651 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001652 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001653 }
1654
1655 goto Exit;
1656 }
1657
1658 /* Only collect the number of nibbles indicated by the glyph */
1659 /* metrics. If there are more columns, they are simply ignored. */
1660 nibbles = glyph->bpr << 1;
1661 bp = glyph->bitmap + p->row * glyph->bpr;
1662
David Turnerb698eed2006-02-23 14:50:13 +00001663 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001664 {
1665 c = line[i];
Werner Lemberg233302a2002-05-22 05:41:06 +00001666 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001667 if ( i + 1 < nibbles && ( i & 1 ) )
1668 *++bp = 0;
1669 }
1670
1671 /* Remove possible garbage at the right. */
1672 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001673 if ( glyph->bbx.width )
1674 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001675
1676 /* If any line has extra columns, indicate they have been removed. */
1677 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1678 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1679 {
1680 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1681 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1682 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001683 }
1684
1685 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001686 goto Exit;
1687 }
David Turner993a8d02002-05-18 12:03:43 +00001688
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001689 /* Expect the SWIDTH (scalable width) field next. */
1690 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1691 {
1692 if ( !( p->flags & _BDF_ENCODING ) )
1693 {
1694 /* Missing ENCODING field. */
1695 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1696 error = BDF_Err_Missing_Encoding_Field;
1697 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001698 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001699
David Turner68df4f72005-03-15 18:18:57 +00001700 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001701 if ( error )
1702 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001703
David Turnerb1b47622002-05-21 21:17:43 +00001704 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001705 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001706
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001707 goto Exit;
1708 }
David Turner993a8d02002-05-18 12:03:43 +00001709
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001710 /* Expect the DWIDTH (scalable width) field next. */
1711 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1712 {
David Turner68df4f72005-03-15 18:18:57 +00001713 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001714 if ( error )
1715 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001716
David Turnerb1b47622002-05-21 21:17:43 +00001717 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001718
1719 if ( !( p->flags & _BDF_SWIDTH ) )
1720 {
1721 /* Missing SWIDTH field. Emit an auto correction message and set */
1722 /* the scalable width from the device width. */
1723 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1724
Werner Lemberg02d4d592002-05-28 22:38:05 +00001725 glyph->swidth = (unsigned short)FT_MulDiv(
1726 glyph->dwidth, 72000L,
1727 (FT_Long)( font->point_size *
1728 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001729 }
1730
1731 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001732 goto Exit;
1733 }
David Turner993a8d02002-05-18 12:03:43 +00001734
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001735 /* Expect the BBX field next. */
1736 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1737 {
David Turner68df4f72005-03-15 18:18:57 +00001738 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001739 if ( error )
1740 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001741
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001742 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1743 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1744 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1745 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1746
1747 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001748 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1749 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001750
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001751 /* Determine the overall font bounding box as the characters are */
1752 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001753 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1754 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001755
David Turnerb1b47622002-05-21 21:17:43 +00001756 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001757
Werner Lembergdfa46192004-03-05 09:26:24 +00001758 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1759 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1760 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001761
1762 if ( !( p->flags & _BDF_DWIDTH ) )
1763 {
1764 /* Missing DWIDTH field. Emit an auto correction message and set */
1765 /* the device width to the glyph width. */
1766 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1767 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001768 }
1769
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001770 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1771 /* value if necessary. */
1772 if ( p->opts->correct_metrics != 0 )
1773 {
1774 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001775 unsigned short sw = (unsigned short)FT_MulDiv(
1776 glyph->dwidth, 72000L,
1777 (FT_Long)( font->point_size *
1778 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001779
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001780
1781 if ( sw != glyph->swidth )
1782 {
1783 glyph->swidth = sw;
1784
1785 if ( p->glyph_enc == -1 )
1786 _bdf_set_glyph_modified( font->umod,
1787 font->unencoded_used - 1 );
1788 else
1789 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1790
1791 p->flags |= _BDF_SWIDTH_ADJ;
1792 font->modified = 1;
1793 }
David Turner993a8d02002-05-18 12:03:43 +00001794 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001795
David Turner993a8d02002-05-18 12:03:43 +00001796 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001797 goto Exit;
1798 }
David Turner993a8d02002-05-18 12:03:43 +00001799
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001800 /* And finally, gather up the bitmap. */
1801 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1802 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001803 unsigned long bitmap_size;
1804
1805
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001806 if ( !( p->flags & _BDF_BBX ) )
1807 {
1808 /* Missing BBX field. */
1809 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1810 error = BDF_Err_Missing_Bbx_Field;
1811 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001812 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001813
1814 /* Allocate enough space for the bitmap. */
1815 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001816
1817 bitmap_size = glyph->bpr * glyph->bbx.height;
1818 if ( bitmap_size > 0xFFFFU )
1819 {
1820 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1821 error = BDF_Err_Bbx_Too_Big;
1822 goto Exit;
1823 }
1824 else
1825 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001826
1827 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1828 goto Exit;
1829
1830 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001831 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001832
1833 goto Exit;
1834 }
1835
1836 error = BDF_Err_Invalid_File_Format;
1837
1838 Exit:
1839 return error;
David Turner993a8d02002-05-18 12:03:43 +00001840 }
1841
David Turner993a8d02002-05-18 12:03:43 +00001842
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001843 /* Load the font properties. */
1844 static FT_Error
1845 _bdf_parse_properties( char* line,
1846 unsigned long linelen,
1847 unsigned long lineno,
1848 void* call_data,
1849 void* client_data )
1850 {
1851 unsigned long vlen;
1852 _bdf_line_func_t* next;
1853 _bdf_parse_t* p;
1854 char* name;
1855 char* value;
1856 char nbuf[128];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001857 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001858
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001859 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001860
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001861
1862 next = (_bdf_line_func_t *)call_data;
1863 p = (_bdf_parse_t *) client_data;
1864
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001865 /* Check for the end of the properties. */
1866 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1867 {
1868 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1869 /* encountered yet, then make sure they are added as properties and */
1870 /* make sure they are set from the font bounding box info. */
1871 /* */
1872 /* This is *always* done regardless of the options, because X11 */
1873 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001874 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001875 {
1876 p->font->font_ascent = p->font->bbx.ascent;
1877 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1878 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
1879 if ( error )
1880 goto Exit;
1881
1882 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1883 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001884 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001885
Werner Lemberg428c2e42003-04-25 05:35:04 +00001886 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001887 {
1888 p->font->font_descent = p->font->bbx.descent;
1889 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1890 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
1891 if ( error )
1892 goto Exit;
1893
1894 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1895 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001896 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001897
David Turner993a8d02002-05-18 12:03:43 +00001898 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001899 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001900
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001901 goto Exit;
1902 }
David Turner993a8d02002-05-18 12:03:43 +00001903
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001904 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1905 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1906 goto Exit;
1907
1908 /* Handle COMMENT fields and properties in a special way to preserve */
1909 /* the spacing. */
1910 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1911 {
David Turner993a8d02002-05-18 12:03:43 +00001912 name = value = line;
1913 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001914 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001915 *value++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001916 error = _bdf_add_property( p->font, name, value );
1917 if ( error )
1918 goto Exit;
1919 }
1920 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1921 {
1922 error = _bdf_add_property( p->font, name, value );
1923 if ( error )
1924 goto Exit;
1925 }
1926 else
1927 {
David Turner68df4f72005-03-15 18:18:57 +00001928 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001929 if ( error )
1930 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001931 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001932
David Turner68df4f72005-03-15 18:18:57 +00001933 _bdf_list_shift( &p->list, 1 );
1934 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001935
1936 error = _bdf_add_property( p->font, name, value );
1937 if ( error )
1938 goto Exit;
1939 }
1940
1941 Exit:
1942 return error;
David Turner993a8d02002-05-18 12:03:43 +00001943 }
1944
David Turner993a8d02002-05-18 12:03:43 +00001945
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001946 /* Load the font header. */
1947 static FT_Error
1948 _bdf_parse_start( char* line,
1949 unsigned long linelen,
1950 unsigned long lineno,
1951 void* call_data,
1952 void* client_data )
1953 {
1954 unsigned long slen;
1955 _bdf_line_func_t* next;
1956 _bdf_parse_t* p;
1957 bdf_font_t* font;
1958 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001959
David Turnerd490e372002-05-28 23:40:37 +00001960 FT_Memory memory = NULL;
1961 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001962
1963 FT_UNUSED( lineno ); /* only used in debug mode */
1964
1965
1966 next = (_bdf_line_func_t *)call_data;
1967 p = (_bdf_parse_t *) client_data;
1968
1969 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00001970 memory = p->font->memory;
1971
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001972 /* Check for a comment. This is done to handle those fonts that have */
1973 /* comments before the STARTFONT line for some reason. */
1974 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1975 {
1976 if ( p->opts->keep_comments != 0 && p->font != 0 )
1977 {
1978 linelen -= 7;
1979
1980 s = line + 7;
1981 if ( *s != 0 )
1982 {
1983 s++;
1984 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00001985 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001986
1987 error = _bdf_add_comment( p->font, s, linelen );
1988 if ( error )
1989 goto Exit;
1990 /* here font is not defined! */
1991 }
1992
1993 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001994 }
1995
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001996 if ( !( p->flags & _BDF_START ) )
1997 {
1998 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00001999
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002000 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2001 {
2002 /* No STARTFONT field is a good indication of a problem. */
2003 error = BDF_Err_Missing_Startfont_Field;
2004 goto Exit;
2005 }
David Turner993a8d02002-05-18 12:03:43 +00002006
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002007 p->flags = _BDF_START;
2008 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002009
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002010 if ( FT_NEW( font ) )
2011 goto Exit;
2012 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002013
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002014 font->memory = p->memory;
2015 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002016
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002017 { /* setup */
2018 unsigned long i;
2019 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002020
David Turner993a8d02002-05-18 12:03:43 +00002021
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002022 error = hash_init( &(font->proptbl), memory );
2023 if ( error )
2024 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002025 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002026 i < _num_bdf_properties; i++, prop++ )
2027 {
2028 error = hash_insert( prop->name, (void *)i,
2029 &(font->proptbl), memory );
2030 if ( error )
2031 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002032 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002033 }
2034
2035 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2036 goto Exit;
2037 error = hash_init( (hashtable *)p->font->internal,memory );
2038 if ( error )
2039 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002040 p->font->spacing = p->opts->font_spacing;
2041 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002042
2043 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002044 }
2045
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002046 /* Check for the start of the properties. */
2047 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2048 {
David Turner68df4f72005-03-15 18:18:57 +00002049 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002050 if ( error )
2051 goto Exit;
2052 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2053
2054 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2055 goto Exit;
2056
2057 p->flags |= _BDF_PROPS;
2058 *next = _bdf_parse_properties;
2059
2060 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002061 }
2062
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002063 /* Check for the FONTBOUNDINGBOX field. */
2064 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2065 {
2066 if ( !(p->flags & _BDF_SIZE ) )
2067 {
2068 /* Missing the SIZE field. */
2069 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2070 error = BDF_Err_Missing_Size_Field;
2071 goto Exit;
2072 }
2073
David Turner68df4f72005-03-15 18:18:57 +00002074 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002075 if ( error )
2076 goto Exit;
2077
2078 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2079 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2080
2081 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2082 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2083
David Turnerd490e372002-05-28 23:40:37 +00002084 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002085 p->font->bbx.y_offset );
2086
2087 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002088
2089 p->flags |= _BDF_FONT_BBX;
2090
2091 goto Exit;
2092 }
2093
2094 /* The next thing to check for is the FONT field. */
2095 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2096 {
David Turner68df4f72005-03-15 18:18:57 +00002097 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002098 if ( error )
2099 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002100 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002101
David Turner68df4f72005-03-15 18:18:57 +00002102 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002103 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2104 goto Exit;
2105 FT_MEM_COPY( p->font->name, s, slen + 1 );
2106
2107 /* If the font name is an XLFD name, set the spacing to the one in */
2108 /* the font name. If there is no spacing fall back on the default. */
2109 error = _bdf_set_default_spacing( p->font, p->opts );
2110 if ( error )
2111 goto Exit;
2112
2113 p->flags |= _BDF_FONT_NAME;
2114
2115 goto Exit;
2116 }
2117
2118 /* Check for the SIZE field. */
2119 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2120 {
2121 if ( !( p->flags & _BDF_FONT_NAME ) )
2122 {
2123 /* Missing the FONT field. */
2124 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2125 error = BDF_Err_Missing_Font_Field;
2126 goto Exit;
2127 }
2128
David Turner68df4f72005-03-15 18:18:57 +00002129 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002130 if ( error )
2131 goto Exit;
2132
2133 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2134 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2135 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2136
2137 /* Check for the bits per pixel field. */
2138 if ( p->list.used == 5 )
2139 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002140 unsigned short bitcount, i, shift;
2141
2142
2143 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2144
2145 /* Only values 1, 2, 4, 8 are allowed. */
2146 shift = p->font->bpp;
2147 bitcount = 0;
2148 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002149 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002150 if ( shift & 1 )
2151 bitcount = i;
2152 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002153 }
David Turner993a8d02002-05-18 12:03:43 +00002154
Werner Lembergbd8e3242002-06-12 08:43:58 +00002155 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002156
2157 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002158 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002159 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002160 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002161 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002162 }
2163 }
2164 else
2165 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002166
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002167 p->flags |= _BDF_SIZE;
2168
2169 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002170 }
2171
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002172 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002173
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002174 Exit:
2175 return error;
2176 }
David Turner993a8d02002-05-18 12:03:43 +00002177
2178
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002179 /*************************************************************************/
2180 /* */
2181 /* API. */
2182 /* */
2183 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002184
David Turner993a8d02002-05-18 12:03:43 +00002185
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002186 FT_LOCAL_DEF( FT_Error )
2187 bdf_load_font( FT_Stream stream,
2188 FT_Memory extmemory,
2189 bdf_options_t* opts,
2190 bdf_font_t* *font )
2191 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002192 unsigned long lineno = 0; /* make compiler happy */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002193 _bdf_parse_t *p;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002194
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002195 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002196 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002197
2198
David Turner68df4f72005-03-15 18:18:57 +00002199 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002200 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002201
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002202 memory = NULL;
2203 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2204 p->minlb = 32767;
2205 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002206
David Turner68df4f72005-03-15 18:18:57 +00002207 _bdf_list_init( &p->list, extmemory );
2208
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002209 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002210 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002211 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002212 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002213
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002214 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002215 {
2216 /* If the font is not proportional, set the font's monowidth */
2217 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002218 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002219
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002220 if ( p->font->spacing != BDF_PROPORTIONAL )
2221 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002222
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002223 /* If the number of glyphs loaded is not that of the original count, */
2224 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002225 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002226 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002227 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2228 p->font->glyphs_used + p->font->unencoded_used ));
2229 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002230 }
2231
2232 /* Once the font has been loaded, adjust the overall font metrics if */
2233 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002234 if ( p->opts->correct_metrics != 0 &&
2235 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002236 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002237 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002238 {
2239 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002240 p->font->bbx.width, p->maxrb - p->minlb ));
2241 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2242 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002243 }
2244
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002245 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002246 {
2247 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002248 p->font->bbx.x_offset, p->minlb ));
2249 p->font->bbx.x_offset = p->minlb;
2250 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002251 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002252
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002253 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002254 {
2255 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002256 p->font->bbx.ascent, p->maxas ));
2257 p->font->bbx.ascent = p->maxas;
2258 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002259 }
2260
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002261 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002262 {
2263 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002264 p->font->bbx.descent, p->maxds ));
2265 p->font->bbx.descent = p->maxds;
2266 p->font->bbx.y_offset = (short)( -p->maxds );
2267 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002268 }
2269
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002270 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002271 {
2272 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002273 p->font->bbx.height, p->maxas + p->maxds ));
2274 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002275 }
2276
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002277 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002278 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2279 }
David Turner993a8d02002-05-18 12:03:43 +00002280 }
2281
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002282 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002283 {
2284 {
2285 /* The ENDFONT field was never reached or did not exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002286 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002287 /* Error happened while parsing header. */
2288 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2289 else
2290 /* Error happened when parsing glyphs. */
2291 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2292 }
David Turner993a8d02002-05-18 12:03:43 +00002293 }
2294
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002295 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002296 {
2297 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002298 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002299
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002300 if ( p->font->comments_len > 0 ) {
2301 if ( FT_RENEW_ARRAY( p->font->comments,
2302 p->font->comments_len,
2303 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002304 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002305
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002306 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002307 }
David Turner993a8d02002-05-18 12:03:43 +00002308 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002309 else if ( error == BDF_Err_Ok )
2310 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002311
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002312 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002313
2314 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002315 if ( p )
2316 {
David Turner68df4f72005-03-15 18:18:57 +00002317 _bdf_list_done( &p->list );
2318
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002319 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002320
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002321 FT_FREE( p );
2322 }
2323
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002324 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002325
2326 Fail:
2327 bdf_free_font( p->font );
2328
2329 memory = extmemory;
2330
2331 FT_FREE( p->font );
2332
2333 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002334 }
David Turner993a8d02002-05-18 12:03:43 +00002335
2336
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002337 FT_LOCAL_DEF( void )
2338 bdf_free_font( bdf_font_t* font )
2339 {
2340 bdf_property_t* prop;
2341 unsigned long i;
2342 bdf_glyph_t* glyphs;
2343 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002344
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002345
2346 if ( font == 0 )
2347 return;
David Turner993a8d02002-05-18 12:03:43 +00002348
2349 memory = font->memory;
2350
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002351 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002352
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002353 /* Free up the internal hash table of property names. */
2354 if ( font->internal )
2355 {
2356 hash_free( (hashtable *)font->internal, memory );
2357 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002358 }
2359
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002360 /* Free up the comment info. */
2361 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002362
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002363 /* Free up the properties. */
2364 for ( i = 0; i < font->props_size; i++ )
2365 {
2366 if ( font->props[i].format == BDF_ATOM )
2367 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002368 }
2369
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002370 FT_FREE( font->props );
2371
2372 /* Free up the character info. */
2373 for ( i = 0, glyphs = font->glyphs;
2374 i < font->glyphs_used; i++, glyphs++ )
2375 {
2376 FT_FREE( glyphs->name );
2377 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002378 }
2379
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002380 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2381 i++, glyphs++ )
2382 {
2383 FT_FREE( glyphs->name );
2384 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002385 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002386
2387 FT_FREE( font->glyphs );
2388 FT_FREE( font->unencoded );
2389
2390 /* Free up the overflow storage if it was used. */
2391 for ( i = 0, glyphs = font->overflow.glyphs;
2392 i < font->overflow.glyphs_used; i++, glyphs++ )
2393 {
2394 FT_FREE( glyphs->name );
2395 FT_FREE( glyphs->bitmap );
2396 }
2397
2398 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002399
2400 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002401 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002402
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002403 /* Free up the user defined properties. */
2404 for (prop = font->user_props, i = 0;
2405 i < font->nuser_props; i++, prop++ )
2406 {
2407 FT_FREE( prop->name );
2408 if ( prop->format == BDF_ATOM )
2409 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002410 }
David Turner993a8d02002-05-18 12:03:43 +00002411
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002412 FT_FREE( font->user_props );
2413
2414 /* FREE( font ); */ /* XXX Fixme */
2415 }
David Turner993a8d02002-05-18 12:03:43 +00002416
2417
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002418 FT_LOCAL_DEF( bdf_property_t * )
2419 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002420 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002421 {
2422 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002423
David Turner993a8d02002-05-18 12:03:43 +00002424
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002425 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002426 return 0;
2427
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002428 hn = hash_lookup( name, (hashtable *)font->internal );
2429
2430 return hn ? ( font->props + (unsigned long)hn->data ) : 0;
2431 }
2432
2433
2434/* END */