blob: 7737e54cb93272b24b6df831a20c8d390dc83b75 [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"
Werner Lemberg26170df2006-03-26 07:19:07 +00001095#define ERRMSG4 "[line %ld] BBX too big.\n"
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001096
1097
1098 static FT_Error
1099 _bdf_add_comment( bdf_font_t* font,
1100 char* comment,
1101 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001102 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001103 char* cp;
1104 FT_Memory memory = font->memory;
1105 FT_Error error = BDF_Err_Ok;
1106
1107
David Turner68df4f72005-03-15 18:18:57 +00001108 if ( FT_RENEW_ARRAY( font->comments,
1109 font->comments_len,
1110 font->comments_len + len + 1 ) )
1111 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001112
1113 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001114
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001115 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001116 cp[len] = '\n';
1117
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001118 font->comments_len += len + 1;
1119
1120 Exit:
1121 return error;
David Turner993a8d02002-05-18 12:03:43 +00001122 }
1123
David Turner993a8d02002-05-18 12:03:43 +00001124
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001125 /* Set the spacing from the font name if it exists, or set it to the */
1126 /* default specified in the options. */
1127 static FT_Error
1128 _bdf_set_default_spacing( bdf_font_t* font,
1129 bdf_options_t* opts )
David Turner993a8d02002-05-18 12:03:43 +00001130 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001131 unsigned long len;
1132 char name[128];
1133 _bdf_list_t list;
1134 FT_Memory memory;
1135 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001136
David Turner993a8d02002-05-18 12:03:43 +00001137
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001138 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1139 {
1140 error = BDF_Err_Invalid_Argument;
1141 goto Exit;
1142 }
David Turner993a8d02002-05-18 12:03:43 +00001143
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001144 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001145
David Turner68df4f72005-03-15 18:18:57 +00001146 _bdf_list_init( &list, memory );
1147
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001148 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001149
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001150 len = (unsigned long)( ft_strlen( font->name ) + 1 );
1151 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001152
David Turner68df4f72005-03-15 18:18:57 +00001153 error = _bdf_list_split( &list, (char *)"-", name, len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001154 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001155 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001156
1157 if ( list.used == 15 )
1158 {
1159 switch ( list.field[11][0] )
1160 {
1161 case 'C':
1162 case 'c':
1163 font->spacing = BDF_CHARCELL;
1164 break;
1165 case 'M':
1166 case 'm':
1167 font->spacing = BDF_MONOWIDTH;
1168 break;
1169 case 'P':
1170 case 'p':
1171 font->spacing = BDF_PROPORTIONAL;
1172 break;
David Turner993a8d02002-05-18 12:03:43 +00001173 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001174 }
1175
David Turner68df4f72005-03-15 18:18:57 +00001176 Fail:
1177 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001178
1179 Exit:
1180 return error;
David Turner993a8d02002-05-18 12:03:43 +00001181 }
David Turner993a8d02002-05-18 12:03:43 +00001182
1183
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001184 /* Determine whether the property is an atom or not. If it is, then */
1185 /* clean it up so the double quotes are removed if they exist. */
1186 static int
1187 _bdf_is_atom( char* line,
1188 unsigned long linelen,
1189 char** name,
1190 char** value,
1191 bdf_font_t* font )
1192 {
1193 int hold;
1194 char *sp, *ep;
1195 bdf_property_t* p;
1196
David Turner993a8d02002-05-18 12:03:43 +00001197
1198 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001199
1200 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001201 ep++;
1202
1203 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001204 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001205 {
1206 hold = *ep;
1207 *ep = 0;
1208 }
1209
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001210 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001211
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001212 /* Restore the character that was saved before any return can happen. */
1213 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001214 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001215
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001216 /* If the property exists and is not an atom, just return here. */
1217 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001218 return 0;
1219
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001220 /* The property is an atom. Trim all leading and trailing whitespace */
1221 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001222 sp = ep;
1223 ep = line + linelen;
1224
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001225 /* Trim the leading whitespace if it exists. */
David Turner993a8d02002-05-18 12:03:43 +00001226 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001227 while ( *sp &&
1228 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001229 sp++;
1230
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001231 /* Trim the leading double quote if it exists. */
1232 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001233 sp++;
1234 *value = sp;
1235
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001236 /* Trim the trailing whitespace if it exists. */
1237 while ( ep > sp &&
1238 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001239 *--ep = 0;
1240
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001241 /* Trim the trailing double quote if it exists. */
1242 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001243 *--ep = 0;
1244
1245 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001246 }
David Turner993a8d02002-05-18 12:03:43 +00001247
1248
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001249 static FT_Error
1250 _bdf_add_property( bdf_font_t* font,
1251 char* name,
1252 char* value )
1253 {
1254 unsigned long propid;
1255 hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001256 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
David Turnerc0f9c4a2007-02-12 14:55:03 +00001274 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001275 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001276 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001277 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001278 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001279 break;
1280
1281 case BDF_INTEGER:
1282 fp->value.int32 = _bdf_atol( value, 0, 10 );
1283 break;
1284
1285 case BDF_CARDINAL:
1286 fp->value.card32 = _bdf_atoul( value, 0, 10 );
1287 break;
David Turnerd490e372002-05-28 23:40:37 +00001288
David Turnerb1b47622002-05-21 21:17:43 +00001289 default:
1290 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001291 }
David Turnerd490e372002-05-28 23:40:37 +00001292
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001293 goto Exit;
1294 }
1295
1296 /* See whether this property type exists yet or not. */
1297 /* If not, create it. */
1298 hn = hash_lookup( name, &(font->proptbl) );
1299 if ( hn == 0 )
1300 {
1301 error = bdf_create_property( name, BDF_ATOM, font );
1302 if ( error )
1303 goto Exit;
1304 hn = hash_lookup( name, &(font->proptbl) );
1305 }
1306
1307 /* Allocate another property if this is overflow. */
1308 if ( font->props_used == font->props_size )
1309 {
1310 if ( font->props_size == 0 )
1311 {
1312 if ( FT_NEW_ARRAY( font->props, 1 ) )
1313 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001314 }
1315 else
1316 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001317 if ( FT_RENEW_ARRAY( font->props,
1318 font->props_size,
1319 font->props_size + 1 ) )
1320 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001321 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001322
David Turner993a8d02002-05-18 12:03:43 +00001323 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001324 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001325 font->props_size++;
1326 }
1327
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001328 propid = (unsigned long)hn->data;
1329 if ( propid >= _num_bdf_properties )
1330 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001331 else
David Turnerb1b47622002-05-21 21:17:43 +00001332 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001333
1334 fp = font->props + font->props_used;
1335
1336 fp->name = prop->name;
1337 fp->format = prop->format;
1338 fp->builtin = prop->builtin;
1339
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001340 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001341 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001342 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001343 fp->value.atom = 0;
1344 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001345 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001346 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001347 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001348 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001349 break;
David Turner993a8d02002-05-18 12:03:43 +00001350
1351 case BDF_INTEGER:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001352 fp->value.int32 = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001353 break;
1354
1355 case BDF_CARDINAL:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001356 fp->value.card32 = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001357 break;
David Turner993a8d02002-05-18 12:03:43 +00001358 }
1359
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001360 /* If the property happens to be a comment, then it doesn't need */
1361 /* to be added to the internal hash table. */
1362 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) {
1363 /* Add the property to the font property table. */
1364 error = hash_insert( fp->name,
1365 (void *)font->props_used,
1366 (hashtable *)font->internal,
1367 memory );
1368 if ( error )
1369 goto Exit;
1370 }
David Turner993a8d02002-05-18 12:03:43 +00001371
1372 font->props_used++;
1373
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001374 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1375 /* property needs to be located if it exists in the property list, the */
1376 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1377 /* present, and the SPACING property should override the default */
1378 /* spacing. */
1379 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
Werner Lemberg8ef41832004-06-22 12:28:17 +00001380 font->default_char = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001381 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001382 font->font_ascent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001383 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001384 font->font_descent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001385 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001386 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001387 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001388 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001389 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001390 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001391 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001392 font->spacing = BDF_CHARCELL;
1393 }
1394
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001395 Exit:
1396 return error;
David Turner993a8d02002-05-18 12:03:43 +00001397 }
1398
David Turner993a8d02002-05-18 12:03:43 +00001399
David Turnerb1b47622002-05-21 21:17:43 +00001400 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001401 {
1402 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1403 };
1404
1405
1406 /* Actually parse the glyph info and bitmaps. */
1407 static FT_Error
1408 _bdf_parse_glyphs( char* line,
1409 unsigned long linelen,
1410 unsigned long lineno,
1411 void* call_data,
1412 void* client_data )
1413 {
1414 int c, mask_index;
1415 char* s;
1416 unsigned char* bp;
1417 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001418
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001419 _bdf_parse_t* p;
1420 bdf_glyph_t* glyph;
1421 bdf_font_t* font;
1422
1423 FT_Memory memory;
1424 FT_Error error = BDF_Err_Ok;
1425
Werner Lemberg319c00d2003-04-23 19:48:24 +00001426 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001427 FT_UNUSED( lineno ); /* only used in debug mode */
1428
1429
Werner Lemberg319c00d2003-04-23 19:48:24 +00001430 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001431
1432 font = p->font;
1433 memory = font->memory;
1434
1435 /* Check for a comment. */
1436 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1437 {
1438 linelen -= 7;
1439
1440 s = line + 7;
1441 if ( *s != 0 )
1442 {
1443 s++;
1444 linelen--;
1445 }
1446 error = _bdf_add_comment( p->font, s, linelen );
1447 goto Exit;
1448 }
1449
1450 /* The very first thing expected is the number of glyphs. */
1451 if ( !( p->flags & _BDF_GLYPHS ) )
1452 {
1453 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1454 {
1455 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1456 error = BDF_Err_Missing_Chars_Field;
1457 goto Exit;
1458 }
1459
David Turner68df4f72005-03-15 18:18:57 +00001460 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001461 if ( error )
1462 goto Exit;
1463 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1464
1465 /* Make sure the number of glyphs is non-zero. */
1466 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001467 font->glyphs_size = 64;
1468
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001469 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1470 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001471
David Turner993a8d02002-05-18 12:03:43 +00001472 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001473
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001474 goto Exit;
1475 }
1476
1477 /* Check for the ENDFONT field. */
1478 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1479 {
1480 /* Sort the glyphs by encoding. */
1481 ft_qsort( (char *)font->glyphs,
1482 font->glyphs_used,
1483 sizeof ( bdf_glyph_t ),
1484 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001485
1486 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001487
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001488 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001489 }
1490
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001491 /* Check for the ENDCHAR field. */
1492 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1493 {
1494 p->glyph_enc = 0;
1495 p->flags &= ~_BDF_GLYPH_BITS;
1496
1497 goto Exit;
1498 }
1499
1500 /* Check to see whether a glyph is being scanned but should be */
1501 /* ignored because it is an unencoded glyph. */
1502 if ( ( p->flags & _BDF_GLYPH ) &&
1503 p->glyph_enc == -1 &&
1504 p->opts->keep_unencoded == 0 )
1505 goto Exit;
1506
1507 /* Check for the STARTCHAR field. */
1508 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1509 {
1510 /* Set the character name in the parse info first until the */
1511 /* encoding can be checked for an unencoded character. */
1512 FT_FREE( p->glyph_name );
1513
David Turner68df4f72005-03-15 18:18:57 +00001514 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001515 if ( error )
1516 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001517
David Turner68df4f72005-03-15 18:18:57 +00001518 _bdf_list_shift( &p->list, 1 );
1519
1520 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001521
1522 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1523 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001524
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001525 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1526
1527 p->flags |= _BDF_GLYPH;
1528
1529 goto Exit;
1530 }
1531
1532 /* Check for the ENCODING field. */
1533 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1534 {
1535 if ( !( p->flags & _BDF_GLYPH ) )
1536 {
1537 /* Missing STARTCHAR field. */
1538 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1539 error = BDF_Err_Missing_Startchar_Field;
1540 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001541 }
1542
David Turner68df4f72005-03-15 18:18:57 +00001543 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001544 if ( error )
1545 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001546
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001547 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001548
David Turner481838e2006-02-23 12:40:14 +00001549 /* Check that the encoding is in the range [0,65536] because */
1550 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lembergd4303da2006-02-23 21:01:34 +00001551 if ( (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
David Turner481838e2006-02-23 12:40:14 +00001552 {
1553 error = BDF_Err_Invalid_File_Format;
1554 goto Exit;
1555 }
1556
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001557 /* Check to see whether this encoding has already been encountered. */
1558 /* If it has then change it to unencoded so it gets added if */
1559 /* indicated. */
1560 if ( p->glyph_enc >= 0 )
1561 {
1562 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1563 {
1564 /* Emit a message saying a glyph has been moved to the */
1565 /* unencoded area. */
1566 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1567 p->glyph_enc, p->glyph_name ));
1568 p->glyph_enc = -1;
1569 font->modified = 1;
1570 }
1571 else
1572 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1573 }
1574
1575 if ( p->glyph_enc >= 0 )
1576 {
1577 /* Make sure there are enough glyphs allocated in case the */
1578 /* number of characters happen to be wrong. */
1579 if ( font->glyphs_used == font->glyphs_size )
1580 {
1581 if ( FT_RENEW_ARRAY( font->glyphs,
1582 font->glyphs_size,
1583 font->glyphs_size + 64 ) )
1584 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001585
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001586 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001587 }
1588
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001589 glyph = font->glyphs + font->glyphs_used++;
1590 glyph->name = p->glyph_name;
1591 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001592
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001593 /* Reset the initial glyph info. */
1594 p->glyph_name = 0;
1595 }
1596 else
1597 {
1598 /* Unencoded glyph. Check to see whether it should */
1599 /* be added or not. */
1600 if ( p->opts->keep_unencoded != 0 )
1601 {
1602 /* Allocate the next unencoded glyph. */
1603 if ( font->unencoded_used == font->unencoded_size )
1604 {
David Turner68df4f72005-03-15 18:18:57 +00001605 if ( FT_RENEW_ARRAY( font->unencoded ,
1606 font->unencoded_size,
1607 font->unencoded_size + 4 ) )
1608 goto Exit;
1609
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001610 font->unencoded_size += 4;
1611 }
1612
1613 glyph = font->unencoded + font->unencoded_used;
1614 glyph->name = p->glyph_name;
1615 glyph->encoding = font->unencoded_used++;
1616 }
1617 else
1618 /* Free up the glyph name if the unencoded shouldn't be */
1619 /* kept. */
1620 FT_FREE( p->glyph_name );
1621
1622 p->glyph_name = 0;
1623 }
1624
1625 /* Clear the flags that might be added when width and height are */
1626 /* checked for consistency. */
1627 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1628
1629 p->flags |= _BDF_ENCODING;
1630
1631 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001632 }
1633
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001634 /* Point at the glyph being constructed. */
1635 if ( p->glyph_enc == -1 )
1636 glyph = font->unencoded + ( font->unencoded_used - 1 );
1637 else
1638 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001639
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001640 /* Check to see whether a bitmap is being constructed. */
1641 if ( p->flags & _BDF_BITMAP )
1642 {
1643 /* If there are more rows than are specified in the glyph metrics, */
1644 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001645 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001646 {
1647 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1648 {
1649 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1650 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001651 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001652 }
1653
1654 goto Exit;
1655 }
1656
1657 /* Only collect the number of nibbles indicated by the glyph */
1658 /* metrics. If there are more columns, they are simply ignored. */
1659 nibbles = glyph->bpr << 1;
1660 bp = glyph->bitmap + p->row * glyph->bpr;
1661
David Turnerb698eed2006-02-23 14:50:13 +00001662 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001663 {
1664 c = line[i];
Werner Lemberg233302a2002-05-22 05:41:06 +00001665 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001666 if ( i + 1 < nibbles && ( i & 1 ) )
1667 *++bp = 0;
1668 }
1669
1670 /* Remove possible garbage at the right. */
1671 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001672 if ( glyph->bbx.width )
1673 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001674
1675 /* If any line has extra columns, indicate they have been removed. */
1676 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1677 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1678 {
1679 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1680 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1681 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001682 }
1683
1684 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001685 goto Exit;
1686 }
David Turner993a8d02002-05-18 12:03:43 +00001687
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001688 /* Expect the SWIDTH (scalable width) field next. */
1689 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1690 {
1691 if ( !( p->flags & _BDF_ENCODING ) )
1692 {
1693 /* Missing ENCODING field. */
1694 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1695 error = BDF_Err_Missing_Encoding_Field;
1696 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001697 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001698
David Turner68df4f72005-03-15 18:18:57 +00001699 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001700 if ( error )
1701 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001702
David Turnerb1b47622002-05-21 21:17:43 +00001703 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001704 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001705
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001706 goto Exit;
1707 }
David Turner993a8d02002-05-18 12:03:43 +00001708
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001709 /* Expect the DWIDTH (scalable width) field next. */
1710 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1711 {
David Turner68df4f72005-03-15 18:18:57 +00001712 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001713 if ( error )
1714 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001715
David Turnerb1b47622002-05-21 21:17:43 +00001716 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001717
1718 if ( !( p->flags & _BDF_SWIDTH ) )
1719 {
1720 /* Missing SWIDTH field. Emit an auto correction message and set */
1721 /* the scalable width from the device width. */
1722 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1723
Werner Lemberg02d4d592002-05-28 22:38:05 +00001724 glyph->swidth = (unsigned short)FT_MulDiv(
1725 glyph->dwidth, 72000L,
1726 (FT_Long)( font->point_size *
1727 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001728 }
1729
1730 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001731 goto Exit;
1732 }
David Turner993a8d02002-05-18 12:03:43 +00001733
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001734 /* Expect the BBX field next. */
1735 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1736 {
David Turner68df4f72005-03-15 18:18:57 +00001737 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001738 if ( error )
1739 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001740
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001741 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1742 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1743 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1744 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1745
1746 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001747 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1748 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001749
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001750 /* Determine the overall font bounding box as the characters are */
1751 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001752 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1753 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001754
David Turnerb1b47622002-05-21 21:17:43 +00001755 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001756
Werner Lembergdfa46192004-03-05 09:26:24 +00001757 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1758 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1759 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001760
1761 if ( !( p->flags & _BDF_DWIDTH ) )
1762 {
1763 /* Missing DWIDTH field. Emit an auto correction message and set */
1764 /* the device width to the glyph width. */
1765 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1766 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001767 }
1768
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001769 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1770 /* value if necessary. */
1771 if ( p->opts->correct_metrics != 0 )
1772 {
1773 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001774 unsigned short sw = (unsigned short)FT_MulDiv(
1775 glyph->dwidth, 72000L,
1776 (FT_Long)( font->point_size *
1777 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001778
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001779
1780 if ( sw != glyph->swidth )
1781 {
1782 glyph->swidth = sw;
1783
1784 if ( p->glyph_enc == -1 )
1785 _bdf_set_glyph_modified( font->umod,
1786 font->unencoded_used - 1 );
1787 else
1788 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1789
1790 p->flags |= _BDF_SWIDTH_ADJ;
1791 font->modified = 1;
1792 }
David Turner993a8d02002-05-18 12:03:43 +00001793 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001794
David Turner993a8d02002-05-18 12:03:43 +00001795 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001796 goto Exit;
1797 }
David Turner993a8d02002-05-18 12:03:43 +00001798
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001799 /* And finally, gather up the bitmap. */
1800 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1801 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001802 unsigned long bitmap_size;
1803
1804
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001805 if ( !( p->flags & _BDF_BBX ) )
1806 {
1807 /* Missing BBX field. */
1808 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1809 error = BDF_Err_Missing_Bbx_Field;
1810 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001811 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001812
1813 /* Allocate enough space for the bitmap. */
1814 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001815
1816 bitmap_size = glyph->bpr * glyph->bbx.height;
1817 if ( bitmap_size > 0xFFFFU )
1818 {
1819 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1820 error = BDF_Err_Bbx_Too_Big;
1821 goto Exit;
1822 }
1823 else
1824 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001825
1826 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1827 goto Exit;
1828
1829 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001830 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001831
1832 goto Exit;
1833 }
1834
1835 error = BDF_Err_Invalid_File_Format;
1836
1837 Exit:
1838 return error;
David Turner993a8d02002-05-18 12:03:43 +00001839 }
1840
David Turner993a8d02002-05-18 12:03:43 +00001841
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001842 /* Load the font properties. */
1843 static FT_Error
1844 _bdf_parse_properties( char* line,
1845 unsigned long linelen,
1846 unsigned long lineno,
1847 void* call_data,
1848 void* client_data )
1849 {
1850 unsigned long vlen;
1851 _bdf_line_func_t* next;
1852 _bdf_parse_t* p;
1853 char* name;
1854 char* value;
1855 char nbuf[128];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001856 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001857
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001858 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001859
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001860
1861 next = (_bdf_line_func_t *)call_data;
1862 p = (_bdf_parse_t *) client_data;
1863
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001864 /* Check for the end of the properties. */
1865 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1866 {
1867 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1868 /* encountered yet, then make sure they are added as properties and */
1869 /* make sure they are set from the font bounding box info. */
1870 /* */
1871 /* This is *always* done regardless of the options, because X11 */
1872 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001873 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001874 {
1875 p->font->font_ascent = p->font->bbx.ascent;
1876 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1877 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
1878 if ( error )
1879 goto Exit;
1880
1881 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1882 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001883 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001884
Werner Lemberg428c2e42003-04-25 05:35:04 +00001885 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001886 {
1887 p->font->font_descent = p->font->bbx.descent;
1888 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1889 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
1890 if ( error )
1891 goto Exit;
1892
1893 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1894 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001895 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001896
David Turner993a8d02002-05-18 12:03:43 +00001897 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001898 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001899
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001900 goto Exit;
1901 }
David Turner993a8d02002-05-18 12:03:43 +00001902
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001903 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1904 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1905 goto Exit;
1906
1907 /* Handle COMMENT fields and properties in a special way to preserve */
1908 /* the spacing. */
1909 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1910 {
David Turner993a8d02002-05-18 12:03:43 +00001911 name = value = line;
1912 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001913 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001914 *value++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001915 error = _bdf_add_property( p->font, name, value );
1916 if ( error )
1917 goto Exit;
1918 }
1919 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1920 {
1921 error = _bdf_add_property( p->font, name, value );
1922 if ( error )
1923 goto Exit;
1924 }
1925 else
1926 {
David Turner68df4f72005-03-15 18:18:57 +00001927 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001928 if ( error )
1929 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001930 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001931
David Turner68df4f72005-03-15 18:18:57 +00001932 _bdf_list_shift( &p->list, 1 );
1933 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001934
1935 error = _bdf_add_property( p->font, name, value );
1936 if ( error )
1937 goto Exit;
1938 }
1939
1940 Exit:
1941 return error;
David Turner993a8d02002-05-18 12:03:43 +00001942 }
1943
David Turner993a8d02002-05-18 12:03:43 +00001944
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001945 /* Load the font header. */
1946 static FT_Error
1947 _bdf_parse_start( char* line,
1948 unsigned long linelen,
1949 unsigned long lineno,
1950 void* call_data,
1951 void* client_data )
1952 {
1953 unsigned long slen;
1954 _bdf_line_func_t* next;
1955 _bdf_parse_t* p;
1956 bdf_font_t* font;
1957 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001958
David Turnerd490e372002-05-28 23:40:37 +00001959 FT_Memory memory = NULL;
1960 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001961
1962 FT_UNUSED( lineno ); /* only used in debug mode */
1963
1964
1965 next = (_bdf_line_func_t *)call_data;
1966 p = (_bdf_parse_t *) client_data;
1967
1968 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00001969 memory = p->font->memory;
1970
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001971 /* Check for a comment. This is done to handle those fonts that have */
1972 /* comments before the STARTFONT line for some reason. */
1973 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1974 {
1975 if ( p->opts->keep_comments != 0 && p->font != 0 )
1976 {
1977 linelen -= 7;
1978
1979 s = line + 7;
1980 if ( *s != 0 )
1981 {
1982 s++;
1983 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00001984 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001985
1986 error = _bdf_add_comment( p->font, s, linelen );
1987 if ( error )
1988 goto Exit;
1989 /* here font is not defined! */
1990 }
1991
1992 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001993 }
1994
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001995 if ( !( p->flags & _BDF_START ) )
1996 {
1997 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00001998
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001999 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2000 {
2001 /* No STARTFONT field is a good indication of a problem. */
2002 error = BDF_Err_Missing_Startfont_Field;
2003 goto Exit;
2004 }
David Turner993a8d02002-05-18 12:03:43 +00002005
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002006 p->flags = _BDF_START;
2007 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002008
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002009 if ( FT_NEW( font ) )
2010 goto Exit;
2011 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002012
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002013 font->memory = p->memory;
2014 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002015
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002016 { /* setup */
2017 unsigned long i;
2018 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002019
David Turner993a8d02002-05-18 12:03:43 +00002020
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002021 error = hash_init( &(font->proptbl), memory );
2022 if ( error )
2023 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002024 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002025 i < _num_bdf_properties; i++, prop++ )
2026 {
2027 error = hash_insert( prop->name, (void *)i,
2028 &(font->proptbl), memory );
2029 if ( error )
2030 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002031 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002032 }
2033
2034 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2035 goto Exit;
2036 error = hash_init( (hashtable *)p->font->internal,memory );
2037 if ( error )
2038 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002039 p->font->spacing = p->opts->font_spacing;
2040 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002041
2042 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002043 }
2044
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002045 /* Check for the start of the properties. */
2046 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2047 {
David Turner68df4f72005-03-15 18:18:57 +00002048 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002049 if ( error )
2050 goto Exit;
2051 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2052
2053 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2054 goto Exit;
2055
2056 p->flags |= _BDF_PROPS;
2057 *next = _bdf_parse_properties;
2058
2059 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002060 }
2061
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002062 /* Check for the FONTBOUNDINGBOX field. */
2063 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2064 {
2065 if ( !(p->flags & _BDF_SIZE ) )
2066 {
2067 /* Missing the SIZE field. */
2068 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2069 error = BDF_Err_Missing_Size_Field;
2070 goto Exit;
2071 }
2072
David Turner68df4f72005-03-15 18:18:57 +00002073 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002074 if ( error )
2075 goto Exit;
2076
2077 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2078 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2079
2080 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2081 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2082
David Turnerd490e372002-05-28 23:40:37 +00002083 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002084 p->font->bbx.y_offset );
2085
2086 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002087
2088 p->flags |= _BDF_FONT_BBX;
2089
2090 goto Exit;
2091 }
2092
2093 /* The next thing to check for is the FONT field. */
2094 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2095 {
David Turner68df4f72005-03-15 18:18:57 +00002096 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002097 if ( error )
2098 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002099 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002100
David Turner68df4f72005-03-15 18:18:57 +00002101 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002102 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2103 goto Exit;
2104 FT_MEM_COPY( p->font->name, s, slen + 1 );
2105
2106 /* If the font name is an XLFD name, set the spacing to the one in */
2107 /* the font name. If there is no spacing fall back on the default. */
2108 error = _bdf_set_default_spacing( p->font, p->opts );
2109 if ( error )
2110 goto Exit;
2111
2112 p->flags |= _BDF_FONT_NAME;
2113
2114 goto Exit;
2115 }
2116
2117 /* Check for the SIZE field. */
2118 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2119 {
2120 if ( !( p->flags & _BDF_FONT_NAME ) )
2121 {
2122 /* Missing the FONT field. */
2123 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2124 error = BDF_Err_Missing_Font_Field;
2125 goto Exit;
2126 }
2127
David Turner68df4f72005-03-15 18:18:57 +00002128 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002129 if ( error )
2130 goto Exit;
2131
2132 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2133 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2134 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2135
2136 /* Check for the bits per pixel field. */
2137 if ( p->list.used == 5 )
2138 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002139 unsigned short bitcount, i, shift;
2140
2141
2142 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2143
2144 /* Only values 1, 2, 4, 8 are allowed. */
2145 shift = p->font->bpp;
2146 bitcount = 0;
2147 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002148 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002149 if ( shift & 1 )
2150 bitcount = i;
2151 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002152 }
David Turner993a8d02002-05-18 12:03:43 +00002153
Werner Lembergbd8e3242002-06-12 08:43:58 +00002154 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002155
2156 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002157 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002158 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002159 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002160 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002161 }
2162 }
2163 else
2164 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002165
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002166 p->flags |= _BDF_SIZE;
2167
2168 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002169 }
2170
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002171 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002172
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002173 Exit:
2174 return error;
2175 }
David Turner993a8d02002-05-18 12:03:43 +00002176
2177
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002178 /*************************************************************************/
2179 /* */
2180 /* API. */
2181 /* */
2182 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002183
David Turner993a8d02002-05-18 12:03:43 +00002184
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002185 FT_LOCAL_DEF( FT_Error )
2186 bdf_load_font( FT_Stream stream,
2187 FT_Memory extmemory,
2188 bdf_options_t* opts,
2189 bdf_font_t* *font )
2190 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002191 unsigned long lineno = 0; /* make compiler happy */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002192 _bdf_parse_t *p;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002193
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002194 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002195 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002196
2197
David Turner68df4f72005-03-15 18:18:57 +00002198 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002199 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002200
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002201 memory = NULL;
2202 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2203 p->minlb = 32767;
2204 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002205
David Turner68df4f72005-03-15 18:18:57 +00002206 _bdf_list_init( &p->list, extmemory );
2207
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002208 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002209 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002210 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002211 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002212
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002213 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002214 {
2215 /* If the font is not proportional, set the font's monowidth */
2216 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002217 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002218
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002219 if ( p->font->spacing != BDF_PROPORTIONAL )
2220 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002221
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002222 /* If the number of glyphs loaded is not that of the original count, */
2223 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002224 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002225 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002226 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2227 p->font->glyphs_used + p->font->unencoded_used ));
2228 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002229 }
2230
2231 /* Once the font has been loaded, adjust the overall font metrics if */
2232 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002233 if ( p->opts->correct_metrics != 0 &&
2234 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002235 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002236 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002237 {
2238 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002239 p->font->bbx.width, p->maxrb - p->minlb ));
2240 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2241 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002242 }
2243
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002244 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002245 {
2246 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002247 p->font->bbx.x_offset, p->minlb ));
2248 p->font->bbx.x_offset = p->minlb;
2249 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002250 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002251
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002252 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002253 {
2254 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002255 p->font->bbx.ascent, p->maxas ));
2256 p->font->bbx.ascent = p->maxas;
2257 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002258 }
2259
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002260 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002261 {
2262 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002263 p->font->bbx.descent, p->maxds ));
2264 p->font->bbx.descent = p->maxds;
2265 p->font->bbx.y_offset = (short)( -p->maxds );
2266 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002267 }
2268
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002269 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002270 {
2271 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002272 p->font->bbx.height, p->maxas + p->maxds ));
2273 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002274 }
2275
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002276 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002277 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2278 }
David Turner993a8d02002-05-18 12:03:43 +00002279 }
2280
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002281 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002282 {
2283 {
2284 /* The ENDFONT field was never reached or did not exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002285 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002286 /* Error happened while parsing header. */
2287 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2288 else
2289 /* Error happened when parsing glyphs. */
2290 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2291 }
David Turner993a8d02002-05-18 12:03:43 +00002292 }
2293
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002294 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002295 {
2296 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002297 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002298
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002299 if ( p->font->comments_len > 0 ) {
2300 if ( FT_RENEW_ARRAY( p->font->comments,
2301 p->font->comments_len,
2302 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002303 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002304
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002305 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002306 }
David Turner993a8d02002-05-18 12:03:43 +00002307 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002308 else if ( error == BDF_Err_Ok )
2309 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002310
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002311 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002312
2313 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002314 if ( p )
2315 {
David Turner68df4f72005-03-15 18:18:57 +00002316 _bdf_list_done( &p->list );
2317
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002318 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002319
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002320 FT_FREE( p );
2321 }
2322
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002323 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002324
2325 Fail:
2326 bdf_free_font( p->font );
2327
2328 memory = extmemory;
2329
2330 FT_FREE( p->font );
2331
2332 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002333 }
David Turner993a8d02002-05-18 12:03:43 +00002334
2335
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002336 FT_LOCAL_DEF( void )
2337 bdf_free_font( bdf_font_t* font )
2338 {
2339 bdf_property_t* prop;
2340 unsigned long i;
2341 bdf_glyph_t* glyphs;
2342 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002343
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002344
2345 if ( font == 0 )
2346 return;
David Turner993a8d02002-05-18 12:03:43 +00002347
2348 memory = font->memory;
2349
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002350 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002351
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002352 /* Free up the internal hash table of property names. */
2353 if ( font->internal )
2354 {
2355 hash_free( (hashtable *)font->internal, memory );
2356 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002357 }
2358
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002359 /* Free up the comment info. */
2360 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002361
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002362 /* Free up the properties. */
2363 for ( i = 0; i < font->props_size; i++ )
2364 {
2365 if ( font->props[i].format == BDF_ATOM )
2366 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002367 }
2368
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002369 FT_FREE( font->props );
2370
2371 /* Free up the character info. */
2372 for ( i = 0, glyphs = font->glyphs;
2373 i < font->glyphs_used; i++, glyphs++ )
2374 {
2375 FT_FREE( glyphs->name );
2376 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002377 }
2378
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002379 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2380 i++, glyphs++ )
2381 {
2382 FT_FREE( glyphs->name );
2383 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002384 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002385
2386 FT_FREE( font->glyphs );
2387 FT_FREE( font->unencoded );
2388
2389 /* Free up the overflow storage if it was used. */
2390 for ( i = 0, glyphs = font->overflow.glyphs;
2391 i < font->overflow.glyphs_used; i++, glyphs++ )
2392 {
2393 FT_FREE( glyphs->name );
2394 FT_FREE( glyphs->bitmap );
2395 }
2396
2397 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002398
2399 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002400 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002401
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002402 /* Free up the user defined properties. */
2403 for (prop = font->user_props, i = 0;
2404 i < font->nuser_props; i++, prop++ )
2405 {
2406 FT_FREE( prop->name );
2407 if ( prop->format == BDF_ATOM )
2408 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002409 }
David Turner993a8d02002-05-18 12:03:43 +00002410
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002411 FT_FREE( font->user_props );
2412
2413 /* FREE( font ); */ /* XXX Fixme */
2414 }
David Turner993a8d02002-05-18 12:03:43 +00002415
2416
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002417 FT_LOCAL_DEF( bdf_property_t * )
2418 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002419 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002420 {
2421 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002422
David Turner993a8d02002-05-18 12:03:43 +00002423
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002424 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002425 return 0;
2426
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002427 hn = hash_lookup( name, (hashtable *)font->internal );
2428
2429 return hn ? ( font->props + (unsigned long)hn->data ) : 0;
2430 }
2431
2432
2433/* END */