blob: ed08a6e0156ff8f034208834bdc061080cab33c1 [file] [log] [blame]
David Turner993a8d02002-05-18 12:03:43 +00001/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
Werner Lemberg320d4972012-02-24 18:06:46 +01003 * Copyright 2001-2012
Werner Lemberg442bfb82007-02-12 21:44:10 +00004 * 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 Lemberge01406b2011-11-25 09:44:28 +0100172 /* Auto correction messages. */
173#define ACMSG1 "FONT_ASCENT property missing. " \
174 "Added `FONT_ASCENT %hd'.\n"
175#define ACMSG2 "FONT_DESCENT property missing. " \
176 "Added `FONT_DESCENT %hd'.\n"
177#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
178#define ACMSG4 "Font left bearing != actual left bearing. " \
179 "Old: %hd New: %hd.\n"
180#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
181#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
182#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
183#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
184#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
185#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
186#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
187#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
188#define ACMSG13 "Glyph %ld extra rows removed.\n"
189#define ACMSG14 "Glyph %ld extra columns removed.\n"
190#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
Werner Lemberg0b1c0c62012-02-25 10:23:04 +0100191#define ACMSG16 "Glyph %ld missing columns padded with zero bits.\n"
Werner Lemberge01406b2011-11-25 09:44:28 +0100192
193 /* Error messages. */
194#define ERRMSG1 "[line %ld] Missing `%s' line.\n"
195#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
196#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
197#define ERRMSG4 "[line %ld] BBX too big.\n"
198#define ERRMSG5 "[line %ld] `%s' value too big.\n"
199#define ERRMSG6 "[line %ld] Input line too long.\n"
200#define ERRMSG7 "[line %ld] Font name too long.\n"
201#define ERRMSG8 "[line %ld] Invalid `%s' value.\n"
202#define ERRMSG9 "[line %ld] Invalid keyword.\n"
203
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +0100204 /* Debug messages. */
205#define DBGMSG1 " [%6ld] %s" /* no \n */
206#define DBGMSG2 " (0x%lX)\n"
207
Werner Lemberge01406b2011-11-25 09:44:28 +0100208
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000209 /*************************************************************************/
210 /* */
211 /* Hash table utilities for the properties. */
212 /* */
213 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +0000214
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000215 /* XXX: Replace this with FreeType's hash functions */
David Turner993a8d02002-05-18 12:03:43 +0000216
David Turner993a8d02002-05-18 12:03:43 +0000217
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000218#define INITIAL_HT_SIZE 241
219
220 typedef void
221 (*hash_free_func)( hashnode node );
222
223 static hashnode*
Werner Lemberg428c2e42003-04-25 05:35:04 +0000224 hash_bucket( const char* key,
225 hashtable* ht )
David Turner993a8d02002-05-18 12:03:43 +0000226 {
Werner Lemberg428c2e42003-04-25 05:35:04 +0000227 const char* kp = key;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000228 unsigned long res = 0;
229 hashnode* bp = ht->table, *ndp;
230
231
232 /* Mocklisp hash function. */
233 while ( *kp )
234 res = ( res << 5 ) - res + *kp++;
235
236 ndp = bp + ( res % ht->size );
237 while ( *ndp )
David Turner993a8d02002-05-18 12:03:43 +0000238 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000239 kp = (*ndp)->key;
240 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
241 break;
242 ndp--;
243 if ( ndp < bp )
244 ndp = bp + ( ht->size - 1 );
David Turner993a8d02002-05-18 12:03:43 +0000245 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000246
247 return ndp;
David Turner993a8d02002-05-18 12:03:43 +0000248 }
David Turner993a8d02002-05-18 12:03:43 +0000249
250
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000251 static FT_Error
252 hash_rehash( hashtable* ht,
253 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000254 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000255 hashnode* obp = ht->table, *bp, *nbp;
David Turner993a8d02002-05-18 12:03:43 +0000256 int i, sz = ht->size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000257 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000258
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000259
260 ht->size <<= 1;
261 ht->limit = ht->size / 3;
262
263 if ( FT_NEW_ARRAY( ht->table, ht->size ) )
264 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000265
266 for ( i = 0, bp = obp; i < sz; i++, bp++ )
David Turner993a8d02002-05-18 12:03:43 +0000267 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000268 if ( *bp )
269 {
270 nbp = hash_bucket( (*bp)->key, ht );
271 *nbp = *bp;
272 }
David Turner993a8d02002-05-18 12:03:43 +0000273 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000274 FT_FREE( obp );
275
276 Exit:
277 return error;
David Turner993a8d02002-05-18 12:03:43 +0000278 }
David Turner993a8d02002-05-18 12:03:43 +0000279
280
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000281 static FT_Error
282 hash_init( hashtable* ht,
283 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000284 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000285 int sz = INITIAL_HT_SIZE;
286 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000287
David Turner993a8d02002-05-18 12:03:43 +0000288
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000289 ht->size = sz;
290 ht->limit = sz / 3;
291 ht->used = 0;
David Turner993a8d02002-05-18 12:03:43 +0000292
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000293 if ( FT_NEW_ARRAY( ht->table, sz ) )
294 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000295
296 Exit:
297 return error;
David Turner993a8d02002-05-18 12:03:43 +0000298 }
David Turner993a8d02002-05-18 12:03:43 +0000299
300
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000301 static void
302 hash_free( hashtable* ht,
303 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000304 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000305 if ( ht != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000306 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000307 int i, sz = ht->size;
308 hashnode* bp = ht->table;
David Turner993a8d02002-05-18 12:03:43 +0000309
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000310
311 for ( i = 0; i < sz; i++, bp++ )
312 FT_FREE( *bp );
313
314 FT_FREE( ht->table );
315 }
David Turner993a8d02002-05-18 12:03:43 +0000316 }
317
David Turner993a8d02002-05-18 12:03:43 +0000318
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000319 static FT_Error
320 hash_insert( char* key,
suzuki toshiya704f4d72009-09-13 00:50:14 +0900321 size_t data,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000322 hashtable* ht,
323 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000324 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000325 hashnode nn, *bp = hash_bucket( key, ht );
326 FT_Error error = BDF_Err_Ok;
327
328
329 nn = *bp;
330 if ( !nn )
331 {
332 if ( FT_NEW( nn ) )
333 goto Exit;
334 *bp = nn;
335
336 nn->key = key;
337 nn->data = data;
338
339 if ( ht->used >= ht->limit )
340 {
341 error = hash_rehash( ht, memory );
342 if ( error )
343 goto Exit;
344 }
345 ht->used++;
346 }
David Turner993a8d02002-05-18 12:03:43 +0000347 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000348 nn->data = data;
349
350 Exit:
351 return error;
David Turner993a8d02002-05-18 12:03:43 +0000352 }
353
David Turner993a8d02002-05-18 12:03:43 +0000354
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000355 static hashnode
Werner Lemberg428c2e42003-04-25 05:35:04 +0000356 hash_lookup( const char* key,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000357 hashtable* ht )
358 {
359 hashnode *np = hash_bucket( key, ht );
360
361
362 return *np;
363 }
364
365
366 /*************************************************************************/
367 /* */
368 /* Utility types and functions. */
369 /* */
370 /*************************************************************************/
371
372
373 /* Function type for parsing lines of a BDF font. */
374
375 typedef FT_Error
376 (*_bdf_line_func_t)( char* line,
377 unsigned long linelen,
378 unsigned long lineno,
379 void* call_data,
380 void* client_data );
381
382
383 /* List structure for splitting lines into fields. */
384
385 typedef struct _bdf_list_t_
386 {
387 char** field;
388 unsigned long size;
389 unsigned long used;
David Turner68df4f72005-03-15 18:18:57 +0000390 FT_Memory memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000391
392 } _bdf_list_t;
393
394
395 /* Structure used while loading BDF fonts. */
396
397 typedef struct _bdf_parse_t_
398 {
399 unsigned long flags;
400 unsigned long cnt;
401 unsigned long row;
402
403 short minlb;
404 short maxlb;
405 short maxrb;
406 short maxas;
407 short maxds;
408
409 short rbearing;
410
411 char* glyph_name;
412 long glyph_enc;
413
414 bdf_font_t* font;
415 bdf_options_t* opts;
416
Werner Lemberged54e432011-11-27 16:39:53 +0100417 unsigned long have[34816]; /* must be in sync with `nmod' and `umod' */
418 /* arrays from `bdf_font_t' structure */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000419 _bdf_list_t list;
420
421 FT_Memory memory;
422
423 } _bdf_parse_t;
424
425
Werner Lemberga08b2172007-03-28 07:17:17 +0000426#define setsbit( m, cc ) \
427 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
428#define sbitset( m, cc ) \
429 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000430
431
David Turner68df4f72005-03-15 18:18:57 +0000432 static void
433 _bdf_list_init( _bdf_list_t* list,
434 FT_Memory memory )
435 {
Werner Lembergebf55852005-03-16 01:49:54 +0000436 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000437 list->memory = memory;
438 }
439
Werner Lembergebf55852005-03-16 01:49:54 +0000440
David Turner68df4f72005-03-15 18:18:57 +0000441 static void
442 _bdf_list_done( _bdf_list_t* list )
443 {
444 FT_Memory memory = list->memory;
445
Werner Lembergebf55852005-03-16 01:49:54 +0000446
David Turner68df4f72005-03-15 18:18:57 +0000447 if ( memory )
448 {
449 FT_FREE( list->field );
Werner Lembergebf55852005-03-16 01:49:54 +0000450 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000451 }
452 }
453
454
455 static FT_Error
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900456 _bdf_list_ensure( _bdf_list_t* list,
457 unsigned long num_items ) /* same as _bdf_list_t.used */
David Turner68df4f72005-03-15 18:18:57 +0000458 {
Werner Lembergebf55852005-03-16 01:49:54 +0000459 FT_Error error = BDF_Err_Ok;
460
David Turner68df4f72005-03-15 18:18:57 +0000461
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900462 if ( num_items > list->size )
David Turner68df4f72005-03-15 18:18:57 +0000463 {
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900464 unsigned long oldsize = list->size; /* same as _bdf_list_t.size */
Werner Lembergcee5d592012-03-01 09:26:03 +0100465 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 5;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900466 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
467 FT_Memory memory = list->memory;
David Turner68df4f72005-03-15 18:18:57 +0000468
Werner Lembergebf55852005-03-16 01:49:54 +0000469
David Turner68df4f72005-03-15 18:18:57 +0000470 if ( oldsize == bigsize )
471 {
Werner Lembergebf55852005-03-16 01:49:54 +0000472 error = BDF_Err_Out_Of_Memory;
David Turner68df4f72005-03-15 18:18:57 +0000473 goto Exit;
474 }
475 else if ( newsize < oldsize || newsize > bigsize )
476 newsize = bigsize;
477
478 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
479 goto Exit;
480
481 list->size = newsize;
482 }
Werner Lembergebf55852005-03-16 01:49:54 +0000483
David Turner68df4f72005-03-15 18:18:57 +0000484 Exit:
485 return error;
486 }
487
488
489 static void
490 _bdf_list_shift( _bdf_list_t* list,
491 unsigned long n )
492 {
493 unsigned long i, u;
494
495
496 if ( list == 0 || list->used == 0 || n == 0 )
497 return;
498
499 if ( n >= list->used )
500 {
501 list->used = 0;
502 return;
503 }
504
505 for ( u = n, i = 0; u < list->used; i++, u++ )
506 list->field[i] = list->field[u];
507 list->used -= n;
508 }
509
510
Werner Lembergf4c94d42010-06-19 16:08:31 +0200511 /* An empty string for empty fields. */
512
513 static const char empty[1] = { 0 }; /* XXX eliminate this */
514
515
David Turner68df4f72005-03-15 18:18:57 +0000516 static char *
517 _bdf_list_join( _bdf_list_t* list,
518 int c,
519 unsigned long *alen )
520 {
521 unsigned long i, j;
522 char *fp, *dp;
523
524
525 *alen = 0;
526
527 if ( list == 0 || list->used == 0 )
528 return 0;
529
530 dp = list->field[0];
531 for ( i = j = 0; i < list->used; i++ )
532 {
533 fp = list->field[i];
534 while ( *fp )
535 dp[j++] = *fp++;
536
537 if ( i + 1 < list->used )
538 dp[j++] = (char)c;
539 }
Werner Lembergf4c94d42010-06-19 16:08:31 +0200540 if ( dp != empty )
541 dp[j] = 0;
David Turner68df4f72005-03-15 18:18:57 +0000542
543 *alen = j;
544 return dp;
545 }
546
547
Werner Lemberg03242f52012-02-26 06:52:56 +0100548 /* The code below ensures that we have at least 4 + 1 `field' */
549 /* elements in `list' (which are possibly NULL) so that we */
550 /* don't have to check the number of fields in most cases. */
551
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000552 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000553 _bdf_list_split( _bdf_list_t* list,
554 char* separators,
555 char* line,
556 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000557 {
558 int mult, final_empty;
559 char *sp, *ep, *end;
560 char seps[32];
561 FT_Error error = BDF_Err_Ok;
562
563
564 /* Initialize the list. */
565 list->used = 0;
Werner Lembergd9c16592012-03-01 15:15:00 +0100566 if ( list->size )
567 {
568 list->field[0] = (char*)empty;
569 list->field[1] = (char*)empty;
570 list->field[2] = (char*)empty;
571 list->field[3] = (char*)empty;
Werner Lemberg649c6732012-03-16 21:12:41 +0100572 list->field[4] = (char*)empty;
Werner Lembergd9c16592012-03-01 15:15:00 +0100573 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000574
575 /* If the line is empty, then simply return. */
576 if ( linelen == 0 || line[0] == 0 )
577 goto Exit;
578
579 /* In the original code, if the `separators' parameter is NULL or */
580 /* empty, the list is split into individual bytes. We don't need */
581 /* this, so an error is signaled. */
582 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000583 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000584 error = BDF_Err_Invalid_Argument;
585 goto Exit;
586 }
587
588 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000589 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000590
591 /* If the very last character of the separator string is a plus, then */
592 /* set the `mult' flag to indicate that multiple separators should be */
593 /* collapsed into one. */
594 for ( mult = 0, sp = separators; sp && *sp; sp++ )
595 {
596 if ( *sp == '+' && *( sp + 1 ) == 0 )
597 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000598 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000599 setsbit( seps, *sp );
600 }
601
602 /* Break the line up into fields. */
603 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
604 sp < end && *sp; )
605 {
606 /* Collect everything that is not a separator. */
607 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
608 ;
609
610 /* Resize the list if necessary. */
611 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000612 {
Werner Lembergebf55852005-03-16 01:49:54 +0000613 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000614 if ( error )
615 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000616 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000617
618 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000619 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000620
621 sp = ep;
622
623 if ( mult )
624 {
625 /* If multiple separators should be collapsed, do it now by */
626 /* setting all the separator characters to 0. */
627 for ( ; *ep && sbitset( seps, *ep ); ep++ )
628 *ep = 0;
629 }
630 else if ( *ep != 0 )
631 /* Don't collapse multiple separators by making them 0, so just */
632 /* make the one encountered 0. */
633 *ep++ = 0;
634
635 final_empty = ( ep > sp && *ep == 0 );
636 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000637 }
638
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000639 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000640 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000641 {
Werner Lembergebf55852005-03-16 01:49:54 +0000642 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000643 if ( error )
644 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000645 }
646
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000647 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000648 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000649
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000650 list->field[list->used] = 0;
651
652 Exit:
653 return error;
David Turner993a8d02002-05-18 12:03:43 +0000654 }
655
David Turner993a8d02002-05-18 12:03:43 +0000656
David Turner68df4f72005-03-15 18:18:57 +0000657#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000658
Werner Lembergebf55852005-03-16 01:49:54 +0000659
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000660 static FT_Error
661 _bdf_readstream( FT_Stream stream,
662 _bdf_line_func_t callback,
663 void* client_data,
664 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000665 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000666 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000667 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900668 int refill, hold, to_skip;
669 ptrdiff_t bytes, start, end, cursor, avail;
David Turner68df4f72005-03-15 18:18:57 +0000670 char* buf = 0;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000671 FT_Memory memory = stream->memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000672 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000673
David Turner993a8d02002-05-18 12:03:43 +0000674
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000675 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000676 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000677 error = BDF_Err_Invalid_Argument;
678 goto Exit;
679 }
David Turner993a8d02002-05-18 12:03:43 +0000680
Werner Lembergebf55852005-03-16 01:49:54 +0000681 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000682 buf_size = 1024;
683
684 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000685 goto Exit;
686
Werner Lembergebf55852005-03-16 01:49:54 +0000687 cb = callback;
688 lineno = 1;
689 buf[0] = 0;
690 start = 0;
691 end = 0;
692 avail = 0;
693 cursor = 0;
694 refill = 1;
695 to_skip = NO_SKIP;
696 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000697
David Turner68df4f72005-03-15 18:18:57 +0000698 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000699 {
David Turner68df4f72005-03-15 18:18:57 +0000700 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000701 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +0200702 bytes = (ptrdiff_t)FT_Stream_TryRead(
703 stream, (FT_Byte*)buf + cursor,
704 (FT_ULong)( buf_size - cursor ) );
David Turner68df4f72005-03-15 18:18:57 +0000705 avail = cursor + bytes;
706 cursor = 0;
707 refill = 0;
708 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000709
David Turner68df4f72005-03-15 18:18:57 +0000710 end = start;
711
Werner Lembergebf55852005-03-16 01:49:54 +0000712 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000713 if ( start < avail && buf[start] == to_skip )
714 {
715 start += 1;
716 to_skip = NO_SKIP;
717 continue;
718 }
719
720 /* try to find the end of the line */
721 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
722 end++;
723
Werner Lembergebf55852005-03-16 01:49:54 +0000724 /* if we hit the end of the buffer, try shifting its content */
725 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000726 if ( end >= avail )
727 {
728 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
729 break; /* ignore it then exit */
730
731 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000732 {
Werner Lembergebf55852005-03-16 01:49:54 +0000733 /* this line is definitely too long; try resizing the input */
734 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000735 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000736
Werner Lembergebf55852005-03-16 01:49:54 +0000737
738 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000739 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100740 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
David Turner68df4f72005-03-15 18:18:57 +0000741 error = BDF_Err_Invalid_Argument;
742 goto Exit;
743 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000744
Werner Lembergebf55852005-03-16 01:49:54 +0000745 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000746 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
747 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000748
David Turner68df4f72005-03-15 18:18:57 +0000749 cursor = buf_size;
750 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000751 }
752 else
753 {
David Turner68df4f72005-03-15 18:18:57 +0000754 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000755
Werner Lembergebf55852005-03-16 01:49:54 +0000756 FT_MEM_COPY( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000757
David Turner68df4f72005-03-15 18:18:57 +0000758 cursor = bytes;
759 avail -= bytes;
760 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000761 }
David Turner68df4f72005-03-15 18:18:57 +0000762 refill = 1;
763 continue;
David Turner993a8d02002-05-18 12:03:43 +0000764 }
David Turner68df4f72005-03-15 18:18:57 +0000765
766 /* Temporarily NUL-terminate the line. */
767 hold = buf[end];
768 buf[end] = 0;
769
770 /* XXX: Use encoding independent value for 0x1a */
771 if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
772 {
Werner Lembergebf55852005-03-16 01:49:54 +0000773 error = (*cb)( buf + start, end - start, lineno,
774 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200775 /* Redo if we have encountered CHARS without properties. */
776 if ( error == -1 )
777 error = (*cb)( buf + start, end - start, lineno,
778 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000779 if ( error )
780 break;
781 }
782
783 lineno += 1;
784 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000785 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000786
787 if ( hold == '\n' )
788 to_skip = '\r';
789 else if ( hold == '\r' )
790 to_skip = '\n';
791 else
792 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000793 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000794
David Turner68df4f72005-03-15 18:18:57 +0000795 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000796
797 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000798 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000799 return error;
David Turner993a8d02002-05-18 12:03:43 +0000800 }
David Turner993a8d02002-05-18 12:03:43 +0000801
802
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000803 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000804
David Turnerb1b47622002-05-21 21:17:43 +0000805 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000806 {
David Turner993a8d02002-05-18 12:03:43 +0000807 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
808 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
809 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
811 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
812 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
813 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
814 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
815 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
816 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
817 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000818 };
David Turner993a8d02002-05-18 12:03:43 +0000819
David Turnerb1b47622002-05-21 21:17:43 +0000820 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000821 {
David Turner993a8d02002-05-18 12:03:43 +0000822 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
823 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
825 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000826 };
David Turner993a8d02002-05-18 12:03:43 +0000827
David Turnerb1b47622002-05-21 21:17:43 +0000828 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000829 {
David Turner993a8d02002-05-18 12:03:43 +0000830 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
831 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
832 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
833 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000834 };
David Turner993a8d02002-05-18 12:03:43 +0000835
David Turnerb1b47622002-05-21 21:17:43 +0000836 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000837 {
David Turner993a8d02002-05-18 12:03:43 +0000838 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
839 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
840 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
841 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000842 };
David Turner993a8d02002-05-18 12:03:43 +0000843
David Turner993a8d02002-05-18 12:03:43 +0000844
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000845 /* Routine to convert an ASCII string into an unsigned long integer. */
846 static unsigned long
847 _bdf_atoul( char* s,
848 char** end,
849 int base )
David Turner993a8d02002-05-18 12:03:43 +0000850 {
David Turnerb1b47622002-05-21 21:17:43 +0000851 unsigned long v;
852 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000853
854
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000855 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000856 return 0;
857
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000858 /* Make sure the radix is something recognizable. Default to 10. */
859 switch ( base )
860 {
861 case 8:
862 dmap = odigits;
863 break;
864 case 16:
865 dmap = hdigits;
866 break;
867 default:
868 base = 10;
869 dmap = ddigits;
870 break;
David Turner993a8d02002-05-18 12:03:43 +0000871 }
872
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000873 /* Check for the special hex prefix. */
874 if ( *s == '0' &&
875 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
876 {
877 base = 16;
878 dmap = hdigits;
879 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000880 }
881
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +0100882 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000883 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000884
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000885 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000886 *end = s;
887
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000888 return v;
889 }
David Turner993a8d02002-05-18 12:03:43 +0000890
David Turner993a8d02002-05-18 12:03:43 +0000891
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000892 /* Routine to convert an ASCII string into an signed long integer. */
893 static long
894 _bdf_atol( char* s,
895 char** end,
896 int base )
897 {
David Turnerb1b47622002-05-21 21:17:43 +0000898 long v, neg;
899 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000900
901
902 if ( s == 0 || *s == 0 )
903 return 0;
904
905 /* Make sure the radix is something recognizable. Default to 10. */
906 switch ( base )
907 {
908 case 8:
909 dmap = odigits;
910 break;
911 case 16:
912 dmap = hdigits;
913 break;
914 default:
915 base = 10;
916 dmap = ddigits;
917 break;
918 }
919
920 /* Check for a minus sign. */
921 neg = 0;
922 if ( *s == '-' )
923 {
924 s++;
925 neg = 1;
926 }
927
928 /* Check for the special hex prefix. */
929 if ( *s == '0' &&
930 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
931 {
932 base = 16;
933 dmap = hdigits;
934 s += 2;
935 }
936
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +0100937 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000938 v = v * base + a2i[(int)*s];
939
940 if ( end != 0 )
941 *end = s;
942
943 return ( !neg ) ? v : -v;
944 }
945
946
947 /* Routine to convert an ASCII string into an signed short integer. */
948 static short
949 _bdf_atos( char* s,
950 char** end,
951 int base )
952 {
David Turnerb1b47622002-05-21 21:17:43 +0000953 short v, neg;
954 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000955
956
957 if ( s == 0 || *s == 0 )
958 return 0;
959
960 /* Make sure the radix is something recognizable. Default to 10. */
961 switch ( base )
962 {
963 case 8:
964 dmap = odigits;
965 break;
966 case 16:
967 dmap = hdigits;
968 break;
969 default:
970 base = 10;
971 dmap = ddigits;
972 break;
973 }
974
975 /* Check for a minus. */
976 neg = 0;
977 if ( *s == '-' )
978 {
979 s++;
980 neg = 1;
981 }
982
983 /* Check for the special hex prefix. */
984 if ( *s == '0' &&
985 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
986 {
987 base = 16;
988 dmap = hdigits;
989 s += 2;
990 }
991
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +0100992 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +0000993 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000994
995 if ( end != 0 )
996 *end = s;
997
Werner Lemberg233302a2002-05-22 05:41:06 +0000998 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000999 }
1000
1001
1002 /* Routine to compare two glyphs by encoding so they can be sorted. */
1003 static int
1004 by_encoding( const void* a,
1005 const void* b )
1006 {
1007 bdf_glyph_t *c1, *c2;
1008
1009
1010 c1 = (bdf_glyph_t *)a;
1011 c2 = (bdf_glyph_t *)b;
1012
1013 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001014 return -1;
David Turner68df4f72005-03-15 18:18:57 +00001015
1016 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001017 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001018
David Turner993a8d02002-05-18 12:03:43 +00001019 return 0;
David Turner993a8d02002-05-18 12:03:43 +00001020 }
1021
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001022
1023 static FT_Error
1024 bdf_create_property( char* name,
1025 int format,
1026 bdf_font_t* font )
1027 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001028 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001029 bdf_property_t* p;
1030 FT_Memory memory = font->memory;
1031 FT_Error error = BDF_Err_Ok;
1032
1033
Werner Lemberg96ddc672011-06-29 09:15:54 +02001034 /* First check whether the property has */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001035 /* already been added or not. If it has, then */
1036 /* simply ignore it. */
1037 if ( hash_lookup( name, &(font->proptbl) ) )
1038 goto Exit;
1039
David Turner68df4f72005-03-15 18:18:57 +00001040 if ( FT_RENEW_ARRAY( font->user_props,
1041 font->nuser_props,
1042 font->nuser_props + 1 ) )
1043 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001044
1045 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +00001046 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001047
suzuki toshiya704f4d72009-09-13 00:50:14 +09001048 n = ft_strlen( name ) + 1;
1049 if ( n > FT_ULONG_MAX )
1050 return BDF_Err_Invalid_Argument;
David Turner68df4f72005-03-15 18:18:57 +00001051
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001052 if ( FT_NEW_ARRAY( p->name, n ) )
1053 goto Exit;
1054
1055 FT_MEM_COPY( (char *)p->name, name, n );
1056
1057 p->format = format;
1058 p->builtin = 0;
1059
1060 n = _num_bdf_properties + font->nuser_props;
1061
suzuki toshiya704f4d72009-09-13 00:50:14 +09001062 error = hash_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001063 if ( error )
1064 goto Exit;
1065
1066 font->nuser_props++;
1067
1068 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001069 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001070 }
David Turner993a8d02002-05-18 12:03:43 +00001071
1072
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001073 FT_LOCAL_DEF( bdf_property_t * )
1074 bdf_get_property( char* name,
1075 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001076 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001077 hashnode hn;
1078 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001079
1080
1081 if ( name == 0 || *name == 0 )
1082 return 0;
1083
1084 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1085 return 0;
1086
suzuki toshiya704f4d72009-09-13 00:50:14 +09001087 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001088 if ( propid >= _num_bdf_properties )
1089 return font->user_props + ( propid - _num_bdf_properties );
1090
Werner Lemberg233302a2002-05-22 05:41:06 +00001091 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001092 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001093
1094
1095 /*************************************************************************/
1096 /* */
1097 /* BDF font file parsing flags and functions. */
1098 /* */
1099 /*************************************************************************/
1100
1101
1102 /* Parse flags. */
1103
1104#define _BDF_START 0x0001
1105#define _BDF_FONT_NAME 0x0002
1106#define _BDF_SIZE 0x0004
1107#define _BDF_FONT_BBX 0x0008
1108#define _BDF_PROPS 0x0010
1109#define _BDF_GLYPHS 0x0020
1110#define _BDF_GLYPH 0x0040
1111#define _BDF_ENCODING 0x0080
1112#define _BDF_SWIDTH 0x0100
1113#define _BDF_DWIDTH 0x0200
1114#define _BDF_BBX 0x0400
1115#define _BDF_BITMAP 0x0800
1116
1117#define _BDF_SWIDTH_ADJ 0x1000
1118
1119#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1120 _BDF_ENCODING | \
1121 _BDF_SWIDTH | \
1122 _BDF_DWIDTH | \
1123 _BDF_BBX | \
1124 _BDF_BITMAP )
1125
Werner Lembergf1c2b912006-01-13 14:53:28 +00001126#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1127#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001128
1129
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001130 static FT_Error
1131 _bdf_add_comment( bdf_font_t* font,
1132 char* comment,
1133 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001134 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001135 char* cp;
1136 FT_Memory memory = font->memory;
1137 FT_Error error = BDF_Err_Ok;
1138
1139
David Turner68df4f72005-03-15 18:18:57 +00001140 if ( FT_RENEW_ARRAY( font->comments,
1141 font->comments_len,
1142 font->comments_len + len + 1 ) )
1143 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001144
1145 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001146
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001147 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001148 cp[len] = '\n';
1149
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001150 font->comments_len += len + 1;
1151
1152 Exit:
1153 return error;
David Turner993a8d02002-05-18 12:03:43 +00001154 }
1155
David Turner993a8d02002-05-18 12:03:43 +00001156
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001157 /* Set the spacing from the font name if it exists, or set it to the */
1158 /* default specified in the options. */
1159 static FT_Error
1160 _bdf_set_default_spacing( bdf_font_t* font,
Werner Lemberge01406b2011-11-25 09:44:28 +01001161 bdf_options_t* opts,
1162 unsigned long lineno )
David Turner993a8d02002-05-18 12:03:43 +00001163 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001164 size_t len;
1165 char name[256];
1166 _bdf_list_t list;
1167 FT_Memory memory;
1168 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001169
David Turner993a8d02002-05-18 12:03:43 +00001170
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001171 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1172 {
1173 error = BDF_Err_Invalid_Argument;
1174 goto Exit;
1175 }
David Turner993a8d02002-05-18 12:03:43 +00001176
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001177 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001178
David Turner68df4f72005-03-15 18:18:57 +00001179 _bdf_list_init( &list, memory );
1180
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001181 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001182
suzuki toshiya704f4d72009-09-13 00:50:14 +09001183 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +00001184 /* Limit ourselves to 256 characters in the font name. */
1185 if ( len >= 256 )
1186 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001187 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
Werner Lemberga08b2172007-03-28 07:17:17 +00001188 error = BDF_Err_Invalid_Argument;
1189 goto Exit;
1190 }
1191
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001192 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001193
David Turner68df4f72005-03-15 18:18:57 +00001194 error = _bdf_list_split( &list, (char *)"-", name, len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001195 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001196 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001197
1198 if ( list.used == 15 )
1199 {
1200 switch ( list.field[11][0] )
1201 {
1202 case 'C':
1203 case 'c':
1204 font->spacing = BDF_CHARCELL;
1205 break;
1206 case 'M':
1207 case 'm':
1208 font->spacing = BDF_MONOWIDTH;
1209 break;
1210 case 'P':
1211 case 'p':
1212 font->spacing = BDF_PROPORTIONAL;
1213 break;
David Turner993a8d02002-05-18 12:03:43 +00001214 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001215 }
1216
David Turner68df4f72005-03-15 18:18:57 +00001217 Fail:
1218 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001219
1220 Exit:
1221 return error;
David Turner993a8d02002-05-18 12:03:43 +00001222 }
David Turner993a8d02002-05-18 12:03:43 +00001223
1224
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001225 /* Determine whether the property is an atom or not. If it is, then */
1226 /* clean it up so the double quotes are removed if they exist. */
1227 static int
1228 _bdf_is_atom( char* line,
1229 unsigned long linelen,
1230 char** name,
1231 char** value,
1232 bdf_font_t* font )
1233 {
1234 int hold;
1235 char *sp, *ep;
1236 bdf_property_t* p;
1237
David Turner993a8d02002-05-18 12:03:43 +00001238
1239 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001240
1241 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001242 ep++;
1243
1244 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001245 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001246 {
1247 hold = *ep;
1248 *ep = 0;
1249 }
1250
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001251 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001252
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001253 /* Restore the character that was saved before any return can happen. */
1254 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001255 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001256
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001257 /* If the property exists and is not an atom, just return here. */
1258 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001259 return 0;
1260
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001261 /* The property is an atom. Trim all leading and trailing whitespace */
1262 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001263 sp = ep;
1264 ep = line + linelen;
1265
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001266 /* Trim the leading whitespace if it exists. */
Werner Lemberg320d4972012-02-24 18:06:46 +01001267 if ( *sp )
1268 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001269 while ( *sp &&
1270 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001271 sp++;
1272
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001273 /* Trim the leading double quote if it exists. */
1274 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001275 sp++;
1276 *value = sp;
1277
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001278 /* Trim the trailing whitespace if it exists. */
1279 while ( ep > sp &&
1280 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001281 *--ep = 0;
1282
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001283 /* Trim the trailing double quote if it exists. */
1284 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001285 *--ep = 0;
1286
1287 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001288 }
David Turner993a8d02002-05-18 12:03:43 +00001289
1290
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001291 static FT_Error
Werner Lemberge01406b2011-11-25 09:44:28 +01001292 _bdf_add_property( bdf_font_t* font,
1293 char* name,
1294 char* value,
1295 unsigned long lineno )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001296 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001297 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001298 hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001299 bdf_property_t *prop, *fp;
1300 FT_Memory memory = font->memory;
1301 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001302
David Turner993a8d02002-05-18 12:03:43 +00001303
Werner Lemberg96ddc672011-06-29 09:15:54 +02001304 /* First, check whether the property already exists in the font. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001305 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001306 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001307 /* The property already exists in the font, so simply replace */
1308 /* the value of the property with the current value. */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001309 fp = font->props + hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001310
David Turnerb1b47622002-05-21 21:17:43 +00001311 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001312 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001313 case BDF_ATOM:
1314 /* Delete the current atom if it exists. */
1315 FT_FREE( fp->value.atom );
1316
David Turnerc0f9c4a2007-02-12 14:55:03 +00001317 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001318 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001319 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001320 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001321 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001322 break;
1323
1324 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001325 fp->value.l = _bdf_atol( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001326 break;
1327
1328 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001329 fp->value.ul = _bdf_atoul( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001330 break;
David Turnerd490e372002-05-28 23:40:37 +00001331
David Turnerb1b47622002-05-21 21:17:43 +00001332 default:
1333 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001334 }
David Turnerd490e372002-05-28 23:40:37 +00001335
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001336 goto Exit;
1337 }
1338
1339 /* See whether this property type exists yet or not. */
1340 /* If not, create it. */
1341 hn = hash_lookup( name, &(font->proptbl) );
1342 if ( hn == 0 )
1343 {
1344 error = bdf_create_property( name, BDF_ATOM, font );
1345 if ( error )
1346 goto Exit;
1347 hn = hash_lookup( name, &(font->proptbl) );
1348 }
1349
1350 /* Allocate another property if this is overflow. */
1351 if ( font->props_used == font->props_size )
1352 {
1353 if ( font->props_size == 0 )
1354 {
1355 if ( FT_NEW_ARRAY( font->props, 1 ) )
1356 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001357 }
1358 else
1359 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001360 if ( FT_RENEW_ARRAY( font->props,
1361 font->props_size,
1362 font->props_size + 1 ) )
1363 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001364 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001365
David Turner993a8d02002-05-18 12:03:43 +00001366 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001367 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001368 font->props_size++;
1369 }
1370
suzuki toshiya704f4d72009-09-13 00:50:14 +09001371 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001372 if ( propid >= _num_bdf_properties )
1373 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001374 else
David Turnerb1b47622002-05-21 21:17:43 +00001375 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001376
1377 fp = font->props + font->props_used;
1378
1379 fp->name = prop->name;
1380 fp->format = prop->format;
1381 fp->builtin = prop->builtin;
1382
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001383 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001384 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001385 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001386 fp->value.atom = 0;
1387 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001388 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001389 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001390 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001391 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001392 break;
David Turner993a8d02002-05-18 12:03:43 +00001393
1394 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001395 fp->value.l = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001396 break;
1397
1398 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001399 fp->value.ul = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001400 break;
David Turner993a8d02002-05-18 12:03:43 +00001401 }
1402
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001403 /* If the property happens to be a comment, then it doesn't need */
1404 /* to be added to the internal hash table. */
Werner Lemberg370aea82010-06-08 08:37:11 +02001405 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 )
1406 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001407 /* Add the property to the font property table. */
1408 error = hash_insert( fp->name,
suzuki toshiya704f4d72009-09-13 00:50:14 +09001409 font->props_used,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001410 (hashtable *)font->internal,
1411 memory );
1412 if ( error )
1413 goto Exit;
1414 }
David Turner993a8d02002-05-18 12:03:43 +00001415
1416 font->props_used++;
1417
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001418 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1419 /* property needs to be located if it exists in the property list, the */
1420 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1421 /* present, and the SPACING property should override the default */
1422 /* spacing. */
1423 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001424 font->default_char = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001425 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001426 font->font_ascent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001427 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001428 font->font_descent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001429 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001430 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001431 if ( !fp->value.atom )
1432 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001433 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lembergb66efef2009-03-12 08:07:49 +00001434 error = BDF_Err_Invalid_File_Format;
1435 goto Exit;
1436 }
1437
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001438 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001439 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001440 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001441 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001442 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001443 font->spacing = BDF_CHARCELL;
1444 }
1445
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001446 Exit:
1447 return error;
David Turner993a8d02002-05-18 12:03:43 +00001448 }
1449
David Turner993a8d02002-05-18 12:03:43 +00001450
David Turnerb1b47622002-05-21 21:17:43 +00001451 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001452 {
1453 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1454 };
1455
1456
1457 /* Actually parse the glyph info and bitmaps. */
1458 static FT_Error
1459 _bdf_parse_glyphs( char* line,
1460 unsigned long linelen,
1461 unsigned long lineno,
1462 void* call_data,
1463 void* client_data )
1464 {
1465 int c, mask_index;
1466 char* s;
1467 unsigned char* bp;
1468 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001469
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001470 _bdf_parse_t* p;
1471 bdf_glyph_t* glyph;
1472 bdf_font_t* font;
1473
1474 FT_Memory memory;
1475 FT_Error error = BDF_Err_Ok;
1476
Werner Lemberg319c00d2003-04-23 19:48:24 +00001477 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001478 FT_UNUSED( lineno ); /* only used in debug mode */
1479
1480
Werner Lemberg319c00d2003-04-23 19:48:24 +00001481 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001482
1483 font = p->font;
1484 memory = font->memory;
1485
1486 /* Check for a comment. */
1487 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1488 {
1489 linelen -= 7;
1490
1491 s = line + 7;
1492 if ( *s != 0 )
1493 {
1494 s++;
1495 linelen--;
1496 }
1497 error = _bdf_add_comment( p->font, s, linelen );
1498 goto Exit;
1499 }
1500
1501 /* The very first thing expected is the number of glyphs. */
1502 if ( !( p->flags & _BDF_GLYPHS ) )
1503 {
1504 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1505 {
1506 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1507 error = BDF_Err_Missing_Chars_Field;
1508 goto Exit;
1509 }
1510
David Turner68df4f72005-03-15 18:18:57 +00001511 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001512 if ( error )
1513 goto Exit;
1514 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1515
1516 /* Make sure the number of glyphs is non-zero. */
1517 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001518 font->glyphs_size = 64;
1519
Werner Lemberga08b2172007-03-28 07:17:17 +00001520 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1521 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001522 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001523 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001524 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberga08b2172007-03-28 07:17:17 +00001525 error = BDF_Err_Invalid_Argument;
1526 goto Exit;
1527 }
1528
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001529 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1530 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001531
David Turner993a8d02002-05-18 12:03:43 +00001532 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001533
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001534 goto Exit;
1535 }
1536
1537 /* Check for the ENDFONT field. */
1538 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1539 {
1540 /* Sort the glyphs by encoding. */
1541 ft_qsort( (char *)font->glyphs,
1542 font->glyphs_used,
1543 sizeof ( bdf_glyph_t ),
1544 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001545
1546 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001547
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001548 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001549 }
1550
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001551 /* Check for the ENDCHAR field. */
1552 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1553 {
1554 p->glyph_enc = 0;
1555 p->flags &= ~_BDF_GLYPH_BITS;
1556
1557 goto Exit;
1558 }
1559
Werner Lemberg96ddc672011-06-29 09:15:54 +02001560 /* Check whether a glyph is being scanned but should be */
1561 /* ignored because it is an unencoded glyph. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001562 if ( ( p->flags & _BDF_GLYPH ) &&
1563 p->glyph_enc == -1 &&
1564 p->opts->keep_unencoded == 0 )
1565 goto Exit;
1566
1567 /* Check for the STARTCHAR field. */
1568 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1569 {
1570 /* Set the character name in the parse info first until the */
1571 /* encoding can be checked for an unencoded character. */
1572 FT_FREE( p->glyph_name );
1573
David Turner68df4f72005-03-15 18:18:57 +00001574 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001575 if ( error )
1576 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001577
David Turner68df4f72005-03-15 18:18:57 +00001578 _bdf_list_shift( &p->list, 1 );
1579
1580 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001581
Werner Lembergba03af62007-05-30 13:57:02 +00001582 if ( !s )
1583 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001584 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lembergba03af62007-05-30 13:57:02 +00001585 error = BDF_Err_Invalid_File_Format;
1586 goto Exit;
1587 }
1588
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001589 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1590 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001591
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001592 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1593
1594 p->flags |= _BDF_GLYPH;
1595
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001596 FT_TRACE4(( DBGMSG1, lineno, s ));
1597
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001598 goto Exit;
1599 }
1600
1601 /* Check for the ENCODING field. */
1602 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1603 {
1604 if ( !( p->flags & _BDF_GLYPH ) )
1605 {
1606 /* Missing STARTCHAR field. */
1607 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1608 error = BDF_Err_Missing_Startchar_Field;
1609 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001610 }
1611
David Turner68df4f72005-03-15 18:18:57 +00001612 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001613 if ( error )
1614 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001615
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001616 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001617
Werner Lemberg28dd2c42012-02-26 06:18:58 +01001618 /* Normalize negative encoding values. The specification only */
1619 /* allows -1, but we can be more generous here. */
1620 if ( p->glyph_enc < -1 )
1621 p->glyph_enc = -1;
1622
Werner Lemberg03242f52012-02-26 06:52:56 +01001623 /* Check for alternative encoding format. */
1624 if ( p->glyph_enc == -1 && p->list.used > 2 )
1625 p->glyph_enc = _bdf_atol( p->list.field[2], 0, 10 );
1626
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001627 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1628
Werner Lemberged54e432011-11-27 16:39:53 +01001629 /* Check that the encoding is in the Unicode range because */
1630 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lemberg96ddc672011-06-29 09:15:54 +02001631 if ( p->glyph_enc > 0 &&
1632 (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
David Turner481838e2006-02-23 12:40:14 +00001633 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001634 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
David Turner481838e2006-02-23 12:40:14 +00001635 error = BDF_Err_Invalid_File_Format;
1636 goto Exit;
1637 }
1638
Werner Lemberg96ddc672011-06-29 09:15:54 +02001639 /* Check whether this encoding has already been encountered. */
1640 /* If it has then change it to unencoded so it gets added if */
1641 /* indicated. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001642 if ( p->glyph_enc >= 0 )
1643 {
1644 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1645 {
1646 /* Emit a message saying a glyph has been moved to the */
1647 /* unencoded area. */
1648 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1649 p->glyph_enc, p->glyph_name ));
1650 p->glyph_enc = -1;
1651 font->modified = 1;
1652 }
1653 else
1654 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1655 }
1656
1657 if ( p->glyph_enc >= 0 )
1658 {
1659 /* Make sure there are enough glyphs allocated in case the */
1660 /* number of characters happen to be wrong. */
1661 if ( font->glyphs_used == font->glyphs_size )
1662 {
1663 if ( FT_RENEW_ARRAY( font->glyphs,
1664 font->glyphs_size,
1665 font->glyphs_size + 64 ) )
1666 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001667
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001668 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001669 }
1670
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001671 glyph = font->glyphs + font->glyphs_used++;
1672 glyph->name = p->glyph_name;
1673 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001674
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001675 /* Reset the initial glyph info. */
1676 p->glyph_name = 0;
1677 }
1678 else
1679 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001680 /* Unencoded glyph. Check whether it should */
1681 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001682 if ( p->opts->keep_unencoded != 0 )
1683 {
1684 /* Allocate the next unencoded glyph. */
1685 if ( font->unencoded_used == font->unencoded_size )
1686 {
David Turner68df4f72005-03-15 18:18:57 +00001687 if ( FT_RENEW_ARRAY( font->unencoded ,
1688 font->unencoded_size,
1689 font->unencoded_size + 4 ) )
1690 goto Exit;
1691
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001692 font->unencoded_size += 4;
1693 }
1694
1695 glyph = font->unencoded + font->unencoded_used;
1696 glyph->name = p->glyph_name;
1697 glyph->encoding = font->unencoded_used++;
1698 }
1699 else
1700 /* Free up the glyph name if the unencoded shouldn't be */
1701 /* kept. */
1702 FT_FREE( p->glyph_name );
1703
1704 p->glyph_name = 0;
1705 }
1706
1707 /* Clear the flags that might be added when width and height are */
1708 /* checked for consistency. */
1709 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1710
1711 p->flags |= _BDF_ENCODING;
1712
1713 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001714 }
1715
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001716 /* Point at the glyph being constructed. */
1717 if ( p->glyph_enc == -1 )
1718 glyph = font->unencoded + ( font->unencoded_used - 1 );
1719 else
1720 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001721
Werner Lemberg96ddc672011-06-29 09:15:54 +02001722 /* Check whether a bitmap is being constructed. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001723 if ( p->flags & _BDF_BITMAP )
1724 {
1725 /* If there are more rows than are specified in the glyph metrics, */
1726 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001727 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001728 {
1729 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1730 {
1731 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1732 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001733 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001734 }
1735
1736 goto Exit;
1737 }
1738
1739 /* Only collect the number of nibbles indicated by the glyph */
1740 /* metrics. If there are more columns, they are simply ignored. */
1741 nibbles = glyph->bpr << 1;
1742 bp = glyph->bitmap + p->row * glyph->bpr;
1743
David Turnerb698eed2006-02-23 14:50:13 +00001744 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001745 {
1746 c = line[i];
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001747 if ( !sbitset( hdigits, c ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001748 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001749 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001750 if ( i + 1 < nibbles && ( i & 1 ) )
1751 *++bp = 0;
1752 }
1753
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001754 /* If any line has not enough columns, */
1755 /* indicate they have been padded with zero bits. */
1756 if ( i < nibbles &&
1757 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1758 {
1759 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
1760 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1761 font->modified = 1;
1762 }
1763
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001764 /* Remove possible garbage at the right. */
1765 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001766 if ( glyph->bbx.width )
1767 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001768
1769 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001770 if ( i == nibbles &&
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001771 sbitset( hdigits, line[nibbles] ) &&
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001772 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001773 {
1774 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1775 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1776 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001777 }
1778
1779 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001780 goto Exit;
1781 }
David Turner993a8d02002-05-18 12:03:43 +00001782
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001783 /* Expect the SWIDTH (scalable width) field next. */
1784 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1785 {
1786 if ( !( p->flags & _BDF_ENCODING ) )
Werner Lemberg4086fb72012-03-01 08:55:40 +01001787 goto Missing_Encoding;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001788
David Turner68df4f72005-03-15 18:18:57 +00001789 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001790 if ( error )
1791 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001792
David Turnerb1b47622002-05-21 21:17:43 +00001793 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001794 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001795
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001796 goto Exit;
1797 }
David Turner993a8d02002-05-18 12:03:43 +00001798
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001799 /* Expect the DWIDTH (scalable width) field next. */
1800 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1801 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001802 if ( !( p->flags & _BDF_ENCODING ) )
1803 goto Missing_Encoding;
1804
David Turner68df4f72005-03-15 18:18:57 +00001805 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001806 if ( error )
1807 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001808
David Turnerb1b47622002-05-21 21:17:43 +00001809 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001810
1811 if ( !( p->flags & _BDF_SWIDTH ) )
1812 {
1813 /* Missing SWIDTH field. Emit an auto correction message and set */
1814 /* the scalable width from the device width. */
1815 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1816
Werner Lemberg02d4d592002-05-28 22:38:05 +00001817 glyph->swidth = (unsigned short)FT_MulDiv(
1818 glyph->dwidth, 72000L,
1819 (FT_Long)( font->point_size *
1820 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001821 }
1822
1823 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001824 goto Exit;
1825 }
David Turner993a8d02002-05-18 12:03:43 +00001826
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001827 /* Expect the BBX field next. */
1828 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1829 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001830 if ( !( p->flags & _BDF_ENCODING ) )
1831 goto Missing_Encoding;
1832
David Turner68df4f72005-03-15 18:18:57 +00001833 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001834 if ( error )
1835 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001836
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001837 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1838 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1839 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1840 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1841
1842 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001843 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1844 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001845
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001846 /* Determine the overall font bounding box as the characters are */
1847 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001848 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1849 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001850
David Turnerb1b47622002-05-21 21:17:43 +00001851 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001852
Werner Lembergdfa46192004-03-05 09:26:24 +00001853 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1854 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1855 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001856
1857 if ( !( p->flags & _BDF_DWIDTH ) )
1858 {
1859 /* Missing DWIDTH field. Emit an auto correction message and set */
1860 /* the device width to the glyph width. */
1861 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1862 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001863 }
1864
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001865 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1866 /* value if necessary. */
1867 if ( p->opts->correct_metrics != 0 )
1868 {
1869 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001870 unsigned short sw = (unsigned short)FT_MulDiv(
1871 glyph->dwidth, 72000L,
1872 (FT_Long)( font->point_size *
1873 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001874
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001875
1876 if ( sw != glyph->swidth )
1877 {
1878 glyph->swidth = sw;
1879
1880 if ( p->glyph_enc == -1 )
1881 _bdf_set_glyph_modified( font->umod,
1882 font->unencoded_used - 1 );
1883 else
1884 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1885
1886 p->flags |= _BDF_SWIDTH_ADJ;
1887 font->modified = 1;
1888 }
David Turner993a8d02002-05-18 12:03:43 +00001889 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001890
David Turner993a8d02002-05-18 12:03:43 +00001891 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001892 goto Exit;
1893 }
David Turner993a8d02002-05-18 12:03:43 +00001894
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001895 /* And finally, gather up the bitmap. */
1896 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1897 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001898 unsigned long bitmap_size;
1899
1900
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001901 if ( !( p->flags & _BDF_BBX ) )
1902 {
1903 /* Missing BBX field. */
1904 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1905 error = BDF_Err_Missing_Bbx_Field;
1906 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001907 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001908
1909 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001910 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001911
1912 bitmap_size = glyph->bpr * glyph->bbx.height;
Werner Lembergc4cad302012-03-08 20:11:37 +01001913 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
Werner Lemberg26170df2006-03-26 07:19:07 +00001914 {
1915 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1916 error = BDF_Err_Bbx_Too_Big;
1917 goto Exit;
1918 }
1919 else
1920 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001921
1922 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1923 goto Exit;
1924
1925 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001926 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001927
1928 goto Exit;
1929 }
1930
Werner Lemberge01406b2011-11-25 09:44:28 +01001931 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001932 error = BDF_Err_Invalid_File_Format;
Werner Lemberg4086fb72012-03-01 08:55:40 +01001933 goto Exit;
1934
1935 Missing_Encoding:
1936 /* Missing ENCODING field. */
1937 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1938 error = BDF_Err_Missing_Encoding_Field;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001939
1940 Exit:
Werner Lembergf4c94d42010-06-19 16:08:31 +02001941 if ( error && ( p->flags & _BDF_GLYPH ) )
1942 FT_FREE( p->glyph_name );
1943
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001944 return error;
David Turner993a8d02002-05-18 12:03:43 +00001945 }
1946
David Turner993a8d02002-05-18 12:03:43 +00001947
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001948 /* Load the font properties. */
1949 static FT_Error
1950 _bdf_parse_properties( char* line,
1951 unsigned long linelen,
1952 unsigned long lineno,
1953 void* call_data,
1954 void* client_data )
1955 {
1956 unsigned long vlen;
1957 _bdf_line_func_t* next;
1958 _bdf_parse_t* p;
1959 char* name;
1960 char* value;
1961 char nbuf[128];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001962 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001963
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001964 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001965
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001966
1967 next = (_bdf_line_func_t *)call_data;
1968 p = (_bdf_parse_t *) client_data;
1969
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001970 /* Check for the end of the properties. */
1971 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1972 {
1973 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1974 /* encountered yet, then make sure they are added as properties and */
1975 /* make sure they are set from the font bounding box info. */
1976 /* */
1977 /* This is *always* done regardless of the options, because X11 */
1978 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001979 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001980 {
1981 p->font->font_ascent = p->font->bbx.ascent;
1982 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001983 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
1984 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001985 if ( error )
1986 goto Exit;
1987
1988 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1989 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001990 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001991
Werner Lemberg428c2e42003-04-25 05:35:04 +00001992 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001993 {
1994 p->font->font_descent = p->font->bbx.descent;
1995 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001996 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
1997 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001998 if ( error )
1999 goto Exit;
2000
2001 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2002 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002003 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002004
David Turner993a8d02002-05-18 12:03:43 +00002005 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002006 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00002007
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002008 goto Exit;
2009 }
David Turner993a8d02002-05-18 12:03:43 +00002010
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002011 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
2012 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
2013 goto Exit;
2014
2015 /* Handle COMMENT fields and properties in a special way to preserve */
2016 /* the spacing. */
2017 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2018 {
David Turner993a8d02002-05-18 12:03:43 +00002019 name = value = line;
2020 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002021 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00002022 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01002023 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002024 if ( error )
2025 goto Exit;
2026 }
2027 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
2028 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002029 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002030 if ( error )
2031 goto Exit;
2032 }
2033 else
2034 {
David Turner68df4f72005-03-15 18:18:57 +00002035 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002036 if ( error )
2037 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002038 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002039
David Turner68df4f72005-03-15 18:18:57 +00002040 _bdf_list_shift( &p->list, 1 );
2041 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002042
Werner Lemberge01406b2011-11-25 09:44:28 +01002043 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002044 if ( error )
2045 goto Exit;
2046 }
2047
2048 Exit:
2049 return error;
David Turner993a8d02002-05-18 12:03:43 +00002050 }
2051
David Turner993a8d02002-05-18 12:03:43 +00002052
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002053 /* Load the font header. */
2054 static FT_Error
2055 _bdf_parse_start( char* line,
2056 unsigned long linelen,
2057 unsigned long lineno,
2058 void* call_data,
2059 void* client_data )
2060 {
2061 unsigned long slen;
2062 _bdf_line_func_t* next;
2063 _bdf_parse_t* p;
2064 bdf_font_t* font;
2065 char *s;
David Turner993a8d02002-05-18 12:03:43 +00002066
David Turnerd490e372002-05-28 23:40:37 +00002067 FT_Memory memory = NULL;
2068 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002069
2070 FT_UNUSED( lineno ); /* only used in debug mode */
2071
2072
2073 next = (_bdf_line_func_t *)call_data;
2074 p = (_bdf_parse_t *) client_data;
2075
2076 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00002077 memory = p->font->memory;
2078
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002079 /* Check for a comment. This is done to handle those fonts that have */
2080 /* comments before the STARTFONT line for some reason. */
2081 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2082 {
2083 if ( p->opts->keep_comments != 0 && p->font != 0 )
2084 {
2085 linelen -= 7;
2086
2087 s = line + 7;
2088 if ( *s != 0 )
2089 {
2090 s++;
2091 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002092 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002093
2094 error = _bdf_add_comment( p->font, s, linelen );
2095 if ( error )
2096 goto Exit;
2097 /* here font is not defined! */
2098 }
2099
2100 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002101 }
2102
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002103 if ( !( p->flags & _BDF_START ) )
2104 {
2105 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002106
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002107 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2108 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01002109 /* we don't emit an error message since this code gets */
2110 /* explicitly caught one level higher */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002111 error = BDF_Err_Missing_Startfont_Field;
2112 goto Exit;
2113 }
David Turner993a8d02002-05-18 12:03:43 +00002114
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002115 p->flags = _BDF_START;
2116 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002117
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002118 if ( FT_NEW( font ) )
2119 goto Exit;
2120 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002121
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002122 font->memory = p->memory;
2123 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002124
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002125 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09002126 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002127 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002128
David Turner993a8d02002-05-18 12:03:43 +00002129
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002130 error = hash_init( &(font->proptbl), memory );
2131 if ( error )
2132 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002133 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002134 i < _num_bdf_properties; i++, prop++ )
2135 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09002136 error = hash_insert( prop->name, i,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002137 &(font->proptbl), memory );
2138 if ( error )
2139 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002140 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002141 }
2142
2143 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2144 goto Exit;
2145 error = hash_init( (hashtable *)p->font->internal,memory );
2146 if ( error )
2147 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002148 p->font->spacing = p->opts->font_spacing;
2149 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002150
2151 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002152 }
2153
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002154 /* Check for the start of the properties. */
2155 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2156 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002157 if ( !( p->flags & _BDF_FONT_BBX ) )
Werner Lembergfb690292010-06-23 10:00:52 +02002158 {
2159 /* Missing the FONTBOUNDINGBOX field. */
2160 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2161 error = BDF_Err_Missing_Fontboundingbox_Field;
2162 goto Exit;
2163 }
2164
David Turner68df4f72005-03-15 18:18:57 +00002165 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002166 if ( error )
2167 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00002168 /* at this point, `p->font' can't be NULL */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002169 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2170
2171 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2172 goto Exit;
2173
2174 p->flags |= _BDF_PROPS;
2175 *next = _bdf_parse_properties;
2176
2177 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002178 }
2179
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002180 /* Check for the FONTBOUNDINGBOX field. */
2181 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2182 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002183 if ( !( p->flags & _BDF_SIZE ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002184 {
2185 /* Missing the SIZE field. */
2186 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2187 error = BDF_Err_Missing_Size_Field;
2188 goto Exit;
2189 }
2190
David Turner68df4f72005-03-15 18:18:57 +00002191 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002192 if ( error )
2193 goto Exit;
2194
2195 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2196 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2197
2198 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2199 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2200
David Turnerd490e372002-05-28 23:40:37 +00002201 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002202 p->font->bbx.y_offset );
2203
2204 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002205
2206 p->flags |= _BDF_FONT_BBX;
2207
2208 goto Exit;
2209 }
2210
2211 /* The next thing to check for is the FONT field. */
2212 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2213 {
David Turner68df4f72005-03-15 18:18:57 +00002214 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002215 if ( error )
2216 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002217 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002218
David Turner68df4f72005-03-15 18:18:57 +00002219 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002220
2221 if ( !s )
2222 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002223 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg5b591e42007-06-01 22:16:43 +00002224 error = BDF_Err_Invalid_File_Format;
2225 goto Exit;
2226 }
2227
Werner Lembergfb690292010-06-23 10:00:52 +02002228 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2229 FT_FREE( p->font->name );
2230
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002231 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2232 goto Exit;
2233 FT_MEM_COPY( p->font->name, s, slen + 1 );
2234
2235 /* If the font name is an XLFD name, set the spacing to the one in */
2236 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002237 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002238 if ( error )
2239 goto Exit;
2240
2241 p->flags |= _BDF_FONT_NAME;
2242
2243 goto Exit;
2244 }
2245
2246 /* Check for the SIZE field. */
2247 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2248 {
2249 if ( !( p->flags & _BDF_FONT_NAME ) )
2250 {
2251 /* Missing the FONT field. */
2252 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2253 error = BDF_Err_Missing_Font_Field;
2254 goto Exit;
2255 }
2256
David Turner68df4f72005-03-15 18:18:57 +00002257 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002258 if ( error )
2259 goto Exit;
2260
2261 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2262 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2263 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2264
2265 /* Check for the bits per pixel field. */
2266 if ( p->list.used == 5 )
2267 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002268 unsigned short bitcount, i, shift;
2269
2270
2271 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2272
2273 /* Only values 1, 2, 4, 8 are allowed. */
2274 shift = p->font->bpp;
2275 bitcount = 0;
2276 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002277 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002278 if ( shift & 1 )
2279 bitcount = i;
2280 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002281 }
David Turner993a8d02002-05-18 12:03:43 +00002282
Werner Lembergbd8e3242002-06-12 08:43:58 +00002283 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002284
2285 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002286 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002287 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002288 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002289 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002290 }
2291 }
2292 else
2293 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002294
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002295 p->flags |= _BDF_SIZE;
2296
2297 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002298 }
2299
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002300 /* Check for the CHARS field -- font properties are optional */
2301 if ( ft_memcmp( line, "CHARS", 5 ) == 0 )
2302 {
2303 char nbuf[128];
2304
2305
2306 if ( !( p->flags & _BDF_FONT_BBX ) )
2307 {
2308 /* Missing the FONTBOUNDINGBOX field. */
2309 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2310 error = BDF_Err_Missing_Fontboundingbox_Field;
2311 goto Exit;
2312 }
2313
2314 /* Add the two standard X11 properties which are required */
2315 /* for compiling fonts. */
2316 p->font->font_ascent = p->font->bbx.ascent;
2317 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002318 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2319 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002320 if ( error )
2321 goto Exit;
2322 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2323
2324 p->font->font_descent = p->font->bbx.descent;
2325 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002326 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2327 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002328 if ( error )
2329 goto Exit;
2330 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2331
2332 p->font->modified = 1;
2333
2334 *next = _bdf_parse_glyphs;
2335
2336 /* A special return value. */
2337 error = -1;
2338 goto Exit;
2339 }
2340
Werner Lemberge01406b2011-11-25 09:44:28 +01002341 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002342 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002343
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002344 Exit:
2345 return error;
2346 }
David Turner993a8d02002-05-18 12:03:43 +00002347
2348
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002349 /*************************************************************************/
2350 /* */
2351 /* API. */
2352 /* */
2353 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002354
David Turner993a8d02002-05-18 12:03:43 +00002355
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002356 FT_LOCAL_DEF( FT_Error )
2357 bdf_load_font( FT_Stream stream,
2358 FT_Memory extmemory,
2359 bdf_options_t* opts,
2360 bdf_font_t* *font )
2361 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002362 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002363 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002364
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002365 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002366 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002367
2368
David Turner68df4f72005-03-15 18:18:57 +00002369 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002370 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002371
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002372 memory = NULL;
2373 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2374 p->minlb = 32767;
2375 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002376
David Turner68df4f72005-03-15 18:18:57 +00002377 _bdf_list_init( &p->list, extmemory );
2378
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002379 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002380 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002381 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002382 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002383
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002384 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002385 {
2386 /* If the font is not proportional, set the font's monowidth */
2387 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002388 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002389
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002390 if ( p->font->spacing != BDF_PROPORTIONAL )
2391 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002392
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002393 /* If the number of glyphs loaded is not that of the original count, */
2394 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002395 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002396 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002397 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2398 p->font->glyphs_used + p->font->unencoded_used ));
2399 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002400 }
2401
2402 /* Once the font has been loaded, adjust the overall font metrics if */
2403 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002404 if ( p->opts->correct_metrics != 0 &&
2405 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002406 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002407 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002408 {
2409 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002410 p->font->bbx.width, p->maxrb - p->minlb ));
2411 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2412 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002413 }
2414
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002415 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002416 {
2417 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002418 p->font->bbx.x_offset, p->minlb ));
2419 p->font->bbx.x_offset = p->minlb;
2420 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002421 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002422
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002423 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002424 {
2425 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002426 p->font->bbx.ascent, p->maxas ));
2427 p->font->bbx.ascent = p->maxas;
2428 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002429 }
2430
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002431 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002432 {
2433 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002434 p->font->bbx.descent, p->maxds ));
2435 p->font->bbx.descent = p->maxds;
2436 p->font->bbx.y_offset = (short)( -p->maxds );
2437 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002438 }
2439
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002440 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002441 {
2442 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002443 p->font->bbx.height, p->maxas + p->maxds ));
2444 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002445 }
2446
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002447 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002448 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2449 }
David Turner993a8d02002-05-18 12:03:43 +00002450 }
2451
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002452 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002453 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002454 /* The ENDFONT field was never reached or did not exist. */
2455 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002456 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002457 /* Error happened while parsing header. */
2458 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2459 error = BDF_Err_Corrupted_Font_Header;
2460 goto Exit;
2461 }
2462 else
2463 {
2464 /* Error happened when parsing glyphs. */
2465 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2466 error = BDF_Err_Corrupted_Font_Glyphs;
2467 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002468 }
David Turner993a8d02002-05-18 12:03:43 +00002469 }
2470
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002471 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002472 {
2473 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002474 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002475
Werner Lemberg370aea82010-06-08 08:37:11 +02002476 if ( p->font->comments_len > 0 )
2477 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002478 if ( FT_RENEW_ARRAY( p->font->comments,
2479 p->font->comments_len,
2480 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002481 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002482
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002483 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002484 }
David Turner993a8d02002-05-18 12:03:43 +00002485 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002486 else if ( error == BDF_Err_Ok )
2487 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002488
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002489 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002490
2491 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002492 if ( p )
2493 {
David Turner68df4f72005-03-15 18:18:57 +00002494 _bdf_list_done( &p->list );
2495
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002496 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002497
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002498 FT_FREE( p );
2499 }
2500
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002501 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002502
2503 Fail:
2504 bdf_free_font( p->font );
2505
2506 memory = extmemory;
2507
2508 FT_FREE( p->font );
2509
2510 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002511 }
David Turner993a8d02002-05-18 12:03:43 +00002512
2513
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002514 FT_LOCAL_DEF( void )
2515 bdf_free_font( bdf_font_t* font )
2516 {
2517 bdf_property_t* prop;
2518 unsigned long i;
2519 bdf_glyph_t* glyphs;
2520 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002521
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002522
2523 if ( font == 0 )
2524 return;
David Turner993a8d02002-05-18 12:03:43 +00002525
2526 memory = font->memory;
2527
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002528 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002529
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002530 /* Free up the internal hash table of property names. */
2531 if ( font->internal )
2532 {
2533 hash_free( (hashtable *)font->internal, memory );
2534 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002535 }
2536
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002537 /* Free up the comment info. */
2538 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002539
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002540 /* Free up the properties. */
2541 for ( i = 0; i < font->props_size; i++ )
2542 {
2543 if ( font->props[i].format == BDF_ATOM )
2544 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002545 }
2546
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002547 FT_FREE( font->props );
2548
2549 /* Free up the character info. */
2550 for ( i = 0, glyphs = font->glyphs;
2551 i < font->glyphs_used; i++, glyphs++ )
2552 {
2553 FT_FREE( glyphs->name );
2554 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002555 }
2556
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002557 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2558 i++, glyphs++ )
2559 {
2560 FT_FREE( glyphs->name );
2561 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002562 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002563
2564 FT_FREE( font->glyphs );
2565 FT_FREE( font->unencoded );
2566
2567 /* Free up the overflow storage if it was used. */
2568 for ( i = 0, glyphs = font->overflow.glyphs;
2569 i < font->overflow.glyphs_used; i++, glyphs++ )
2570 {
2571 FT_FREE( glyphs->name );
2572 FT_FREE( glyphs->bitmap );
2573 }
2574
2575 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002576
2577 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002578 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002579
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002580 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002581 for ( prop = font->user_props, i = 0;
2582 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002583 {
2584 FT_FREE( prop->name );
2585 if ( prop->format == BDF_ATOM )
2586 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002587 }
David Turner993a8d02002-05-18 12:03:43 +00002588
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002589 FT_FREE( font->user_props );
2590
2591 /* FREE( font ); */ /* XXX Fixme */
2592 }
David Turner993a8d02002-05-18 12:03:43 +00002593
2594
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002595 FT_LOCAL_DEF( bdf_property_t * )
2596 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002597 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002598 {
2599 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002600
David Turner993a8d02002-05-18 12:03:43 +00002601
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002602 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002603 return 0;
2604
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002605 hn = hash_lookup( name, (hashtable *)font->internal );
2606
suzuki toshiya704f4d72009-09-13 00:50:14 +09002607 return hn ? ( font->props + hn->data ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002608 }
2609
2610
2611/* END */