blob: 7208d99c943279b9f5f3e4ee5dc7be55ac4860b3 [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 Lemberga9f6f852012-12-17 09:08:09 +0100773 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergebf55852005-03-16 01:49:54 +0000774 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200775 /* Redo if we have encountered CHARS without properties. */
776 if ( error == -1 )
Werner Lemberga9f6f852012-12-17 09:08:09 +0100777 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200778 (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 Lemberg7f2e4f42012-12-15 09:39:41 +01001627 if ( p->glyph_enc < -1 )
1628 p->glyph_enc = -1;
1629
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001630 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1631
Werner Lemberged54e432011-11-27 16:39:53 +01001632 /* Check that the encoding is in the Unicode range because */
1633 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lemberg07bdb6e2012-12-15 02:02:23 +01001634 if ( p->glyph_enc > 0 &&
1635 (size_t)p->glyph_enc >= sizeof ( p->have ) /
1636 sizeof ( unsigned long ) * 32 )
David Turner481838e2006-02-23 12:40:14 +00001637 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001638 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
David Turner481838e2006-02-23 12:40:14 +00001639 error = BDF_Err_Invalid_File_Format;
1640 goto Exit;
1641 }
1642
Werner Lemberg96ddc672011-06-29 09:15:54 +02001643 /* Check whether this encoding has already been encountered. */
1644 /* If it has then change it to unencoded so it gets added if */
1645 /* indicated. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001646 if ( p->glyph_enc >= 0 )
1647 {
1648 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1649 {
1650 /* Emit a message saying a glyph has been moved to the */
1651 /* unencoded area. */
1652 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1653 p->glyph_enc, p->glyph_name ));
1654 p->glyph_enc = -1;
1655 font->modified = 1;
1656 }
1657 else
1658 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1659 }
1660
1661 if ( p->glyph_enc >= 0 )
1662 {
1663 /* Make sure there are enough glyphs allocated in case the */
1664 /* number of characters happen to be wrong. */
1665 if ( font->glyphs_used == font->glyphs_size )
1666 {
1667 if ( FT_RENEW_ARRAY( font->glyphs,
1668 font->glyphs_size,
1669 font->glyphs_size + 64 ) )
1670 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001671
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001672 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001673 }
1674
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001675 glyph = font->glyphs + font->glyphs_used++;
1676 glyph->name = p->glyph_name;
1677 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001678
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001679 /* Reset the initial glyph info. */
1680 p->glyph_name = 0;
1681 }
1682 else
1683 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001684 /* Unencoded glyph. Check whether it should */
1685 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001686 if ( p->opts->keep_unencoded != 0 )
1687 {
1688 /* Allocate the next unencoded glyph. */
1689 if ( font->unencoded_used == font->unencoded_size )
1690 {
David Turner68df4f72005-03-15 18:18:57 +00001691 if ( FT_RENEW_ARRAY( font->unencoded ,
1692 font->unencoded_size,
1693 font->unencoded_size + 4 ) )
1694 goto Exit;
1695
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001696 font->unencoded_size += 4;
1697 }
1698
1699 glyph = font->unencoded + font->unencoded_used;
1700 glyph->name = p->glyph_name;
1701 glyph->encoding = font->unencoded_used++;
1702 }
1703 else
1704 /* Free up the glyph name if the unencoded shouldn't be */
1705 /* kept. */
1706 FT_FREE( p->glyph_name );
1707
1708 p->glyph_name = 0;
1709 }
1710
1711 /* Clear the flags that might be added when width and height are */
1712 /* checked for consistency. */
1713 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1714
1715 p->flags |= _BDF_ENCODING;
1716
1717 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001718 }
1719
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001720 /* Point at the glyph being constructed. */
1721 if ( p->glyph_enc == -1 )
1722 glyph = font->unencoded + ( font->unencoded_used - 1 );
1723 else
1724 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001725
Werner Lemberg96ddc672011-06-29 09:15:54 +02001726 /* Check whether a bitmap is being constructed. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001727 if ( p->flags & _BDF_BITMAP )
1728 {
1729 /* If there are more rows than are specified in the glyph metrics, */
1730 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001731 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001732 {
1733 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1734 {
1735 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1736 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001737 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001738 }
1739
1740 goto Exit;
1741 }
1742
1743 /* Only collect the number of nibbles indicated by the glyph */
1744 /* metrics. If there are more columns, they are simply ignored. */
1745 nibbles = glyph->bpr << 1;
1746 bp = glyph->bitmap + p->row * glyph->bpr;
1747
David Turnerb698eed2006-02-23 14:50:13 +00001748 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001749 {
1750 c = line[i];
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001751 if ( !sbitset( hdigits, c ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001752 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001753 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001754 if ( i + 1 < nibbles && ( i & 1 ) )
1755 *++bp = 0;
1756 }
1757
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001758 /* If any line has not enough columns, */
1759 /* indicate they have been padded with zero bits. */
1760 if ( i < nibbles &&
1761 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1762 {
1763 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
1764 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1765 font->modified = 1;
1766 }
1767
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001768 /* Remove possible garbage at the right. */
1769 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001770 if ( glyph->bbx.width )
1771 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001772
1773 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001774 if ( i == nibbles &&
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001775 sbitset( hdigits, line[nibbles] ) &&
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001776 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001777 {
1778 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1779 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1780 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001781 }
1782
1783 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001784 goto Exit;
1785 }
David Turner993a8d02002-05-18 12:03:43 +00001786
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001787 /* Expect the SWIDTH (scalable width) field next. */
1788 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1789 {
1790 if ( !( p->flags & _BDF_ENCODING ) )
Werner Lemberg4086fb72012-03-01 08:55:40 +01001791 goto Missing_Encoding;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001792
David Turner68df4f72005-03-15 18:18:57 +00001793 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001794 if ( error )
1795 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001796
David Turnerb1b47622002-05-21 21:17:43 +00001797 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001798 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001799
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001800 goto Exit;
1801 }
David Turner993a8d02002-05-18 12:03:43 +00001802
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001803 /* Expect the DWIDTH (scalable width) field next. */
1804 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1805 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001806 if ( !( p->flags & _BDF_ENCODING ) )
1807 goto Missing_Encoding;
1808
David Turner68df4f72005-03-15 18:18:57 +00001809 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001810 if ( error )
1811 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001812
David Turnerb1b47622002-05-21 21:17:43 +00001813 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001814
1815 if ( !( p->flags & _BDF_SWIDTH ) )
1816 {
1817 /* Missing SWIDTH field. Emit an auto correction message and set */
1818 /* the scalable width from the device width. */
1819 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1820
Werner Lemberg02d4d592002-05-28 22:38:05 +00001821 glyph->swidth = (unsigned short)FT_MulDiv(
1822 glyph->dwidth, 72000L,
1823 (FT_Long)( font->point_size *
1824 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001825 }
1826
1827 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001828 goto Exit;
1829 }
David Turner993a8d02002-05-18 12:03:43 +00001830
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001831 /* Expect the BBX field next. */
1832 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1833 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001834 if ( !( p->flags & _BDF_ENCODING ) )
1835 goto Missing_Encoding;
1836
David Turner68df4f72005-03-15 18:18:57 +00001837 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001838 if ( error )
1839 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001840
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001841 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1842 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1843 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1844 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1845
1846 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001847 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1848 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001849
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001850 /* Determine the overall font bounding box as the characters are */
1851 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001852 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1853 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001854
David Turnerb1b47622002-05-21 21:17:43 +00001855 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001856
Werner Lembergdfa46192004-03-05 09:26:24 +00001857 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1858 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1859 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001860
1861 if ( !( p->flags & _BDF_DWIDTH ) )
1862 {
1863 /* Missing DWIDTH field. Emit an auto correction message and set */
1864 /* the device width to the glyph width. */
1865 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1866 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001867 }
1868
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001869 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1870 /* value if necessary. */
1871 if ( p->opts->correct_metrics != 0 )
1872 {
1873 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001874 unsigned short sw = (unsigned short)FT_MulDiv(
1875 glyph->dwidth, 72000L,
1876 (FT_Long)( font->point_size *
1877 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001878
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001879
1880 if ( sw != glyph->swidth )
1881 {
1882 glyph->swidth = sw;
1883
1884 if ( p->glyph_enc == -1 )
1885 _bdf_set_glyph_modified( font->umod,
1886 font->unencoded_used - 1 );
1887 else
1888 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1889
1890 p->flags |= _BDF_SWIDTH_ADJ;
1891 font->modified = 1;
1892 }
David Turner993a8d02002-05-18 12:03:43 +00001893 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001894
David Turner993a8d02002-05-18 12:03:43 +00001895 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001896 goto Exit;
1897 }
David Turner993a8d02002-05-18 12:03:43 +00001898
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001899 /* And finally, gather up the bitmap. */
1900 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1901 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001902 unsigned long bitmap_size;
1903
1904
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001905 if ( !( p->flags & _BDF_BBX ) )
1906 {
1907 /* Missing BBX field. */
1908 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1909 error = BDF_Err_Missing_Bbx_Field;
1910 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001911 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001912
1913 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001914 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001915
1916 bitmap_size = glyph->bpr * glyph->bbx.height;
Werner Lembergc4cad302012-03-08 20:11:37 +01001917 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
Werner Lemberg26170df2006-03-26 07:19:07 +00001918 {
1919 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1920 error = BDF_Err_Bbx_Too_Big;
1921 goto Exit;
1922 }
1923 else
1924 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001925
1926 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1927 goto Exit;
1928
1929 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001930 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001931
1932 goto Exit;
1933 }
1934
Werner Lemberge01406b2011-11-25 09:44:28 +01001935 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001936 error = BDF_Err_Invalid_File_Format;
Werner Lemberg4086fb72012-03-01 08:55:40 +01001937 goto Exit;
1938
1939 Missing_Encoding:
1940 /* Missing ENCODING field. */
1941 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1942 error = BDF_Err_Missing_Encoding_Field;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001943
1944 Exit:
Werner Lembergf4c94d42010-06-19 16:08:31 +02001945 if ( error && ( p->flags & _BDF_GLYPH ) )
1946 FT_FREE( p->glyph_name );
1947
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001948 return error;
David Turner993a8d02002-05-18 12:03:43 +00001949 }
1950
David Turner993a8d02002-05-18 12:03:43 +00001951
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001952 /* Load the font properties. */
1953 static FT_Error
1954 _bdf_parse_properties( char* line,
1955 unsigned long linelen,
1956 unsigned long lineno,
1957 void* call_data,
1958 void* client_data )
1959 {
1960 unsigned long vlen;
1961 _bdf_line_func_t* next;
1962 _bdf_parse_t* p;
1963 char* name;
1964 char* value;
1965 char nbuf[128];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001966 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001967
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001968 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001969
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001970
1971 next = (_bdf_line_func_t *)call_data;
1972 p = (_bdf_parse_t *) client_data;
1973
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001974 /* Check for the end of the properties. */
1975 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1976 {
1977 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1978 /* encountered yet, then make sure they are added as properties and */
1979 /* make sure they are set from the font bounding box info. */
1980 /* */
1981 /* This is *always* done regardless of the options, because X11 */
1982 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001983 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001984 {
1985 p->font->font_ascent = p->font->bbx.ascent;
1986 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001987 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
1988 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001989 if ( error )
1990 goto Exit;
1991
1992 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1993 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001994 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001995
Werner Lemberg428c2e42003-04-25 05:35:04 +00001996 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001997 {
1998 p->font->font_descent = p->font->bbx.descent;
1999 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002000 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2001 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002002 if ( error )
2003 goto Exit;
2004
2005 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2006 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002007 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002008
David Turner993a8d02002-05-18 12:03:43 +00002009 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002010 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00002011
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002012 goto Exit;
2013 }
David Turner993a8d02002-05-18 12:03:43 +00002014
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002015 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
2016 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
2017 goto Exit;
2018
2019 /* Handle COMMENT fields and properties in a special way to preserve */
2020 /* the spacing. */
2021 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2022 {
David Turner993a8d02002-05-18 12:03:43 +00002023 name = value = line;
2024 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002025 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00002026 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01002027 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002028 if ( error )
2029 goto Exit;
2030 }
2031 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
2032 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002033 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002034 if ( error )
2035 goto Exit;
2036 }
2037 else
2038 {
David Turner68df4f72005-03-15 18:18:57 +00002039 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002040 if ( error )
2041 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002042 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002043
David Turner68df4f72005-03-15 18:18:57 +00002044 _bdf_list_shift( &p->list, 1 );
2045 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002046
Werner Lemberge01406b2011-11-25 09:44:28 +01002047 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002048 if ( error )
2049 goto Exit;
2050 }
2051
2052 Exit:
2053 return error;
David Turner993a8d02002-05-18 12:03:43 +00002054 }
2055
David Turner993a8d02002-05-18 12:03:43 +00002056
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002057 /* Load the font header. */
2058 static FT_Error
2059 _bdf_parse_start( char* line,
2060 unsigned long linelen,
2061 unsigned long lineno,
2062 void* call_data,
2063 void* client_data )
2064 {
2065 unsigned long slen;
2066 _bdf_line_func_t* next;
2067 _bdf_parse_t* p;
2068 bdf_font_t* font;
2069 char *s;
David Turner993a8d02002-05-18 12:03:43 +00002070
David Turnerd490e372002-05-28 23:40:37 +00002071 FT_Memory memory = NULL;
2072 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002073
2074 FT_UNUSED( lineno ); /* only used in debug mode */
2075
2076
2077 next = (_bdf_line_func_t *)call_data;
2078 p = (_bdf_parse_t *) client_data;
2079
2080 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00002081 memory = p->font->memory;
2082
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002083 /* Check for a comment. This is done to handle those fonts that have */
2084 /* comments before the STARTFONT line for some reason. */
2085 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2086 {
2087 if ( p->opts->keep_comments != 0 && p->font != 0 )
2088 {
2089 linelen -= 7;
2090
2091 s = line + 7;
2092 if ( *s != 0 )
2093 {
2094 s++;
2095 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002096 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002097
2098 error = _bdf_add_comment( p->font, s, linelen );
2099 if ( error )
2100 goto Exit;
2101 /* here font is not defined! */
2102 }
2103
2104 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002105 }
2106
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002107 if ( !( p->flags & _BDF_START ) )
2108 {
2109 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002110
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002111 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2112 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01002113 /* we don't emit an error message since this code gets */
2114 /* explicitly caught one level higher */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002115 error = BDF_Err_Missing_Startfont_Field;
2116 goto Exit;
2117 }
David Turner993a8d02002-05-18 12:03:43 +00002118
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002119 p->flags = _BDF_START;
2120 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002121
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002122 if ( FT_NEW( font ) )
2123 goto Exit;
2124 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002125
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002126 font->memory = p->memory;
2127 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002128
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002129 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09002130 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002131 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002132
David Turner993a8d02002-05-18 12:03:43 +00002133
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002134 error = hash_init( &(font->proptbl), memory );
2135 if ( error )
2136 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002137 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002138 i < _num_bdf_properties; i++, prop++ )
2139 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09002140 error = hash_insert( prop->name, i,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002141 &(font->proptbl), memory );
2142 if ( error )
2143 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002144 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002145 }
2146
2147 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2148 goto Exit;
2149 error = hash_init( (hashtable *)p->font->internal,memory );
2150 if ( error )
2151 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002152 p->font->spacing = p->opts->font_spacing;
2153 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002154
2155 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002156 }
2157
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002158 /* Check for the start of the properties. */
2159 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2160 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002161 if ( !( p->flags & _BDF_FONT_BBX ) )
Werner Lembergfb690292010-06-23 10:00:52 +02002162 {
2163 /* Missing the FONTBOUNDINGBOX field. */
2164 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2165 error = BDF_Err_Missing_Fontboundingbox_Field;
2166 goto Exit;
2167 }
2168
David Turner68df4f72005-03-15 18:18:57 +00002169 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002170 if ( error )
2171 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00002172 /* at this point, `p->font' can't be NULL */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002173 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2174
2175 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
Werner Lemberg9b6b5752012-12-15 01:34:41 +01002176 {
2177 p->font->props_size = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002178 goto Exit;
Werner Lemberg9b6b5752012-12-15 01:34:41 +01002179 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002180
2181 p->flags |= _BDF_PROPS;
2182 *next = _bdf_parse_properties;
2183
2184 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002185 }
2186
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002187 /* Check for the FONTBOUNDINGBOX field. */
2188 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2189 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002190 if ( !( p->flags & _BDF_SIZE ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002191 {
2192 /* Missing the SIZE field. */
2193 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2194 error = BDF_Err_Missing_Size_Field;
2195 goto Exit;
2196 }
2197
David Turner68df4f72005-03-15 18:18:57 +00002198 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002199 if ( error )
2200 goto Exit;
2201
2202 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2203 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2204
2205 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2206 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2207
David Turnerd490e372002-05-28 23:40:37 +00002208 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002209 p->font->bbx.y_offset );
2210
2211 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002212
2213 p->flags |= _BDF_FONT_BBX;
2214
2215 goto Exit;
2216 }
2217
2218 /* The next thing to check for is the FONT field. */
2219 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2220 {
David Turner68df4f72005-03-15 18:18:57 +00002221 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002222 if ( error )
2223 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002224 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002225
David Turner68df4f72005-03-15 18:18:57 +00002226 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002227
2228 if ( !s )
2229 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002230 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg5b591e42007-06-01 22:16:43 +00002231 error = BDF_Err_Invalid_File_Format;
2232 goto Exit;
2233 }
2234
Werner Lembergfb690292010-06-23 10:00:52 +02002235 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2236 FT_FREE( p->font->name );
2237
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002238 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2239 goto Exit;
2240 FT_MEM_COPY( p->font->name, s, slen + 1 );
2241
2242 /* If the font name is an XLFD name, set the spacing to the one in */
2243 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002244 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002245 if ( error )
2246 goto Exit;
2247
2248 p->flags |= _BDF_FONT_NAME;
2249
2250 goto Exit;
2251 }
2252
2253 /* Check for the SIZE field. */
2254 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2255 {
2256 if ( !( p->flags & _BDF_FONT_NAME ) )
2257 {
2258 /* Missing the FONT field. */
2259 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2260 error = BDF_Err_Missing_Font_Field;
2261 goto Exit;
2262 }
2263
David Turner68df4f72005-03-15 18:18:57 +00002264 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002265 if ( error )
2266 goto Exit;
2267
2268 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2269 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2270 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2271
2272 /* Check for the bits per pixel field. */
2273 if ( p->list.used == 5 )
2274 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002275 unsigned short bitcount, i, shift;
2276
2277
2278 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2279
2280 /* Only values 1, 2, 4, 8 are allowed. */
2281 shift = p->font->bpp;
2282 bitcount = 0;
2283 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002284 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002285 if ( shift & 1 )
2286 bitcount = i;
2287 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002288 }
David Turner993a8d02002-05-18 12:03:43 +00002289
Werner Lembergbd8e3242002-06-12 08:43:58 +00002290 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002291
2292 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002293 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002294 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002295 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002296 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002297 }
2298 }
2299 else
2300 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002301
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002302 p->flags |= _BDF_SIZE;
2303
2304 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002305 }
2306
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002307 /* Check for the CHARS field -- font properties are optional */
2308 if ( ft_memcmp( line, "CHARS", 5 ) == 0 )
2309 {
2310 char nbuf[128];
2311
2312
2313 if ( !( p->flags & _BDF_FONT_BBX ) )
2314 {
2315 /* Missing the FONTBOUNDINGBOX field. */
2316 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2317 error = BDF_Err_Missing_Fontboundingbox_Field;
2318 goto Exit;
2319 }
2320
2321 /* Add the two standard X11 properties which are required */
2322 /* for compiling fonts. */
2323 p->font->font_ascent = p->font->bbx.ascent;
2324 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002325 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2326 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002327 if ( error )
2328 goto Exit;
2329 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2330
2331 p->font->font_descent = p->font->bbx.descent;
2332 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002333 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2334 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002335 if ( error )
2336 goto Exit;
2337 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2338
2339 p->font->modified = 1;
2340
2341 *next = _bdf_parse_glyphs;
2342
2343 /* A special return value. */
2344 error = -1;
2345 goto Exit;
2346 }
2347
Werner Lemberge01406b2011-11-25 09:44:28 +01002348 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002349 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002350
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002351 Exit:
2352 return error;
2353 }
David Turner993a8d02002-05-18 12:03:43 +00002354
2355
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002356 /*************************************************************************/
2357 /* */
2358 /* API. */
2359 /* */
2360 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002361
David Turner993a8d02002-05-18 12:03:43 +00002362
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002363 FT_LOCAL_DEF( FT_Error )
2364 bdf_load_font( FT_Stream stream,
2365 FT_Memory extmemory,
2366 bdf_options_t* opts,
2367 bdf_font_t* *font )
2368 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002369 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002370 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002371
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002372 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002373 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002374
2375
David Turner68df4f72005-03-15 18:18:57 +00002376 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002377 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002378
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002379 memory = NULL;
2380 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2381 p->minlb = 32767;
2382 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002383
David Turner68df4f72005-03-15 18:18:57 +00002384 _bdf_list_init( &p->list, extmemory );
2385
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002386 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002387 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002388 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002389 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002390
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002391 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002392 {
2393 /* If the font is not proportional, set the font's monowidth */
2394 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002395 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002396
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002397 if ( p->font->spacing != BDF_PROPORTIONAL )
2398 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002399
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002400 /* If the number of glyphs loaded is not that of the original count, */
2401 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002402 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002403 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002404 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2405 p->font->glyphs_used + p->font->unencoded_used ));
2406 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002407 }
2408
2409 /* Once the font has been loaded, adjust the overall font metrics if */
2410 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002411 if ( p->opts->correct_metrics != 0 &&
2412 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002413 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002414 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002415 {
2416 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002417 p->font->bbx.width, p->maxrb - p->minlb ));
2418 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2419 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002420 }
2421
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002422 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002423 {
2424 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002425 p->font->bbx.x_offset, p->minlb ));
2426 p->font->bbx.x_offset = p->minlb;
2427 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002428 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002429
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002430 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002431 {
2432 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002433 p->font->bbx.ascent, p->maxas ));
2434 p->font->bbx.ascent = p->maxas;
2435 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002436 }
2437
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002438 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002439 {
2440 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002441 p->font->bbx.descent, p->maxds ));
2442 p->font->bbx.descent = p->maxds;
2443 p->font->bbx.y_offset = (short)( -p->maxds );
2444 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002445 }
2446
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002447 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002448 {
2449 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002450 p->font->bbx.height, p->maxas + p->maxds ));
2451 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002452 }
2453
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002454 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002455 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2456 }
David Turner993a8d02002-05-18 12:03:43 +00002457 }
2458
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002459 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002460 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002461 /* The ENDFONT field was never reached or did not exist. */
2462 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002463 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002464 /* Error happened while parsing header. */
2465 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2466 error = BDF_Err_Corrupted_Font_Header;
2467 goto Exit;
2468 }
2469 else
2470 {
2471 /* Error happened when parsing glyphs. */
2472 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2473 error = BDF_Err_Corrupted_Font_Glyphs;
2474 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002475 }
David Turner993a8d02002-05-18 12:03:43 +00002476 }
2477
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002478 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002479 {
2480 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002481 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002482
Werner Lemberg370aea82010-06-08 08:37:11 +02002483 if ( p->font->comments_len > 0 )
2484 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002485 if ( FT_RENEW_ARRAY( p->font->comments,
2486 p->font->comments_len,
2487 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002488 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002489
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002490 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002491 }
David Turner993a8d02002-05-18 12:03:43 +00002492 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002493 else if ( error == BDF_Err_Ok )
2494 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002495
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002496 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002497
2498 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002499 if ( p )
2500 {
David Turner68df4f72005-03-15 18:18:57 +00002501 _bdf_list_done( &p->list );
2502
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002503 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002504
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002505 FT_FREE( p );
2506 }
2507
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002508 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002509
2510 Fail:
2511 bdf_free_font( p->font );
2512
2513 memory = extmemory;
2514
2515 FT_FREE( p->font );
2516
2517 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002518 }
David Turner993a8d02002-05-18 12:03:43 +00002519
2520
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002521 FT_LOCAL_DEF( void )
2522 bdf_free_font( bdf_font_t* font )
2523 {
2524 bdf_property_t* prop;
2525 unsigned long i;
2526 bdf_glyph_t* glyphs;
2527 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002528
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002529
2530 if ( font == 0 )
2531 return;
David Turner993a8d02002-05-18 12:03:43 +00002532
2533 memory = font->memory;
2534
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002535 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002536
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002537 /* Free up the internal hash table of property names. */
2538 if ( font->internal )
2539 {
2540 hash_free( (hashtable *)font->internal, memory );
2541 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002542 }
2543
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002544 /* Free up the comment info. */
2545 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002546
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002547 /* Free up the properties. */
2548 for ( i = 0; i < font->props_size; i++ )
2549 {
2550 if ( font->props[i].format == BDF_ATOM )
2551 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002552 }
2553
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002554 FT_FREE( font->props );
2555
2556 /* Free up the character info. */
2557 for ( i = 0, glyphs = font->glyphs;
2558 i < font->glyphs_used; i++, glyphs++ )
2559 {
2560 FT_FREE( glyphs->name );
2561 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002562 }
2563
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002564 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2565 i++, glyphs++ )
2566 {
2567 FT_FREE( glyphs->name );
2568 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002569 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002570
2571 FT_FREE( font->glyphs );
2572 FT_FREE( font->unencoded );
2573
2574 /* Free up the overflow storage if it was used. */
2575 for ( i = 0, glyphs = font->overflow.glyphs;
2576 i < font->overflow.glyphs_used; i++, glyphs++ )
2577 {
2578 FT_FREE( glyphs->name );
2579 FT_FREE( glyphs->bitmap );
2580 }
2581
2582 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002583
2584 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002585 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002586
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002587 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002588 for ( prop = font->user_props, i = 0;
2589 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002590 {
2591 FT_FREE( prop->name );
2592 if ( prop->format == BDF_ATOM )
2593 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002594 }
David Turner993a8d02002-05-18 12:03:43 +00002595
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002596 FT_FREE( font->user_props );
2597
2598 /* FREE( font ); */ /* XXX Fixme */
2599 }
David Turner993a8d02002-05-18 12:03:43 +00002600
2601
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002602 FT_LOCAL_DEF( bdf_property_t * )
2603 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002604 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002605 {
2606 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002607
David Turner993a8d02002-05-18 12:03:43 +00002608
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002609 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002610 return 0;
2611
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002612 hn = hash_lookup( name, (hashtable *)font->internal );
2613
suzuki toshiya704f4d72009-09-13 00:50:14 +09002614 return hn ? ( font->props + hn->data ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002615 }
2616
2617
2618/* END */