blob: 6a66d1d1f02c4129b280fa799c8ed4cd81b47584 [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;
572 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000573
574 /* If the line is empty, then simply return. */
575 if ( linelen == 0 || line[0] == 0 )
576 goto Exit;
577
578 /* In the original code, if the `separators' parameter is NULL or */
579 /* empty, the list is split into individual bytes. We don't need */
580 /* this, so an error is signaled. */
581 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000582 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000583 error = BDF_Err_Invalid_Argument;
584 goto Exit;
585 }
586
587 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000588 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000589
590 /* If the very last character of the separator string is a plus, then */
591 /* set the `mult' flag to indicate that multiple separators should be */
592 /* collapsed into one. */
593 for ( mult = 0, sp = separators; sp && *sp; sp++ )
594 {
595 if ( *sp == '+' && *( sp + 1 ) == 0 )
596 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000597 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000598 setsbit( seps, *sp );
599 }
600
601 /* Break the line up into fields. */
602 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
603 sp < end && *sp; )
604 {
605 /* Collect everything that is not a separator. */
606 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
607 ;
608
609 /* Resize the list if necessary. */
610 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000611 {
Werner Lembergebf55852005-03-16 01:49:54 +0000612 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000613 if ( error )
614 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000615 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000616
617 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000618 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000619
620 sp = ep;
621
622 if ( mult )
623 {
624 /* If multiple separators should be collapsed, do it now by */
625 /* setting all the separator characters to 0. */
626 for ( ; *ep && sbitset( seps, *ep ); ep++ )
627 *ep = 0;
628 }
629 else if ( *ep != 0 )
630 /* Don't collapse multiple separators by making them 0, so just */
631 /* make the one encountered 0. */
632 *ep++ = 0;
633
634 final_empty = ( ep > sp && *ep == 0 );
635 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000636 }
637
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000638 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000639 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000640 {
Werner Lembergebf55852005-03-16 01:49:54 +0000641 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000642 if ( error )
643 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000644 }
645
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000646 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000647 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000648
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000649 list->field[list->used] = 0;
650
651 Exit:
652 return error;
David Turner993a8d02002-05-18 12:03:43 +0000653 }
654
David Turner993a8d02002-05-18 12:03:43 +0000655
David Turner68df4f72005-03-15 18:18:57 +0000656#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000657
Werner Lembergebf55852005-03-16 01:49:54 +0000658
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000659 static FT_Error
660 _bdf_readstream( FT_Stream stream,
661 _bdf_line_func_t callback,
662 void* client_data,
663 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000664 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000665 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000666 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900667 int refill, hold, to_skip;
668 ptrdiff_t bytes, start, end, cursor, avail;
David Turner68df4f72005-03-15 18:18:57 +0000669 char* buf = 0;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000670 FT_Memory memory = stream->memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000671 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000672
David Turner993a8d02002-05-18 12:03:43 +0000673
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000674 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000675 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000676 error = BDF_Err_Invalid_Argument;
677 goto Exit;
678 }
David Turner993a8d02002-05-18 12:03:43 +0000679
Werner Lembergebf55852005-03-16 01:49:54 +0000680 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000681 buf_size = 1024;
682
683 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000684 goto Exit;
685
Werner Lembergebf55852005-03-16 01:49:54 +0000686 cb = callback;
687 lineno = 1;
688 buf[0] = 0;
689 start = 0;
690 end = 0;
691 avail = 0;
692 cursor = 0;
693 refill = 1;
694 to_skip = NO_SKIP;
695 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000696
David Turner68df4f72005-03-15 18:18:57 +0000697 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000698 {
David Turner68df4f72005-03-15 18:18:57 +0000699 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000700 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +0200701 bytes = (ptrdiff_t)FT_Stream_TryRead(
702 stream, (FT_Byte*)buf + cursor,
703 (FT_ULong)( buf_size - cursor ) );
David Turner68df4f72005-03-15 18:18:57 +0000704 avail = cursor + bytes;
705 cursor = 0;
706 refill = 0;
707 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000708
David Turner68df4f72005-03-15 18:18:57 +0000709 end = start;
710
Werner Lembergebf55852005-03-16 01:49:54 +0000711 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000712 if ( start < avail && buf[start] == to_skip )
713 {
714 start += 1;
715 to_skip = NO_SKIP;
716 continue;
717 }
718
719 /* try to find the end of the line */
720 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
721 end++;
722
Werner Lembergebf55852005-03-16 01:49:54 +0000723 /* if we hit the end of the buffer, try shifting its content */
724 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000725 if ( end >= avail )
726 {
727 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
728 break; /* ignore it then exit */
729
730 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000731 {
Werner Lembergebf55852005-03-16 01:49:54 +0000732 /* this line is definitely too long; try resizing the input */
733 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000734 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000735
Werner Lembergebf55852005-03-16 01:49:54 +0000736
737 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000738 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100739 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
David Turner68df4f72005-03-15 18:18:57 +0000740 error = BDF_Err_Invalid_Argument;
741 goto Exit;
742 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000743
Werner Lembergebf55852005-03-16 01:49:54 +0000744 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000745 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
746 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000747
David Turner68df4f72005-03-15 18:18:57 +0000748 cursor = buf_size;
749 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000750 }
751 else
752 {
David Turner68df4f72005-03-15 18:18:57 +0000753 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000754
Werner Lembergebf55852005-03-16 01:49:54 +0000755 FT_MEM_COPY( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000756
David Turner68df4f72005-03-15 18:18:57 +0000757 cursor = bytes;
758 avail -= bytes;
759 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000760 }
David Turner68df4f72005-03-15 18:18:57 +0000761 refill = 1;
762 continue;
David Turner993a8d02002-05-18 12:03:43 +0000763 }
David Turner68df4f72005-03-15 18:18:57 +0000764
765 /* Temporarily NUL-terminate the line. */
766 hold = buf[end];
767 buf[end] = 0;
768
769 /* XXX: Use encoding independent value for 0x1a */
770 if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
771 {
Werner Lembergebf55852005-03-16 01:49:54 +0000772 error = (*cb)( buf + start, end - start, lineno,
773 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200774 /* Redo if we have encountered CHARS without properties. */
775 if ( error == -1 )
776 error = (*cb)( buf + start, end - start, lineno,
777 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000778 if ( error )
779 break;
780 }
781
782 lineno += 1;
783 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000784 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000785
786 if ( hold == '\n' )
787 to_skip = '\r';
788 else if ( hold == '\r' )
789 to_skip = '\n';
790 else
791 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000792 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000793
David Turner68df4f72005-03-15 18:18:57 +0000794 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000795
796 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000797 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000798 return error;
David Turner993a8d02002-05-18 12:03:43 +0000799 }
David Turner993a8d02002-05-18 12:03:43 +0000800
801
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000802 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000803
David Turnerb1b47622002-05-21 21:17:43 +0000804 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000805 {
David Turner993a8d02002-05-18 12:03:43 +0000806 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
807 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, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
811 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
812 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
813 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
814 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
815 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
816 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000817 };
David Turner993a8d02002-05-18 12:03:43 +0000818
David Turnerb1b47622002-05-21 21:17:43 +0000819 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000820 {
David Turner993a8d02002-05-18 12:03:43 +0000821 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
822 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
823 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000825 };
David Turner993a8d02002-05-18 12:03:43 +0000826
David Turnerb1b47622002-05-21 21:17:43 +0000827 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000828 {
David Turner993a8d02002-05-18 12:03:43 +0000829 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
830 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
831 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
832 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000833 };
David Turner993a8d02002-05-18 12:03:43 +0000834
David Turnerb1b47622002-05-21 21:17:43 +0000835 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000836 {
David Turner993a8d02002-05-18 12:03:43 +0000837 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
838 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
839 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
840 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000841 };
David Turner993a8d02002-05-18 12:03:43 +0000842
David Turner993a8d02002-05-18 12:03:43 +0000843
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000844#define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
David Turner993a8d02002-05-18 12:03:43 +0000845
David Turner993a8d02002-05-18 12:03:43 +0000846
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000847 /* Routine to convert an ASCII string into an unsigned long integer. */
848 static unsigned long
849 _bdf_atoul( char* s,
850 char** end,
851 int base )
David Turner993a8d02002-05-18 12:03:43 +0000852 {
David Turnerb1b47622002-05-21 21:17:43 +0000853 unsigned long v;
854 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000855
856
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000857 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000858 return 0;
859
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000860 /* Make sure the radix is something recognizable. Default to 10. */
861 switch ( base )
862 {
863 case 8:
864 dmap = odigits;
865 break;
866 case 16:
867 dmap = hdigits;
868 break;
869 default:
870 base = 10;
871 dmap = ddigits;
872 break;
David Turner993a8d02002-05-18 12:03:43 +0000873 }
874
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000875 /* Check for the special hex prefix. */
876 if ( *s == '0' &&
877 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
878 {
879 base = 16;
880 dmap = hdigits;
881 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000882 }
883
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000884 for ( v = 0; isdigok( dmap, *s ); s++ )
885 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000886
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000887 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000888 *end = s;
889
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000890 return v;
891 }
David Turner993a8d02002-05-18 12:03:43 +0000892
David Turner993a8d02002-05-18 12:03:43 +0000893
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000894 /* Routine to convert an ASCII string into an signed long integer. */
895 static long
896 _bdf_atol( char* s,
897 char** end,
898 int base )
899 {
David Turnerb1b47622002-05-21 21:17:43 +0000900 long v, neg;
901 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000902
903
904 if ( s == 0 || *s == 0 )
905 return 0;
906
907 /* Make sure the radix is something recognizable. Default to 10. */
908 switch ( base )
909 {
910 case 8:
911 dmap = odigits;
912 break;
913 case 16:
914 dmap = hdigits;
915 break;
916 default:
917 base = 10;
918 dmap = ddigits;
919 break;
920 }
921
922 /* Check for a minus sign. */
923 neg = 0;
924 if ( *s == '-' )
925 {
926 s++;
927 neg = 1;
928 }
929
930 /* Check for the special hex prefix. */
931 if ( *s == '0' &&
932 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
933 {
934 base = 16;
935 dmap = hdigits;
936 s += 2;
937 }
938
939 for ( v = 0; isdigok( dmap, *s ); s++ )
940 v = v * base + a2i[(int)*s];
941
942 if ( end != 0 )
943 *end = s;
944
945 return ( !neg ) ? v : -v;
946 }
947
948
949 /* Routine to convert an ASCII string into an signed short integer. */
950 static short
951 _bdf_atos( char* s,
952 char** end,
953 int base )
954 {
David Turnerb1b47622002-05-21 21:17:43 +0000955 short v, neg;
956 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000957
958
959 if ( s == 0 || *s == 0 )
960 return 0;
961
962 /* Make sure the radix is something recognizable. Default to 10. */
963 switch ( base )
964 {
965 case 8:
966 dmap = odigits;
967 break;
968 case 16:
969 dmap = hdigits;
970 break;
971 default:
972 base = 10;
973 dmap = ddigits;
974 break;
975 }
976
977 /* Check for a minus. */
978 neg = 0;
979 if ( *s == '-' )
980 {
981 s++;
982 neg = 1;
983 }
984
985 /* Check for the special hex prefix. */
986 if ( *s == '0' &&
987 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
988 {
989 base = 16;
990 dmap = hdigits;
991 s += 2;
992 }
993
994 for ( v = 0; isdigok( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +0000995 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000996
997 if ( end != 0 )
998 *end = s;
999
Werner Lemberg233302a2002-05-22 05:41:06 +00001000 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001001 }
1002
1003
1004 /* Routine to compare two glyphs by encoding so they can be sorted. */
1005 static int
1006 by_encoding( const void* a,
1007 const void* b )
1008 {
1009 bdf_glyph_t *c1, *c2;
1010
1011
1012 c1 = (bdf_glyph_t *)a;
1013 c2 = (bdf_glyph_t *)b;
1014
1015 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001016 return -1;
David Turner68df4f72005-03-15 18:18:57 +00001017
1018 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001019 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001020
David Turner993a8d02002-05-18 12:03:43 +00001021 return 0;
David Turner993a8d02002-05-18 12:03:43 +00001022 }
1023
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001024
1025 static FT_Error
1026 bdf_create_property( char* name,
1027 int format,
1028 bdf_font_t* font )
1029 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001030 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001031 bdf_property_t* p;
1032 FT_Memory memory = font->memory;
1033 FT_Error error = BDF_Err_Ok;
1034
1035
Werner Lemberg96ddc672011-06-29 09:15:54 +02001036 /* First check whether the property has */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001037 /* already been added or not. If it has, then */
1038 /* simply ignore it. */
1039 if ( hash_lookup( name, &(font->proptbl) ) )
1040 goto Exit;
1041
David Turner68df4f72005-03-15 18:18:57 +00001042 if ( FT_RENEW_ARRAY( font->user_props,
1043 font->nuser_props,
1044 font->nuser_props + 1 ) )
1045 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001046
1047 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +00001048 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001049
suzuki toshiya704f4d72009-09-13 00:50:14 +09001050 n = ft_strlen( name ) + 1;
1051 if ( n > FT_ULONG_MAX )
1052 return BDF_Err_Invalid_Argument;
David Turner68df4f72005-03-15 18:18:57 +00001053
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001054 if ( FT_NEW_ARRAY( p->name, n ) )
1055 goto Exit;
1056
1057 FT_MEM_COPY( (char *)p->name, name, n );
1058
1059 p->format = format;
1060 p->builtin = 0;
1061
1062 n = _num_bdf_properties + font->nuser_props;
1063
suzuki toshiya704f4d72009-09-13 00:50:14 +09001064 error = hash_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001065 if ( error )
1066 goto Exit;
1067
1068 font->nuser_props++;
1069
1070 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001071 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001072 }
David Turner993a8d02002-05-18 12:03:43 +00001073
1074
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001075 FT_LOCAL_DEF( bdf_property_t * )
1076 bdf_get_property( char* name,
1077 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001078 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001079 hashnode hn;
1080 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001081
1082
1083 if ( name == 0 || *name == 0 )
1084 return 0;
1085
1086 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1087 return 0;
1088
suzuki toshiya704f4d72009-09-13 00:50:14 +09001089 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001090 if ( propid >= _num_bdf_properties )
1091 return font->user_props + ( propid - _num_bdf_properties );
1092
Werner Lemberg233302a2002-05-22 05:41:06 +00001093 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001094 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001095
1096
1097 /*************************************************************************/
1098 /* */
1099 /* BDF font file parsing flags and functions. */
1100 /* */
1101 /*************************************************************************/
1102
1103
1104 /* Parse flags. */
1105
1106#define _BDF_START 0x0001
1107#define _BDF_FONT_NAME 0x0002
1108#define _BDF_SIZE 0x0004
1109#define _BDF_FONT_BBX 0x0008
1110#define _BDF_PROPS 0x0010
1111#define _BDF_GLYPHS 0x0020
1112#define _BDF_GLYPH 0x0040
1113#define _BDF_ENCODING 0x0080
1114#define _BDF_SWIDTH 0x0100
1115#define _BDF_DWIDTH 0x0200
1116#define _BDF_BBX 0x0400
1117#define _BDF_BITMAP 0x0800
1118
1119#define _BDF_SWIDTH_ADJ 0x1000
1120
1121#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1122 _BDF_ENCODING | \
1123 _BDF_SWIDTH | \
1124 _BDF_DWIDTH | \
1125 _BDF_BBX | \
1126 _BDF_BITMAP )
1127
Werner Lembergf1c2b912006-01-13 14:53:28 +00001128#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1129#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001130
1131
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001132 static FT_Error
1133 _bdf_add_comment( bdf_font_t* font,
1134 char* comment,
1135 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001136 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001137 char* cp;
1138 FT_Memory memory = font->memory;
1139 FT_Error error = BDF_Err_Ok;
1140
1141
David Turner68df4f72005-03-15 18:18:57 +00001142 if ( FT_RENEW_ARRAY( font->comments,
1143 font->comments_len,
1144 font->comments_len + len + 1 ) )
1145 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001146
1147 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001148
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001149 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001150 cp[len] = '\n';
1151
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001152 font->comments_len += len + 1;
1153
1154 Exit:
1155 return error;
David Turner993a8d02002-05-18 12:03:43 +00001156 }
1157
David Turner993a8d02002-05-18 12:03:43 +00001158
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001159 /* Set the spacing from the font name if it exists, or set it to the */
1160 /* default specified in the options. */
1161 static FT_Error
1162 _bdf_set_default_spacing( bdf_font_t* font,
Werner Lemberge01406b2011-11-25 09:44:28 +01001163 bdf_options_t* opts,
1164 unsigned long lineno )
David Turner993a8d02002-05-18 12:03:43 +00001165 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001166 size_t len;
1167 char name[256];
1168 _bdf_list_t list;
1169 FT_Memory memory;
1170 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001171
David Turner993a8d02002-05-18 12:03:43 +00001172
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001173 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1174 {
1175 error = BDF_Err_Invalid_Argument;
1176 goto Exit;
1177 }
David Turner993a8d02002-05-18 12:03:43 +00001178
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001179 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001180
David Turner68df4f72005-03-15 18:18:57 +00001181 _bdf_list_init( &list, memory );
1182
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001183 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001184
suzuki toshiya704f4d72009-09-13 00:50:14 +09001185 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +00001186 /* Limit ourselves to 256 characters in the font name. */
1187 if ( len >= 256 )
1188 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001189 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
Werner Lemberga08b2172007-03-28 07:17:17 +00001190 error = BDF_Err_Invalid_Argument;
1191 goto Exit;
1192 }
1193
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001194 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001195
David Turner68df4f72005-03-15 18:18:57 +00001196 error = _bdf_list_split( &list, (char *)"-", name, len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001197 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001198 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001199
1200 if ( list.used == 15 )
1201 {
1202 switch ( list.field[11][0] )
1203 {
1204 case 'C':
1205 case 'c':
1206 font->spacing = BDF_CHARCELL;
1207 break;
1208 case 'M':
1209 case 'm':
1210 font->spacing = BDF_MONOWIDTH;
1211 break;
1212 case 'P':
1213 case 'p':
1214 font->spacing = BDF_PROPORTIONAL;
1215 break;
David Turner993a8d02002-05-18 12:03:43 +00001216 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001217 }
1218
David Turner68df4f72005-03-15 18:18:57 +00001219 Fail:
1220 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001221
1222 Exit:
1223 return error;
David Turner993a8d02002-05-18 12:03:43 +00001224 }
David Turner993a8d02002-05-18 12:03:43 +00001225
1226
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001227 /* Determine whether the property is an atom or not. If it is, then */
1228 /* clean it up so the double quotes are removed if they exist. */
1229 static int
1230 _bdf_is_atom( char* line,
1231 unsigned long linelen,
1232 char** name,
1233 char** value,
1234 bdf_font_t* font )
1235 {
1236 int hold;
1237 char *sp, *ep;
1238 bdf_property_t* p;
1239
David Turner993a8d02002-05-18 12:03:43 +00001240
1241 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001242
1243 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001244 ep++;
1245
1246 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001247 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001248 {
1249 hold = *ep;
1250 *ep = 0;
1251 }
1252
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001253 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001254
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001255 /* Restore the character that was saved before any return can happen. */
1256 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001257 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001258
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001259 /* If the property exists and is not an atom, just return here. */
1260 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001261 return 0;
1262
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001263 /* The property is an atom. Trim all leading and trailing whitespace */
1264 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001265 sp = ep;
1266 ep = line + linelen;
1267
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001268 /* Trim the leading whitespace if it exists. */
Werner Lemberg320d4972012-02-24 18:06:46 +01001269 if ( *sp )
1270 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001271 while ( *sp &&
1272 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001273 sp++;
1274
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001275 /* Trim the leading double quote if it exists. */
1276 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001277 sp++;
1278 *value = sp;
1279
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001280 /* Trim the trailing whitespace if it exists. */
1281 while ( ep > sp &&
1282 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001283 *--ep = 0;
1284
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001285 /* Trim the trailing double quote if it exists. */
1286 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001287 *--ep = 0;
1288
1289 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001290 }
David Turner993a8d02002-05-18 12:03:43 +00001291
1292
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001293 static FT_Error
Werner Lemberge01406b2011-11-25 09:44:28 +01001294 _bdf_add_property( bdf_font_t* font,
1295 char* name,
1296 char* value,
1297 unsigned long lineno )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001298 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001299 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001300 hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001301 bdf_property_t *prop, *fp;
1302 FT_Memory memory = font->memory;
1303 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001304
David Turner993a8d02002-05-18 12:03:43 +00001305
Werner Lemberg96ddc672011-06-29 09:15:54 +02001306 /* First, check whether the property already exists in the font. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001307 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001308 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001309 /* The property already exists in the font, so simply replace */
1310 /* the value of the property with the current value. */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001311 fp = font->props + hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001312
David Turnerb1b47622002-05-21 21:17:43 +00001313 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001314 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001315 case BDF_ATOM:
1316 /* Delete the current atom if it exists. */
1317 FT_FREE( fp->value.atom );
1318
David Turnerc0f9c4a2007-02-12 14:55:03 +00001319 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001320 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001321 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001322 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001323 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001324 break;
1325
1326 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001327 fp->value.l = _bdf_atol( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001328 break;
1329
1330 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001331 fp->value.ul = _bdf_atoul( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001332 break;
David Turnerd490e372002-05-28 23:40:37 +00001333
David Turnerb1b47622002-05-21 21:17:43 +00001334 default:
1335 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001336 }
David Turnerd490e372002-05-28 23:40:37 +00001337
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001338 goto Exit;
1339 }
1340
1341 /* See whether this property type exists yet or not. */
1342 /* If not, create it. */
1343 hn = hash_lookup( name, &(font->proptbl) );
1344 if ( hn == 0 )
1345 {
1346 error = bdf_create_property( name, BDF_ATOM, font );
1347 if ( error )
1348 goto Exit;
1349 hn = hash_lookup( name, &(font->proptbl) );
1350 }
1351
1352 /* Allocate another property if this is overflow. */
1353 if ( font->props_used == font->props_size )
1354 {
1355 if ( font->props_size == 0 )
1356 {
1357 if ( FT_NEW_ARRAY( font->props, 1 ) )
1358 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001359 }
1360 else
1361 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001362 if ( FT_RENEW_ARRAY( font->props,
1363 font->props_size,
1364 font->props_size + 1 ) )
1365 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001366 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001367
David Turner993a8d02002-05-18 12:03:43 +00001368 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001369 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001370 font->props_size++;
1371 }
1372
suzuki toshiya704f4d72009-09-13 00:50:14 +09001373 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001374 if ( propid >= _num_bdf_properties )
1375 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001376 else
David Turnerb1b47622002-05-21 21:17:43 +00001377 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001378
1379 fp = font->props + font->props_used;
1380
1381 fp->name = prop->name;
1382 fp->format = prop->format;
1383 fp->builtin = prop->builtin;
1384
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001385 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001386 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001387 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001388 fp->value.atom = 0;
1389 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001390 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001391 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001392 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001393 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001394 break;
David Turner993a8d02002-05-18 12:03:43 +00001395
1396 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001397 fp->value.l = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001398 break;
1399
1400 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001401 fp->value.ul = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001402 break;
David Turner993a8d02002-05-18 12:03:43 +00001403 }
1404
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001405 /* If the property happens to be a comment, then it doesn't need */
1406 /* to be added to the internal hash table. */
Werner Lemberg370aea82010-06-08 08:37:11 +02001407 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 )
1408 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001409 /* Add the property to the font property table. */
1410 error = hash_insert( fp->name,
suzuki toshiya704f4d72009-09-13 00:50:14 +09001411 font->props_used,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001412 (hashtable *)font->internal,
1413 memory );
1414 if ( error )
1415 goto Exit;
1416 }
David Turner993a8d02002-05-18 12:03:43 +00001417
1418 font->props_used++;
1419
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001420 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1421 /* property needs to be located if it exists in the property list, the */
1422 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1423 /* present, and the SPACING property should override the default */
1424 /* spacing. */
1425 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001426 font->default_char = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001427 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001428 font->font_ascent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001429 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001430 font->font_descent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001431 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001432 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001433 if ( !fp->value.atom )
1434 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001435 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lembergb66efef2009-03-12 08:07:49 +00001436 error = BDF_Err_Invalid_File_Format;
1437 goto Exit;
1438 }
1439
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001440 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001441 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001442 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001443 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001444 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001445 font->spacing = BDF_CHARCELL;
1446 }
1447
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001448 Exit:
1449 return error;
David Turner993a8d02002-05-18 12:03:43 +00001450 }
1451
David Turner993a8d02002-05-18 12:03:43 +00001452
David Turnerb1b47622002-05-21 21:17:43 +00001453 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001454 {
1455 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1456 };
1457
1458
1459 /* Actually parse the glyph info and bitmaps. */
1460 static FT_Error
1461 _bdf_parse_glyphs( char* line,
1462 unsigned long linelen,
1463 unsigned long lineno,
1464 void* call_data,
1465 void* client_data )
1466 {
1467 int c, mask_index;
1468 char* s;
1469 unsigned char* bp;
1470 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001471
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001472 _bdf_parse_t* p;
1473 bdf_glyph_t* glyph;
1474 bdf_font_t* font;
1475
1476 FT_Memory memory;
1477 FT_Error error = BDF_Err_Ok;
1478
Werner Lemberg319c00d2003-04-23 19:48:24 +00001479 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001480 FT_UNUSED( lineno ); /* only used in debug mode */
1481
1482
Werner Lemberg319c00d2003-04-23 19:48:24 +00001483 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001484
1485 font = p->font;
1486 memory = font->memory;
1487
1488 /* Check for a comment. */
1489 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1490 {
1491 linelen -= 7;
1492
1493 s = line + 7;
1494 if ( *s != 0 )
1495 {
1496 s++;
1497 linelen--;
1498 }
1499 error = _bdf_add_comment( p->font, s, linelen );
1500 goto Exit;
1501 }
1502
1503 /* The very first thing expected is the number of glyphs. */
1504 if ( !( p->flags & _BDF_GLYPHS ) )
1505 {
1506 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1507 {
1508 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1509 error = BDF_Err_Missing_Chars_Field;
1510 goto Exit;
1511 }
1512
David Turner68df4f72005-03-15 18:18:57 +00001513 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001514 if ( error )
1515 goto Exit;
1516 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1517
1518 /* Make sure the number of glyphs is non-zero. */
1519 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001520 font->glyphs_size = 64;
1521
Werner Lemberga08b2172007-03-28 07:17:17 +00001522 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1523 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001524 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001525 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001526 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberga08b2172007-03-28 07:17:17 +00001527 error = BDF_Err_Invalid_Argument;
1528 goto Exit;
1529 }
1530
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001531 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1532 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001533
David Turner993a8d02002-05-18 12:03:43 +00001534 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001535
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001536 goto Exit;
1537 }
1538
1539 /* Check for the ENDFONT field. */
1540 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1541 {
1542 /* Sort the glyphs by encoding. */
1543 ft_qsort( (char *)font->glyphs,
1544 font->glyphs_used,
1545 sizeof ( bdf_glyph_t ),
1546 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001547
1548 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001549
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001550 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001551 }
1552
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001553 /* Check for the ENDCHAR field. */
1554 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1555 {
1556 p->glyph_enc = 0;
1557 p->flags &= ~_BDF_GLYPH_BITS;
1558
1559 goto Exit;
1560 }
1561
Werner Lemberg96ddc672011-06-29 09:15:54 +02001562 /* Check whether a glyph is being scanned but should be */
1563 /* ignored because it is an unencoded glyph. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001564 if ( ( p->flags & _BDF_GLYPH ) &&
1565 p->glyph_enc == -1 &&
1566 p->opts->keep_unencoded == 0 )
1567 goto Exit;
1568
1569 /* Check for the STARTCHAR field. */
1570 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1571 {
1572 /* Set the character name in the parse info first until the */
1573 /* encoding can be checked for an unencoded character. */
1574 FT_FREE( p->glyph_name );
1575
David Turner68df4f72005-03-15 18:18:57 +00001576 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001577 if ( error )
1578 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001579
David Turner68df4f72005-03-15 18:18:57 +00001580 _bdf_list_shift( &p->list, 1 );
1581
1582 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001583
Werner Lembergba03af62007-05-30 13:57:02 +00001584 if ( !s )
1585 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001586 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lembergba03af62007-05-30 13:57:02 +00001587 error = BDF_Err_Invalid_File_Format;
1588 goto Exit;
1589 }
1590
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001591 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1592 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001593
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001594 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1595
1596 p->flags |= _BDF_GLYPH;
1597
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001598 FT_TRACE4(( DBGMSG1, lineno, s ));
1599
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001600 goto Exit;
1601 }
1602
1603 /* Check for the ENCODING field. */
1604 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1605 {
1606 if ( !( p->flags & _BDF_GLYPH ) )
1607 {
1608 /* Missing STARTCHAR field. */
1609 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1610 error = BDF_Err_Missing_Startchar_Field;
1611 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001612 }
1613
David Turner68df4f72005-03-15 18:18:57 +00001614 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001615 if ( error )
1616 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001617
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001618 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001619
Werner Lemberg28dd2c42012-02-26 06:18:58 +01001620 /* Normalize negative encoding values. The specification only */
1621 /* allows -1, but we can be more generous here. */
1622 if ( p->glyph_enc < -1 )
1623 p->glyph_enc = -1;
1624
Werner Lemberg03242f52012-02-26 06:52:56 +01001625 /* Check for alternative encoding format. */
1626 if ( p->glyph_enc == -1 && p->list.used > 2 )
1627 p->glyph_enc = _bdf_atol( p->list.field[2], 0, 10 );
1628
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001629 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1630
Werner Lemberged54e432011-11-27 16:39:53 +01001631 /* Check that the encoding is in the Unicode range because */
1632 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lemberg96ddc672011-06-29 09:15:54 +02001633 if ( p->glyph_enc > 0 &&
1634 (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
David Turner481838e2006-02-23 12:40:14 +00001635 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001636 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
David Turner481838e2006-02-23 12:40:14 +00001637 error = BDF_Err_Invalid_File_Format;
1638 goto Exit;
1639 }
1640
Werner Lemberg96ddc672011-06-29 09:15:54 +02001641 /* Check whether this encoding has already been encountered. */
1642 /* If it has then change it to unencoded so it gets added if */
1643 /* indicated. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001644 if ( p->glyph_enc >= 0 )
1645 {
1646 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1647 {
1648 /* Emit a message saying a glyph has been moved to the */
1649 /* unencoded area. */
1650 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1651 p->glyph_enc, p->glyph_name ));
1652 p->glyph_enc = -1;
1653 font->modified = 1;
1654 }
1655 else
1656 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1657 }
1658
1659 if ( p->glyph_enc >= 0 )
1660 {
1661 /* Make sure there are enough glyphs allocated in case the */
1662 /* number of characters happen to be wrong. */
1663 if ( font->glyphs_used == font->glyphs_size )
1664 {
1665 if ( FT_RENEW_ARRAY( font->glyphs,
1666 font->glyphs_size,
1667 font->glyphs_size + 64 ) )
1668 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001669
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001670 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001671 }
1672
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001673 glyph = font->glyphs + font->glyphs_used++;
1674 glyph->name = p->glyph_name;
1675 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001676
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001677 /* Reset the initial glyph info. */
1678 p->glyph_name = 0;
1679 }
1680 else
1681 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001682 /* Unencoded glyph. Check whether it should */
1683 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001684 if ( p->opts->keep_unencoded != 0 )
1685 {
1686 /* Allocate the next unencoded glyph. */
1687 if ( font->unencoded_used == font->unencoded_size )
1688 {
David Turner68df4f72005-03-15 18:18:57 +00001689 if ( FT_RENEW_ARRAY( font->unencoded ,
1690 font->unencoded_size,
1691 font->unencoded_size + 4 ) )
1692 goto Exit;
1693
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001694 font->unencoded_size += 4;
1695 }
1696
1697 glyph = font->unencoded + font->unencoded_used;
1698 glyph->name = p->glyph_name;
1699 glyph->encoding = font->unencoded_used++;
1700 }
1701 else
1702 /* Free up the glyph name if the unencoded shouldn't be */
1703 /* kept. */
1704 FT_FREE( p->glyph_name );
1705
1706 p->glyph_name = 0;
1707 }
1708
1709 /* Clear the flags that might be added when width and height are */
1710 /* checked for consistency. */
1711 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1712
1713 p->flags |= _BDF_ENCODING;
1714
1715 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001716 }
1717
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001718 /* Point at the glyph being constructed. */
1719 if ( p->glyph_enc == -1 )
1720 glyph = font->unencoded + ( font->unencoded_used - 1 );
1721 else
1722 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001723
Werner Lemberg96ddc672011-06-29 09:15:54 +02001724 /* Check whether a bitmap is being constructed. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001725 if ( p->flags & _BDF_BITMAP )
1726 {
1727 /* If there are more rows than are specified in the glyph metrics, */
1728 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001729 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001730 {
1731 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1732 {
1733 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1734 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001735 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001736 }
1737
1738 goto Exit;
1739 }
1740
1741 /* Only collect the number of nibbles indicated by the glyph */
1742 /* metrics. If there are more columns, they are simply ignored. */
1743 nibbles = glyph->bpr << 1;
1744 bp = glyph->bitmap + p->row * glyph->bpr;
1745
David Turnerb698eed2006-02-23 14:50:13 +00001746 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001747 {
1748 c = line[i];
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001749 if ( !isdigok( hdigits, c ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001750 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001751 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001752 if ( i + 1 < nibbles && ( i & 1 ) )
1753 *++bp = 0;
1754 }
1755
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001756 /* If any line has not enough columns, */
1757 /* indicate they have been padded with zero bits. */
1758 if ( i < nibbles &&
1759 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1760 {
1761 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
1762 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1763 font->modified = 1;
1764 }
1765
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001766 /* Remove possible garbage at the right. */
1767 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001768 if ( glyph->bbx.width )
1769 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001770
1771 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001772 if ( i == nibbles &&
1773 isdigok( hdigits, line[nibbles] ) &&
1774 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001775 {
1776 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1777 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1778 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001779 }
1780
1781 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001782 goto Exit;
1783 }
David Turner993a8d02002-05-18 12:03:43 +00001784
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001785 /* Expect the SWIDTH (scalable width) field next. */
1786 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1787 {
1788 if ( !( p->flags & _BDF_ENCODING ) )
Werner Lemberg4086fb72012-03-01 08:55:40 +01001789 goto Missing_Encoding;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001790
David Turner68df4f72005-03-15 18:18:57 +00001791 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001792 if ( error )
1793 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001794
David Turnerb1b47622002-05-21 21:17:43 +00001795 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001796 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001797
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001798 goto Exit;
1799 }
David Turner993a8d02002-05-18 12:03:43 +00001800
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001801 /* Expect the DWIDTH (scalable width) field next. */
1802 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1803 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001804 if ( !( p->flags & _BDF_ENCODING ) )
1805 goto Missing_Encoding;
1806
David Turner68df4f72005-03-15 18:18:57 +00001807 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001808 if ( error )
1809 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001810
David Turnerb1b47622002-05-21 21:17:43 +00001811 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001812
1813 if ( !( p->flags & _BDF_SWIDTH ) )
1814 {
1815 /* Missing SWIDTH field. Emit an auto correction message and set */
1816 /* the scalable width from the device width. */
1817 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1818
Werner Lemberg02d4d592002-05-28 22:38:05 +00001819 glyph->swidth = (unsigned short)FT_MulDiv(
1820 glyph->dwidth, 72000L,
1821 (FT_Long)( font->point_size *
1822 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001823 }
1824
1825 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001826 goto Exit;
1827 }
David Turner993a8d02002-05-18 12:03:43 +00001828
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001829 /* Expect the BBX field next. */
1830 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1831 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001832 if ( !( p->flags & _BDF_ENCODING ) )
1833 goto Missing_Encoding;
1834
David Turner68df4f72005-03-15 18:18:57 +00001835 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001836 if ( error )
1837 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001838
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001839 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1840 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1841 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1842 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1843
1844 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001845 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1846 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001847
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001848 /* Determine the overall font bounding box as the characters are */
1849 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001850 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1851 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001852
David Turnerb1b47622002-05-21 21:17:43 +00001853 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001854
Werner Lembergdfa46192004-03-05 09:26:24 +00001855 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1856 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1857 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001858
1859 if ( !( p->flags & _BDF_DWIDTH ) )
1860 {
1861 /* Missing DWIDTH field. Emit an auto correction message and set */
1862 /* the device width to the glyph width. */
1863 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1864 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001865 }
1866
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001867 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1868 /* value if necessary. */
1869 if ( p->opts->correct_metrics != 0 )
1870 {
1871 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001872 unsigned short sw = (unsigned short)FT_MulDiv(
1873 glyph->dwidth, 72000L,
1874 (FT_Long)( font->point_size *
1875 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001876
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001877
1878 if ( sw != glyph->swidth )
1879 {
1880 glyph->swidth = sw;
1881
1882 if ( p->glyph_enc == -1 )
1883 _bdf_set_glyph_modified( font->umod,
1884 font->unencoded_used - 1 );
1885 else
1886 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1887
1888 p->flags |= _BDF_SWIDTH_ADJ;
1889 font->modified = 1;
1890 }
David Turner993a8d02002-05-18 12:03:43 +00001891 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001892
David Turner993a8d02002-05-18 12:03:43 +00001893 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001894 goto Exit;
1895 }
David Turner993a8d02002-05-18 12:03:43 +00001896
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001897 /* And finally, gather up the bitmap. */
1898 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1899 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001900 unsigned long bitmap_size;
1901
1902
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001903 if ( !( p->flags & _BDF_BBX ) )
1904 {
1905 /* Missing BBX field. */
1906 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1907 error = BDF_Err_Missing_Bbx_Field;
1908 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001909 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001910
1911 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001912 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001913
1914 bitmap_size = glyph->bpr * glyph->bbx.height;
1915 if ( bitmap_size > 0xFFFFU )
1916 {
1917 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1918 error = BDF_Err_Bbx_Too_Big;
1919 goto Exit;
1920 }
1921 else
1922 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001923
1924 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1925 goto Exit;
1926
1927 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001928 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001929
1930 goto Exit;
1931 }
1932
Werner Lemberge01406b2011-11-25 09:44:28 +01001933 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001934 error = BDF_Err_Invalid_File_Format;
Werner Lemberg4086fb72012-03-01 08:55:40 +01001935 goto Exit;
1936
1937 Missing_Encoding:
1938 /* Missing ENCODING field. */
1939 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1940 error = BDF_Err_Missing_Encoding_Field;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001941
1942 Exit:
Werner Lembergf4c94d42010-06-19 16:08:31 +02001943 if ( error && ( p->flags & _BDF_GLYPH ) )
1944 FT_FREE( p->glyph_name );
1945
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001946 return error;
David Turner993a8d02002-05-18 12:03:43 +00001947 }
1948
David Turner993a8d02002-05-18 12:03:43 +00001949
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001950 /* Load the font properties. */
1951 static FT_Error
1952 _bdf_parse_properties( char* line,
1953 unsigned long linelen,
1954 unsigned long lineno,
1955 void* call_data,
1956 void* client_data )
1957 {
1958 unsigned long vlen;
1959 _bdf_line_func_t* next;
1960 _bdf_parse_t* p;
1961 char* name;
1962 char* value;
1963 char nbuf[128];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001964 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001965
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001966 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001967
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001968
1969 next = (_bdf_line_func_t *)call_data;
1970 p = (_bdf_parse_t *) client_data;
1971
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001972 /* Check for the end of the properties. */
1973 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1974 {
1975 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1976 /* encountered yet, then make sure they are added as properties and */
1977 /* make sure they are set from the font bounding box info. */
1978 /* */
1979 /* This is *always* done regardless of the options, because X11 */
1980 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001981 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001982 {
1983 p->font->font_ascent = p->font->bbx.ascent;
1984 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001985 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
1986 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001987 if ( error )
1988 goto Exit;
1989
1990 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1991 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001992 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001993
Werner Lemberg428c2e42003-04-25 05:35:04 +00001994 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001995 {
1996 p->font->font_descent = p->font->bbx.descent;
1997 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001998 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
1999 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002000 if ( error )
2001 goto Exit;
2002
2003 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2004 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002005 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002006
David Turner993a8d02002-05-18 12:03:43 +00002007 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002008 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00002009
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002010 goto Exit;
2011 }
David Turner993a8d02002-05-18 12:03:43 +00002012
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002013 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
2014 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
2015 goto Exit;
2016
2017 /* Handle COMMENT fields and properties in a special way to preserve */
2018 /* the spacing. */
2019 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2020 {
David Turner993a8d02002-05-18 12:03:43 +00002021 name = value = line;
2022 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002023 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00002024 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01002025 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002026 if ( error )
2027 goto Exit;
2028 }
2029 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
2030 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002031 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002032 if ( error )
2033 goto Exit;
2034 }
2035 else
2036 {
David Turner68df4f72005-03-15 18:18:57 +00002037 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002038 if ( error )
2039 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002040 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002041
David Turner68df4f72005-03-15 18:18:57 +00002042 _bdf_list_shift( &p->list, 1 );
2043 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002044
Werner Lemberge01406b2011-11-25 09:44:28 +01002045 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002046 if ( error )
2047 goto Exit;
2048 }
2049
2050 Exit:
2051 return error;
David Turner993a8d02002-05-18 12:03:43 +00002052 }
2053
David Turner993a8d02002-05-18 12:03:43 +00002054
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002055 /* Load the font header. */
2056 static FT_Error
2057 _bdf_parse_start( char* line,
2058 unsigned long linelen,
2059 unsigned long lineno,
2060 void* call_data,
2061 void* client_data )
2062 {
2063 unsigned long slen;
2064 _bdf_line_func_t* next;
2065 _bdf_parse_t* p;
2066 bdf_font_t* font;
2067 char *s;
David Turner993a8d02002-05-18 12:03:43 +00002068
David Turnerd490e372002-05-28 23:40:37 +00002069 FT_Memory memory = NULL;
2070 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002071
2072 FT_UNUSED( lineno ); /* only used in debug mode */
2073
2074
2075 next = (_bdf_line_func_t *)call_data;
2076 p = (_bdf_parse_t *) client_data;
2077
2078 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00002079 memory = p->font->memory;
2080
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002081 /* Check for a comment. This is done to handle those fonts that have */
2082 /* comments before the STARTFONT line for some reason. */
2083 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2084 {
2085 if ( p->opts->keep_comments != 0 && p->font != 0 )
2086 {
2087 linelen -= 7;
2088
2089 s = line + 7;
2090 if ( *s != 0 )
2091 {
2092 s++;
2093 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002094 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002095
2096 error = _bdf_add_comment( p->font, s, linelen );
2097 if ( error )
2098 goto Exit;
2099 /* here font is not defined! */
2100 }
2101
2102 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002103 }
2104
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002105 if ( !( p->flags & _BDF_START ) )
2106 {
2107 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002108
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002109 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2110 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01002111 /* we don't emit an error message since this code gets */
2112 /* explicitly caught one level higher */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002113 error = BDF_Err_Missing_Startfont_Field;
2114 goto Exit;
2115 }
David Turner993a8d02002-05-18 12:03:43 +00002116
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002117 p->flags = _BDF_START;
2118 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002119
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002120 if ( FT_NEW( font ) )
2121 goto Exit;
2122 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002123
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002124 font->memory = p->memory;
2125 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002126
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002127 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09002128 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002129 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002130
David Turner993a8d02002-05-18 12:03:43 +00002131
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002132 error = hash_init( &(font->proptbl), memory );
2133 if ( error )
2134 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002135 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002136 i < _num_bdf_properties; i++, prop++ )
2137 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09002138 error = hash_insert( prop->name, i,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002139 &(font->proptbl), memory );
2140 if ( error )
2141 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002142 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002143 }
2144
2145 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2146 goto Exit;
2147 error = hash_init( (hashtable *)p->font->internal,memory );
2148 if ( error )
2149 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002150 p->font->spacing = p->opts->font_spacing;
2151 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002152
2153 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002154 }
2155
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002156 /* Check for the start of the properties. */
2157 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2158 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002159 if ( !( p->flags & _BDF_FONT_BBX ) )
Werner Lembergfb690292010-06-23 10:00:52 +02002160 {
2161 /* Missing the FONTBOUNDINGBOX field. */
2162 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2163 error = BDF_Err_Missing_Fontboundingbox_Field;
2164 goto Exit;
2165 }
2166
David Turner68df4f72005-03-15 18:18:57 +00002167 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002168 if ( error )
2169 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00002170 /* at this point, `p->font' can't be NULL */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002171 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2172
2173 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2174 goto Exit;
2175
2176 p->flags |= _BDF_PROPS;
2177 *next = _bdf_parse_properties;
2178
2179 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002180 }
2181
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002182 /* Check for the FONTBOUNDINGBOX field. */
2183 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2184 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002185 if ( !( p->flags & _BDF_SIZE ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002186 {
2187 /* Missing the SIZE field. */
2188 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2189 error = BDF_Err_Missing_Size_Field;
2190 goto Exit;
2191 }
2192
David Turner68df4f72005-03-15 18:18:57 +00002193 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002194 if ( error )
2195 goto Exit;
2196
2197 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2198 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2199
2200 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2201 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2202
David Turnerd490e372002-05-28 23:40:37 +00002203 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002204 p->font->bbx.y_offset );
2205
2206 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002207
2208 p->flags |= _BDF_FONT_BBX;
2209
2210 goto Exit;
2211 }
2212
2213 /* The next thing to check for is the FONT field. */
2214 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2215 {
David Turner68df4f72005-03-15 18:18:57 +00002216 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002217 if ( error )
2218 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002219 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002220
David Turner68df4f72005-03-15 18:18:57 +00002221 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002222
2223 if ( !s )
2224 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002225 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg5b591e42007-06-01 22:16:43 +00002226 error = BDF_Err_Invalid_File_Format;
2227 goto Exit;
2228 }
2229
Werner Lembergfb690292010-06-23 10:00:52 +02002230 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2231 FT_FREE( p->font->name );
2232
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002233 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2234 goto Exit;
2235 FT_MEM_COPY( p->font->name, s, slen + 1 );
2236
2237 /* If the font name is an XLFD name, set the spacing to the one in */
2238 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002239 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002240 if ( error )
2241 goto Exit;
2242
2243 p->flags |= _BDF_FONT_NAME;
2244
2245 goto Exit;
2246 }
2247
2248 /* Check for the SIZE field. */
2249 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2250 {
2251 if ( !( p->flags & _BDF_FONT_NAME ) )
2252 {
2253 /* Missing the FONT field. */
2254 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2255 error = BDF_Err_Missing_Font_Field;
2256 goto Exit;
2257 }
2258
David Turner68df4f72005-03-15 18:18:57 +00002259 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002260 if ( error )
2261 goto Exit;
2262
2263 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2264 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2265 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2266
2267 /* Check for the bits per pixel field. */
2268 if ( p->list.used == 5 )
2269 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002270 unsigned short bitcount, i, shift;
2271
2272
2273 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2274
2275 /* Only values 1, 2, 4, 8 are allowed. */
2276 shift = p->font->bpp;
2277 bitcount = 0;
2278 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002279 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002280 if ( shift & 1 )
2281 bitcount = i;
2282 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002283 }
David Turner993a8d02002-05-18 12:03:43 +00002284
Werner Lembergbd8e3242002-06-12 08:43:58 +00002285 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002286
2287 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002288 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002289 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002290 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002291 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002292 }
2293 }
2294 else
2295 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002296
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002297 p->flags |= _BDF_SIZE;
2298
2299 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002300 }
2301
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002302 /* Check for the CHARS field -- font properties are optional */
2303 if ( ft_memcmp( line, "CHARS", 5 ) == 0 )
2304 {
2305 char nbuf[128];
2306
2307
2308 if ( !( p->flags & _BDF_FONT_BBX ) )
2309 {
2310 /* Missing the FONTBOUNDINGBOX field. */
2311 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2312 error = BDF_Err_Missing_Fontboundingbox_Field;
2313 goto Exit;
2314 }
2315
2316 /* Add the two standard X11 properties which are required */
2317 /* for compiling fonts. */
2318 p->font->font_ascent = p->font->bbx.ascent;
2319 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002320 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2321 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002322 if ( error )
2323 goto Exit;
2324 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2325
2326 p->font->font_descent = p->font->bbx.descent;
2327 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002328 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2329 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002330 if ( error )
2331 goto Exit;
2332 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2333
2334 p->font->modified = 1;
2335
2336 *next = _bdf_parse_glyphs;
2337
2338 /* A special return value. */
2339 error = -1;
2340 goto Exit;
2341 }
2342
Werner Lemberge01406b2011-11-25 09:44:28 +01002343 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002344 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002345
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002346 Exit:
2347 return error;
2348 }
David Turner993a8d02002-05-18 12:03:43 +00002349
2350
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002351 /*************************************************************************/
2352 /* */
2353 /* API. */
2354 /* */
2355 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002356
David Turner993a8d02002-05-18 12:03:43 +00002357
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002358 FT_LOCAL_DEF( FT_Error )
2359 bdf_load_font( FT_Stream stream,
2360 FT_Memory extmemory,
2361 bdf_options_t* opts,
2362 bdf_font_t* *font )
2363 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002364 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002365 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002366
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002367 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002368 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002369
2370
David Turner68df4f72005-03-15 18:18:57 +00002371 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002372 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002373
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002374 memory = NULL;
2375 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2376 p->minlb = 32767;
2377 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002378
David Turner68df4f72005-03-15 18:18:57 +00002379 _bdf_list_init( &p->list, extmemory );
2380
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002381 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002382 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002383 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002384 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002385
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002386 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002387 {
2388 /* If the font is not proportional, set the font's monowidth */
2389 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002390 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002391
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002392 if ( p->font->spacing != BDF_PROPORTIONAL )
2393 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002394
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002395 /* If the number of glyphs loaded is not that of the original count, */
2396 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002397 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002398 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002399 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2400 p->font->glyphs_used + p->font->unencoded_used ));
2401 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002402 }
2403
2404 /* Once the font has been loaded, adjust the overall font metrics if */
2405 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002406 if ( p->opts->correct_metrics != 0 &&
2407 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002408 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002409 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002410 {
2411 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002412 p->font->bbx.width, p->maxrb - p->minlb ));
2413 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2414 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002415 }
2416
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002417 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002418 {
2419 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002420 p->font->bbx.x_offset, p->minlb ));
2421 p->font->bbx.x_offset = p->minlb;
2422 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002423 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002424
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002425 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002426 {
2427 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002428 p->font->bbx.ascent, p->maxas ));
2429 p->font->bbx.ascent = p->maxas;
2430 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002431 }
2432
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002433 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002434 {
2435 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002436 p->font->bbx.descent, p->maxds ));
2437 p->font->bbx.descent = p->maxds;
2438 p->font->bbx.y_offset = (short)( -p->maxds );
2439 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002440 }
2441
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002442 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002443 {
2444 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002445 p->font->bbx.height, p->maxas + p->maxds ));
2446 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002447 }
2448
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002449 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002450 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2451 }
David Turner993a8d02002-05-18 12:03:43 +00002452 }
2453
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002454 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002455 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002456 /* The ENDFONT field was never reached or did not exist. */
2457 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002458 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002459 /* Error happened while parsing header. */
2460 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2461 error = BDF_Err_Corrupted_Font_Header;
2462 goto Exit;
2463 }
2464 else
2465 {
2466 /* Error happened when parsing glyphs. */
2467 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2468 error = BDF_Err_Corrupted_Font_Glyphs;
2469 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002470 }
David Turner993a8d02002-05-18 12:03:43 +00002471 }
2472
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002473 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002474 {
2475 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002476 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002477
Werner Lemberg370aea82010-06-08 08:37:11 +02002478 if ( p->font->comments_len > 0 )
2479 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002480 if ( FT_RENEW_ARRAY( p->font->comments,
2481 p->font->comments_len,
2482 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002483 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002484
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002485 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002486 }
David Turner993a8d02002-05-18 12:03:43 +00002487 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002488 else if ( error == BDF_Err_Ok )
2489 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002490
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002491 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002492
2493 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002494 if ( p )
2495 {
David Turner68df4f72005-03-15 18:18:57 +00002496 _bdf_list_done( &p->list );
2497
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002498 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002499
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002500 FT_FREE( p );
2501 }
2502
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002503 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002504
2505 Fail:
2506 bdf_free_font( p->font );
2507
2508 memory = extmemory;
2509
2510 FT_FREE( p->font );
2511
2512 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002513 }
David Turner993a8d02002-05-18 12:03:43 +00002514
2515
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002516 FT_LOCAL_DEF( void )
2517 bdf_free_font( bdf_font_t* font )
2518 {
2519 bdf_property_t* prop;
2520 unsigned long i;
2521 bdf_glyph_t* glyphs;
2522 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002523
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002524
2525 if ( font == 0 )
2526 return;
David Turner993a8d02002-05-18 12:03:43 +00002527
2528 memory = font->memory;
2529
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002530 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002531
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002532 /* Free up the internal hash table of property names. */
2533 if ( font->internal )
2534 {
2535 hash_free( (hashtable *)font->internal, memory );
2536 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002537 }
2538
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002539 /* Free up the comment info. */
2540 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002541
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002542 /* Free up the properties. */
2543 for ( i = 0; i < font->props_size; i++ )
2544 {
2545 if ( font->props[i].format == BDF_ATOM )
2546 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002547 }
2548
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002549 FT_FREE( font->props );
2550
2551 /* Free up the character info. */
2552 for ( i = 0, glyphs = font->glyphs;
2553 i < font->glyphs_used; i++, glyphs++ )
2554 {
2555 FT_FREE( glyphs->name );
2556 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002557 }
2558
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002559 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2560 i++, glyphs++ )
2561 {
2562 FT_FREE( glyphs->name );
2563 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002564 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002565
2566 FT_FREE( font->glyphs );
2567 FT_FREE( font->unencoded );
2568
2569 /* Free up the overflow storage if it was used. */
2570 for ( i = 0, glyphs = font->overflow.glyphs;
2571 i < font->overflow.glyphs_used; i++, glyphs++ )
2572 {
2573 FT_FREE( glyphs->name );
2574 FT_FREE( glyphs->bitmap );
2575 }
2576
2577 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002578
2579 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002580 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002581
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002582 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002583 for ( prop = font->user_props, i = 0;
2584 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002585 {
2586 FT_FREE( prop->name );
2587 if ( prop->format == BDF_ATOM )
2588 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002589 }
David Turner993a8d02002-05-18 12:03:43 +00002590
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002591 FT_FREE( font->user_props );
2592
2593 /* FREE( font ); */ /* XXX Fixme */
2594 }
David Turner993a8d02002-05-18 12:03:43 +00002595
2596
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002597 FT_LOCAL_DEF( bdf_property_t * )
2598 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002599 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002600 {
2601 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002602
David Turner993a8d02002-05-18 12:03:43 +00002603
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002604 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002605 return 0;
2606
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002607 hn = hash_lookup( name, (hashtable *)font->internal );
2608
suzuki toshiya704f4d72009-09-13 00:50:14 +09002609 return hn ? ( font->props + hn->data ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002610 }
2611
2612
2613/* END */