blob: 93061bb8300b10ca33f8061b65c0b286e67b1c2d [file] [log] [blame]
David Turner993a8d02002-05-18 12:03:43 +00001/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
Werner Lemberg442bfb82007-02-12 21:44:10 +00003 * Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007
4 * Francesco Zappa Nardelli
David Turner993a8d02002-05-18 12:03:43 +00005 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
Werner Lemberg7cf4d372002-05-21 14:13:01 +000025 /*************************************************************************/
26 /* */
27 /* This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 */
28 /* */
29 /* taken from Mark Leisher's xmbdfed package */
30 /* */
31 /*************************************************************************/
32
David Turner993a8d02002-05-18 12:03:43 +000033
34#include <ft2build.h>
35
Werner Lemberg02d4d592002-05-28 22:38:05 +000036#include FT_FREETYPE_H
David Turner993a8d02002-05-18 12:03:43 +000037#include FT_INTERNAL_DEBUG_H
38#include FT_INTERNAL_STREAM_H
39#include FT_INTERNAL_OBJECTS_H
40
41#include "bdf.h"
David Turner993a8d02002-05-18 12:03:43 +000042#include "bdferror.h"
43
David Turner993a8d02002-05-18 12:03:43 +000044
Werner Lemberg7cf4d372002-05-21 14:13:01 +000045 /*************************************************************************/
46 /* */
47 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
48 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
49 /* messages during execution. */
50 /* */
51#undef FT_COMPONENT
52#define FT_COMPONENT trace_bdflib
David Turner993a8d02002-05-18 12:03:43 +000053
David Turner993a8d02002-05-18 12:03:43 +000054
Werner Lemberg7cf4d372002-05-21 14:13:01 +000055 /*************************************************************************/
56 /* */
57 /* Default BDF font options. */
58 /* */
59 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000060
David Turner993a8d02002-05-18 12:03:43 +000061
David Turnerb1b47622002-05-21 21:17:43 +000062 static const bdf_options_t _bdf_opts =
Werner Lemberg7cf4d372002-05-21 14:13:01 +000063 {
David Turner993a8d02002-05-18 12:03:43 +000064 1, /* Correct metrics. */
65 1, /* Preserve unencoded glyphs. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000066 0, /* Preserve comments. */
67 BDF_PROPORTIONAL /* Default spacing. */
68 };
David Turner993a8d02002-05-18 12:03:43 +000069
David Turner993a8d02002-05-18 12:03:43 +000070
Werner Lemberg7cf4d372002-05-21 14:13:01 +000071 /*************************************************************************/
72 /* */
73 /* Builtin BDF font properties. */
74 /* */
75 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000076
Werner Lemberg7cf4d372002-05-21 14:13:01 +000077 /* List of most properties that might appear in a font. Doesn't include */
78 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
David Turner993a8d02002-05-18 12:03:43 +000079
David Turnerb1b47622002-05-21 21:17:43 +000080 static const bdf_property_t _bdf_properties[] =
David Turner993a8d02002-05-18 12:03:43 +000081 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +000082 { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
83 { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
84 { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
85 { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
86 { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
87 { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
88 { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
89 { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
90 { (char *)"COMMENT", BDF_ATOM, 1, { 0 } },
91 { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } },
92 { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
93 { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } },
94 { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
95 { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } },
96 { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } },
97 { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } },
98 { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
99 { (char *)"FONT", BDF_ATOM, 1, { 0 } },
100 { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
101 { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
102 { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
103 { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } },
104 { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } },
105 { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
106 { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } },
107 { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } },
108 { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } },
109 { (char *)"NOTICE", BDF_ATOM, 1, { 0 } },
110 { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
111 { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } },
112 { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
113 { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
114 { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
115 { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
116 { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
117 { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
118 { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
119 { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
120 { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
121 { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
122 { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
123 { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
124 { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
125 { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
126 { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
127 { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
128 { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
129 { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
130 { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
131 { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
132 { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
133 { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
134 { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
135 { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
136 { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
137 { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
138 { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
139 { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
140 { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
141 { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
142 { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
143 { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } },
144 { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
145 { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
146 { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
147 { (char *)"SLANT", BDF_ATOM, 1, { 0 } },
148 { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
149 { (char *)"SPACING", BDF_ATOM, 1, { 0 } },
150 { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
151 { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
152 { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
153 { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
154 { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
155 { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
156 { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
157 { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
158 { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
159 { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
160 { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } },
161 { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
162 { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } },
163 { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
164 { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
165 };
David Turner993a8d02002-05-18 12:03:43 +0000166
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000167 static const unsigned long
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000168 _num_bdf_properties = sizeof ( _bdf_properties ) /
169 sizeof ( _bdf_properties[0] );
David Turner993a8d02002-05-18 12:03:43 +0000170
171
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000172 /*************************************************************************/
173 /* */
174 /* Hash table utilities for the properties. */
175 /* */
176 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +0000177
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000178 /* XXX: Replace this with FreeType's hash functions */
David Turner993a8d02002-05-18 12:03:43 +0000179
David Turner993a8d02002-05-18 12:03:43 +0000180
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000181#define INITIAL_HT_SIZE 241
182
183 typedef void
184 (*hash_free_func)( hashnode node );
185
186 static hashnode*
Werner Lemberg428c2e42003-04-25 05:35:04 +0000187 hash_bucket( const char* key,
188 hashtable* ht )
David Turner993a8d02002-05-18 12:03:43 +0000189 {
Werner Lemberg428c2e42003-04-25 05:35:04 +0000190 const char* kp = key;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000191 unsigned long res = 0;
192 hashnode* bp = ht->table, *ndp;
193
194
195 /* Mocklisp hash function. */
196 while ( *kp )
197 res = ( res << 5 ) - res + *kp++;
198
199 ndp = bp + ( res % ht->size );
200 while ( *ndp )
David Turner993a8d02002-05-18 12:03:43 +0000201 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000202 kp = (*ndp)->key;
203 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
204 break;
205 ndp--;
206 if ( ndp < bp )
207 ndp = bp + ( ht->size - 1 );
David Turner993a8d02002-05-18 12:03:43 +0000208 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000209
210 return ndp;
David Turner993a8d02002-05-18 12:03:43 +0000211 }
David Turner993a8d02002-05-18 12:03:43 +0000212
213
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000214 static FT_Error
215 hash_rehash( hashtable* ht,
216 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000217 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000218 hashnode* obp = ht->table, *bp, *nbp;
David Turner993a8d02002-05-18 12:03:43 +0000219 int i, sz = ht->size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000220 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000221
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000222
223 ht->size <<= 1;
224 ht->limit = ht->size / 3;
225
226 if ( FT_NEW_ARRAY( ht->table, ht->size ) )
227 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000228
229 for ( i = 0, bp = obp; i < sz; i++, bp++ )
David Turner993a8d02002-05-18 12:03:43 +0000230 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000231 if ( *bp )
232 {
233 nbp = hash_bucket( (*bp)->key, ht );
234 *nbp = *bp;
235 }
David Turner993a8d02002-05-18 12:03:43 +0000236 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000237 FT_FREE( obp );
238
239 Exit:
240 return error;
David Turner993a8d02002-05-18 12:03:43 +0000241 }
David Turner993a8d02002-05-18 12:03:43 +0000242
243
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000244 static FT_Error
245 hash_init( hashtable* ht,
246 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000247 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000248 int sz = INITIAL_HT_SIZE;
249 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000250
David Turner993a8d02002-05-18 12:03:43 +0000251
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000252 ht->size = sz;
253 ht->limit = sz / 3;
254 ht->used = 0;
David Turner993a8d02002-05-18 12:03:43 +0000255
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000256 if ( FT_NEW_ARRAY( ht->table, sz ) )
257 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000258
259 Exit:
260 return error;
David Turner993a8d02002-05-18 12:03:43 +0000261 }
David Turner993a8d02002-05-18 12:03:43 +0000262
263
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000264 static void
265 hash_free( hashtable* ht,
266 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000267 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000268 if ( ht != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000269 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000270 int i, sz = ht->size;
271 hashnode* bp = ht->table;
David Turner993a8d02002-05-18 12:03:43 +0000272
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000273
274 for ( i = 0; i < sz; i++, bp++ )
275 FT_FREE( *bp );
276
277 FT_FREE( ht->table );
278 }
David Turner993a8d02002-05-18 12:03:43 +0000279 }
280
David Turner993a8d02002-05-18 12:03:43 +0000281
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000282 static FT_Error
283 hash_insert( char* key,
284 void* data,
285 hashtable* ht,
286 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000287 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000288 hashnode nn, *bp = hash_bucket( key, ht );
289 FT_Error error = BDF_Err_Ok;
290
291
292 nn = *bp;
293 if ( !nn )
294 {
295 if ( FT_NEW( nn ) )
296 goto Exit;
297 *bp = nn;
298
299 nn->key = key;
300 nn->data = data;
301
302 if ( ht->used >= ht->limit )
303 {
304 error = hash_rehash( ht, memory );
305 if ( error )
306 goto Exit;
307 }
308 ht->used++;
309 }
David Turner993a8d02002-05-18 12:03:43 +0000310 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000311 nn->data = data;
312
313 Exit:
314 return error;
David Turner993a8d02002-05-18 12:03:43 +0000315 }
316
David Turner993a8d02002-05-18 12:03:43 +0000317
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000318 static hashnode
Werner Lemberg428c2e42003-04-25 05:35:04 +0000319 hash_lookup( const char* key,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000320 hashtable* ht )
321 {
322 hashnode *np = hash_bucket( key, ht );
323
324
325 return *np;
326 }
327
328
329 /*************************************************************************/
330 /* */
331 /* Utility types and functions. */
332 /* */
333 /*************************************************************************/
334
335
336 /* Function type for parsing lines of a BDF font. */
337
338 typedef FT_Error
339 (*_bdf_line_func_t)( char* line,
340 unsigned long linelen,
341 unsigned long lineno,
342 void* call_data,
343 void* client_data );
344
345
346 /* List structure for splitting lines into fields. */
347
348 typedef struct _bdf_list_t_
349 {
350 char** field;
351 unsigned long size;
352 unsigned long used;
David Turner68df4f72005-03-15 18:18:57 +0000353 FT_Memory memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000354
355 } _bdf_list_t;
356
357
358 /* Structure used while loading BDF fonts. */
359
360 typedef struct _bdf_parse_t_
361 {
362 unsigned long flags;
363 unsigned long cnt;
364 unsigned long row;
365
366 short minlb;
367 short maxlb;
368 short maxrb;
369 short maxas;
370 short maxds;
371
372 short rbearing;
373
374 char* glyph_name;
375 long glyph_enc;
376
377 bdf_font_t* font;
378 bdf_options_t* opts;
379
380 unsigned long have[2048];
381 _bdf_list_t list;
382
383 FT_Memory memory;
384
385 } _bdf_parse_t;
386
387
Werner Lemberga08b2172007-03-28 07:17:17 +0000388#define setsbit( m, cc ) \
389 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
390#define sbitset( m, cc ) \
391 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000392
393
David Turner68df4f72005-03-15 18:18:57 +0000394 static void
395 _bdf_list_init( _bdf_list_t* list,
396 FT_Memory memory )
397 {
Werner Lembergebf55852005-03-16 01:49:54 +0000398 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000399 list->memory = memory;
400 }
401
Werner Lembergebf55852005-03-16 01:49:54 +0000402
David Turner68df4f72005-03-15 18:18:57 +0000403 static void
404 _bdf_list_done( _bdf_list_t* list )
405 {
406 FT_Memory memory = list->memory;
407
Werner Lembergebf55852005-03-16 01:49:54 +0000408
David Turner68df4f72005-03-15 18:18:57 +0000409 if ( memory )
410 {
411 FT_FREE( list->field );
Werner Lembergebf55852005-03-16 01:49:54 +0000412 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000413 }
414 }
415
416
417 static FT_Error
418 _bdf_list_ensure( _bdf_list_t* list,
419 int num_items )
420 {
Werner Lembergebf55852005-03-16 01:49:54 +0000421 FT_Error error = BDF_Err_Ok;
422
David Turner68df4f72005-03-15 18:18:57 +0000423
David Turner5d02b8a2005-03-15 23:48:15 +0000424 if ( num_items > (int)list->size )
David Turner68df4f72005-03-15 18:18:57 +0000425 {
Werner Lembergebf55852005-03-16 01:49:54 +0000426 int oldsize = list->size;
427 int newsize = oldsize + ( oldsize >> 1 ) + 4;
428 int bigsize = FT_INT_MAX / sizeof ( char* );
David Turner68df4f72005-03-15 18:18:57 +0000429 FT_Memory memory = list->memory;
430
Werner Lembergebf55852005-03-16 01:49:54 +0000431
David Turner68df4f72005-03-15 18:18:57 +0000432 if ( oldsize == bigsize )
433 {
Werner Lembergebf55852005-03-16 01:49:54 +0000434 error = BDF_Err_Out_Of_Memory;
David Turner68df4f72005-03-15 18:18:57 +0000435 goto Exit;
436 }
437 else if ( newsize < oldsize || newsize > bigsize )
438 newsize = bigsize;
439
440 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
441 goto Exit;
442
443 list->size = newsize;
444 }
Werner Lembergebf55852005-03-16 01:49:54 +0000445
David Turner68df4f72005-03-15 18:18:57 +0000446 Exit:
447 return error;
448 }
449
450
451 static void
452 _bdf_list_shift( _bdf_list_t* list,
453 unsigned long n )
454 {
455 unsigned long i, u;
456
457
458 if ( list == 0 || list->used == 0 || n == 0 )
459 return;
460
461 if ( n >= list->used )
462 {
463 list->used = 0;
464 return;
465 }
466
467 for ( u = n, i = 0; u < list->used; i++, u++ )
468 list->field[i] = list->field[u];
469 list->used -= n;
470 }
471
472
473 static char *
474 _bdf_list_join( _bdf_list_t* list,
475 int c,
476 unsigned long *alen )
477 {
478 unsigned long i, j;
479 char *fp, *dp;
480
481
482 *alen = 0;
483
484 if ( list == 0 || list->used == 0 )
485 return 0;
486
487 dp = list->field[0];
488 for ( i = j = 0; i < list->used; i++ )
489 {
490 fp = list->field[i];
491 while ( *fp )
492 dp[j++] = *fp++;
493
494 if ( i + 1 < list->used )
495 dp[j++] = (char)c;
496 }
497 dp[j] = 0;
498
499 *alen = j;
500 return dp;
501 }
502
503
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000504 /* An empty string for empty fields. */
505
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000506 static const char empty[1] = { 0 }; /* XXX eliminate this */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000507
508
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000509 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000510 _bdf_list_split( _bdf_list_t* list,
511 char* separators,
512 char* line,
513 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000514 {
515 int mult, final_empty;
516 char *sp, *ep, *end;
517 char seps[32];
518 FT_Error error = BDF_Err_Ok;
519
520
521 /* Initialize the list. */
522 list->used = 0;
523
524 /* If the line is empty, then simply return. */
525 if ( linelen == 0 || line[0] == 0 )
526 goto Exit;
527
528 /* In the original code, if the `separators' parameter is NULL or */
529 /* empty, the list is split into individual bytes. We don't need */
530 /* this, so an error is signaled. */
531 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000532 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000533 error = BDF_Err_Invalid_Argument;
534 goto Exit;
535 }
536
537 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000538 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000539
540 /* If the very last character of the separator string is a plus, then */
541 /* set the `mult' flag to indicate that multiple separators should be */
542 /* collapsed into one. */
543 for ( mult = 0, sp = separators; sp && *sp; sp++ )
544 {
545 if ( *sp == '+' && *( sp + 1 ) == 0 )
546 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000547 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000548 setsbit( seps, *sp );
549 }
550
551 /* Break the line up into fields. */
552 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
553 sp < end && *sp; )
554 {
555 /* Collect everything that is not a separator. */
556 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
557 ;
558
559 /* Resize the list if necessary. */
560 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000561 {
Werner Lembergebf55852005-03-16 01:49:54 +0000562 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000563 if ( error )
564 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000565 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000566
567 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000568 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000569
570 sp = ep;
571
572 if ( mult )
573 {
574 /* If multiple separators should be collapsed, do it now by */
575 /* setting all the separator characters to 0. */
576 for ( ; *ep && sbitset( seps, *ep ); ep++ )
577 *ep = 0;
578 }
579 else if ( *ep != 0 )
580 /* Don't collapse multiple separators by making them 0, so just */
581 /* make the one encountered 0. */
582 *ep++ = 0;
583
584 final_empty = ( ep > sp && *ep == 0 );
585 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000586 }
587
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000588 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000589 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000590 {
Werner Lembergebf55852005-03-16 01:49:54 +0000591 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000592 if ( error )
593 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000594 }
595
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000596 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000597 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000598
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000599 list->field[list->used] = 0;
600
601 Exit:
602 return error;
David Turner993a8d02002-05-18 12:03:43 +0000603 }
604
David Turner993a8d02002-05-18 12:03:43 +0000605
David Turner68df4f72005-03-15 18:18:57 +0000606#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000607
Werner Lembergebf55852005-03-16 01:49:54 +0000608
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000609 static FT_Error
610 _bdf_readstream( FT_Stream stream,
611 _bdf_line_func_t callback,
612 void* client_data,
613 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000614 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000615 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000616 unsigned long lineno, buf_size;
617 int refill, bytes, hold, to_skip;
618 int start, end, cursor, avail;
619 char* buf = 0;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000620 FT_Memory memory = stream->memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000621 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000622
David Turner993a8d02002-05-18 12:03:43 +0000623
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000624 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000625 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000626 error = BDF_Err_Invalid_Argument;
627 goto Exit;
628 }
David Turner993a8d02002-05-18 12:03:43 +0000629
Werner Lembergebf55852005-03-16 01:49:54 +0000630 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000631 buf_size = 1024;
632
633 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000634 goto Exit;
635
Werner Lembergebf55852005-03-16 01:49:54 +0000636 cb = callback;
637 lineno = 1;
638 buf[0] = 0;
639 start = 0;
640 end = 0;
641 avail = 0;
642 cursor = 0;
643 refill = 1;
644 to_skip = NO_SKIP;
645 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000646
David Turner68df4f72005-03-15 18:18:57 +0000647 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000648 {
David Turner68df4f72005-03-15 18:18:57 +0000649 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000650 {
Werner Lembergebf55852005-03-16 01:49:54 +0000651 bytes = (int)FT_Stream_TryRead( stream, (FT_Byte*)buf + cursor,
David Turner68df4f72005-03-15 18:18:57 +0000652 (FT_ULong)(buf_size - cursor) );
653 avail = cursor + bytes;
654 cursor = 0;
655 refill = 0;
656 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000657
David Turner68df4f72005-03-15 18:18:57 +0000658 end = start;
659
Werner Lembergebf55852005-03-16 01:49:54 +0000660 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000661 if ( start < avail && buf[start] == to_skip )
662 {
663 start += 1;
664 to_skip = NO_SKIP;
665 continue;
666 }
667
668 /* try to find the end of the line */
669 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
670 end++;
671
Werner Lembergebf55852005-03-16 01:49:54 +0000672 /* if we hit the end of the buffer, try shifting its content */
673 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000674 if ( end >= avail )
675 {
676 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
677 break; /* ignore it then exit */
678
679 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000680 {
Werner Lembergebf55852005-03-16 01:49:54 +0000681 /* this line is definitely too long; try resizing the input */
682 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000683 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000684
Werner Lembergebf55852005-03-16 01:49:54 +0000685
686 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000687 {
688 error = BDF_Err_Invalid_Argument;
689 goto Exit;
690 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000691
Werner Lembergebf55852005-03-16 01:49:54 +0000692 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000693 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
694 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000695
David Turner68df4f72005-03-15 18:18:57 +0000696 cursor = buf_size;
697 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000698 }
699 else
700 {
David Turner68df4f72005-03-15 18:18:57 +0000701 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000702
Werner Lembergebf55852005-03-16 01:49:54 +0000703 FT_MEM_COPY( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000704
David Turner68df4f72005-03-15 18:18:57 +0000705 cursor = bytes;
706 avail -= bytes;
707 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000708 }
David Turner68df4f72005-03-15 18:18:57 +0000709 refill = 1;
710 continue;
David Turner993a8d02002-05-18 12:03:43 +0000711 }
David Turner68df4f72005-03-15 18:18:57 +0000712
713 /* Temporarily NUL-terminate the line. */
714 hold = buf[end];
715 buf[end] = 0;
716
717 /* XXX: Use encoding independent value for 0x1a */
718 if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
719 {
Werner Lembergebf55852005-03-16 01:49:54 +0000720 error = (*cb)( buf + start, end - start, lineno,
721 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000722 if ( error )
723 break;
724 }
725
726 lineno += 1;
727 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000728 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000729
730 if ( hold == '\n' )
731 to_skip = '\r';
732 else if ( hold == '\r' )
733 to_skip = '\n';
734 else
735 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000736 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000737
David Turner68df4f72005-03-15 18:18:57 +0000738 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000739
740 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000741 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000742 return error;
David Turner993a8d02002-05-18 12:03:43 +0000743 }
David Turner993a8d02002-05-18 12:03:43 +0000744
745
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000746 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000747
David Turnerb1b47622002-05-21 21:17:43 +0000748 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000749 {
David Turner993a8d02002-05-18 12:03:43 +0000750 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
751 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
752 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
753 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
754 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
755 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
756 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
758 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
759 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
760 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000761 };
David Turner993a8d02002-05-18 12:03:43 +0000762
David Turnerb1b47622002-05-21 21:17:43 +0000763 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000764 {
David Turner993a8d02002-05-18 12:03:43 +0000765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
767 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
768 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000769 };
David Turner993a8d02002-05-18 12:03:43 +0000770
David Turnerb1b47622002-05-21 21:17:43 +0000771 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000772 {
David Turner993a8d02002-05-18 12:03:43 +0000773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
774 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
775 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
776 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000777 };
David Turner993a8d02002-05-18 12:03:43 +0000778
David Turnerb1b47622002-05-21 21:17:43 +0000779 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000780 {
David Turner993a8d02002-05-18 12:03:43 +0000781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
782 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
783 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
784 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000785 };
David Turner993a8d02002-05-18 12:03:43 +0000786
David Turner993a8d02002-05-18 12:03:43 +0000787
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000788#define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
David Turner993a8d02002-05-18 12:03:43 +0000789
David Turner993a8d02002-05-18 12:03:43 +0000790
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000791 /* Routine to convert an ASCII string into an unsigned long integer. */
792 static unsigned long
793 _bdf_atoul( char* s,
794 char** end,
795 int base )
David Turner993a8d02002-05-18 12:03:43 +0000796 {
David Turnerb1b47622002-05-21 21:17:43 +0000797 unsigned long v;
798 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000799
800
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000801 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000802 return 0;
803
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000804 /* Make sure the radix is something recognizable. Default to 10. */
805 switch ( base )
806 {
807 case 8:
808 dmap = odigits;
809 break;
810 case 16:
811 dmap = hdigits;
812 break;
813 default:
814 base = 10;
815 dmap = ddigits;
816 break;
David Turner993a8d02002-05-18 12:03:43 +0000817 }
818
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000819 /* Check for the special hex prefix. */
820 if ( *s == '0' &&
821 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
822 {
823 base = 16;
824 dmap = hdigits;
825 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000826 }
827
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000828 for ( v = 0; isdigok( dmap, *s ); s++ )
829 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000830
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000831 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000832 *end = s;
833
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000834 return v;
835 }
David Turner993a8d02002-05-18 12:03:43 +0000836
David Turner993a8d02002-05-18 12:03:43 +0000837
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000838 /* Routine to convert an ASCII string into an signed long integer. */
839 static long
840 _bdf_atol( char* s,
841 char** end,
842 int base )
843 {
David Turnerb1b47622002-05-21 21:17:43 +0000844 long v, neg;
845 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000846
847
848 if ( s == 0 || *s == 0 )
849 return 0;
850
851 /* Make sure the radix is something recognizable. Default to 10. */
852 switch ( base )
853 {
854 case 8:
855 dmap = odigits;
856 break;
857 case 16:
858 dmap = hdigits;
859 break;
860 default:
861 base = 10;
862 dmap = ddigits;
863 break;
864 }
865
866 /* Check for a minus sign. */
867 neg = 0;
868 if ( *s == '-' )
869 {
870 s++;
871 neg = 1;
872 }
873
874 /* Check for the special hex prefix. */
875 if ( *s == '0' &&
876 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
877 {
878 base = 16;
879 dmap = hdigits;
880 s += 2;
881 }
882
883 for ( v = 0; isdigok( dmap, *s ); s++ )
884 v = v * base + a2i[(int)*s];
885
886 if ( end != 0 )
887 *end = s;
888
889 return ( !neg ) ? v : -v;
890 }
891
892
893 /* Routine to convert an ASCII string into an signed short integer. */
894 static short
895 _bdf_atos( char* s,
896 char** end,
897 int base )
898 {
David Turnerb1b47622002-05-21 21:17:43 +0000899 short v, neg;
900 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000901
902
903 if ( s == 0 || *s == 0 )
904 return 0;
905
906 /* Make sure the radix is something recognizable. Default to 10. */
907 switch ( base )
908 {
909 case 8:
910 dmap = odigits;
911 break;
912 case 16:
913 dmap = hdigits;
914 break;
915 default:
916 base = 10;
917 dmap = ddigits;
918 break;
919 }
920
921 /* Check for a minus. */
922 neg = 0;
923 if ( *s == '-' )
924 {
925 s++;
926 neg = 1;
927 }
928
929 /* Check for the special hex prefix. */
930 if ( *s == '0' &&
931 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
932 {
933 base = 16;
934 dmap = hdigits;
935 s += 2;
936 }
937
938 for ( v = 0; isdigok( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +0000939 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000940
941 if ( end != 0 )
942 *end = s;
943
Werner Lemberg233302a2002-05-22 05:41:06 +0000944 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000945 }
946
947
948 /* Routine to compare two glyphs by encoding so they can be sorted. */
949 static int
950 by_encoding( const void* a,
951 const void* b )
952 {
953 bdf_glyph_t *c1, *c2;
954
955
956 c1 = (bdf_glyph_t *)a;
957 c2 = (bdf_glyph_t *)b;
958
959 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000960 return -1;
David Turner68df4f72005-03-15 18:18:57 +0000961
962 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000963 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000964
David Turner993a8d02002-05-18 12:03:43 +0000965 return 0;
David Turner993a8d02002-05-18 12:03:43 +0000966 }
967
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000968
969 static FT_Error
970 bdf_create_property( char* name,
971 int format,
972 bdf_font_t* font )
973 {
974 unsigned long n;
975 bdf_property_t* p;
976 FT_Memory memory = font->memory;
977 FT_Error error = BDF_Err_Ok;
978
979
980 /* First check to see if the property has */
981 /* already been added or not. If it has, then */
982 /* simply ignore it. */
983 if ( hash_lookup( name, &(font->proptbl) ) )
984 goto Exit;
985
David Turner68df4f72005-03-15 18:18:57 +0000986 if ( FT_RENEW_ARRAY( font->user_props,
987 font->nuser_props,
988 font->nuser_props + 1 ) )
989 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000990
991 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +0000992 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000993
994 n = (unsigned long)( ft_strlen( name ) + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000995
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000996 if ( FT_NEW_ARRAY( p->name, n ) )
997 goto Exit;
998
999 FT_MEM_COPY( (char *)p->name, name, n );
1000
1001 p->format = format;
1002 p->builtin = 0;
1003
1004 n = _num_bdf_properties + font->nuser_props;
1005
1006 error = hash_insert( p->name, (void *)n, &(font->proptbl), memory );
1007 if ( error )
1008 goto Exit;
1009
1010 font->nuser_props++;
1011
1012 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001013 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001014 }
David Turner993a8d02002-05-18 12:03:43 +00001015
1016
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001017 FT_LOCAL_DEF( bdf_property_t * )
1018 bdf_get_property( char* name,
1019 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001020 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001021 hashnode hn;
1022 unsigned long propid;
1023
1024
1025 if ( name == 0 || *name == 0 )
1026 return 0;
1027
1028 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1029 return 0;
1030
1031 propid = (unsigned long)hn->data;
1032 if ( propid >= _num_bdf_properties )
1033 return font->user_props + ( propid - _num_bdf_properties );
1034
Werner Lemberg233302a2002-05-22 05:41:06 +00001035 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001036 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001037
1038
1039 /*************************************************************************/
1040 /* */
1041 /* BDF font file parsing flags and functions. */
1042 /* */
1043 /*************************************************************************/
1044
1045
1046 /* Parse flags. */
1047
1048#define _BDF_START 0x0001
1049#define _BDF_FONT_NAME 0x0002
1050#define _BDF_SIZE 0x0004
1051#define _BDF_FONT_BBX 0x0008
1052#define _BDF_PROPS 0x0010
1053#define _BDF_GLYPHS 0x0020
1054#define _BDF_GLYPH 0x0040
1055#define _BDF_ENCODING 0x0080
1056#define _BDF_SWIDTH 0x0100
1057#define _BDF_DWIDTH 0x0200
1058#define _BDF_BBX 0x0400
1059#define _BDF_BITMAP 0x0800
1060
1061#define _BDF_SWIDTH_ADJ 0x1000
1062
1063#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1064 _BDF_ENCODING | \
1065 _BDF_SWIDTH | \
1066 _BDF_DWIDTH | \
1067 _BDF_BBX | \
1068 _BDF_BITMAP )
1069
Werner Lembergf1c2b912006-01-13 14:53:28 +00001070#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1071#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001072
1073
1074 /* Auto correction messages. */
1075#define ACMSG1 "FONT_ASCENT property missing. " \
1076 "Added \"FONT_ASCENT %hd\".\n"
1077#define ACMSG2 "FONT_DESCENT property missing. " \
1078 "Added \"FONT_DESCENT %hd\".\n"
1079#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
1080#define ACMSG4 "Font left bearing != actual left bearing. " \
1081 "Old: %hd New: %hd.\n"
1082#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
1083#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
1084#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
1085#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
1086#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
1087#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
1088#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
1089#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
1090#define ACMSG13 "Glyph %ld extra rows removed.\n"
1091#define ACMSG14 "Glyph %ld extra columns removed.\n"
1092#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
1093
1094 /* Error messages. */
1095#define ERRMSG1 "[line %ld] Missing \"%s\" line.\n"
1096#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
1097#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
Werner Lemberg26170df2006-03-26 07:19:07 +00001098#define ERRMSG4 "[line %ld] BBX too big.\n"
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001099
1100
1101 static FT_Error
1102 _bdf_add_comment( bdf_font_t* font,
1103 char* comment,
1104 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001105 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001106 char* cp;
1107 FT_Memory memory = font->memory;
1108 FT_Error error = BDF_Err_Ok;
1109
1110
David Turner68df4f72005-03-15 18:18:57 +00001111 if ( FT_RENEW_ARRAY( font->comments,
1112 font->comments_len,
1113 font->comments_len + len + 1 ) )
1114 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001115
1116 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001117
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001118 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001119 cp[len] = '\n';
1120
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001121 font->comments_len += len + 1;
1122
1123 Exit:
1124 return error;
David Turner993a8d02002-05-18 12:03:43 +00001125 }
1126
David Turner993a8d02002-05-18 12:03:43 +00001127
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001128 /* Set the spacing from the font name if it exists, or set it to the */
1129 /* default specified in the options. */
1130 static FT_Error
1131 _bdf_set_default_spacing( bdf_font_t* font,
1132 bdf_options_t* opts )
David Turner993a8d02002-05-18 12:03:43 +00001133 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001134 unsigned long len;
Werner Lemberga08b2172007-03-28 07:17:17 +00001135 char name[256];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001136 _bdf_list_t list;
1137 FT_Memory memory;
1138 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001139
David Turner993a8d02002-05-18 12:03:43 +00001140
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001141 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1142 {
1143 error = BDF_Err_Invalid_Argument;
1144 goto Exit;
1145 }
David Turner993a8d02002-05-18 12:03:43 +00001146
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001147 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001148
David Turner68df4f72005-03-15 18:18:57 +00001149 _bdf_list_init( &list, memory );
1150
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001151 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001152
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001153 len = (unsigned long)( ft_strlen( font->name ) + 1 );
Werner Lemberga08b2172007-03-28 07:17:17 +00001154 /* Limit ourselves to 256 characters in the font name. */
1155 if ( len >= 256 )
1156 {
1157 error = BDF_Err_Invalid_Argument;
1158 goto Exit;
1159 }
1160
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001161 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001162
David Turner68df4f72005-03-15 18:18:57 +00001163 error = _bdf_list_split( &list, (char *)"-", name, len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001164 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001165 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001166
1167 if ( list.used == 15 )
1168 {
1169 switch ( list.field[11][0] )
1170 {
1171 case 'C':
1172 case 'c':
1173 font->spacing = BDF_CHARCELL;
1174 break;
1175 case 'M':
1176 case 'm':
1177 font->spacing = BDF_MONOWIDTH;
1178 break;
1179 case 'P':
1180 case 'p':
1181 font->spacing = BDF_PROPORTIONAL;
1182 break;
David Turner993a8d02002-05-18 12:03:43 +00001183 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001184 }
1185
David Turner68df4f72005-03-15 18:18:57 +00001186 Fail:
1187 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001188
1189 Exit:
1190 return error;
David Turner993a8d02002-05-18 12:03:43 +00001191 }
David Turner993a8d02002-05-18 12:03:43 +00001192
1193
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001194 /* Determine whether the property is an atom or not. If it is, then */
1195 /* clean it up so the double quotes are removed if they exist. */
1196 static int
1197 _bdf_is_atom( char* line,
1198 unsigned long linelen,
1199 char** name,
1200 char** value,
1201 bdf_font_t* font )
1202 {
1203 int hold;
1204 char *sp, *ep;
1205 bdf_property_t* p;
1206
David Turner993a8d02002-05-18 12:03:43 +00001207
1208 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001209
1210 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001211 ep++;
1212
1213 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001214 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001215 {
1216 hold = *ep;
1217 *ep = 0;
1218 }
1219
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001220 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001221
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001222 /* Restore the character that was saved before any return can happen. */
1223 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001224 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001225
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001226 /* If the property exists and is not an atom, just return here. */
1227 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001228 return 0;
1229
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001230 /* The property is an atom. Trim all leading and trailing whitespace */
1231 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001232 sp = ep;
1233 ep = line + linelen;
1234
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001235 /* Trim the leading whitespace if it exists. */
David Turner993a8d02002-05-18 12:03:43 +00001236 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001237 while ( *sp &&
1238 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001239 sp++;
1240
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001241 /* Trim the leading double quote if it exists. */
1242 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001243 sp++;
1244 *value = sp;
1245
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001246 /* Trim the trailing whitespace if it exists. */
1247 while ( ep > sp &&
1248 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001249 *--ep = 0;
1250
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001251 /* Trim the trailing double quote if it exists. */
1252 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001253 *--ep = 0;
1254
1255 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001256 }
David Turner993a8d02002-05-18 12:03:43 +00001257
1258
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001259 static FT_Error
1260 _bdf_add_property( bdf_font_t* font,
1261 char* name,
1262 char* value )
1263 {
1264 unsigned long propid;
1265 hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001266 bdf_property_t *prop, *fp;
1267 FT_Memory memory = font->memory;
1268 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001269
David Turner993a8d02002-05-18 12:03:43 +00001270
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001271 /* First, check to see if the property already exists in the font. */
1272 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001273 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001274 /* The property already exists in the font, so simply replace */
1275 /* the value of the property with the current value. */
1276 fp = font->props + (unsigned long)hn->data;
1277
David Turnerb1b47622002-05-21 21:17:43 +00001278 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001279 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001280 case BDF_ATOM:
1281 /* Delete the current atom if it exists. */
1282 FT_FREE( fp->value.atom );
1283
David Turnerc0f9c4a2007-02-12 14:55:03 +00001284 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001285 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001286 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001287 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001288 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001289 break;
1290
1291 case BDF_INTEGER:
1292 fp->value.int32 = _bdf_atol( value, 0, 10 );
1293 break;
1294
1295 case BDF_CARDINAL:
1296 fp->value.card32 = _bdf_atoul( value, 0, 10 );
1297 break;
David Turnerd490e372002-05-28 23:40:37 +00001298
David Turnerb1b47622002-05-21 21:17:43 +00001299 default:
1300 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001301 }
David Turnerd490e372002-05-28 23:40:37 +00001302
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001303 goto Exit;
1304 }
1305
1306 /* See whether this property type exists yet or not. */
1307 /* If not, create it. */
1308 hn = hash_lookup( name, &(font->proptbl) );
1309 if ( hn == 0 )
1310 {
1311 error = bdf_create_property( name, BDF_ATOM, font );
1312 if ( error )
1313 goto Exit;
1314 hn = hash_lookup( name, &(font->proptbl) );
1315 }
1316
1317 /* Allocate another property if this is overflow. */
1318 if ( font->props_used == font->props_size )
1319 {
1320 if ( font->props_size == 0 )
1321 {
1322 if ( FT_NEW_ARRAY( font->props, 1 ) )
1323 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001324 }
1325 else
1326 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001327 if ( FT_RENEW_ARRAY( font->props,
1328 font->props_size,
1329 font->props_size + 1 ) )
1330 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001331 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001332
David Turner993a8d02002-05-18 12:03:43 +00001333 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001334 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001335 font->props_size++;
1336 }
1337
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001338 propid = (unsigned long)hn->data;
1339 if ( propid >= _num_bdf_properties )
1340 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001341 else
David Turnerb1b47622002-05-21 21:17:43 +00001342 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001343
1344 fp = font->props + font->props_used;
1345
1346 fp->name = prop->name;
1347 fp->format = prop->format;
1348 fp->builtin = prop->builtin;
1349
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001350 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001351 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001352 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001353 fp->value.atom = 0;
1354 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001355 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001356 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001357 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001358 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001359 break;
David Turner993a8d02002-05-18 12:03:43 +00001360
1361 case BDF_INTEGER:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001362 fp->value.int32 = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001363 break;
1364
1365 case BDF_CARDINAL:
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001366 fp->value.card32 = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001367 break;
David Turner993a8d02002-05-18 12:03:43 +00001368 }
1369
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001370 /* If the property happens to be a comment, then it doesn't need */
1371 /* to be added to the internal hash table. */
1372 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) {
1373 /* Add the property to the font property table. */
1374 error = hash_insert( fp->name,
1375 (void *)font->props_used,
1376 (hashtable *)font->internal,
1377 memory );
1378 if ( error )
1379 goto Exit;
1380 }
David Turner993a8d02002-05-18 12:03:43 +00001381
1382 font->props_used++;
1383
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001384 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1385 /* property needs to be located if it exists in the property list, the */
1386 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1387 /* present, and the SPACING property should override the default */
1388 /* spacing. */
1389 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
Werner Lemberg8ef41832004-06-22 12:28:17 +00001390 font->default_char = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001391 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001392 font->font_ascent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001393 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001394 font->font_descent = fp->value.int32;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001395 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001396 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001397 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001398 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001399 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001400 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001401 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001402 font->spacing = BDF_CHARCELL;
1403 }
1404
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001405 Exit:
1406 return error;
David Turner993a8d02002-05-18 12:03:43 +00001407 }
1408
David Turner993a8d02002-05-18 12:03:43 +00001409
David Turnerb1b47622002-05-21 21:17:43 +00001410 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001411 {
1412 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1413 };
1414
1415
1416 /* Actually parse the glyph info and bitmaps. */
1417 static FT_Error
1418 _bdf_parse_glyphs( char* line,
1419 unsigned long linelen,
1420 unsigned long lineno,
1421 void* call_data,
1422 void* client_data )
1423 {
1424 int c, mask_index;
1425 char* s;
1426 unsigned char* bp;
1427 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001428
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001429 _bdf_parse_t* p;
1430 bdf_glyph_t* glyph;
1431 bdf_font_t* font;
1432
1433 FT_Memory memory;
1434 FT_Error error = BDF_Err_Ok;
1435
Werner Lemberg319c00d2003-04-23 19:48:24 +00001436 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001437 FT_UNUSED( lineno ); /* only used in debug mode */
1438
1439
Werner Lemberg319c00d2003-04-23 19:48:24 +00001440 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001441
1442 font = p->font;
1443 memory = font->memory;
1444
1445 /* Check for a comment. */
1446 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1447 {
1448 linelen -= 7;
1449
1450 s = line + 7;
1451 if ( *s != 0 )
1452 {
1453 s++;
1454 linelen--;
1455 }
1456 error = _bdf_add_comment( p->font, s, linelen );
1457 goto Exit;
1458 }
1459
1460 /* The very first thing expected is the number of glyphs. */
1461 if ( !( p->flags & _BDF_GLYPHS ) )
1462 {
1463 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1464 {
1465 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1466 error = BDF_Err_Missing_Chars_Field;
1467 goto Exit;
1468 }
1469
David Turner68df4f72005-03-15 18:18:57 +00001470 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001471 if ( error )
1472 goto Exit;
1473 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1474
1475 /* Make sure the number of glyphs is non-zero. */
1476 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001477 font->glyphs_size = 64;
1478
Werner Lemberga08b2172007-03-28 07:17:17 +00001479 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1480 /* number of code points available in Unicode). */
1481 if ( p->cnt >= 1114112UL )
1482 {
1483 error = BDF_Err_Invalid_Argument;
1484 goto Exit;
1485 }
1486
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001487 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1488 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001489
David Turner993a8d02002-05-18 12:03:43 +00001490 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001491
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001492 goto Exit;
1493 }
1494
1495 /* Check for the ENDFONT field. */
1496 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1497 {
1498 /* Sort the glyphs by encoding. */
1499 ft_qsort( (char *)font->glyphs,
1500 font->glyphs_used,
1501 sizeof ( bdf_glyph_t ),
1502 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001503
1504 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001505
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001506 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001507 }
1508
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001509 /* Check for the ENDCHAR field. */
1510 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1511 {
1512 p->glyph_enc = 0;
1513 p->flags &= ~_BDF_GLYPH_BITS;
1514
1515 goto Exit;
1516 }
1517
1518 /* Check to see whether a glyph is being scanned but should be */
1519 /* ignored because it is an unencoded glyph. */
1520 if ( ( p->flags & _BDF_GLYPH ) &&
1521 p->glyph_enc == -1 &&
1522 p->opts->keep_unencoded == 0 )
1523 goto Exit;
1524
1525 /* Check for the STARTCHAR field. */
1526 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1527 {
1528 /* Set the character name in the parse info first until the */
1529 /* encoding can be checked for an unencoded character. */
1530 FT_FREE( p->glyph_name );
1531
David Turner68df4f72005-03-15 18:18:57 +00001532 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001533 if ( error )
1534 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001535
David Turner68df4f72005-03-15 18:18:57 +00001536 _bdf_list_shift( &p->list, 1 );
1537
1538 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001539
1540 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1541 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001542
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001543 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1544
1545 p->flags |= _BDF_GLYPH;
1546
1547 goto Exit;
1548 }
1549
1550 /* Check for the ENCODING field. */
1551 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1552 {
1553 if ( !( p->flags & _BDF_GLYPH ) )
1554 {
1555 /* Missing STARTCHAR field. */
1556 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1557 error = BDF_Err_Missing_Startchar_Field;
1558 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001559 }
1560
David Turner68df4f72005-03-15 18:18:57 +00001561 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001562 if ( error )
1563 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001564
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001565 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001566
David Turner481838e2006-02-23 12:40:14 +00001567 /* Check that the encoding is in the range [0,65536] because */
1568 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lembergd4303da2006-02-23 21:01:34 +00001569 if ( (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
David Turner481838e2006-02-23 12:40:14 +00001570 {
1571 error = BDF_Err_Invalid_File_Format;
1572 goto Exit;
1573 }
1574
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001575 /* Check to see whether this encoding has already been encountered. */
1576 /* If it has then change it to unencoded so it gets added if */
1577 /* indicated. */
1578 if ( p->glyph_enc >= 0 )
1579 {
1580 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1581 {
1582 /* Emit a message saying a glyph has been moved to the */
1583 /* unencoded area. */
1584 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1585 p->glyph_enc, p->glyph_name ));
1586 p->glyph_enc = -1;
1587 font->modified = 1;
1588 }
1589 else
1590 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1591 }
1592
1593 if ( p->glyph_enc >= 0 )
1594 {
1595 /* Make sure there are enough glyphs allocated in case the */
1596 /* number of characters happen to be wrong. */
1597 if ( font->glyphs_used == font->glyphs_size )
1598 {
1599 if ( FT_RENEW_ARRAY( font->glyphs,
1600 font->glyphs_size,
1601 font->glyphs_size + 64 ) )
1602 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001603
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001604 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001605 }
1606
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001607 glyph = font->glyphs + font->glyphs_used++;
1608 glyph->name = p->glyph_name;
1609 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001610
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001611 /* Reset the initial glyph info. */
1612 p->glyph_name = 0;
1613 }
1614 else
1615 {
1616 /* Unencoded glyph. Check to see whether it should */
1617 /* be added or not. */
1618 if ( p->opts->keep_unencoded != 0 )
1619 {
1620 /* Allocate the next unencoded glyph. */
1621 if ( font->unencoded_used == font->unencoded_size )
1622 {
David Turner68df4f72005-03-15 18:18:57 +00001623 if ( FT_RENEW_ARRAY( font->unencoded ,
1624 font->unencoded_size,
1625 font->unencoded_size + 4 ) )
1626 goto Exit;
1627
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001628 font->unencoded_size += 4;
1629 }
1630
1631 glyph = font->unencoded + font->unencoded_used;
1632 glyph->name = p->glyph_name;
1633 glyph->encoding = font->unencoded_used++;
1634 }
1635 else
1636 /* Free up the glyph name if the unencoded shouldn't be */
1637 /* kept. */
1638 FT_FREE( p->glyph_name );
1639
1640 p->glyph_name = 0;
1641 }
1642
1643 /* Clear the flags that might be added when width and height are */
1644 /* checked for consistency. */
1645 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1646
1647 p->flags |= _BDF_ENCODING;
1648
1649 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001650 }
1651
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001652 /* Point at the glyph being constructed. */
1653 if ( p->glyph_enc == -1 )
1654 glyph = font->unencoded + ( font->unencoded_used - 1 );
1655 else
1656 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001657
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001658 /* Check to see whether a bitmap is being constructed. */
1659 if ( p->flags & _BDF_BITMAP )
1660 {
1661 /* If there are more rows than are specified in the glyph metrics, */
1662 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001663 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001664 {
1665 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1666 {
1667 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1668 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001669 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001670 }
1671
1672 goto Exit;
1673 }
1674
1675 /* Only collect the number of nibbles indicated by the glyph */
1676 /* metrics. If there are more columns, they are simply ignored. */
1677 nibbles = glyph->bpr << 1;
1678 bp = glyph->bitmap + p->row * glyph->bpr;
1679
David Turnerb698eed2006-02-23 14:50:13 +00001680 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001681 {
1682 c = line[i];
Werner Lemberg233302a2002-05-22 05:41:06 +00001683 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001684 if ( i + 1 < nibbles && ( i & 1 ) )
1685 *++bp = 0;
1686 }
1687
1688 /* Remove possible garbage at the right. */
1689 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001690 if ( glyph->bbx.width )
1691 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001692
1693 /* If any line has extra columns, indicate they have been removed. */
1694 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1695 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1696 {
1697 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1698 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1699 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001700 }
1701
1702 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001703 goto Exit;
1704 }
David Turner993a8d02002-05-18 12:03:43 +00001705
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001706 /* Expect the SWIDTH (scalable width) field next. */
1707 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1708 {
1709 if ( !( p->flags & _BDF_ENCODING ) )
1710 {
1711 /* Missing ENCODING field. */
1712 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1713 error = BDF_Err_Missing_Encoding_Field;
1714 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001715 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001716
David Turner68df4f72005-03-15 18:18:57 +00001717 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001718 if ( error )
1719 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001720
David Turnerb1b47622002-05-21 21:17:43 +00001721 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001722 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001723
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001724 goto Exit;
1725 }
David Turner993a8d02002-05-18 12:03:43 +00001726
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001727 /* Expect the DWIDTH (scalable width) field next. */
1728 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1729 {
David Turner68df4f72005-03-15 18:18:57 +00001730 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001731 if ( error )
1732 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001733
David Turnerb1b47622002-05-21 21:17:43 +00001734 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001735
1736 if ( !( p->flags & _BDF_SWIDTH ) )
1737 {
1738 /* Missing SWIDTH field. Emit an auto correction message and set */
1739 /* the scalable width from the device width. */
1740 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1741
Werner Lemberg02d4d592002-05-28 22:38:05 +00001742 glyph->swidth = (unsigned short)FT_MulDiv(
1743 glyph->dwidth, 72000L,
1744 (FT_Long)( font->point_size *
1745 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001746 }
1747
1748 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001749 goto Exit;
1750 }
David Turner993a8d02002-05-18 12:03:43 +00001751
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001752 /* Expect the BBX field next. */
1753 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1754 {
David Turner68df4f72005-03-15 18:18:57 +00001755 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001756 if ( error )
1757 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001758
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001759 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1760 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1761 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1762 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1763
1764 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001765 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1766 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001767
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001768 /* Determine the overall font bounding box as the characters are */
1769 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001770 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1771 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001772
David Turnerb1b47622002-05-21 21:17:43 +00001773 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001774
Werner Lembergdfa46192004-03-05 09:26:24 +00001775 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1776 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1777 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001778
1779 if ( !( p->flags & _BDF_DWIDTH ) )
1780 {
1781 /* Missing DWIDTH field. Emit an auto correction message and set */
1782 /* the device width to the glyph width. */
1783 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1784 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001785 }
1786
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001787 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1788 /* value if necessary. */
1789 if ( p->opts->correct_metrics != 0 )
1790 {
1791 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001792 unsigned short sw = (unsigned short)FT_MulDiv(
1793 glyph->dwidth, 72000L,
1794 (FT_Long)( font->point_size *
1795 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001796
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001797
1798 if ( sw != glyph->swidth )
1799 {
1800 glyph->swidth = sw;
1801
1802 if ( p->glyph_enc == -1 )
1803 _bdf_set_glyph_modified( font->umod,
1804 font->unencoded_used - 1 );
1805 else
1806 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1807
1808 p->flags |= _BDF_SWIDTH_ADJ;
1809 font->modified = 1;
1810 }
David Turner993a8d02002-05-18 12:03:43 +00001811 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001812
David Turner993a8d02002-05-18 12:03:43 +00001813 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001814 goto Exit;
1815 }
David Turner993a8d02002-05-18 12:03:43 +00001816
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001817 /* And finally, gather up the bitmap. */
1818 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1819 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001820 unsigned long bitmap_size;
1821
1822
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001823 if ( !( p->flags & _BDF_BBX ) )
1824 {
1825 /* Missing BBX field. */
1826 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1827 error = BDF_Err_Missing_Bbx_Field;
1828 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001829 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001830
1831 /* Allocate enough space for the bitmap. */
1832 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001833
1834 bitmap_size = glyph->bpr * glyph->bbx.height;
1835 if ( bitmap_size > 0xFFFFU )
1836 {
1837 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1838 error = BDF_Err_Bbx_Too_Big;
1839 goto Exit;
1840 }
1841 else
1842 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001843
1844 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1845 goto Exit;
1846
1847 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001848 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001849
1850 goto Exit;
1851 }
1852
1853 error = BDF_Err_Invalid_File_Format;
1854
1855 Exit:
1856 return error;
David Turner993a8d02002-05-18 12:03:43 +00001857 }
1858
David Turner993a8d02002-05-18 12:03:43 +00001859
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001860 /* Load the font properties. */
1861 static FT_Error
1862 _bdf_parse_properties( char* line,
1863 unsigned long linelen,
1864 unsigned long lineno,
1865 void* call_data,
1866 void* client_data )
1867 {
1868 unsigned long vlen;
1869 _bdf_line_func_t* next;
1870 _bdf_parse_t* p;
1871 char* name;
1872 char* value;
1873 char nbuf[128];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001874 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001875
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001876 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001877
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001878
1879 next = (_bdf_line_func_t *)call_data;
1880 p = (_bdf_parse_t *) client_data;
1881
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001882 /* Check for the end of the properties. */
1883 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1884 {
1885 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1886 /* encountered yet, then make sure they are added as properties and */
1887 /* make sure they are set from the font bounding box info. */
1888 /* */
1889 /* This is *always* done regardless of the options, because X11 */
1890 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001891 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001892 {
1893 p->font->font_ascent = p->font->bbx.ascent;
1894 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1895 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
1896 if ( error )
1897 goto Exit;
1898
1899 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1900 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001901 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001902
Werner Lemberg428c2e42003-04-25 05:35:04 +00001903 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001904 {
1905 p->font->font_descent = p->font->bbx.descent;
1906 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1907 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
1908 if ( error )
1909 goto Exit;
1910
1911 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1912 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001913 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001914
David Turner993a8d02002-05-18 12:03:43 +00001915 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001916 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001917
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001918 goto Exit;
1919 }
David Turner993a8d02002-05-18 12:03:43 +00001920
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001921 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1922 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1923 goto Exit;
1924
1925 /* Handle COMMENT fields and properties in a special way to preserve */
1926 /* the spacing. */
1927 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1928 {
David Turner993a8d02002-05-18 12:03:43 +00001929 name = value = line;
1930 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001931 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001932 *value++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001933 error = _bdf_add_property( p->font, name, value );
1934 if ( error )
1935 goto Exit;
1936 }
1937 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1938 {
1939 error = _bdf_add_property( p->font, name, value );
1940 if ( error )
1941 goto Exit;
1942 }
1943 else
1944 {
David Turner68df4f72005-03-15 18:18:57 +00001945 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001946 if ( error )
1947 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001948 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001949
David Turner68df4f72005-03-15 18:18:57 +00001950 _bdf_list_shift( &p->list, 1 );
1951 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001952
1953 error = _bdf_add_property( p->font, name, value );
1954 if ( error )
1955 goto Exit;
1956 }
1957
1958 Exit:
1959 return error;
David Turner993a8d02002-05-18 12:03:43 +00001960 }
1961
David Turner993a8d02002-05-18 12:03:43 +00001962
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001963 /* Load the font header. */
1964 static FT_Error
1965 _bdf_parse_start( char* line,
1966 unsigned long linelen,
1967 unsigned long lineno,
1968 void* call_data,
1969 void* client_data )
1970 {
1971 unsigned long slen;
1972 _bdf_line_func_t* next;
1973 _bdf_parse_t* p;
1974 bdf_font_t* font;
1975 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001976
David Turnerd490e372002-05-28 23:40:37 +00001977 FT_Memory memory = NULL;
1978 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001979
1980 FT_UNUSED( lineno ); /* only used in debug mode */
1981
1982
1983 next = (_bdf_line_func_t *)call_data;
1984 p = (_bdf_parse_t *) client_data;
1985
1986 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00001987 memory = p->font->memory;
1988
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001989 /* Check for a comment. This is done to handle those fonts that have */
1990 /* comments before the STARTFONT line for some reason. */
1991 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1992 {
1993 if ( p->opts->keep_comments != 0 && p->font != 0 )
1994 {
1995 linelen -= 7;
1996
1997 s = line + 7;
1998 if ( *s != 0 )
1999 {
2000 s++;
2001 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002002 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002003
2004 error = _bdf_add_comment( p->font, s, linelen );
2005 if ( error )
2006 goto Exit;
2007 /* here font is not defined! */
2008 }
2009
2010 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002011 }
2012
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002013 if ( !( p->flags & _BDF_START ) )
2014 {
2015 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002016
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002017 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2018 {
2019 /* No STARTFONT field is a good indication of a problem. */
2020 error = BDF_Err_Missing_Startfont_Field;
2021 goto Exit;
2022 }
David Turner993a8d02002-05-18 12:03:43 +00002023
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002024 p->flags = _BDF_START;
2025 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002026
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002027 if ( FT_NEW( font ) )
2028 goto Exit;
2029 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002030
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002031 font->memory = p->memory;
2032 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002033
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002034 { /* setup */
2035 unsigned long i;
2036 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002037
David Turner993a8d02002-05-18 12:03:43 +00002038
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002039 error = hash_init( &(font->proptbl), memory );
2040 if ( error )
2041 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002042 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002043 i < _num_bdf_properties; i++, prop++ )
2044 {
2045 error = hash_insert( prop->name, (void *)i,
2046 &(font->proptbl), memory );
2047 if ( error )
2048 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002049 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002050 }
2051
2052 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2053 goto Exit;
2054 error = hash_init( (hashtable *)p->font->internal,memory );
2055 if ( error )
2056 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002057 p->font->spacing = p->opts->font_spacing;
2058 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002059
2060 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002061 }
2062
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002063 /* Check for the start of the properties. */
2064 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2065 {
David Turner68df4f72005-03-15 18:18:57 +00002066 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002067 if ( error )
2068 goto Exit;
2069 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2070
2071 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2072 goto Exit;
2073
2074 p->flags |= _BDF_PROPS;
2075 *next = _bdf_parse_properties;
2076
2077 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002078 }
2079
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002080 /* Check for the FONTBOUNDINGBOX field. */
2081 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2082 {
2083 if ( !(p->flags & _BDF_SIZE ) )
2084 {
2085 /* Missing the SIZE field. */
2086 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2087 error = BDF_Err_Missing_Size_Field;
2088 goto Exit;
2089 }
2090
David Turner68df4f72005-03-15 18:18:57 +00002091 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002092 if ( error )
2093 goto Exit;
2094
2095 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2096 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2097
2098 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2099 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2100
David Turnerd490e372002-05-28 23:40:37 +00002101 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002102 p->font->bbx.y_offset );
2103
2104 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002105
2106 p->flags |= _BDF_FONT_BBX;
2107
2108 goto Exit;
2109 }
2110
2111 /* The next thing to check for is the FONT field. */
2112 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2113 {
David Turner68df4f72005-03-15 18:18:57 +00002114 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002115 if ( error )
2116 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002117 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002118
David Turner68df4f72005-03-15 18:18:57 +00002119 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002120 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2121 goto Exit;
2122 FT_MEM_COPY( p->font->name, s, slen + 1 );
2123
2124 /* If the font name is an XLFD name, set the spacing to the one in */
2125 /* the font name. If there is no spacing fall back on the default. */
2126 error = _bdf_set_default_spacing( p->font, p->opts );
2127 if ( error )
2128 goto Exit;
2129
2130 p->flags |= _BDF_FONT_NAME;
2131
2132 goto Exit;
2133 }
2134
2135 /* Check for the SIZE field. */
2136 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2137 {
2138 if ( !( p->flags & _BDF_FONT_NAME ) )
2139 {
2140 /* Missing the FONT field. */
2141 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2142 error = BDF_Err_Missing_Font_Field;
2143 goto Exit;
2144 }
2145
David Turner68df4f72005-03-15 18:18:57 +00002146 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002147 if ( error )
2148 goto Exit;
2149
2150 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2151 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2152 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2153
2154 /* Check for the bits per pixel field. */
2155 if ( p->list.used == 5 )
2156 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002157 unsigned short bitcount, i, shift;
2158
2159
2160 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2161
2162 /* Only values 1, 2, 4, 8 are allowed. */
2163 shift = p->font->bpp;
2164 bitcount = 0;
2165 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002166 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002167 if ( shift & 1 )
2168 bitcount = i;
2169 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002170 }
David Turner993a8d02002-05-18 12:03:43 +00002171
Werner Lembergbd8e3242002-06-12 08:43:58 +00002172 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002173
2174 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002175 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002176 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002177 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002178 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002179 }
2180 }
2181 else
2182 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002183
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002184 p->flags |= _BDF_SIZE;
2185
2186 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002187 }
2188
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002189 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002190
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002191 Exit:
2192 return error;
2193 }
David Turner993a8d02002-05-18 12:03:43 +00002194
2195
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002196 /*************************************************************************/
2197 /* */
2198 /* API. */
2199 /* */
2200 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002201
David Turner993a8d02002-05-18 12:03:43 +00002202
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002203 FT_LOCAL_DEF( FT_Error )
2204 bdf_load_font( FT_Stream stream,
2205 FT_Memory extmemory,
2206 bdf_options_t* opts,
2207 bdf_font_t* *font )
2208 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002209 unsigned long lineno = 0; /* make compiler happy */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002210 _bdf_parse_t *p;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002211
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002212 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002213 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002214
2215
David Turner68df4f72005-03-15 18:18:57 +00002216 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002217 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002218
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002219 memory = NULL;
2220 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2221 p->minlb = 32767;
2222 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002223
David Turner68df4f72005-03-15 18:18:57 +00002224 _bdf_list_init( &p->list, extmemory );
2225
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002226 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002227 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002228 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002229 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002230
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002231 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002232 {
2233 /* If the font is not proportional, set the font's monowidth */
2234 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002235 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002236
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002237 if ( p->font->spacing != BDF_PROPORTIONAL )
2238 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002239
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002240 /* If the number of glyphs loaded is not that of the original count, */
2241 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002242 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002243 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002244 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2245 p->font->glyphs_used + p->font->unencoded_used ));
2246 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002247 }
2248
2249 /* Once the font has been loaded, adjust the overall font metrics if */
2250 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002251 if ( p->opts->correct_metrics != 0 &&
2252 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002253 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002254 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002255 {
2256 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002257 p->font->bbx.width, p->maxrb - p->minlb ));
2258 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2259 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002260 }
2261
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002262 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002263 {
2264 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002265 p->font->bbx.x_offset, p->minlb ));
2266 p->font->bbx.x_offset = p->minlb;
2267 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002268 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002269
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002270 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002271 {
2272 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002273 p->font->bbx.ascent, p->maxas ));
2274 p->font->bbx.ascent = p->maxas;
2275 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002276 }
2277
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002278 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002279 {
2280 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002281 p->font->bbx.descent, p->maxds ));
2282 p->font->bbx.descent = p->maxds;
2283 p->font->bbx.y_offset = (short)( -p->maxds );
2284 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002285 }
2286
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002287 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002288 {
2289 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002290 p->font->bbx.height, p->maxas + p->maxds ));
2291 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002292 }
2293
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002294 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002295 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2296 }
David Turner993a8d02002-05-18 12:03:43 +00002297 }
2298
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002299 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002300 {
2301 {
2302 /* The ENDFONT field was never reached or did not exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002303 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002304 /* Error happened while parsing header. */
2305 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2306 else
2307 /* Error happened when parsing glyphs. */
2308 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2309 }
David Turner993a8d02002-05-18 12:03:43 +00002310 }
2311
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002312 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002313 {
2314 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002315 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002316
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002317 if ( p->font->comments_len > 0 ) {
2318 if ( FT_RENEW_ARRAY( p->font->comments,
2319 p->font->comments_len,
2320 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002321 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002322
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002323 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002324 }
David Turner993a8d02002-05-18 12:03:43 +00002325 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002326 else if ( error == BDF_Err_Ok )
2327 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002328
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002329 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002330
2331 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002332 if ( p )
2333 {
David Turner68df4f72005-03-15 18:18:57 +00002334 _bdf_list_done( &p->list );
2335
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002336 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002337
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002338 FT_FREE( p );
2339 }
2340
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002341 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002342
2343 Fail:
2344 bdf_free_font( p->font );
2345
2346 memory = extmemory;
2347
2348 FT_FREE( p->font );
2349
2350 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002351 }
David Turner993a8d02002-05-18 12:03:43 +00002352
2353
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002354 FT_LOCAL_DEF( void )
2355 bdf_free_font( bdf_font_t* font )
2356 {
2357 bdf_property_t* prop;
2358 unsigned long i;
2359 bdf_glyph_t* glyphs;
2360 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002361
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002362
2363 if ( font == 0 )
2364 return;
David Turner993a8d02002-05-18 12:03:43 +00002365
2366 memory = font->memory;
2367
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002368 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002369
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002370 /* Free up the internal hash table of property names. */
2371 if ( font->internal )
2372 {
2373 hash_free( (hashtable *)font->internal, memory );
2374 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002375 }
2376
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002377 /* Free up the comment info. */
2378 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002379
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002380 /* Free up the properties. */
2381 for ( i = 0; i < font->props_size; i++ )
2382 {
2383 if ( font->props[i].format == BDF_ATOM )
2384 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002385 }
2386
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002387 FT_FREE( font->props );
2388
2389 /* Free up the character info. */
2390 for ( i = 0, glyphs = font->glyphs;
2391 i < font->glyphs_used; i++, glyphs++ )
2392 {
2393 FT_FREE( glyphs->name );
2394 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002395 }
2396
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002397 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2398 i++, glyphs++ )
2399 {
2400 FT_FREE( glyphs->name );
2401 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002402 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002403
2404 FT_FREE( font->glyphs );
2405 FT_FREE( font->unencoded );
2406
2407 /* Free up the overflow storage if it was used. */
2408 for ( i = 0, glyphs = font->overflow.glyphs;
2409 i < font->overflow.glyphs_used; i++, glyphs++ )
2410 {
2411 FT_FREE( glyphs->name );
2412 FT_FREE( glyphs->bitmap );
2413 }
2414
2415 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002416
2417 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002418 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002419
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002420 /* Free up the user defined properties. */
2421 for (prop = font->user_props, i = 0;
2422 i < font->nuser_props; i++, prop++ )
2423 {
2424 FT_FREE( prop->name );
2425 if ( prop->format == BDF_ATOM )
2426 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002427 }
David Turner993a8d02002-05-18 12:03:43 +00002428
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002429 FT_FREE( font->user_props );
2430
2431 /* FREE( font ); */ /* XXX Fixme */
2432 }
David Turner993a8d02002-05-18 12:03:43 +00002433
2434
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002435 FT_LOCAL_DEF( bdf_property_t * )
2436 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002437 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002438 {
2439 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002440
David Turner993a8d02002-05-18 12:03:43 +00002441
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002442 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002443 return 0;
2444
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002445 hn = hash_lookup( name, (hashtable *)font->internal );
2446
2447 return hn ? ( font->props + (unsigned long)hn->data ) : 0;
2448 }
2449
2450
2451/* END */