blob: 3c928e56344513f7472f8a4972e42956683d3e67 [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;
1256 int len;
1257 bdf_property_t *prop, *fp;
1258 FT_Memory memory = font->memory;
1259 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001260
David Turner993a8d02002-05-18 12:03:43 +00001261
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001262 /* First, check to see if the property already exists in the font. */
1263 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001264 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001265 /* The property already exists in the font, so simply replace */
1266 /* the value of the property with the current value. */
1267 fp = font->props + (unsigned long)hn->data;
1268
David Turnerb1b47622002-05-21 21:17:43 +00001269 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001270 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001271 case BDF_ATOM:
1272 /* Delete the current atom if it exists. */
1273 FT_FREE( fp->value.atom );
1274
1275 if ( value == 0 )
1276 len = 1;
1277 else
1278 len = ft_strlen( value ) + 1;
1279
1280 if ( len > 1 )
1281 {
1282 if ( FT_NEW_ARRAY( fp->value.atom, len ) )
1283 goto Exit;
1284 FT_MEM_COPY( fp->value.atom, value, len );
1285 }
1286 else
1287 fp->value.atom = 0;
1288 break;
1289
1290 case BDF_INTEGER:
1291 fp->value.int32 = _bdf_atol( value, 0, 10 );
1292 break;
1293
1294 case BDF_CARDINAL:
1295 fp->value.card32 = _bdf_atoul( value, 0, 10 );
1296 break;
David Turnerd490e372002-05-28 23:40:37 +00001297
David Turnerb1b47622002-05-21 21:17:43 +00001298 default:
1299 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001300 }
David Turnerd490e372002-05-28 23:40:37 +00001301
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001302 goto Exit;
1303 }
1304
1305 /* See whether this property type exists yet or not. */
1306 /* If not, create it. */
1307 hn = hash_lookup( name, &(font->proptbl) );
1308 if ( hn == 0 )
1309 {
1310 error = bdf_create_property( name, BDF_ATOM, font );
1311 if ( error )
1312 goto Exit;
1313 hn = hash_lookup( name, &(font->proptbl) );
1314 }
1315
1316 /* Allocate another property if this is overflow. */
1317 if ( font->props_used == font->props_size )
1318 {
1319 if ( font->props_size == 0 )
1320 {
1321 if ( FT_NEW_ARRAY( font->props, 1 ) )
1322 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001323 }
1324 else
1325 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001326 if ( FT_RENEW_ARRAY( font->props,
1327 font->props_size,
1328 font->props_size + 1 ) )
1329 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001330 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001331
David Turner993a8d02002-05-18 12:03:43 +00001332 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001333 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001334 font->props_size++;
1335 }
1336
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001337 propid = (unsigned long)hn->data;
1338 if ( propid >= _num_bdf_properties )
1339 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001340 else
David Turnerb1b47622002-05-21 21:17:43 +00001341 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001342
1343 fp = font->props + font->props_used;
1344
1345 fp->name = prop->name;
1346 fp->format = prop->format;
1347 fp->builtin = prop->builtin;
1348
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001349 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001350 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001351 case BDF_ATOM:
1352 if ( value == 0 )
1353 len = 1;
1354 else
1355 len = ft_strlen( value ) + 1;
David Turner993a8d02002-05-18 12:03:43 +00001356
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001357 if ( len > 1 )
1358 {
1359 if ( FT_NEW_ARRAY( fp->value.atom, len ) )
1360 goto Exit;
1361 FT_MEM_COPY( fp->value.atom, value, len );
1362 }
1363 else
1364 fp->value.atom = 0;
1365 break;
David Turner993a8d02002-05-18 12:03:43 +00001366
1367 case BDF_INTEGER:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001368 fp->value.int32 = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001369 break;
1370
1371 case BDF_CARDINAL:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001372 fp->value.card32 = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001373 break;
David Turner993a8d02002-05-18 12:03:43 +00001374 }
1375
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001376 /* If the property happens to be a comment, then it doesn't need */
1377 /* to be added to the internal hash table. */
1378 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) {
1379 /* Add the property to the font property table. */
1380 error = hash_insert( fp->name,
1381 (void *)font->props_used,
1382 (hashtable *)font->internal,
1383 memory );
1384 if ( error )
1385 goto Exit;
1386 }
David Turner993a8d02002-05-18 12:03:43 +00001387
1388 font->props_used++;
1389
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001390 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1391 /* property needs to be located if it exists in the property list, the */
1392 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1393 /* present, and the SPACING property should override the default */
1394 /* spacing. */
1395 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
Werner Lemberg8ef41832004-06-22 12:28:17 +00001396 font->default_char = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001397 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001398 font->font_ascent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001399 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001400 font->font_descent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001401 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001402 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001403 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001404 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001405 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001406 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001407 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001408 font->spacing = BDF_CHARCELL;
1409 }
1410
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001411 Exit:
1412 return error;
David Turner993a8d02002-05-18 12:03:43 +00001413 }
1414
David Turner993a8d02002-05-18 12:03:43 +00001415
David Turnerb1b47622002-05-21 21:17:43 +00001416 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001417 {
1418 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1419 };
1420
1421
1422 /* Actually parse the glyph info and bitmaps. */
1423 static FT_Error
1424 _bdf_parse_glyphs( char* line,
1425 unsigned long linelen,
1426 unsigned long lineno,
1427 void* call_data,
1428 void* client_data )
1429 {
1430 int c, mask_index;
1431 char* s;
1432 unsigned char* bp;
1433 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001434
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001435 _bdf_parse_t* p;
1436 bdf_glyph_t* glyph;
1437 bdf_font_t* font;
1438
1439 FT_Memory memory;
1440 FT_Error error = BDF_Err_Ok;
1441
Werner Lemberg319c00d2003-04-23 19:48:24 +00001442 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001443 FT_UNUSED( lineno ); /* only used in debug mode */
1444
1445
Werner Lemberg319c00d2003-04-23 19:48:24 +00001446 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001447
1448 font = p->font;
1449 memory = font->memory;
1450
1451 /* Check for a comment. */
1452 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1453 {
1454 linelen -= 7;
1455
1456 s = line + 7;
1457 if ( *s != 0 )
1458 {
1459 s++;
1460 linelen--;
1461 }
1462 error = _bdf_add_comment( p->font, s, linelen );
1463 goto Exit;
1464 }
1465
1466 /* The very first thing expected is the number of glyphs. */
1467 if ( !( p->flags & _BDF_GLYPHS ) )
1468 {
1469 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1470 {
1471 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1472 error = BDF_Err_Missing_Chars_Field;
1473 goto Exit;
1474 }
1475
David Turner68df4f72005-03-15 18:18:57 +00001476 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001477 if ( error )
1478 goto Exit;
1479 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1480
1481 /* Make sure the number of glyphs is non-zero. */
1482 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001483 font->glyphs_size = 64;
1484
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001485 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1486 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001487
David Turner993a8d02002-05-18 12:03:43 +00001488 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001489
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001490 goto Exit;
1491 }
1492
1493 /* Check for the ENDFONT field. */
1494 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1495 {
1496 /* Sort the glyphs by encoding. */
1497 ft_qsort( (char *)font->glyphs,
1498 font->glyphs_used,
1499 sizeof ( bdf_glyph_t ),
1500 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001501
1502 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001503
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001504 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001505 }
1506
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001507 /* Check for the ENDCHAR field. */
1508 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1509 {
1510 p->glyph_enc = 0;
1511 p->flags &= ~_BDF_GLYPH_BITS;
1512
1513 goto Exit;
1514 }
1515
1516 /* Check to see whether a glyph is being scanned but should be */
1517 /* ignored because it is an unencoded glyph. */
1518 if ( ( p->flags & _BDF_GLYPH ) &&
1519 p->glyph_enc == -1 &&
1520 p->opts->keep_unencoded == 0 )
1521 goto Exit;
1522
1523 /* Check for the STARTCHAR field. */
1524 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1525 {
1526 /* Set the character name in the parse info first until the */
1527 /* encoding can be checked for an unencoded character. */
1528 FT_FREE( p->glyph_name );
1529
David Turner68df4f72005-03-15 18:18:57 +00001530 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001531 if ( error )
1532 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001533
David Turner68df4f72005-03-15 18:18:57 +00001534 _bdf_list_shift( &p->list, 1 );
1535
1536 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001537
1538 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1539 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001540
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001541 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1542
1543 p->flags |= _BDF_GLYPH;
1544
1545 goto Exit;
1546 }
1547
1548 /* Check for the ENCODING field. */
1549 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1550 {
1551 if ( !( p->flags & _BDF_GLYPH ) )
1552 {
1553 /* Missing STARTCHAR field. */
1554 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1555 error = BDF_Err_Missing_Startchar_Field;
1556 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001557 }
1558
David Turner68df4f72005-03-15 18:18:57 +00001559 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001560 if ( error )
1561 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001562
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001563 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001564
David Turner481838e2006-02-23 12:40:14 +00001565 /* Check that the encoding is in the range [0,65536] because */
1566 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lembergd4303da2006-02-23 21:01:34 +00001567 if ( (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
David Turner481838e2006-02-23 12:40:14 +00001568 {
1569 error = BDF_Err_Invalid_File_Format;
1570 goto Exit;
1571 }
1572
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001573 /* Check to see whether this encoding has already been encountered. */
1574 /* If it has then change it to unencoded so it gets added if */
1575 /* indicated. */
1576 if ( p->glyph_enc >= 0 )
1577 {
1578 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1579 {
1580 /* Emit a message saying a glyph has been moved to the */
1581 /* unencoded area. */
1582 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1583 p->glyph_enc, p->glyph_name ));
1584 p->glyph_enc = -1;
1585 font->modified = 1;
1586 }
1587 else
1588 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1589 }
1590
1591 if ( p->glyph_enc >= 0 )
1592 {
1593 /* Make sure there are enough glyphs allocated in case the */
1594 /* number of characters happen to be wrong. */
1595 if ( font->glyphs_used == font->glyphs_size )
1596 {
1597 if ( FT_RENEW_ARRAY( font->glyphs,
1598 font->glyphs_size,
1599 font->glyphs_size + 64 ) )
1600 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001601
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001602 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001603 }
1604
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001605 glyph = font->glyphs + font->glyphs_used++;
1606 glyph->name = p->glyph_name;
1607 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001608
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001609 /* Reset the initial glyph info. */
1610 p->glyph_name = 0;
1611 }
1612 else
1613 {
1614 /* Unencoded glyph. Check to see whether it should */
1615 /* be added or not. */
1616 if ( p->opts->keep_unencoded != 0 )
1617 {
1618 /* Allocate the next unencoded glyph. */
1619 if ( font->unencoded_used == font->unencoded_size )
1620 {
David Turner68df4f72005-03-15 18:18:57 +00001621 if ( FT_RENEW_ARRAY( font->unencoded ,
1622 font->unencoded_size,
1623 font->unencoded_size + 4 ) )
1624 goto Exit;
1625
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001626 font->unencoded_size += 4;
1627 }
1628
1629 glyph = font->unencoded + font->unencoded_used;
1630 glyph->name = p->glyph_name;
1631 glyph->encoding = font->unencoded_used++;
1632 }
1633 else
1634 /* Free up the glyph name if the unencoded shouldn't be */
1635 /* kept. */
1636 FT_FREE( p->glyph_name );
1637
1638 p->glyph_name = 0;
1639 }
1640
1641 /* Clear the flags that might be added when width and height are */
1642 /* checked for consistency. */
1643 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1644
1645 p->flags |= _BDF_ENCODING;
1646
1647 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001648 }
1649
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001650 /* Point at the glyph being constructed. */
1651 if ( p->glyph_enc == -1 )
1652 glyph = font->unencoded + ( font->unencoded_used - 1 );
1653 else
1654 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001655
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001656 /* Check to see whether a bitmap is being constructed. */
1657 if ( p->flags & _BDF_BITMAP )
1658 {
1659 /* If there are more rows than are specified in the glyph metrics, */
1660 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001661 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001662 {
1663 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1664 {
1665 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1666 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001667 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001668 }
1669
1670 goto Exit;
1671 }
1672
1673 /* Only collect the number of nibbles indicated by the glyph */
1674 /* metrics. If there are more columns, they are simply ignored. */
1675 nibbles = glyph->bpr << 1;
1676 bp = glyph->bitmap + p->row * glyph->bpr;
1677
David Turnerb698eed2006-02-23 14:50:13 +00001678 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001679 {
1680 c = line[i];
Werner Lemberg233302a2002-05-22 05:41:06 +00001681 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001682 if ( i + 1 < nibbles && ( i & 1 ) )
1683 *++bp = 0;
1684 }
1685
1686 /* Remove possible garbage at the right. */
1687 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001688 if ( glyph->bbx.width )
1689 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001690
1691 /* If any line has extra columns, indicate they have been removed. */
1692 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1693 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1694 {
1695 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1696 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1697 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001698 }
1699
1700 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001701 goto Exit;
1702 }
David Turner993a8d02002-05-18 12:03:43 +00001703
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001704 /* Expect the SWIDTH (scalable width) field next. */
1705 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1706 {
1707 if ( !( p->flags & _BDF_ENCODING ) )
1708 {
1709 /* Missing ENCODING field. */
1710 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1711 error = BDF_Err_Missing_Encoding_Field;
1712 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001713 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001714
David Turner68df4f72005-03-15 18:18:57 +00001715 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001716 if ( error )
1717 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001718
David Turnerb1b47622002-05-21 21:17:43 +00001719 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001720 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001721
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001722 goto Exit;
1723 }
David Turner993a8d02002-05-18 12:03:43 +00001724
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001725 /* Expect the DWIDTH (scalable width) field next. */
1726 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1727 {
David Turner68df4f72005-03-15 18:18:57 +00001728 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001729 if ( error )
1730 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001731
David Turnerb1b47622002-05-21 21:17:43 +00001732 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001733
1734 if ( !( p->flags & _BDF_SWIDTH ) )
1735 {
1736 /* Missing SWIDTH field. Emit an auto correction message and set */
1737 /* the scalable width from the device width. */
1738 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1739
Werner Lemberg02d4d592002-05-28 22:38:05 +00001740 glyph->swidth = (unsigned short)FT_MulDiv(
1741 glyph->dwidth, 72000L,
1742 (FT_Long)( font->point_size *
1743 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001744 }
1745
1746 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001747 goto Exit;
1748 }
David Turner993a8d02002-05-18 12:03:43 +00001749
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001750 /* Expect the BBX field next. */
1751 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1752 {
David Turner68df4f72005-03-15 18:18:57 +00001753 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001754 if ( error )
1755 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001756
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001757 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1758 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1759 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1760 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1761
1762 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001763 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1764 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001765
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001766 /* Determine the overall font bounding box as the characters are */
1767 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001768 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1769 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001770
David Turnerb1b47622002-05-21 21:17:43 +00001771 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001772
Werner Lembergdfa46192004-03-05 09:26:24 +00001773 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1774 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1775 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001776
1777 if ( !( p->flags & _BDF_DWIDTH ) )
1778 {
1779 /* Missing DWIDTH field. Emit an auto correction message and set */
1780 /* the device width to the glyph width. */
1781 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1782 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001783 }
1784
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001785 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1786 /* value if necessary. */
1787 if ( p->opts->correct_metrics != 0 )
1788 {
1789 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001790 unsigned short sw = (unsigned short)FT_MulDiv(
1791 glyph->dwidth, 72000L,
1792 (FT_Long)( font->point_size *
1793 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001794
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001795
1796 if ( sw != glyph->swidth )
1797 {
1798 glyph->swidth = sw;
1799
1800 if ( p->glyph_enc == -1 )
1801 _bdf_set_glyph_modified( font->umod,
1802 font->unencoded_used - 1 );
1803 else
1804 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1805
1806 p->flags |= _BDF_SWIDTH_ADJ;
1807 font->modified = 1;
1808 }
David Turner993a8d02002-05-18 12:03:43 +00001809 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001810
David Turner993a8d02002-05-18 12:03:43 +00001811 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001812 goto Exit;
1813 }
David Turner993a8d02002-05-18 12:03:43 +00001814
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001815 /* And finally, gather up the bitmap. */
1816 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1817 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001818 unsigned long bitmap_size;
1819
1820
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001821 if ( !( p->flags & _BDF_BBX ) )
1822 {
1823 /* Missing BBX field. */
1824 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1825 error = BDF_Err_Missing_Bbx_Field;
1826 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001827 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001828
1829 /* Allocate enough space for the bitmap. */
1830 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001831
1832 bitmap_size = glyph->bpr * glyph->bbx.height;
1833 if ( bitmap_size > 0xFFFFU )
1834 {
1835 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1836 error = BDF_Err_Bbx_Too_Big;
1837 goto Exit;
1838 }
1839 else
1840 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001841
1842 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1843 goto Exit;
1844
1845 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001846 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001847
1848 goto Exit;
1849 }
1850
1851 error = BDF_Err_Invalid_File_Format;
1852
1853 Exit:
1854 return error;
David Turner993a8d02002-05-18 12:03:43 +00001855 }
1856
David Turner993a8d02002-05-18 12:03:43 +00001857
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001858 /* Load the font properties. */
1859 static FT_Error
1860 _bdf_parse_properties( char* line,
1861 unsigned long linelen,
1862 unsigned long lineno,
1863 void* call_data,
1864 void* client_data )
1865 {
1866 unsigned long vlen;
1867 _bdf_line_func_t* next;
1868 _bdf_parse_t* p;
1869 char* name;
1870 char* value;
1871 char nbuf[128];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001872 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001873
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001874 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001875
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001876
1877 next = (_bdf_line_func_t *)call_data;
1878 p = (_bdf_parse_t *) client_data;
1879
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001880 /* Check for the end of the properties. */
1881 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1882 {
1883 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1884 /* encountered yet, then make sure they are added as properties and */
1885 /* make sure they are set from the font bounding box info. */
1886 /* */
1887 /* This is *always* done regardless of the options, because X11 */
1888 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001889 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001890 {
1891 p->font->font_ascent = p->font->bbx.ascent;
1892 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1893 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
1894 if ( error )
1895 goto Exit;
1896
1897 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1898 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001899 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001900
Werner Lemberg428c2e42003-04-25 05:35:04 +00001901 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001902 {
1903 p->font->font_descent = p->font->bbx.descent;
1904 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1905 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
1906 if ( error )
1907 goto Exit;
1908
1909 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1910 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001911 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001912
David Turner993a8d02002-05-18 12:03:43 +00001913 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001914 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001915
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001916 goto Exit;
1917 }
David Turner993a8d02002-05-18 12:03:43 +00001918
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001919 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1920 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1921 goto Exit;
1922
1923 /* Handle COMMENT fields and properties in a special way to preserve */
1924 /* the spacing. */
1925 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1926 {
David Turner993a8d02002-05-18 12:03:43 +00001927 name = value = line;
1928 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001929 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001930 *value++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001931 error = _bdf_add_property( p->font, name, value );
1932 if ( error )
1933 goto Exit;
1934 }
1935 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1936 {
1937 error = _bdf_add_property( p->font, name, value );
1938 if ( error )
1939 goto Exit;
1940 }
1941 else
1942 {
David Turner68df4f72005-03-15 18:18:57 +00001943 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001944 if ( error )
1945 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001946 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001947
David Turner68df4f72005-03-15 18:18:57 +00001948 _bdf_list_shift( &p->list, 1 );
1949 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001950
1951 error = _bdf_add_property( p->font, name, value );
1952 if ( error )
1953 goto Exit;
1954 }
1955
1956 Exit:
1957 return error;
David Turner993a8d02002-05-18 12:03:43 +00001958 }
1959
David Turner993a8d02002-05-18 12:03:43 +00001960
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001961 /* Load the font header. */
1962 static FT_Error
1963 _bdf_parse_start( char* line,
1964 unsigned long linelen,
1965 unsigned long lineno,
1966 void* call_data,
1967 void* client_data )
1968 {
1969 unsigned long slen;
1970 _bdf_line_func_t* next;
1971 _bdf_parse_t* p;
1972 bdf_font_t* font;
1973 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001974
David Turnerd490e372002-05-28 23:40:37 +00001975 FT_Memory memory = NULL;
1976 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001977
1978 FT_UNUSED( lineno ); /* only used in debug mode */
1979
1980
1981 next = (_bdf_line_func_t *)call_data;
1982 p = (_bdf_parse_t *) client_data;
1983
1984 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00001985 memory = p->font->memory;
1986
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001987 /* Check for a comment. This is done to handle those fonts that have */
1988 /* comments before the STARTFONT line for some reason. */
1989 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1990 {
1991 if ( p->opts->keep_comments != 0 && p->font != 0 )
1992 {
1993 linelen -= 7;
1994
1995 s = line + 7;
1996 if ( *s != 0 )
1997 {
1998 s++;
1999 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002000 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002001
2002 error = _bdf_add_comment( p->font, s, linelen );
2003 if ( error )
2004 goto Exit;
2005 /* here font is not defined! */
2006 }
2007
2008 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002009 }
2010
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002011 if ( !( p->flags & _BDF_START ) )
2012 {
2013 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002014
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002015 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2016 {
2017 /* No STARTFONT field is a good indication of a problem. */
2018 error = BDF_Err_Missing_Startfont_Field;
2019 goto Exit;
2020 }
David Turner993a8d02002-05-18 12:03:43 +00002021
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002022 p->flags = _BDF_START;
2023 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002024
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002025 if ( FT_NEW( font ) )
2026 goto Exit;
2027 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002028
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002029 font->memory = p->memory;
2030 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002031
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002032 { /* setup */
2033 unsigned long i;
2034 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002035
David Turner993a8d02002-05-18 12:03:43 +00002036
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002037 error = hash_init( &(font->proptbl), memory );
2038 if ( error )
2039 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002040 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002041 i < _num_bdf_properties; i++, prop++ )
2042 {
2043 error = hash_insert( prop->name, (void *)i,
2044 &(font->proptbl), memory );
2045 if ( error )
2046 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002047 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002048 }
2049
2050 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2051 goto Exit;
2052 error = hash_init( (hashtable *)p->font->internal,memory );
2053 if ( error )
2054 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002055 p->font->spacing = p->opts->font_spacing;
2056 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002057
2058 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002059 }
2060
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002061 /* Check for the start of the properties. */
2062 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2063 {
David Turner68df4f72005-03-15 18:18:57 +00002064 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002065 if ( error )
2066 goto Exit;
2067 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2068
2069 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2070 goto Exit;
2071
2072 p->flags |= _BDF_PROPS;
2073 *next = _bdf_parse_properties;
2074
2075 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002076 }
2077
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002078 /* Check for the FONTBOUNDINGBOX field. */
2079 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2080 {
2081 if ( !(p->flags & _BDF_SIZE ) )
2082 {
2083 /* Missing the SIZE field. */
2084 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2085 error = BDF_Err_Missing_Size_Field;
2086 goto Exit;
2087 }
2088
David Turner68df4f72005-03-15 18:18:57 +00002089 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002090 if ( error )
2091 goto Exit;
2092
2093 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2094 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2095
2096 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2097 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2098
David Turnerd490e372002-05-28 23:40:37 +00002099 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002100 p->font->bbx.y_offset );
2101
2102 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002103
2104 p->flags |= _BDF_FONT_BBX;
2105
2106 goto Exit;
2107 }
2108
2109 /* The next thing to check for is the FONT field. */
2110 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2111 {
David Turner68df4f72005-03-15 18:18:57 +00002112 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002113 if ( error )
2114 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002115 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002116
David Turner68df4f72005-03-15 18:18:57 +00002117 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002118 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2119 goto Exit;
2120 FT_MEM_COPY( p->font->name, s, slen + 1 );
2121
2122 /* If the font name is an XLFD name, set the spacing to the one in */
2123 /* the font name. If there is no spacing fall back on the default. */
2124 error = _bdf_set_default_spacing( p->font, p->opts );
2125 if ( error )
2126 goto Exit;
2127
2128 p->flags |= _BDF_FONT_NAME;
2129
2130 goto Exit;
2131 }
2132
2133 /* Check for the SIZE field. */
2134 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2135 {
2136 if ( !( p->flags & _BDF_FONT_NAME ) )
2137 {
2138 /* Missing the FONT field. */
2139 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2140 error = BDF_Err_Missing_Font_Field;
2141 goto Exit;
2142 }
2143
David Turner68df4f72005-03-15 18:18:57 +00002144 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002145 if ( error )
2146 goto Exit;
2147
2148 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2149 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2150 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2151
2152 /* Check for the bits per pixel field. */
2153 if ( p->list.used == 5 )
2154 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002155 unsigned short bitcount, i, shift;
2156
2157
2158 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2159
2160 /* Only values 1, 2, 4, 8 are allowed. */
2161 shift = p->font->bpp;
2162 bitcount = 0;
2163 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002164 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002165 if ( shift & 1 )
2166 bitcount = i;
2167 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002168 }
David Turner993a8d02002-05-18 12:03:43 +00002169
Werner Lembergbd8e3242002-06-12 08:43:58 +00002170 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002171
2172 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002173 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002174 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002175 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002176 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002177 }
2178 }
2179 else
2180 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002181
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002182 p->flags |= _BDF_SIZE;
2183
2184 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002185 }
2186
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002187 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002188
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002189 Exit:
2190 return error;
2191 }
David Turner993a8d02002-05-18 12:03:43 +00002192
2193
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002194 /*************************************************************************/
2195 /* */
2196 /* API. */
2197 /* */
2198 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002199
David Turner993a8d02002-05-18 12:03:43 +00002200
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002201 FT_LOCAL_DEF( FT_Error )
2202 bdf_load_font( FT_Stream stream,
2203 FT_Memory extmemory,
2204 bdf_options_t* opts,
2205 bdf_font_t* *font )
2206 {
2207 unsigned long lineno;
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002208 _bdf_parse_t *p;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002209
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002210 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002211 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002212
2213
David Turner68df4f72005-03-15 18:18:57 +00002214 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002215 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002216
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002217 memory = NULL;
2218 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2219 p->minlb = 32767;
2220 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002221
David Turner68df4f72005-03-15 18:18:57 +00002222 _bdf_list_init( &p->list, extmemory );
2223
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002224 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002225 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002226 if ( error )
2227 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002228
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002229 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002230 {
2231 /* If the font is not proportional, set the font's monowidth */
2232 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002233 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002234
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002235 if ( p->font->spacing != BDF_PROPORTIONAL )
2236 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002237
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002238 /* If the number of glyphs loaded is not that of the original count, */
2239 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002240 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002241 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002242 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2243 p->font->glyphs_used + p->font->unencoded_used ));
2244 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002245 }
2246
2247 /* Once the font has been loaded, adjust the overall font metrics if */
2248 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002249 if ( p->opts->correct_metrics != 0 &&
2250 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002251 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002252 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002253 {
2254 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002255 p->font->bbx.width, p->maxrb - p->minlb ));
2256 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2257 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002258 }
2259
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002260 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002261 {
2262 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002263 p->font->bbx.x_offset, p->minlb ));
2264 p->font->bbx.x_offset = p->minlb;
2265 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002266 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002267
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002268 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002269 {
2270 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002271 p->font->bbx.ascent, p->maxas ));
2272 p->font->bbx.ascent = p->maxas;
2273 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002274 }
2275
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002276 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002277 {
2278 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002279 p->font->bbx.descent, p->maxds ));
2280 p->font->bbx.descent = p->maxds;
2281 p->font->bbx.y_offset = (short)( -p->maxds );
2282 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002283 }
2284
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002285 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002286 {
2287 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002288 p->font->bbx.height, p->maxas + p->maxds ));
2289 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002290 }
2291
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002292 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002293 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2294 }
David Turner993a8d02002-05-18 12:03:43 +00002295 }
2296
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002297 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002298 {
2299 {
2300 /* The ENDFONT field was never reached or did not exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002301 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002302 /* Error happened while parsing header. */
2303 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2304 else
2305 /* Error happened when parsing glyphs. */
2306 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2307 }
David Turner993a8d02002-05-18 12:03:43 +00002308 }
2309
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002310 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002311 {
2312 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002313 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002314
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002315 if ( p->font->comments_len > 0 ) {
2316 if ( FT_RENEW_ARRAY( p->font->comments,
2317 p->font->comments_len,
2318 p->font->comments_len + 1 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002319 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002320
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002321 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002322 }
David Turner993a8d02002-05-18 12:03:43 +00002323 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002324 else if ( error == BDF_Err_Ok )
2325 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002326
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002327 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002328
2329 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002330 if ( p )
2331 {
David Turner68df4f72005-03-15 18:18:57 +00002332 _bdf_list_done( &p->list );
2333
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002334 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002335
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002336 FT_FREE( p );
2337 }
2338
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002339 return error;
2340 }
David Turner993a8d02002-05-18 12:03:43 +00002341
2342
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002343 FT_LOCAL_DEF( void )
2344 bdf_free_font( bdf_font_t* font )
2345 {
2346 bdf_property_t* prop;
2347 unsigned long i;
2348 bdf_glyph_t* glyphs;
2349 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002350
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002351
2352 if ( font == 0 )
2353 return;
David Turner993a8d02002-05-18 12:03:43 +00002354
2355 memory = font->memory;
2356
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002357 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002358
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002359 /* Free up the internal hash table of property names. */
2360 if ( font->internal )
2361 {
2362 hash_free( (hashtable *)font->internal, memory );
2363 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002364 }
2365
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002366 /* Free up the comment info. */
2367 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002368
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002369 /* Free up the properties. */
2370 for ( i = 0; i < font->props_size; i++ )
2371 {
2372 if ( font->props[i].format == BDF_ATOM )
2373 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002374 }
2375
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002376 FT_FREE( font->props );
2377
2378 /* Free up the character info. */
2379 for ( i = 0, glyphs = font->glyphs;
2380 i < font->glyphs_used; i++, glyphs++ )
2381 {
2382 FT_FREE( glyphs->name );
2383 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002384 }
2385
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002386 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2387 i++, glyphs++ )
2388 {
2389 FT_FREE( glyphs->name );
2390 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002391 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002392
2393 FT_FREE( font->glyphs );
2394 FT_FREE( font->unencoded );
2395
2396 /* Free up the overflow storage if it was used. */
2397 for ( i = 0, glyphs = font->overflow.glyphs;
2398 i < font->overflow.glyphs_used; i++, glyphs++ )
2399 {
2400 FT_FREE( glyphs->name );
2401 FT_FREE( glyphs->bitmap );
2402 }
2403
2404 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002405
2406 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002407 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002408
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002409 /* Free up the user defined properties. */
2410 for (prop = font->user_props, i = 0;
2411 i < font->nuser_props; i++, prop++ )
2412 {
2413 FT_FREE( prop->name );
2414 if ( prop->format == BDF_ATOM )
2415 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002416 }
David Turner993a8d02002-05-18 12:03:43 +00002417
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002418 FT_FREE( font->user_props );
2419
2420 /* FREE( font ); */ /* XXX Fixme */
2421 }
David Turner993a8d02002-05-18 12:03:43 +00002422
2423
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002424 FT_LOCAL_DEF( bdf_property_t * )
2425 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002426 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002427 {
2428 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002429
David Turner993a8d02002-05-18 12:03:43 +00002430
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002431 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002432 return 0;
2433
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002434 hn = hash_lookup( name, (hashtable *)font->internal );
2435
2436 return hn ? ( font->props + (unsigned long)hn->data ) : 0;
2437 }
2438
2439
2440/* END */