blob: 167acb23b081819406ab7885cebd545fb6eb5eee [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
David Turner481838e2006-02-23 12:40:14 +00001564 /* Check that the encoding is in the range [0,65536] because */
1565 /* otherwise p->have (a bitmap with static size) overflows. */
David Turnerb698eed2006-02-23 14:50:13 +00001566 if ( (size_t)p->glyph_enc >= sizeof(p->have)*8 )
David Turner481838e2006-02-23 12:40:14 +00001567 {
1568 error = BDF_Err_Invalid_File_Format;
1569 goto Exit;
1570 }
1571
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001572 /* Check to see whether this encoding has already been encountered. */
1573 /* If it has then change it to unencoded so it gets added if */
1574 /* indicated. */
1575 if ( p->glyph_enc >= 0 )
1576 {
1577 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1578 {
1579 /* Emit a message saying a glyph has been moved to the */
1580 /* unencoded area. */
1581 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1582 p->glyph_enc, p->glyph_name ));
1583 p->glyph_enc = -1;
1584 font->modified = 1;
1585 }
1586 else
1587 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1588 }
1589
1590 if ( p->glyph_enc >= 0 )
1591 {
1592 /* Make sure there are enough glyphs allocated in case the */
1593 /* number of characters happen to be wrong. */
1594 if ( font->glyphs_used == font->glyphs_size )
1595 {
1596 if ( FT_RENEW_ARRAY( font->glyphs,
1597 font->glyphs_size,
1598 font->glyphs_size + 64 ) )
1599 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001600
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001601 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001602 }
1603
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001604 glyph = font->glyphs + font->glyphs_used++;
1605 glyph->name = p->glyph_name;
1606 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001607
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001608 /* Reset the initial glyph info. */
1609 p->glyph_name = 0;
1610 }
1611 else
1612 {
1613 /* Unencoded glyph. Check to see whether it should */
1614 /* be added or not. */
1615 if ( p->opts->keep_unencoded != 0 )
1616 {
1617 /* Allocate the next unencoded glyph. */
1618 if ( font->unencoded_used == font->unencoded_size )
1619 {
David Turner68df4f72005-03-15 18:18:57 +00001620 if ( FT_RENEW_ARRAY( font->unencoded ,
1621 font->unencoded_size,
1622 font->unencoded_size + 4 ) )
1623 goto Exit;
1624
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001625 font->unencoded_size += 4;
1626 }
1627
1628 glyph = font->unencoded + font->unencoded_used;
1629 glyph->name = p->glyph_name;
1630 glyph->encoding = font->unencoded_used++;
1631 }
1632 else
1633 /* Free up the glyph name if the unencoded shouldn't be */
1634 /* kept. */
1635 FT_FREE( p->glyph_name );
1636
1637 p->glyph_name = 0;
1638 }
1639
1640 /* Clear the flags that might be added when width and height are */
1641 /* checked for consistency. */
1642 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1643
1644 p->flags |= _BDF_ENCODING;
1645
1646 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001647 }
1648
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001649 /* Point at the glyph being constructed. */
1650 if ( p->glyph_enc == -1 )
1651 glyph = font->unencoded + ( font->unencoded_used - 1 );
1652 else
1653 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001654
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001655 /* Check to see whether a bitmap is being constructed. */
1656 if ( p->flags & _BDF_BITMAP )
1657 {
1658 /* If there are more rows than are specified in the glyph metrics, */
1659 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001660 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001661 {
1662 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1663 {
1664 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1665 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001666 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001667 }
1668
1669 goto Exit;
1670 }
1671
1672 /* Only collect the number of nibbles indicated by the glyph */
1673 /* metrics. If there are more columns, they are simply ignored. */
1674 nibbles = glyph->bpr << 1;
1675 bp = glyph->bitmap + p->row * glyph->bpr;
1676
David Turnerb698eed2006-02-23 14:50:13 +00001677 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001678 {
1679 c = line[i];
Werner Lemberg233302a2002-05-22 05:41:06 +00001680 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001681 if ( i + 1 < nibbles && ( i & 1 ) )
1682 *++bp = 0;
1683 }
1684
1685 /* Remove possible garbage at the right. */
1686 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001687 if ( glyph->bbx.width )
1688 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001689
1690 /* If any line has extra columns, indicate they have been removed. */
1691 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1692 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1693 {
1694 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1695 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1696 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001697 }
1698
1699 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001700 goto Exit;
1701 }
David Turner993a8d02002-05-18 12:03:43 +00001702
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001703 /* Expect the SWIDTH (scalable width) field next. */
1704 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1705 {
1706 if ( !( p->flags & _BDF_ENCODING ) )
1707 {
1708 /* Missing ENCODING field. */
1709 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1710 error = BDF_Err_Missing_Encoding_Field;
1711 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001712 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001713
David Turner68df4f72005-03-15 18:18:57 +00001714 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001715 if ( error )
1716 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001717
David Turnerb1b47622002-05-21 21:17:43 +00001718 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001719 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001720
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001721 goto Exit;
1722 }
David Turner993a8d02002-05-18 12:03:43 +00001723
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001724 /* Expect the DWIDTH (scalable width) field next. */
1725 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1726 {
David Turner68df4f72005-03-15 18:18:57 +00001727 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001728 if ( error )
1729 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001730
David Turnerb1b47622002-05-21 21:17:43 +00001731 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001732
1733 if ( !( p->flags & _BDF_SWIDTH ) )
1734 {
1735 /* Missing SWIDTH field. Emit an auto correction message and set */
1736 /* the scalable width from the device width. */
1737 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1738
Werner Lemberg02d4d592002-05-28 22:38:05 +00001739 glyph->swidth = (unsigned short)FT_MulDiv(
1740 glyph->dwidth, 72000L,
1741 (FT_Long)( font->point_size *
1742 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001743 }
1744
1745 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001746 goto Exit;
1747 }
David Turner993a8d02002-05-18 12:03:43 +00001748
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001749 /* Expect the BBX field next. */
1750 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1751 {
David Turner68df4f72005-03-15 18:18:57 +00001752 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001753 if ( error )
1754 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001755
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001756 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1757 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1758 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1759 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1760
1761 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001762 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1763 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001764
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001765 /* Determine the overall font bounding box as the characters are */
1766 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001767 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1768 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001769
David Turnerb1b47622002-05-21 21:17:43 +00001770 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001771
Werner Lembergdfa46192004-03-05 09:26:24 +00001772 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1773 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1774 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001775
1776 if ( !( p->flags & _BDF_DWIDTH ) )
1777 {
1778 /* Missing DWIDTH field. Emit an auto correction message and set */
1779 /* the device width to the glyph width. */
1780 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1781 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001782 }
1783
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001784 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1785 /* value if necessary. */
1786 if ( p->opts->correct_metrics != 0 )
1787 {
1788 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001789 unsigned short sw = (unsigned short)FT_MulDiv(
1790 glyph->dwidth, 72000L,
1791 (FT_Long)( font->point_size *
1792 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001793
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001794
1795 if ( sw != glyph->swidth )
1796 {
1797 glyph->swidth = sw;
1798
1799 if ( p->glyph_enc == -1 )
1800 _bdf_set_glyph_modified( font->umod,
1801 font->unencoded_used - 1 );
1802 else
1803 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1804
1805 p->flags |= _BDF_SWIDTH_ADJ;
1806 font->modified = 1;
1807 }
David Turner993a8d02002-05-18 12:03:43 +00001808 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001809
David Turner993a8d02002-05-18 12:03:43 +00001810 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001811 goto Exit;
1812 }
David Turner993a8d02002-05-18 12:03:43 +00001813
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001814 /* And finally, gather up the bitmap. */
1815 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1816 {
1817 if ( !( p->flags & _BDF_BBX ) )
1818 {
1819 /* Missing BBX field. */
1820 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1821 error = BDF_Err_Missing_Bbx_Field;
1822 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001823 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001824
1825 /* Allocate enough space for the bitmap. */
1826 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg233302a2002-05-22 05:41:06 +00001827 glyph->bytes = (unsigned short)( glyph->bpr * glyph->bbx.height );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001828
1829 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1830 goto Exit;
1831
1832 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001833 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001834
1835 goto Exit;
1836 }
1837
1838 error = BDF_Err_Invalid_File_Format;
1839
1840 Exit:
1841 return error;
David Turner993a8d02002-05-18 12:03:43 +00001842 }
1843
David Turner993a8d02002-05-18 12:03:43 +00001844
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001845 /* Load the font properties. */
1846 static FT_Error
1847 _bdf_parse_properties( char* line,
1848 unsigned long linelen,
1849 unsigned long lineno,
1850 void* call_data,
1851 void* client_data )
1852 {
1853 unsigned long vlen;
1854 _bdf_line_func_t* next;
1855 _bdf_parse_t* p;
1856 char* name;
1857 char* value;
1858 char nbuf[128];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001859 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001860
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001861 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001862
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001863
1864 next = (_bdf_line_func_t *)call_data;
1865 p = (_bdf_parse_t *) client_data;
1866
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001867 /* Check for the end of the properties. */
1868 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1869 {
1870 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1871 /* encountered yet, then make sure they are added as properties and */
1872 /* make sure they are set from the font bounding box info. */
1873 /* */
1874 /* This is *always* done regardless of the options, because X11 */
1875 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001876 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001877 {
1878 p->font->font_ascent = p->font->bbx.ascent;
1879 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1880 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
1881 if ( error )
1882 goto Exit;
1883
1884 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1885 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001886 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001887
Werner Lemberg428c2e42003-04-25 05:35:04 +00001888 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001889 {
1890 p->font->font_descent = p->font->bbx.descent;
1891 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1892 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
1893 if ( error )
1894 goto Exit;
1895
1896 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1897 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001898 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001899
David Turner993a8d02002-05-18 12:03:43 +00001900 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001901 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001902
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001903 goto Exit;
1904 }
David Turner993a8d02002-05-18 12:03:43 +00001905
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001906 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1907 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1908 goto Exit;
1909
1910 /* Handle COMMENT fields and properties in a special way to preserve */
1911 /* the spacing. */
1912 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1913 {
David Turner993a8d02002-05-18 12:03:43 +00001914 name = value = line;
1915 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001916 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001917 *value++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001918 error = _bdf_add_property( p->font, name, value );
1919 if ( error )
1920 goto Exit;
1921 }
1922 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1923 {
1924 error = _bdf_add_property( p->font, name, value );
1925 if ( error )
1926 goto Exit;
1927 }
1928 else
1929 {
David Turner68df4f72005-03-15 18:18:57 +00001930 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001931 if ( error )
1932 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001933 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001934
David Turner68df4f72005-03-15 18:18:57 +00001935 _bdf_list_shift( &p->list, 1 );
1936 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001937
1938 error = _bdf_add_property( p->font, name, value );
1939 if ( error )
1940 goto Exit;
1941 }
1942
1943 Exit:
1944 return error;
David Turner993a8d02002-05-18 12:03:43 +00001945 }
1946
David Turner993a8d02002-05-18 12:03:43 +00001947
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001948 /* Load the font header. */
1949 static FT_Error
1950 _bdf_parse_start( char* line,
1951 unsigned long linelen,
1952 unsigned long lineno,
1953 void* call_data,
1954 void* client_data )
1955 {
1956 unsigned long slen;
1957 _bdf_line_func_t* next;
1958 _bdf_parse_t* p;
1959 bdf_font_t* font;
1960 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001961
David Turnerd490e372002-05-28 23:40:37 +00001962 FT_Memory memory = NULL;
1963 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001964
1965 FT_UNUSED( lineno ); /* only used in debug mode */
1966
1967
1968 next = (_bdf_line_func_t *)call_data;
1969 p = (_bdf_parse_t *) client_data;
1970
1971 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00001972 memory = p->font->memory;
1973
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001974 /* Check for a comment. This is done to handle those fonts that have */
1975 /* comments before the STARTFONT line for some reason. */
1976 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1977 {
1978 if ( p->opts->keep_comments != 0 && p->font != 0 )
1979 {
1980 linelen -= 7;
1981
1982 s = line + 7;
1983 if ( *s != 0 )
1984 {
1985 s++;
1986 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00001987 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001988
1989 error = _bdf_add_comment( p->font, s, linelen );
1990 if ( error )
1991 goto Exit;
1992 /* here font is not defined! */
1993 }
1994
1995 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001996 }
1997
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001998 if ( !( p->flags & _BDF_START ) )
1999 {
2000 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002001
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002002 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2003 {
2004 /* No STARTFONT field is a good indication of a problem. */
2005 error = BDF_Err_Missing_Startfont_Field;
2006 goto Exit;
2007 }
David Turner993a8d02002-05-18 12:03:43 +00002008
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002009 p->flags = _BDF_START;
2010 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002011
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002012 if ( FT_NEW( font ) )
2013 goto Exit;
2014 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002015
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002016 font->memory = p->memory;
2017 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002018
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002019 { /* setup */
2020 unsigned long i;
2021 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002022
David Turner993a8d02002-05-18 12:03:43 +00002023
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002024 error = hash_init( &(font->proptbl), memory );
2025 if ( error )
2026 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002027 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002028 i < _num_bdf_properties; i++, prop++ )
2029 {
2030 error = hash_insert( prop->name, (void *)i,
2031 &(font->proptbl), memory );
2032 if ( error )
2033 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002034 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002035 }
2036
2037 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2038 goto Exit;
2039 error = hash_init( (hashtable *)p->font->internal,memory );
2040 if ( error )
2041 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002042 p->font->spacing = p->opts->font_spacing;
2043 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002044
2045 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002046 }
2047
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002048 /* Check for the start of the properties. */
2049 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2050 {
David Turner68df4f72005-03-15 18:18:57 +00002051 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002052 if ( error )
2053 goto Exit;
2054 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2055
2056 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2057 goto Exit;
2058
2059 p->flags |= _BDF_PROPS;
2060 *next = _bdf_parse_properties;
2061
2062 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002063 }
2064
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002065 /* Check for the FONTBOUNDINGBOX field. */
2066 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2067 {
2068 if ( !(p->flags & _BDF_SIZE ) )
2069 {
2070 /* Missing the SIZE field. */
2071 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2072 error = BDF_Err_Missing_Size_Field;
2073 goto Exit;
2074 }
2075
David Turner68df4f72005-03-15 18:18:57 +00002076 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002077 if ( error )
2078 goto Exit;
2079
2080 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2081 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2082
2083 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2084 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2085
David Turnerd490e372002-05-28 23:40:37 +00002086 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002087 p->font->bbx.y_offset );
2088
2089 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002090
2091 p->flags |= _BDF_FONT_BBX;
2092
2093 goto Exit;
2094 }
2095
2096 /* The next thing to check for is the FONT field. */
2097 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2098 {
David Turner68df4f72005-03-15 18:18:57 +00002099 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002100 if ( error )
2101 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002102 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002103
David Turner68df4f72005-03-15 18:18:57 +00002104 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002105 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2106 goto Exit;
2107 FT_MEM_COPY( p->font->name, s, slen + 1 );
2108
2109 /* If the font name is an XLFD name, set the spacing to the one in */
2110 /* the font name. If there is no spacing fall back on the default. */
2111 error = _bdf_set_default_spacing( p->font, p->opts );
2112 if ( error )
2113 goto Exit;
2114
2115 p->flags |= _BDF_FONT_NAME;
2116
2117 goto Exit;
2118 }
2119
2120 /* Check for the SIZE field. */
2121 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2122 {
2123 if ( !( p->flags & _BDF_FONT_NAME ) )
2124 {
2125 /* Missing the FONT field. */
2126 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2127 error = BDF_Err_Missing_Font_Field;
2128 goto Exit;
2129 }
2130
David Turner68df4f72005-03-15 18:18:57 +00002131 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002132 if ( error )
2133 goto Exit;
2134
2135 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2136 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2137 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2138
2139 /* Check for the bits per pixel field. */
2140 if ( p->list.used == 5 )
2141 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002142 unsigned short bitcount, i, shift;
2143
2144
2145 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2146
2147 /* Only values 1, 2, 4, 8 are allowed. */
2148 shift = p->font->bpp;
2149 bitcount = 0;
2150 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002151 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002152 if ( shift & 1 )
2153 bitcount = i;
2154 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002155 }
David Turner993a8d02002-05-18 12:03:43 +00002156
Werner Lembergbd8e3242002-06-12 08:43:58 +00002157 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002158
2159 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002160 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002161 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002162 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002163 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002164 }
2165 }
2166 else
2167 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002168
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002169 p->flags |= _BDF_SIZE;
2170
2171 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002172 }
2173
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002174 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002175
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002176 Exit:
2177 return error;
2178 }
David Turner993a8d02002-05-18 12:03:43 +00002179
2180
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002181 /*************************************************************************/
2182 /* */
2183 /* API. */
2184 /* */
2185 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002186
David Turner993a8d02002-05-18 12:03:43 +00002187
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002188 FT_LOCAL_DEF( FT_Error )
2189 bdf_load_font( FT_Stream stream,
2190 FT_Memory extmemory,
2191 bdf_options_t* opts,
2192 bdf_font_t* *font )
2193 {
2194 unsigned long lineno;
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002195 _bdf_parse_t *p;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002196
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002197 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002198 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002199
2200
David Turner68df4f72005-03-15 18:18:57 +00002201 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002202 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002203
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002204 memory = NULL;
2205 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2206 p->minlb = 32767;
2207 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002208
David Turner68df4f72005-03-15 18:18:57 +00002209 _bdf_list_init( &p->list, extmemory );
2210
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002211 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002212 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002213 if ( error )
2214 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002215
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002216 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002217 {
2218 /* If the font is not proportional, set the font's monowidth */
2219 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002220 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002221
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002222 if ( p->font->spacing != BDF_PROPORTIONAL )
2223 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002224
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002225 /* If the number of glyphs loaded is not that of the original count, */
2226 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002227 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002228 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002229 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2230 p->font->glyphs_used + p->font->unencoded_used ));
2231 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002232 }
2233
2234 /* Once the font has been loaded, adjust the overall font metrics if */
2235 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002236 if ( p->opts->correct_metrics != 0 &&
2237 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002238 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002239 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002240 {
2241 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002242 p->font->bbx.width, p->maxrb - p->minlb ));
2243 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2244 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002245 }
2246
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002247 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002248 {
2249 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002250 p->font->bbx.x_offset, p->minlb ));
2251 p->font->bbx.x_offset = p->minlb;
2252 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002253 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002254
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002255 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002256 {
2257 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002258 p->font->bbx.ascent, p->maxas ));
2259 p->font->bbx.ascent = p->maxas;
2260 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002261 }
2262
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002263 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002264 {
2265 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002266 p->font->bbx.descent, p->maxds ));
2267 p->font->bbx.descent = p->maxds;
2268 p->font->bbx.y_offset = (short)( -p->maxds );
2269 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002270 }
2271
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002272 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002273 {
2274 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002275 p->font->bbx.height, p->maxas + p->maxds ));
2276 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002277 }
2278
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002279 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002280 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2281 }
David Turner993a8d02002-05-18 12:03:43 +00002282 }
2283
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002284 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002285 {
2286 {
2287 /* The ENDFONT field was never reached or did not exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002288 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002289 /* Error happened while parsing header. */
2290 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2291 else
2292 /* Error happened when parsing glyphs. */
2293 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2294 }
David Turner993a8d02002-05-18 12:03:43 +00002295 }
2296
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002297 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002298 {
2299 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002300 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002301
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002302 if ( p->font->comments_len > 0 ) {
2303 if ( FT_RENEW_ARRAY( p->font->comments,
2304 p->font->comments_len,
2305 p->font->comments_len + 1 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002306 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002307
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002308 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002309 }
David Turner993a8d02002-05-18 12:03:43 +00002310 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002311 else if ( error == BDF_Err_Ok )
2312 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002313
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002314 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002315
2316 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002317 if ( p )
2318 {
David Turner68df4f72005-03-15 18:18:57 +00002319 _bdf_list_done( &p->list );
2320
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002321 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002322
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002323 FT_FREE( p );
2324 }
2325
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002326 return error;
2327 }
David Turner993a8d02002-05-18 12:03:43 +00002328
2329
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002330 FT_LOCAL_DEF( void )
2331 bdf_free_font( bdf_font_t* font )
2332 {
2333 bdf_property_t* prop;
2334 unsigned long i;
2335 bdf_glyph_t* glyphs;
2336 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002337
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002338
2339 if ( font == 0 )
2340 return;
David Turner993a8d02002-05-18 12:03:43 +00002341
2342 memory = font->memory;
2343
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002344 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002345
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002346 /* Free up the internal hash table of property names. */
2347 if ( font->internal )
2348 {
2349 hash_free( (hashtable *)font->internal, memory );
2350 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002351 }
2352
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002353 /* Free up the comment info. */
2354 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002355
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002356 /* Free up the properties. */
2357 for ( i = 0; i < font->props_size; i++ )
2358 {
2359 if ( font->props[i].format == BDF_ATOM )
2360 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002361 }
2362
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002363 FT_FREE( font->props );
2364
2365 /* Free up the character info. */
2366 for ( i = 0, glyphs = font->glyphs;
2367 i < font->glyphs_used; i++, glyphs++ )
2368 {
2369 FT_FREE( glyphs->name );
2370 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002371 }
2372
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002373 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2374 i++, glyphs++ )
2375 {
2376 FT_FREE( glyphs->name );
2377 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002378 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002379
2380 FT_FREE( font->glyphs );
2381 FT_FREE( font->unencoded );
2382
2383 /* Free up the overflow storage if it was used. */
2384 for ( i = 0, glyphs = font->overflow.glyphs;
2385 i < font->overflow.glyphs_used; i++, glyphs++ )
2386 {
2387 FT_FREE( glyphs->name );
2388 FT_FREE( glyphs->bitmap );
2389 }
2390
2391 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002392
2393 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002394 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002395
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002396 /* Free up the user defined properties. */
2397 for (prop = font->user_props, i = 0;
2398 i < font->nuser_props; i++, prop++ )
2399 {
2400 FT_FREE( prop->name );
2401 if ( prop->format == BDF_ATOM )
2402 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002403 }
David Turner993a8d02002-05-18 12:03:43 +00002404
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002405 FT_FREE( font->user_props );
2406
2407 /* FREE( font ); */ /* XXX Fixme */
2408 }
David Turner993a8d02002-05-18 12:03:43 +00002409
2410
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002411 FT_LOCAL_DEF( bdf_property_t * )
2412 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002413 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002414 {
2415 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002416
David Turner993a8d02002-05-18 12:03:43 +00002417
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002418 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002419 return 0;
2420
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002421 hn = hash_lookup( name, (hashtable *)font->internal );
2422
2423 return hn ? ( font->props + (unsigned long)hn->data ) : 0;
2424 }
2425
2426
2427/* END */