blob: 8f7bd64330ba689fc1f7da79560797f731df85b9 [file] [log] [blame]
David Turner993a8d02002-05-18 12:03:43 +00001/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
Werner Lembergf1c2b912006-01-13 14:53:28 +00003 * Copyright 2001, 2002, 2003, 2004, 2005, 2006 Francesco Zappa Nardelli
David Turner993a8d02002-05-18 12:03:43 +00004 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
20 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
Werner Lemberg7cf4d372002-05-21 14:13:01 +000024 /*************************************************************************/
25 /* */
26 /* This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 */
27 /* */
28 /* taken from Mark Leisher's xmbdfed package */
29 /* */
30 /*************************************************************************/
31
David Turner993a8d02002-05-18 12:03:43 +000032
33#include <ft2build.h>
34
Werner Lemberg02d4d592002-05-28 22:38:05 +000035#include FT_FREETYPE_H
David Turner993a8d02002-05-18 12:03:43 +000036#include FT_INTERNAL_DEBUG_H
37#include FT_INTERNAL_STREAM_H
38#include FT_INTERNAL_OBJECTS_H
39
40#include "bdf.h"
David Turner993a8d02002-05-18 12:03:43 +000041#include "bdferror.h"
42
David Turner993a8d02002-05-18 12:03:43 +000043
Werner Lemberg7cf4d372002-05-21 14:13:01 +000044 /*************************************************************************/
45 /* */
46 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
47 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
48 /* messages during execution. */
49 /* */
50#undef FT_COMPONENT
51#define FT_COMPONENT trace_bdflib
David Turner993a8d02002-05-18 12:03:43 +000052
David Turner993a8d02002-05-18 12:03:43 +000053
Werner Lemberg7cf4d372002-05-21 14:13:01 +000054 /*************************************************************************/
55 /* */
56 /* Default BDF font options. */
57 /* */
58 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000059
David Turner993a8d02002-05-18 12:03:43 +000060
David Turnerb1b47622002-05-21 21:17:43 +000061 static const bdf_options_t _bdf_opts =
Werner Lemberg7cf4d372002-05-21 14:13:01 +000062 {
David Turner993a8d02002-05-18 12:03:43 +000063 1, /* Correct metrics. */
64 1, /* Preserve unencoded glyphs. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000065 0, /* Preserve comments. */
66 BDF_PROPORTIONAL /* Default spacing. */
67 };
David Turner993a8d02002-05-18 12:03:43 +000068
David Turner993a8d02002-05-18 12:03:43 +000069
Werner Lemberg7cf4d372002-05-21 14:13:01 +000070 /*************************************************************************/
71 /* */
72 /* Builtin BDF font properties. */
73 /* */
74 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000075
Werner Lemberg7cf4d372002-05-21 14:13:01 +000076 /* List of most properties that might appear in a font. Doesn't include */
77 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
David Turner993a8d02002-05-18 12:03:43 +000078
David Turnerb1b47622002-05-21 21:17:43 +000079 static const bdf_property_t _bdf_properties[] =
David Turner993a8d02002-05-18 12:03:43 +000080 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +000081 { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
82 { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
83 { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
84 { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
85 { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
86 { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
87 { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
88 { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
89 { (char *)"COMMENT", BDF_ATOM, 1, { 0 } },
90 { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } },
91 { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
92 { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } },
93 { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
94 { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } },
95 { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } },
96 { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } },
97 { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
98 { (char *)"FONT", BDF_ATOM, 1, { 0 } },
99 { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
100 { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
101 { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
102 { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } },
103 { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } },
104 { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
105 { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } },
106 { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } },
107 { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } },
108 { (char *)"NOTICE", BDF_ATOM, 1, { 0 } },
109 { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
110 { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } },
111 { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
112 { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
113 { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
114 { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
115 { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
116 { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
117 { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
118 { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
119 { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
120 { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
121 { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
122 { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
123 { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
124 { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
125 { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
126 { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
127 { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
128 { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
129 { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
130 { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
131 { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
132 { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
133 { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
134 { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
135 { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
136 { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
137 { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
138 { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
139 { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
140 { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
141 { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
142 { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } },
143 { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
144 { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
145 { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
146 { (char *)"SLANT", BDF_ATOM, 1, { 0 } },
147 { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
148 { (char *)"SPACING", BDF_ATOM, 1, { 0 } },
149 { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
150 { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
151 { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
152 { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
153 { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
154 { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
155 { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
156 { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
157 { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
158 { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
159 { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } },
160 { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
161 { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } },
162 { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
163 { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
164 };
David Turner993a8d02002-05-18 12:03:43 +0000165
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000166 static const unsigned long
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000167 _num_bdf_properties = sizeof ( _bdf_properties ) /
168 sizeof ( _bdf_properties[0] );
David Turner993a8d02002-05-18 12:03:43 +0000169
170
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000171 /*************************************************************************/
172 /* */
173 /* Hash table utilities for the properties. */
174 /* */
175 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +0000176
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000177 /* XXX: Replace this with FreeType's hash functions */
David Turner993a8d02002-05-18 12:03:43 +0000178
David Turner993a8d02002-05-18 12:03:43 +0000179
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000180#define INITIAL_HT_SIZE 241
181
182 typedef void
183 (*hash_free_func)( hashnode node );
184
185 static hashnode*
Werner Lemberg428c2e42003-04-25 05:35:04 +0000186 hash_bucket( const char* key,
187 hashtable* ht )
David Turner993a8d02002-05-18 12:03:43 +0000188 {
Werner Lemberg428c2e42003-04-25 05:35:04 +0000189 const char* kp = key;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000190 unsigned long res = 0;
191 hashnode* bp = ht->table, *ndp;
192
193
194 /* Mocklisp hash function. */
195 while ( *kp )
196 res = ( res << 5 ) - res + *kp++;
197
198 ndp = bp + ( res % ht->size );
199 while ( *ndp )
David Turner993a8d02002-05-18 12:03:43 +0000200 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000201 kp = (*ndp)->key;
202 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
203 break;
204 ndp--;
205 if ( ndp < bp )
206 ndp = bp + ( ht->size - 1 );
David Turner993a8d02002-05-18 12:03:43 +0000207 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000208
209 return ndp;
David Turner993a8d02002-05-18 12:03:43 +0000210 }
David Turner993a8d02002-05-18 12:03:43 +0000211
212
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000213 static FT_Error
214 hash_rehash( hashtable* ht,
215 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000216 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000217 hashnode* obp = ht->table, *bp, *nbp;
David Turner993a8d02002-05-18 12:03:43 +0000218 int i, sz = ht->size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000219 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000220
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000221
222 ht->size <<= 1;
223 ht->limit = ht->size / 3;
224
225 if ( FT_NEW_ARRAY( ht->table, ht->size ) )
226 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000227
228 for ( i = 0, bp = obp; i < sz; i++, bp++ )
David Turner993a8d02002-05-18 12:03:43 +0000229 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000230 if ( *bp )
231 {
232 nbp = hash_bucket( (*bp)->key, ht );
233 *nbp = *bp;
234 }
David Turner993a8d02002-05-18 12:03:43 +0000235 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000236 FT_FREE( obp );
237
238 Exit:
239 return error;
David Turner993a8d02002-05-18 12:03:43 +0000240 }
David Turner993a8d02002-05-18 12:03:43 +0000241
242
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000243 static FT_Error
244 hash_init( hashtable* ht,
245 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000246 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000247 int sz = INITIAL_HT_SIZE;
248 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000249
David Turner993a8d02002-05-18 12:03:43 +0000250
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000251 ht->size = sz;
252 ht->limit = sz / 3;
253 ht->used = 0;
David Turner993a8d02002-05-18 12:03:43 +0000254
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000255 if ( FT_NEW_ARRAY( ht->table, sz ) )
256 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000257
258 Exit:
259 return error;
David Turner993a8d02002-05-18 12:03:43 +0000260 }
David Turner993a8d02002-05-18 12:03:43 +0000261
262
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000263 static void
264 hash_free( hashtable* ht,
265 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000266 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000267 if ( ht != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000268 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000269 int i, sz = ht->size;
270 hashnode* bp = ht->table;
David Turner993a8d02002-05-18 12:03:43 +0000271
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000272
273 for ( i = 0; i < sz; i++, bp++ )
274 FT_FREE( *bp );
275
276 FT_FREE( ht->table );
277 }
David Turner993a8d02002-05-18 12:03:43 +0000278 }
279
David Turner993a8d02002-05-18 12:03:43 +0000280
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000281 static FT_Error
282 hash_insert( char* key,
283 void* data,
284 hashtable* ht,
285 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000286 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000287 hashnode nn, *bp = hash_bucket( key, ht );
288 FT_Error error = BDF_Err_Ok;
289
290
291 nn = *bp;
292 if ( !nn )
293 {
294 if ( FT_NEW( nn ) )
295 goto Exit;
296 *bp = nn;
297
298 nn->key = key;
299 nn->data = data;
300
301 if ( ht->used >= ht->limit )
302 {
303 error = hash_rehash( ht, memory );
304 if ( error )
305 goto Exit;
306 }
307 ht->used++;
308 }
David Turner993a8d02002-05-18 12:03:43 +0000309 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000310 nn->data = data;
311
312 Exit:
313 return error;
David Turner993a8d02002-05-18 12:03:43 +0000314 }
315
David Turner993a8d02002-05-18 12:03:43 +0000316
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000317 static hashnode
Werner Lemberg428c2e42003-04-25 05:35:04 +0000318 hash_lookup( const char* key,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000319 hashtable* ht )
320 {
321 hashnode *np = hash_bucket( key, ht );
322
323
324 return *np;
325 }
326
327
328 /*************************************************************************/
329 /* */
330 /* Utility types and functions. */
331 /* */
332 /*************************************************************************/
333
334
335 /* Function type for parsing lines of a BDF font. */
336
337 typedef FT_Error
338 (*_bdf_line_func_t)( char* line,
339 unsigned long linelen,
340 unsigned long lineno,
341 void* call_data,
342 void* client_data );
343
344
345 /* List structure for splitting lines into fields. */
346
347 typedef struct _bdf_list_t_
348 {
349 char** field;
350 unsigned long size;
351 unsigned long used;
David Turner68df4f72005-03-15 18:18:57 +0000352 FT_Memory memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000353
354 } _bdf_list_t;
355
356
357 /* Structure used while loading BDF fonts. */
358
359 typedef struct _bdf_parse_t_
360 {
361 unsigned long flags;
362 unsigned long cnt;
363 unsigned long row;
364
365 short minlb;
366 short maxlb;
367 short maxrb;
368 short maxas;
369 short maxds;
370
371 short rbearing;
372
373 char* glyph_name;
374 long glyph_enc;
375
376 bdf_font_t* font;
377 bdf_options_t* opts;
378
379 unsigned long have[2048];
380 _bdf_list_t list;
381
382 FT_Memory memory;
383
384 } _bdf_parse_t;
385
386
David Turnerb1b47622002-05-21 21:17:43 +0000387#define setsbit( m, cc ) ( m[(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000388#define sbitset( m, cc ) ( m[(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
389
390
David Turner68df4f72005-03-15 18:18:57 +0000391 static void
392 _bdf_list_init( _bdf_list_t* list,
393 FT_Memory memory )
394 {
Werner Lembergebf55852005-03-16 01:49:54 +0000395 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000396 list->memory = memory;
397 }
398
Werner Lembergebf55852005-03-16 01:49:54 +0000399
David Turner68df4f72005-03-15 18:18:57 +0000400 static void
401 _bdf_list_done( _bdf_list_t* list )
402 {
403 FT_Memory memory = list->memory;
404
Werner Lembergebf55852005-03-16 01:49:54 +0000405
David Turner68df4f72005-03-15 18:18:57 +0000406 if ( memory )
407 {
408 FT_FREE( list->field );
Werner Lembergebf55852005-03-16 01:49:54 +0000409 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000410 }
411 }
412
413
414 static FT_Error
415 _bdf_list_ensure( _bdf_list_t* list,
416 int num_items )
417 {
Werner Lembergebf55852005-03-16 01:49:54 +0000418 FT_Error error = BDF_Err_Ok;
419
David Turner68df4f72005-03-15 18:18:57 +0000420
David Turner5d02b8a2005-03-15 23:48:15 +0000421 if ( num_items > (int)list->size )
David Turner68df4f72005-03-15 18:18:57 +0000422 {
Werner Lembergebf55852005-03-16 01:49:54 +0000423 int oldsize = list->size;
424 int newsize = oldsize + ( oldsize >> 1 ) + 4;
425 int bigsize = FT_INT_MAX / sizeof ( char* );
David Turner68df4f72005-03-15 18:18:57 +0000426 FT_Memory memory = list->memory;
427
Werner Lembergebf55852005-03-16 01:49:54 +0000428
David Turner68df4f72005-03-15 18:18:57 +0000429 if ( oldsize == bigsize )
430 {
Werner Lembergebf55852005-03-16 01:49:54 +0000431 error = BDF_Err_Out_Of_Memory;
David Turner68df4f72005-03-15 18:18:57 +0000432 goto Exit;
433 }
434 else if ( newsize < oldsize || newsize > bigsize )
435 newsize = bigsize;
436
437 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
438 goto Exit;
439
440 list->size = newsize;
441 }
Werner Lembergebf55852005-03-16 01:49:54 +0000442
David Turner68df4f72005-03-15 18:18:57 +0000443 Exit:
444 return error;
445 }
446
447
448 static void
449 _bdf_list_shift( _bdf_list_t* list,
450 unsigned long n )
451 {
452 unsigned long i, u;
453
454
455 if ( list == 0 || list->used == 0 || n == 0 )
456 return;
457
458 if ( n >= list->used )
459 {
460 list->used = 0;
461 return;
462 }
463
464 for ( u = n, i = 0; u < list->used; i++, u++ )
465 list->field[i] = list->field[u];
466 list->used -= n;
467 }
468
469
470 static char *
471 _bdf_list_join( _bdf_list_t* list,
472 int c,
473 unsigned long *alen )
474 {
475 unsigned long i, j;
476 char *fp, *dp;
477
478
479 *alen = 0;
480
481 if ( list == 0 || list->used == 0 )
482 return 0;
483
484 dp = list->field[0];
485 for ( i = j = 0; i < list->used; i++ )
486 {
487 fp = list->field[i];
488 while ( *fp )
489 dp[j++] = *fp++;
490
491 if ( i + 1 < list->used )
492 dp[j++] = (char)c;
493 }
494 dp[j] = 0;
495
496 *alen = j;
497 return dp;
498 }
499
500
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000501 /* An empty string for empty fields. */
502
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000503 static const char empty[1] = { 0 }; /* XXX eliminate this */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000504
505
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000506 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000507 _bdf_list_split( _bdf_list_t* list,
508 char* separators,
509 char* line,
510 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000511 {
512 int mult, final_empty;
513 char *sp, *ep, *end;
514 char seps[32];
515 FT_Error error = BDF_Err_Ok;
516
517
518 /* Initialize the list. */
519 list->used = 0;
520
521 /* If the line is empty, then simply return. */
522 if ( linelen == 0 || line[0] == 0 )
523 goto Exit;
524
525 /* In the original code, if the `separators' parameter is NULL or */
526 /* empty, the list is split into individual bytes. We don't need */
527 /* this, so an error is signaled. */
528 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000529 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000530 error = BDF_Err_Invalid_Argument;
531 goto Exit;
532 }
533
534 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000535 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000536
537 /* If the very last character of the separator string is a plus, then */
538 /* set the `mult' flag to indicate that multiple separators should be */
539 /* collapsed into one. */
540 for ( mult = 0, sp = separators; sp && *sp; sp++ )
541 {
542 if ( *sp == '+' && *( sp + 1 ) == 0 )
543 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000544 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000545 setsbit( seps, *sp );
546 }
547
548 /* Break the line up into fields. */
549 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
550 sp < end && *sp; )
551 {
552 /* Collect everything that is not a separator. */
553 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
554 ;
555
556 /* Resize the list if necessary. */
557 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000558 {
Werner Lembergebf55852005-03-16 01:49:54 +0000559 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000560 if ( error )
561 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000562 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000563
564 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000565 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000566
567 sp = ep;
568
569 if ( mult )
570 {
571 /* If multiple separators should be collapsed, do it now by */
572 /* setting all the separator characters to 0. */
573 for ( ; *ep && sbitset( seps, *ep ); ep++ )
574 *ep = 0;
575 }
576 else if ( *ep != 0 )
577 /* Don't collapse multiple separators by making them 0, so just */
578 /* make the one encountered 0. */
579 *ep++ = 0;
580
581 final_empty = ( ep > sp && *ep == 0 );
582 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000583 }
584
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000585 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000586 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000587 {
Werner Lembergebf55852005-03-16 01:49:54 +0000588 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000589 if ( error )
590 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000591 }
592
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000593 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000594 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000595
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000596 list->field[list->used] = 0;
597
598 Exit:
599 return error;
David Turner993a8d02002-05-18 12:03:43 +0000600 }
601
David Turner993a8d02002-05-18 12:03:43 +0000602
David Turner68df4f72005-03-15 18:18:57 +0000603#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000604
Werner Lembergebf55852005-03-16 01:49:54 +0000605
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000606 static FT_Error
607 _bdf_readstream( FT_Stream stream,
608 _bdf_line_func_t callback,
609 void* client_data,
610 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000611 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000612 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000613 unsigned long lineno, buf_size;
614 int refill, bytes, hold, to_skip;
615 int start, end, cursor, avail;
616 char* buf = 0;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000617 FT_Memory memory = stream->memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000618 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000619
David Turner993a8d02002-05-18 12:03:43 +0000620
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000621 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000622 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000623 error = BDF_Err_Invalid_Argument;
624 goto Exit;
625 }
David Turner993a8d02002-05-18 12:03:43 +0000626
Werner Lembergebf55852005-03-16 01:49:54 +0000627 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000628 buf_size = 1024;
629
630 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000631 goto Exit;
632
Werner Lembergebf55852005-03-16 01:49:54 +0000633 cb = callback;
634 lineno = 1;
635 buf[0] = 0;
636 start = 0;
637 end = 0;
638 avail = 0;
639 cursor = 0;
640 refill = 1;
641 to_skip = NO_SKIP;
642 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000643
David Turner68df4f72005-03-15 18:18:57 +0000644 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000645 {
David Turner68df4f72005-03-15 18:18:57 +0000646 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000647 {
Werner Lembergebf55852005-03-16 01:49:54 +0000648 bytes = (int)FT_Stream_TryRead( stream, (FT_Byte*)buf + cursor,
David Turner68df4f72005-03-15 18:18:57 +0000649 (FT_ULong)(buf_size - cursor) );
650 avail = cursor + bytes;
651 cursor = 0;
652 refill = 0;
653 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000654
David Turner68df4f72005-03-15 18:18:57 +0000655 end = start;
656
Werner Lembergebf55852005-03-16 01:49:54 +0000657 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000658 if ( start < avail && buf[start] == to_skip )
659 {
660 start += 1;
661 to_skip = NO_SKIP;
662 continue;
663 }
664
665 /* try to find the end of the line */
666 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
667 end++;
668
Werner Lembergebf55852005-03-16 01:49:54 +0000669 /* if we hit the end of the buffer, try shifting its content */
670 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000671 if ( end >= avail )
672 {
673 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
674 break; /* ignore it then exit */
675
676 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000677 {
Werner Lembergebf55852005-03-16 01:49:54 +0000678 /* this line is definitely too long; try resizing the input */
679 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000680 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000681
Werner Lembergebf55852005-03-16 01:49:54 +0000682
683 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000684 {
685 error = BDF_Err_Invalid_Argument;
686 goto Exit;
687 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000688
Werner Lembergebf55852005-03-16 01:49:54 +0000689 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000690 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
691 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000692
David Turner68df4f72005-03-15 18:18:57 +0000693 cursor = buf_size;
694 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000695 }
696 else
697 {
David Turner68df4f72005-03-15 18:18:57 +0000698 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000699
Werner Lembergebf55852005-03-16 01:49:54 +0000700 FT_MEM_COPY( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000701
David Turner68df4f72005-03-15 18:18:57 +0000702 cursor = bytes;
703 avail -= bytes;
704 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000705 }
David Turner68df4f72005-03-15 18:18:57 +0000706 refill = 1;
707 continue;
David Turner993a8d02002-05-18 12:03:43 +0000708 }
David Turner68df4f72005-03-15 18:18:57 +0000709
710 /* Temporarily NUL-terminate the line. */
711 hold = buf[end];
712 buf[end] = 0;
713
714 /* XXX: Use encoding independent value for 0x1a */
715 if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
716 {
Werner Lembergebf55852005-03-16 01:49:54 +0000717 error = (*cb)( buf + start, end - start, lineno,
718 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000719 if ( error )
720 break;
721 }
722
723 lineno += 1;
724 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000725 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000726
727 if ( hold == '\n' )
728 to_skip = '\r';
729 else if ( hold == '\r' )
730 to_skip = '\n';
731 else
732 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000733 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000734
David Turner68df4f72005-03-15 18:18:57 +0000735 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000736
737 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000738 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000739 return error;
David Turner993a8d02002-05-18 12:03:43 +0000740 }
David Turner993a8d02002-05-18 12:03:43 +0000741
742
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000743 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000744
David Turnerb1b47622002-05-21 21:17:43 +0000745 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000746 {
David Turner993a8d02002-05-18 12:03:43 +0000747 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
748 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
749 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
750 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
751 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
752 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
753 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
754 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
755 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
756 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000758 };
David Turner993a8d02002-05-18 12:03:43 +0000759
David Turnerb1b47622002-05-21 21:17:43 +0000760 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000761 {
David Turner993a8d02002-05-18 12:03:43 +0000762 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
764 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000766 };
David Turner993a8d02002-05-18 12:03:43 +0000767
David Turnerb1b47622002-05-21 21:17:43 +0000768 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000769 {
David Turner993a8d02002-05-18 12:03:43 +0000770 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
771 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000774 };
David Turner993a8d02002-05-18 12:03:43 +0000775
David Turnerb1b47622002-05-21 21:17:43 +0000776 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000777 {
David Turner993a8d02002-05-18 12:03:43 +0000778 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
779 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
780 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000782 };
David Turner993a8d02002-05-18 12:03:43 +0000783
David Turner993a8d02002-05-18 12:03:43 +0000784
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000785#define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
David Turner993a8d02002-05-18 12:03:43 +0000786
David Turner993a8d02002-05-18 12:03:43 +0000787
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000788 /* Routine to convert an ASCII string into an unsigned long integer. */
789 static unsigned long
790 _bdf_atoul( char* s,
791 char** end,
792 int base )
David Turner993a8d02002-05-18 12:03:43 +0000793 {
David Turnerb1b47622002-05-21 21:17:43 +0000794 unsigned long v;
795 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000796
797
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000798 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000799 return 0;
800
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000801 /* Make sure the radix is something recognizable. Default to 10. */
802 switch ( base )
803 {
804 case 8:
805 dmap = odigits;
806 break;
807 case 16:
808 dmap = hdigits;
809 break;
810 default:
811 base = 10;
812 dmap = ddigits;
813 break;
David Turner993a8d02002-05-18 12:03:43 +0000814 }
815
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000816 /* Check for the special hex prefix. */
817 if ( *s == '0' &&
818 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
819 {
820 base = 16;
821 dmap = hdigits;
822 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000823 }
824
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000825 for ( v = 0; isdigok( dmap, *s ); s++ )
826 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000827
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000828 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000829 *end = s;
830
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000831 return v;
832 }
David Turner993a8d02002-05-18 12:03:43 +0000833
David Turner993a8d02002-05-18 12:03:43 +0000834
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000835 /* Routine to convert an ASCII string into an signed long integer. */
836 static long
837 _bdf_atol( char* s,
838 char** end,
839 int base )
840 {
David Turnerb1b47622002-05-21 21:17:43 +0000841 long v, neg;
842 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000843
844
845 if ( s == 0 || *s == 0 )
846 return 0;
847
848 /* Make sure the radix is something recognizable. Default to 10. */
849 switch ( base )
850 {
851 case 8:
852 dmap = odigits;
853 break;
854 case 16:
855 dmap = hdigits;
856 break;
857 default:
858 base = 10;
859 dmap = ddigits;
860 break;
861 }
862
863 /* Check for a minus sign. */
864 neg = 0;
865 if ( *s == '-' )
866 {
867 s++;
868 neg = 1;
869 }
870
871 /* Check for the special hex prefix. */
872 if ( *s == '0' &&
873 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
874 {
875 base = 16;
876 dmap = hdigits;
877 s += 2;
878 }
879
880 for ( v = 0; isdigok( dmap, *s ); s++ )
881 v = v * base + a2i[(int)*s];
882
883 if ( end != 0 )
884 *end = s;
885
886 return ( !neg ) ? v : -v;
887 }
888
889
890 /* Routine to convert an ASCII string into an signed short integer. */
891 static short
892 _bdf_atos( char* s,
893 char** end,
894 int base )
895 {
David Turnerb1b47622002-05-21 21:17:43 +0000896 short v, neg;
897 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000898
899
900 if ( s == 0 || *s == 0 )
901 return 0;
902
903 /* Make sure the radix is something recognizable. Default to 10. */
904 switch ( base )
905 {
906 case 8:
907 dmap = odigits;
908 break;
909 case 16:
910 dmap = hdigits;
911 break;
912 default:
913 base = 10;
914 dmap = ddigits;
915 break;
916 }
917
918 /* Check for a minus. */
919 neg = 0;
920 if ( *s == '-' )
921 {
922 s++;
923 neg = 1;
924 }
925
926 /* Check for the special hex prefix. */
927 if ( *s == '0' &&
928 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
929 {
930 base = 16;
931 dmap = hdigits;
932 s += 2;
933 }
934
935 for ( v = 0; isdigok( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +0000936 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000937
938 if ( end != 0 )
939 *end = s;
940
Werner Lemberg233302a2002-05-22 05:41:06 +0000941 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000942 }
943
944
945 /* Routine to compare two glyphs by encoding so they can be sorted. */
946 static int
947 by_encoding( const void* a,
948 const void* b )
949 {
950 bdf_glyph_t *c1, *c2;
951
952
953 c1 = (bdf_glyph_t *)a;
954 c2 = (bdf_glyph_t *)b;
955
956 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000957 return -1;
David Turner68df4f72005-03-15 18:18:57 +0000958
959 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000960 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000961
David Turner993a8d02002-05-18 12:03:43 +0000962 return 0;
David Turner993a8d02002-05-18 12:03:43 +0000963 }
964
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000965
966 static FT_Error
967 bdf_create_property( char* name,
968 int format,
969 bdf_font_t* font )
970 {
971 unsigned long n;
972 bdf_property_t* p;
973 FT_Memory memory = font->memory;
974 FT_Error error = BDF_Err_Ok;
975
976
977 /* First check to see if the property has */
978 /* already been added or not. If it has, then */
979 /* simply ignore it. */
980 if ( hash_lookup( name, &(font->proptbl) ) )
981 goto Exit;
982
David Turner68df4f72005-03-15 18:18:57 +0000983 if ( FT_RENEW_ARRAY( font->user_props,
984 font->nuser_props,
985 font->nuser_props + 1 ) )
986 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000987
988 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +0000989 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000990
991 n = (unsigned long)( ft_strlen( name ) + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000992
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000993 if ( FT_NEW_ARRAY( p->name, n ) )
994 goto Exit;
995
996 FT_MEM_COPY( (char *)p->name, name, n );
997
998 p->format = format;
999 p->builtin = 0;
1000
1001 n = _num_bdf_properties + font->nuser_props;
1002
1003 error = hash_insert( p->name, (void *)n, &(font->proptbl), memory );
1004 if ( error )
1005 goto Exit;
1006
1007 font->nuser_props++;
1008
1009 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001010 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001011 }
David Turner993a8d02002-05-18 12:03:43 +00001012
1013
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001014 FT_LOCAL_DEF( bdf_property_t * )
1015 bdf_get_property( char* name,
1016 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001017 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001018 hashnode hn;
1019 unsigned long propid;
1020
1021
1022 if ( name == 0 || *name == 0 )
1023 return 0;
1024
1025 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1026 return 0;
1027
1028 propid = (unsigned long)hn->data;
1029 if ( propid >= _num_bdf_properties )
1030 return font->user_props + ( propid - _num_bdf_properties );
1031
Werner Lemberg233302a2002-05-22 05:41:06 +00001032 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001033 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001034
1035
1036 /*************************************************************************/
1037 /* */
1038 /* BDF font file parsing flags and functions. */
1039 /* */
1040 /*************************************************************************/
1041
1042
1043 /* Parse flags. */
1044
1045#define _BDF_START 0x0001
1046#define _BDF_FONT_NAME 0x0002
1047#define _BDF_SIZE 0x0004
1048#define _BDF_FONT_BBX 0x0008
1049#define _BDF_PROPS 0x0010
1050#define _BDF_GLYPHS 0x0020
1051#define _BDF_GLYPH 0x0040
1052#define _BDF_ENCODING 0x0080
1053#define _BDF_SWIDTH 0x0100
1054#define _BDF_DWIDTH 0x0200
1055#define _BDF_BBX 0x0400
1056#define _BDF_BITMAP 0x0800
1057
1058#define _BDF_SWIDTH_ADJ 0x1000
1059
1060#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1061 _BDF_ENCODING | \
1062 _BDF_SWIDTH | \
1063 _BDF_DWIDTH | \
1064 _BDF_BBX | \
1065 _BDF_BITMAP )
1066
Werner Lembergf1c2b912006-01-13 14:53:28 +00001067#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1068#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001069
1070
1071 /* Auto correction messages. */
1072#define ACMSG1 "FONT_ASCENT property missing. " \
1073 "Added \"FONT_ASCENT %hd\".\n"
1074#define ACMSG2 "FONT_DESCENT property missing. " \
1075 "Added \"FONT_DESCENT %hd\".\n"
1076#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
1077#define ACMSG4 "Font left bearing != actual left bearing. " \
1078 "Old: %hd New: %hd.\n"
1079#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
1080#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
1081#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
1082#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
1083#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
1084#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
1085#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
1086#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
1087#define ACMSG13 "Glyph %ld extra rows removed.\n"
1088#define ACMSG14 "Glyph %ld extra columns removed.\n"
1089#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
1090
1091 /* Error messages. */
1092#define ERRMSG1 "[line %ld] Missing \"%s\" line.\n"
1093#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
1094#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
1095
1096
1097 static FT_Error
1098 _bdf_add_comment( bdf_font_t* font,
1099 char* comment,
1100 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001101 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001102 char* cp;
1103 FT_Memory memory = font->memory;
1104 FT_Error error = BDF_Err_Ok;
1105
1106
David Turner68df4f72005-03-15 18:18:57 +00001107 if ( FT_RENEW_ARRAY( font->comments,
1108 font->comments_len,
1109 font->comments_len + len + 1 ) )
1110 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001111
1112 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001113
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001114 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001115 cp[len] = '\n';
1116
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001117 font->comments_len += len + 1;
1118
1119 Exit:
1120 return error;
David Turner993a8d02002-05-18 12:03:43 +00001121 }
1122
David Turner993a8d02002-05-18 12:03:43 +00001123
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001124 /* Set the spacing from the font name if it exists, or set it to the */
1125 /* default specified in the options. */
1126 static FT_Error
1127 _bdf_set_default_spacing( bdf_font_t* font,
1128 bdf_options_t* opts )
David Turner993a8d02002-05-18 12:03:43 +00001129 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001130 unsigned long len;
1131 char name[128];
1132 _bdf_list_t list;
1133 FT_Memory memory;
1134 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001135
David Turner993a8d02002-05-18 12:03:43 +00001136
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001137 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1138 {
1139 error = BDF_Err_Invalid_Argument;
1140 goto Exit;
1141 }
David Turner993a8d02002-05-18 12:03:43 +00001142
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001143 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001144
David Turner68df4f72005-03-15 18:18:57 +00001145 _bdf_list_init( &list, memory );
1146
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001147 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001148
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001149 len = (unsigned long)( ft_strlen( font->name ) + 1 );
1150 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001151
David Turner68df4f72005-03-15 18:18:57 +00001152 error = _bdf_list_split( &list, (char *)"-", name, len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001153 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001154 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001155
1156 if ( list.used == 15 )
1157 {
1158 switch ( list.field[11][0] )
1159 {
1160 case 'C':
1161 case 'c':
1162 font->spacing = BDF_CHARCELL;
1163 break;
1164 case 'M':
1165 case 'm':
1166 font->spacing = BDF_MONOWIDTH;
1167 break;
1168 case 'P':
1169 case 'p':
1170 font->spacing = BDF_PROPORTIONAL;
1171 break;
David Turner993a8d02002-05-18 12:03:43 +00001172 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001173 }
1174
David Turner68df4f72005-03-15 18:18:57 +00001175 Fail:
1176 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001177
1178 Exit:
1179 return error;
David Turner993a8d02002-05-18 12:03:43 +00001180 }
David Turner993a8d02002-05-18 12:03:43 +00001181
1182
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001183 /* Determine whether the property is an atom or not. If it is, then */
1184 /* clean it up so the double quotes are removed if they exist. */
1185 static int
1186 _bdf_is_atom( char* line,
1187 unsigned long linelen,
1188 char** name,
1189 char** value,
1190 bdf_font_t* font )
1191 {
1192 int hold;
1193 char *sp, *ep;
1194 bdf_property_t* p;
1195
David Turner993a8d02002-05-18 12:03:43 +00001196
1197 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001198
1199 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001200 ep++;
1201
1202 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001203 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001204 {
1205 hold = *ep;
1206 *ep = 0;
1207 }
1208
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001209 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001210
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001211 /* Restore the character that was saved before any return can happen. */
1212 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001213 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001214
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001215 /* If the property exists and is not an atom, just return here. */
1216 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001217 return 0;
1218
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001219 /* The property is an atom. Trim all leading and trailing whitespace */
1220 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001221 sp = ep;
1222 ep = line + linelen;
1223
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001224 /* Trim the leading whitespace if it exists. */
David Turner993a8d02002-05-18 12:03:43 +00001225 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001226 while ( *sp &&
1227 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001228 sp++;
1229
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001230 /* Trim the leading double quote if it exists. */
1231 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001232 sp++;
1233 *value = sp;
1234
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001235 /* Trim the trailing whitespace if it exists. */
1236 while ( ep > sp &&
1237 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001238 *--ep = 0;
1239
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001240 /* Trim the trailing double quote if it exists. */
1241 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001242 *--ep = 0;
1243
1244 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001245 }
David Turner993a8d02002-05-18 12:03:43 +00001246
1247
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001248 static FT_Error
1249 _bdf_add_property( bdf_font_t* font,
1250 char* name,
1251 char* value )
1252 {
1253 unsigned long propid;
1254 hashnode hn;
1255 int len;
1256 bdf_property_t *prop, *fp;
1257 FT_Memory memory = font->memory;
1258 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001259
David Turner993a8d02002-05-18 12:03:43 +00001260
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001261 /* First, check to see if the property already exists in the font. */
1262 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001263 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001264 /* The property already exists in the font, so simply replace */
1265 /* the value of the property with the current value. */
1266 fp = font->props + (unsigned long)hn->data;
1267
David Turnerb1b47622002-05-21 21:17:43 +00001268 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001269 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001270 case BDF_ATOM:
1271 /* Delete the current atom if it exists. */
1272 FT_FREE( fp->value.atom );
1273
1274 if ( value == 0 )
1275 len = 1;
1276 else
1277 len = ft_strlen( value ) + 1;
1278
1279 if ( len > 1 )
1280 {
1281 if ( FT_NEW_ARRAY( fp->value.atom, len ) )
1282 goto Exit;
1283 FT_MEM_COPY( fp->value.atom, value, len );
1284 }
1285 else
1286 fp->value.atom = 0;
1287 break;
1288
1289 case BDF_INTEGER:
1290 fp->value.int32 = _bdf_atol( value, 0, 10 );
1291 break;
1292
1293 case BDF_CARDINAL:
1294 fp->value.card32 = _bdf_atoul( value, 0, 10 );
1295 break;
David Turnerd490e372002-05-28 23:40:37 +00001296
David Turnerb1b47622002-05-21 21:17:43 +00001297 default:
1298 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001299 }
David Turnerd490e372002-05-28 23:40:37 +00001300
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001301 goto Exit;
1302 }
1303
1304 /* See whether this property type exists yet or not. */
1305 /* If not, create it. */
1306 hn = hash_lookup( name, &(font->proptbl) );
1307 if ( hn == 0 )
1308 {
1309 error = bdf_create_property( name, BDF_ATOM, font );
1310 if ( error )
1311 goto Exit;
1312 hn = hash_lookup( name, &(font->proptbl) );
1313 }
1314
1315 /* Allocate another property if this is overflow. */
1316 if ( font->props_used == font->props_size )
1317 {
1318 if ( font->props_size == 0 )
1319 {
1320 if ( FT_NEW_ARRAY( font->props, 1 ) )
1321 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001322 }
1323 else
1324 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001325 if ( FT_RENEW_ARRAY( font->props,
1326 font->props_size,
1327 font->props_size + 1 ) )
1328 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001329 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001330
David Turner993a8d02002-05-18 12:03:43 +00001331 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001332 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001333 font->props_size++;
1334 }
1335
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001336 propid = (unsigned long)hn->data;
1337 if ( propid >= _num_bdf_properties )
1338 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001339 else
David Turnerb1b47622002-05-21 21:17:43 +00001340 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001341
1342 fp = font->props + font->props_used;
1343
1344 fp->name = prop->name;
1345 fp->format = prop->format;
1346 fp->builtin = prop->builtin;
1347
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001348 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001349 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001350 case BDF_ATOM:
1351 if ( value == 0 )
1352 len = 1;
1353 else
1354 len = ft_strlen( value ) + 1;
David Turner993a8d02002-05-18 12:03:43 +00001355
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001356 if ( len > 1 )
1357 {
1358 if ( FT_NEW_ARRAY( fp->value.atom, len ) )
1359 goto Exit;
1360 FT_MEM_COPY( fp->value.atom, value, len );
1361 }
1362 else
1363 fp->value.atom = 0;
1364 break;
David Turner993a8d02002-05-18 12:03:43 +00001365
1366 case BDF_INTEGER:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001367 fp->value.int32 = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001368 break;
1369
1370 case BDF_CARDINAL:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001371 fp->value.card32 = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001372 break;
David Turner993a8d02002-05-18 12:03:43 +00001373 }
1374
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001375 /* If the property happens to be a comment, then it doesn't need */
1376 /* to be added to the internal hash table. */
1377 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) {
1378 /* Add the property to the font property table. */
1379 error = hash_insert( fp->name,
1380 (void *)font->props_used,
1381 (hashtable *)font->internal,
1382 memory );
1383 if ( error )
1384 goto Exit;
1385 }
David Turner993a8d02002-05-18 12:03:43 +00001386
1387 font->props_used++;
1388
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001389 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1390 /* property needs to be located if it exists in the property list, the */
1391 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1392 /* present, and the SPACING property should override the default */
1393 /* spacing. */
1394 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
Werner Lemberg8ef41832004-06-22 12:28:17 +00001395 font->default_char = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001396 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001397 font->font_ascent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001398 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001399 font->font_descent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001400 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001401 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001402 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001403 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001404 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001405 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001406 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001407 font->spacing = BDF_CHARCELL;
1408 }
1409
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001410 Exit:
1411 return error;
David Turner993a8d02002-05-18 12:03:43 +00001412 }
1413
David Turner993a8d02002-05-18 12:03:43 +00001414
David Turnerb1b47622002-05-21 21:17:43 +00001415 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001416 {
1417 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1418 };
1419
1420
1421 /* Actually parse the glyph info and bitmaps. */
1422 static FT_Error
1423 _bdf_parse_glyphs( char* line,
1424 unsigned long linelen,
1425 unsigned long lineno,
1426 void* call_data,
1427 void* client_data )
1428 {
1429 int c, mask_index;
1430 char* s;
1431 unsigned char* bp;
1432 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001433
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001434 _bdf_parse_t* p;
1435 bdf_glyph_t* glyph;
1436 bdf_font_t* font;
1437
1438 FT_Memory memory;
1439 FT_Error error = BDF_Err_Ok;
1440
Werner Lemberg319c00d2003-04-23 19:48:24 +00001441 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001442 FT_UNUSED( lineno ); /* only used in debug mode */
1443
1444
Werner Lemberg319c00d2003-04-23 19:48:24 +00001445 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001446
1447 font = p->font;
1448 memory = font->memory;
1449
1450 /* Check for a comment. */
1451 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1452 {
1453 linelen -= 7;
1454
1455 s = line + 7;
1456 if ( *s != 0 )
1457 {
1458 s++;
1459 linelen--;
1460 }
1461 error = _bdf_add_comment( p->font, s, linelen );
1462 goto Exit;
1463 }
1464
1465 /* The very first thing expected is the number of glyphs. */
1466 if ( !( p->flags & _BDF_GLYPHS ) )
1467 {
1468 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1469 {
1470 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1471 error = BDF_Err_Missing_Chars_Field;
1472 goto Exit;
1473 }
1474
David Turner68df4f72005-03-15 18:18:57 +00001475 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001476 if ( error )
1477 goto Exit;
1478 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1479
1480 /* Make sure the number of glyphs is non-zero. */
1481 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001482 font->glyphs_size = 64;
1483
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001484 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1485 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001486
David Turner993a8d02002-05-18 12:03:43 +00001487 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001488
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001489 goto Exit;
1490 }
1491
1492 /* Check for the ENDFONT field. */
1493 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1494 {
1495 /* Sort the glyphs by encoding. */
1496 ft_qsort( (char *)font->glyphs,
1497 font->glyphs_used,
1498 sizeof ( bdf_glyph_t ),
1499 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001500
1501 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001502
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001503 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001504 }
1505
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001506 /* Check for the ENDCHAR field. */
1507 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1508 {
1509 p->glyph_enc = 0;
1510 p->flags &= ~_BDF_GLYPH_BITS;
1511
1512 goto Exit;
1513 }
1514
1515 /* Check to see whether a glyph is being scanned but should be */
1516 /* ignored because it is an unencoded glyph. */
1517 if ( ( p->flags & _BDF_GLYPH ) &&
1518 p->glyph_enc == -1 &&
1519 p->opts->keep_unencoded == 0 )
1520 goto Exit;
1521
1522 /* Check for the STARTCHAR field. */
1523 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1524 {
1525 /* Set the character name in the parse info first until the */
1526 /* encoding can be checked for an unencoded character. */
1527 FT_FREE( p->glyph_name );
1528
David Turner68df4f72005-03-15 18:18:57 +00001529 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001530 if ( error )
1531 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001532
David Turner68df4f72005-03-15 18:18:57 +00001533 _bdf_list_shift( &p->list, 1 );
1534
1535 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001536
1537 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1538 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001539
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001540 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1541
1542 p->flags |= _BDF_GLYPH;
1543
1544 goto Exit;
1545 }
1546
1547 /* Check for the ENCODING field. */
1548 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1549 {
1550 if ( !( p->flags & _BDF_GLYPH ) )
1551 {
1552 /* Missing STARTCHAR field. */
1553 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1554 error = BDF_Err_Missing_Startchar_Field;
1555 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001556 }
1557
David Turner68df4f72005-03-15 18:18:57 +00001558 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001559 if ( error )
1560 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001561
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001562 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001563
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001564 /* Check to see whether this encoding has already been encountered. */
1565 /* If it has then change it to unencoded so it gets added if */
1566 /* indicated. */
1567 if ( p->glyph_enc >= 0 )
1568 {
1569 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1570 {
1571 /* Emit a message saying a glyph has been moved to the */
1572 /* unencoded area. */
1573 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1574 p->glyph_enc, p->glyph_name ));
1575 p->glyph_enc = -1;
1576 font->modified = 1;
1577 }
1578 else
1579 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1580 }
1581
1582 if ( p->glyph_enc >= 0 )
1583 {
1584 /* Make sure there are enough glyphs allocated in case the */
1585 /* number of characters happen to be wrong. */
1586 if ( font->glyphs_used == font->glyphs_size )
1587 {
1588 if ( FT_RENEW_ARRAY( font->glyphs,
1589 font->glyphs_size,
1590 font->glyphs_size + 64 ) )
1591 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001592
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001593 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001594 }
1595
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001596 glyph = font->glyphs + font->glyphs_used++;
1597 glyph->name = p->glyph_name;
1598 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001599
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001600 /* Reset the initial glyph info. */
1601 p->glyph_name = 0;
1602 }
1603 else
1604 {
1605 /* Unencoded glyph. Check to see whether it should */
1606 /* be added or not. */
1607 if ( p->opts->keep_unencoded != 0 )
1608 {
1609 /* Allocate the next unencoded glyph. */
1610 if ( font->unencoded_used == font->unencoded_size )
1611 {
David Turner68df4f72005-03-15 18:18:57 +00001612 if ( FT_RENEW_ARRAY( font->unencoded ,
1613 font->unencoded_size,
1614 font->unencoded_size + 4 ) )
1615 goto Exit;
1616
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001617 font->unencoded_size += 4;
1618 }
1619
1620 glyph = font->unencoded + font->unencoded_used;
1621 glyph->name = p->glyph_name;
1622 glyph->encoding = font->unencoded_used++;
1623 }
1624 else
1625 /* Free up the glyph name if the unencoded shouldn't be */
1626 /* kept. */
1627 FT_FREE( p->glyph_name );
1628
1629 p->glyph_name = 0;
1630 }
1631
1632 /* Clear the flags that might be added when width and height are */
1633 /* checked for consistency. */
1634 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1635
1636 p->flags |= _BDF_ENCODING;
1637
1638 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001639 }
1640
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001641 /* Point at the glyph being constructed. */
1642 if ( p->glyph_enc == -1 )
1643 glyph = font->unencoded + ( font->unencoded_used - 1 );
1644 else
1645 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001646
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001647 /* Check to see whether a bitmap is being constructed. */
1648 if ( p->flags & _BDF_BITMAP )
1649 {
1650 /* If there are more rows than are specified in the glyph metrics, */
1651 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001652 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001653 {
1654 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1655 {
1656 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1657 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001658 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001659 }
1660
1661 goto Exit;
1662 }
1663
1664 /* Only collect the number of nibbles indicated by the glyph */
1665 /* metrics. If there are more columns, they are simply ignored. */
1666 nibbles = glyph->bpr << 1;
1667 bp = glyph->bitmap + p->row * glyph->bpr;
1668
David Turner6cda6c02006-02-23 12:37:18 +00001669 for ( i = 0, i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001670 {
1671 c = line[i];
Werner Lemberg233302a2002-05-22 05:41:06 +00001672 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001673 if ( i + 1 < nibbles && ( i & 1 ) )
1674 *++bp = 0;
1675 }
1676
1677 /* Remove possible garbage at the right. */
1678 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001679 if ( glyph->bbx.width )
1680 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001681
1682 /* If any line has extra columns, indicate they have been removed. */
1683 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1684 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1685 {
1686 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1687 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1688 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001689 }
1690
1691 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001692 goto Exit;
1693 }
David Turner993a8d02002-05-18 12:03:43 +00001694
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001695 /* Expect the SWIDTH (scalable width) field next. */
1696 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1697 {
1698 if ( !( p->flags & _BDF_ENCODING ) )
1699 {
1700 /* Missing ENCODING field. */
1701 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1702 error = BDF_Err_Missing_Encoding_Field;
1703 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001704 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001705
David Turner68df4f72005-03-15 18:18:57 +00001706 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001707 if ( error )
1708 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001709
David Turnerb1b47622002-05-21 21:17:43 +00001710 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001711 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001712
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001713 goto Exit;
1714 }
David Turner993a8d02002-05-18 12:03:43 +00001715
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001716 /* Expect the DWIDTH (scalable width) field next. */
1717 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1718 {
David Turner68df4f72005-03-15 18:18:57 +00001719 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001720 if ( error )
1721 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001722
David Turnerb1b47622002-05-21 21:17:43 +00001723 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001724
1725 if ( !( p->flags & _BDF_SWIDTH ) )
1726 {
1727 /* Missing SWIDTH field. Emit an auto correction message and set */
1728 /* the scalable width from the device width. */
1729 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1730
Werner Lemberg02d4d592002-05-28 22:38:05 +00001731 glyph->swidth = (unsigned short)FT_MulDiv(
1732 glyph->dwidth, 72000L,
1733 (FT_Long)( font->point_size *
1734 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001735 }
1736
1737 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001738 goto Exit;
1739 }
David Turner993a8d02002-05-18 12:03:43 +00001740
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001741 /* Expect the BBX field next. */
1742 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1743 {
David Turner68df4f72005-03-15 18:18:57 +00001744 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001745 if ( error )
1746 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001747
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001748 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1749 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1750 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1751 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1752
1753 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001754 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1755 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001756
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001757 /* Determine the overall font bounding box as the characters are */
1758 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001759 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1760 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001761
David Turnerb1b47622002-05-21 21:17:43 +00001762 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001763
Werner Lembergdfa46192004-03-05 09:26:24 +00001764 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1765 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1766 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001767
1768 if ( !( p->flags & _BDF_DWIDTH ) )
1769 {
1770 /* Missing DWIDTH field. Emit an auto correction message and set */
1771 /* the device width to the glyph width. */
1772 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1773 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001774 }
1775
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001776 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1777 /* value if necessary. */
1778 if ( p->opts->correct_metrics != 0 )
1779 {
1780 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001781 unsigned short sw = (unsigned short)FT_MulDiv(
1782 glyph->dwidth, 72000L,
1783 (FT_Long)( font->point_size *
1784 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001785
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001786
1787 if ( sw != glyph->swidth )
1788 {
1789 glyph->swidth = sw;
1790
1791 if ( p->glyph_enc == -1 )
1792 _bdf_set_glyph_modified( font->umod,
1793 font->unencoded_used - 1 );
1794 else
1795 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1796
1797 p->flags |= _BDF_SWIDTH_ADJ;
1798 font->modified = 1;
1799 }
David Turner993a8d02002-05-18 12:03:43 +00001800 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001801
David Turner993a8d02002-05-18 12:03:43 +00001802 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001803 goto Exit;
1804 }
David Turner993a8d02002-05-18 12:03:43 +00001805
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001806 /* And finally, gather up the bitmap. */
1807 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1808 {
1809 if ( !( p->flags & _BDF_BBX ) )
1810 {
1811 /* Missing BBX field. */
1812 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1813 error = BDF_Err_Missing_Bbx_Field;
1814 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001815 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001816
1817 /* Allocate enough space for the bitmap. */
1818 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg233302a2002-05-22 05:41:06 +00001819 glyph->bytes = (unsigned short)( glyph->bpr * glyph->bbx.height );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001820
1821 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1822 goto Exit;
1823
1824 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001825 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001826
1827 goto Exit;
1828 }
1829
1830 error = BDF_Err_Invalid_File_Format;
1831
1832 Exit:
1833 return error;
David Turner993a8d02002-05-18 12:03:43 +00001834 }
1835
David Turner993a8d02002-05-18 12:03:43 +00001836
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001837 /* Load the font properties. */
1838 static FT_Error
1839 _bdf_parse_properties( char* line,
1840 unsigned long linelen,
1841 unsigned long lineno,
1842 void* call_data,
1843 void* client_data )
1844 {
1845 unsigned long vlen;
1846 _bdf_line_func_t* next;
1847 _bdf_parse_t* p;
1848 char* name;
1849 char* value;
1850 char nbuf[128];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001851 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001852
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001853 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001854
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001855
1856 next = (_bdf_line_func_t *)call_data;
1857 p = (_bdf_parse_t *) client_data;
1858
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001859 /* Check for the end of the properties. */
1860 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1861 {
1862 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1863 /* encountered yet, then make sure they are added as properties and */
1864 /* make sure they are set from the font bounding box info. */
1865 /* */
1866 /* This is *always* done regardless of the options, because X11 */
1867 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001868 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001869 {
1870 p->font->font_ascent = p->font->bbx.ascent;
1871 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1872 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
1873 if ( error )
1874 goto Exit;
1875
1876 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1877 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001878 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001879
Werner Lemberg428c2e42003-04-25 05:35:04 +00001880 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001881 {
1882 p->font->font_descent = p->font->bbx.descent;
1883 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1884 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
1885 if ( error )
1886 goto Exit;
1887
1888 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1889 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001890 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001891
David Turner993a8d02002-05-18 12:03:43 +00001892 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001893 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001894
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001895 goto Exit;
1896 }
David Turner993a8d02002-05-18 12:03:43 +00001897
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001898 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1899 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1900 goto Exit;
1901
1902 /* Handle COMMENT fields and properties in a special way to preserve */
1903 /* the spacing. */
1904 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1905 {
David Turner993a8d02002-05-18 12:03:43 +00001906 name = value = line;
1907 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001908 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001909 *value++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001910 error = _bdf_add_property( p->font, name, value );
1911 if ( error )
1912 goto Exit;
1913 }
1914 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1915 {
1916 error = _bdf_add_property( p->font, name, value );
1917 if ( error )
1918 goto Exit;
1919 }
1920 else
1921 {
David Turner68df4f72005-03-15 18:18:57 +00001922 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001923 if ( error )
1924 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001925 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001926
David Turner68df4f72005-03-15 18:18:57 +00001927 _bdf_list_shift( &p->list, 1 );
1928 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001929
1930 error = _bdf_add_property( p->font, name, value );
1931 if ( error )
1932 goto Exit;
1933 }
1934
1935 Exit:
1936 return error;
David Turner993a8d02002-05-18 12:03:43 +00001937 }
1938
David Turner993a8d02002-05-18 12:03:43 +00001939
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001940 /* Load the font header. */
1941 static FT_Error
1942 _bdf_parse_start( char* line,
1943 unsigned long linelen,
1944 unsigned long lineno,
1945 void* call_data,
1946 void* client_data )
1947 {
1948 unsigned long slen;
1949 _bdf_line_func_t* next;
1950 _bdf_parse_t* p;
1951 bdf_font_t* font;
1952 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001953
David Turnerd490e372002-05-28 23:40:37 +00001954 FT_Memory memory = NULL;
1955 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001956
1957 FT_UNUSED( lineno ); /* only used in debug mode */
1958
1959
1960 next = (_bdf_line_func_t *)call_data;
1961 p = (_bdf_parse_t *) client_data;
1962
1963 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00001964 memory = p->font->memory;
1965
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001966 /* Check for a comment. This is done to handle those fonts that have */
1967 /* comments before the STARTFONT line for some reason. */
1968 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1969 {
1970 if ( p->opts->keep_comments != 0 && p->font != 0 )
1971 {
1972 linelen -= 7;
1973
1974 s = line + 7;
1975 if ( *s != 0 )
1976 {
1977 s++;
1978 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00001979 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001980
1981 error = _bdf_add_comment( p->font, s, linelen );
1982 if ( error )
1983 goto Exit;
1984 /* here font is not defined! */
1985 }
1986
1987 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001988 }
1989
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001990 if ( !( p->flags & _BDF_START ) )
1991 {
1992 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00001993
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001994 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
1995 {
1996 /* No STARTFONT field is a good indication of a problem. */
1997 error = BDF_Err_Missing_Startfont_Field;
1998 goto Exit;
1999 }
David Turner993a8d02002-05-18 12:03:43 +00002000
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002001 p->flags = _BDF_START;
2002 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002003
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002004 if ( FT_NEW( font ) )
2005 goto Exit;
2006 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002007
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002008 font->memory = p->memory;
2009 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002010
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002011 { /* setup */
2012 unsigned long i;
2013 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002014
David Turner993a8d02002-05-18 12:03:43 +00002015
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002016 error = hash_init( &(font->proptbl), memory );
2017 if ( error )
2018 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002019 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002020 i < _num_bdf_properties; i++, prop++ )
2021 {
2022 error = hash_insert( prop->name, (void *)i,
2023 &(font->proptbl), memory );
2024 if ( error )
2025 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002026 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002027 }
2028
2029 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2030 goto Exit;
2031 error = hash_init( (hashtable *)p->font->internal,memory );
2032 if ( error )
2033 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002034 p->font->spacing = p->opts->font_spacing;
2035 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002036
2037 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002038 }
2039
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002040 /* Check for the start of the properties. */
2041 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2042 {
David Turner68df4f72005-03-15 18:18:57 +00002043 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002044 if ( error )
2045 goto Exit;
2046 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2047
2048 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2049 goto Exit;
2050
2051 p->flags |= _BDF_PROPS;
2052 *next = _bdf_parse_properties;
2053
2054 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002055 }
2056
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002057 /* Check for the FONTBOUNDINGBOX field. */
2058 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2059 {
2060 if ( !(p->flags & _BDF_SIZE ) )
2061 {
2062 /* Missing the SIZE field. */
2063 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2064 error = BDF_Err_Missing_Size_Field;
2065 goto Exit;
2066 }
2067
David Turner68df4f72005-03-15 18:18:57 +00002068 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002069 if ( error )
2070 goto Exit;
2071
2072 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2073 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2074
2075 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2076 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2077
David Turnerd490e372002-05-28 23:40:37 +00002078 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002079 p->font->bbx.y_offset );
2080
2081 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002082
2083 p->flags |= _BDF_FONT_BBX;
2084
2085 goto Exit;
2086 }
2087
2088 /* The next thing to check for is the FONT field. */
2089 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2090 {
David Turner68df4f72005-03-15 18:18:57 +00002091 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002092 if ( error )
2093 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002094 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002095
David Turner68df4f72005-03-15 18:18:57 +00002096 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002097 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2098 goto Exit;
2099 FT_MEM_COPY( p->font->name, s, slen + 1 );
2100
2101 /* If the font name is an XLFD name, set the spacing to the one in */
2102 /* the font name. If there is no spacing fall back on the default. */
2103 error = _bdf_set_default_spacing( p->font, p->opts );
2104 if ( error )
2105 goto Exit;
2106
2107 p->flags |= _BDF_FONT_NAME;
2108
2109 goto Exit;
2110 }
2111
2112 /* Check for the SIZE field. */
2113 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2114 {
2115 if ( !( p->flags & _BDF_FONT_NAME ) )
2116 {
2117 /* Missing the FONT field. */
2118 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2119 error = BDF_Err_Missing_Font_Field;
2120 goto Exit;
2121 }
2122
David Turner68df4f72005-03-15 18:18:57 +00002123 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002124 if ( error )
2125 goto Exit;
2126
2127 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2128 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2129 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2130
2131 /* Check for the bits per pixel field. */
2132 if ( p->list.used == 5 )
2133 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002134 unsigned short bitcount, i, shift;
2135
2136
2137 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2138
2139 /* Only values 1, 2, 4, 8 are allowed. */
2140 shift = p->font->bpp;
2141 bitcount = 0;
2142 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002143 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002144 if ( shift & 1 )
2145 bitcount = i;
2146 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002147 }
David Turner993a8d02002-05-18 12:03:43 +00002148
Werner Lembergbd8e3242002-06-12 08:43:58 +00002149 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002150
2151 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002152 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002153 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002154 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002155 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002156 }
2157 }
2158 else
2159 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002160
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002161 p->flags |= _BDF_SIZE;
2162
2163 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002164 }
2165
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002166 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002167
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002168 Exit:
2169 return error;
2170 }
David Turner993a8d02002-05-18 12:03:43 +00002171
2172
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002173 /*************************************************************************/
2174 /* */
2175 /* API. */
2176 /* */
2177 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002178
David Turner993a8d02002-05-18 12:03:43 +00002179
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002180 FT_LOCAL_DEF( FT_Error )
2181 bdf_load_font( FT_Stream stream,
2182 FT_Memory extmemory,
2183 bdf_options_t* opts,
2184 bdf_font_t* *font )
2185 {
2186 unsigned long lineno;
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002187 _bdf_parse_t *p;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002188
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002189 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002190 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002191
2192
David Turner68df4f72005-03-15 18:18:57 +00002193 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002194 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002195
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002196 memory = NULL;
2197 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2198 p->minlb = 32767;
2199 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002200
David Turner68df4f72005-03-15 18:18:57 +00002201 _bdf_list_init( &p->list, extmemory );
2202
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002203 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002204 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002205 if ( error )
2206 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002207
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002208 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002209 {
2210 /* If the font is not proportional, set the font's monowidth */
2211 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002212 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002213
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002214 if ( p->font->spacing != BDF_PROPORTIONAL )
2215 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002216
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002217 /* If the number of glyphs loaded is not that of the original count, */
2218 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002219 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002220 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002221 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2222 p->font->glyphs_used + p->font->unencoded_used ));
2223 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002224 }
2225
2226 /* Once the font has been loaded, adjust the overall font metrics if */
2227 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002228 if ( p->opts->correct_metrics != 0 &&
2229 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002230 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002231 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002232 {
2233 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002234 p->font->bbx.width, p->maxrb - p->minlb ));
2235 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2236 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002237 }
2238
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002239 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002240 {
2241 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002242 p->font->bbx.x_offset, p->minlb ));
2243 p->font->bbx.x_offset = p->minlb;
2244 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002245 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002246
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002247 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002248 {
2249 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002250 p->font->bbx.ascent, p->maxas ));
2251 p->font->bbx.ascent = p->maxas;
2252 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002253 }
2254
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002255 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002256 {
2257 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002258 p->font->bbx.descent, p->maxds ));
2259 p->font->bbx.descent = p->maxds;
2260 p->font->bbx.y_offset = (short)( -p->maxds );
2261 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002262 }
2263
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002264 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002265 {
2266 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002267 p->font->bbx.height, p->maxas + p->maxds ));
2268 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002269 }
2270
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002271 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002272 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2273 }
David Turner993a8d02002-05-18 12:03:43 +00002274 }
2275
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002276 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002277 {
2278 {
2279 /* The ENDFONT field was never reached or did not exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002280 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002281 /* Error happened while parsing header. */
2282 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2283 else
2284 /* Error happened when parsing glyphs. */
2285 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2286 }
David Turner993a8d02002-05-18 12:03:43 +00002287 }
2288
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002289 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002290 {
2291 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002292 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002293
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002294 if ( p->font->comments_len > 0 ) {
2295 if ( FT_RENEW_ARRAY( p->font->comments,
2296 p->font->comments_len,
2297 p->font->comments_len + 1 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002298 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002299
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002300 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002301 }
David Turner993a8d02002-05-18 12:03:43 +00002302 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002303 else if ( error == BDF_Err_Ok )
2304 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002305
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002306 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002307
2308 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002309 if ( p )
2310 {
David Turner68df4f72005-03-15 18:18:57 +00002311 _bdf_list_done( &p->list );
2312
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002313 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002314
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002315 FT_FREE( p );
2316 }
2317
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002318 return error;
2319 }
David Turner993a8d02002-05-18 12:03:43 +00002320
2321
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002322 FT_LOCAL_DEF( void )
2323 bdf_free_font( bdf_font_t* font )
2324 {
2325 bdf_property_t* prop;
2326 unsigned long i;
2327 bdf_glyph_t* glyphs;
2328 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002329
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002330
2331 if ( font == 0 )
2332 return;
David Turner993a8d02002-05-18 12:03:43 +00002333
2334 memory = font->memory;
2335
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002336 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002337
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002338 /* Free up the internal hash table of property names. */
2339 if ( font->internal )
2340 {
2341 hash_free( (hashtable *)font->internal, memory );
2342 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002343 }
2344
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002345 /* Free up the comment info. */
2346 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002347
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002348 /* Free up the properties. */
2349 for ( i = 0; i < font->props_size; i++ )
2350 {
2351 if ( font->props[i].format == BDF_ATOM )
2352 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002353 }
2354
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002355 FT_FREE( font->props );
2356
2357 /* Free up the character info. */
2358 for ( i = 0, glyphs = font->glyphs;
2359 i < font->glyphs_used; i++, glyphs++ )
2360 {
2361 FT_FREE( glyphs->name );
2362 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002363 }
2364
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002365 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2366 i++, glyphs++ )
2367 {
2368 FT_FREE( glyphs->name );
2369 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002370 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002371
2372 FT_FREE( font->glyphs );
2373 FT_FREE( font->unencoded );
2374
2375 /* Free up the overflow storage if it was used. */
2376 for ( i = 0, glyphs = font->overflow.glyphs;
2377 i < font->overflow.glyphs_used; i++, glyphs++ )
2378 {
2379 FT_FREE( glyphs->name );
2380 FT_FREE( glyphs->bitmap );
2381 }
2382
2383 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002384
2385 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002386 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002387
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002388 /* Free up the user defined properties. */
2389 for (prop = font->user_props, i = 0;
2390 i < font->nuser_props; i++, prop++ )
2391 {
2392 FT_FREE( prop->name );
2393 if ( prop->format == BDF_ATOM )
2394 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002395 }
David Turner993a8d02002-05-18 12:03:43 +00002396
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002397 FT_FREE( font->user_props );
2398
2399 /* FREE( font ); */ /* XXX Fixme */
2400 }
David Turner993a8d02002-05-18 12:03:43 +00002401
2402
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002403 FT_LOCAL_DEF( bdf_property_t * )
2404 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002405 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002406 {
2407 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002408
David Turner993a8d02002-05-18 12:03:43 +00002409
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002410 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002411 return 0;
2412
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002413 hn = hash_lookup( name, (hashtable *)font->internal );
2414
2415 return hn ? ( font->props + (unsigned long)hn->data ) : 0;
2416 }
2417
2418
2419/* END */