blob: 4242cab6bd0132e07d627f13bddc5123dd919493 [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 */
465 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 4;
466 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 Lemberg7cf4d372002-05-21 14:13:01 +0000548 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000549 _bdf_list_split( _bdf_list_t* list,
550 char* separators,
551 char* line,
552 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000553 {
554 int mult, final_empty;
555 char *sp, *ep, *end;
556 char seps[32];
557 FT_Error error = BDF_Err_Ok;
558
559
560 /* Initialize the list. */
561 list->used = 0;
562
563 /* If the line is empty, then simply return. */
564 if ( linelen == 0 || line[0] == 0 )
565 goto Exit;
566
567 /* In the original code, if the `separators' parameter is NULL or */
568 /* empty, the list is split into individual bytes. We don't need */
569 /* this, so an error is signaled. */
570 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000571 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000572 error = BDF_Err_Invalid_Argument;
573 goto Exit;
574 }
575
576 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000577 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000578
579 /* If the very last character of the separator string is a plus, then */
580 /* set the `mult' flag to indicate that multiple separators should be */
581 /* collapsed into one. */
582 for ( mult = 0, sp = separators; sp && *sp; sp++ )
583 {
584 if ( *sp == '+' && *( sp + 1 ) == 0 )
585 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000586 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000587 setsbit( seps, *sp );
588 }
589
590 /* Break the line up into fields. */
591 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
592 sp < end && *sp; )
593 {
594 /* Collect everything that is not a separator. */
595 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
596 ;
597
598 /* Resize the list if necessary. */
599 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000600 {
Werner Lembergebf55852005-03-16 01:49:54 +0000601 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000602 if ( error )
603 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000604 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000605
606 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000607 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000608
609 sp = ep;
610
611 if ( mult )
612 {
613 /* If multiple separators should be collapsed, do it now by */
614 /* setting all the separator characters to 0. */
615 for ( ; *ep && sbitset( seps, *ep ); ep++ )
616 *ep = 0;
617 }
618 else if ( *ep != 0 )
619 /* Don't collapse multiple separators by making them 0, so just */
620 /* make the one encountered 0. */
621 *ep++ = 0;
622
623 final_empty = ( ep > sp && *ep == 0 );
624 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000625 }
626
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000627 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000628 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000629 {
Werner Lembergebf55852005-03-16 01:49:54 +0000630 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000631 if ( error )
632 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000633 }
634
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000635 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000636 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000637
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000638 list->field[list->used] = 0;
639
640 Exit:
641 return error;
David Turner993a8d02002-05-18 12:03:43 +0000642 }
643
David Turner993a8d02002-05-18 12:03:43 +0000644
David Turner68df4f72005-03-15 18:18:57 +0000645#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000646
Werner Lembergebf55852005-03-16 01:49:54 +0000647
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000648 static FT_Error
649 _bdf_readstream( FT_Stream stream,
650 _bdf_line_func_t callback,
651 void* client_data,
652 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000653 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000654 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000655 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900656 int refill, hold, to_skip;
657 ptrdiff_t bytes, start, end, cursor, avail;
David Turner68df4f72005-03-15 18:18:57 +0000658 char* buf = 0;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000659 FT_Memory memory = stream->memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000660 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000661
David Turner993a8d02002-05-18 12:03:43 +0000662
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000663 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000664 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000665 error = BDF_Err_Invalid_Argument;
666 goto Exit;
667 }
David Turner993a8d02002-05-18 12:03:43 +0000668
Werner Lembergebf55852005-03-16 01:49:54 +0000669 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000670 buf_size = 1024;
671
672 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000673 goto Exit;
674
Werner Lembergebf55852005-03-16 01:49:54 +0000675 cb = callback;
676 lineno = 1;
677 buf[0] = 0;
678 start = 0;
679 end = 0;
680 avail = 0;
681 cursor = 0;
682 refill = 1;
683 to_skip = NO_SKIP;
684 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000685
David Turner68df4f72005-03-15 18:18:57 +0000686 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000687 {
David Turner68df4f72005-03-15 18:18:57 +0000688 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000689 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +0200690 bytes = (ptrdiff_t)FT_Stream_TryRead(
691 stream, (FT_Byte*)buf + cursor,
692 (FT_ULong)( buf_size - cursor ) );
David Turner68df4f72005-03-15 18:18:57 +0000693 avail = cursor + bytes;
694 cursor = 0;
695 refill = 0;
696 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000697
David Turner68df4f72005-03-15 18:18:57 +0000698 end = start;
699
Werner Lembergebf55852005-03-16 01:49:54 +0000700 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000701 if ( start < avail && buf[start] == to_skip )
702 {
703 start += 1;
704 to_skip = NO_SKIP;
705 continue;
706 }
707
708 /* try to find the end of the line */
709 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
710 end++;
711
Werner Lembergebf55852005-03-16 01:49:54 +0000712 /* if we hit the end of the buffer, try shifting its content */
713 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000714 if ( end >= avail )
715 {
716 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
717 break; /* ignore it then exit */
718
719 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000720 {
Werner Lembergebf55852005-03-16 01:49:54 +0000721 /* this line is definitely too long; try resizing the input */
722 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000723 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000724
Werner Lembergebf55852005-03-16 01:49:54 +0000725
726 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000727 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100728 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
David Turner68df4f72005-03-15 18:18:57 +0000729 error = BDF_Err_Invalid_Argument;
730 goto Exit;
731 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000732
Werner Lembergebf55852005-03-16 01:49:54 +0000733 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000734 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
735 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000736
David Turner68df4f72005-03-15 18:18:57 +0000737 cursor = buf_size;
738 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000739 }
740 else
741 {
David Turner68df4f72005-03-15 18:18:57 +0000742 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000743
Werner Lembergebf55852005-03-16 01:49:54 +0000744 FT_MEM_COPY( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000745
David Turner68df4f72005-03-15 18:18:57 +0000746 cursor = bytes;
747 avail -= bytes;
748 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000749 }
David Turner68df4f72005-03-15 18:18:57 +0000750 refill = 1;
751 continue;
David Turner993a8d02002-05-18 12:03:43 +0000752 }
David Turner68df4f72005-03-15 18:18:57 +0000753
754 /* Temporarily NUL-terminate the line. */
755 hold = buf[end];
756 buf[end] = 0;
757
758 /* XXX: Use encoding independent value for 0x1a */
759 if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
760 {
Werner Lembergebf55852005-03-16 01:49:54 +0000761 error = (*cb)( buf + start, end - start, lineno,
762 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200763 /* Redo if we have encountered CHARS without properties. */
764 if ( error == -1 )
765 error = (*cb)( buf + start, end - start, lineno,
766 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000767 if ( error )
768 break;
769 }
770
771 lineno += 1;
772 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000773 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000774
775 if ( hold == '\n' )
776 to_skip = '\r';
777 else if ( hold == '\r' )
778 to_skip = '\n';
779 else
780 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000781 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000782
David Turner68df4f72005-03-15 18:18:57 +0000783 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000784
785 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000786 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000787 return error;
David Turner993a8d02002-05-18 12:03:43 +0000788 }
David Turner993a8d02002-05-18 12:03:43 +0000789
790
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000791 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000792
David Turnerb1b47622002-05-21 21:17:43 +0000793 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000794 {
David Turner993a8d02002-05-18 12:03:43 +0000795 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
796 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
797 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
798 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
799 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
800 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
801 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
802 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
803 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
804 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
805 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000806 };
David Turner993a8d02002-05-18 12:03:43 +0000807
David Turnerb1b47622002-05-21 21:17:43 +0000808 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000809 {
David Turner993a8d02002-05-18 12:03:43 +0000810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
811 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
812 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
813 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000814 };
David Turner993a8d02002-05-18 12:03:43 +0000815
David Turnerb1b47622002-05-21 21:17:43 +0000816 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000817 {
David Turner993a8d02002-05-18 12:03:43 +0000818 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
819 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
820 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
821 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000822 };
David Turner993a8d02002-05-18 12:03:43 +0000823
David Turnerb1b47622002-05-21 21:17:43 +0000824 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000825 {
David Turner993a8d02002-05-18 12:03:43 +0000826 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
827 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
828 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
829 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000830 };
David Turner993a8d02002-05-18 12:03:43 +0000831
David Turner993a8d02002-05-18 12:03:43 +0000832
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000833#define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
David Turner993a8d02002-05-18 12:03:43 +0000834
David Turner993a8d02002-05-18 12:03:43 +0000835
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000836 /* Routine to convert an ASCII string into an unsigned long integer. */
837 static unsigned long
838 _bdf_atoul( char* s,
839 char** end,
840 int base )
David Turner993a8d02002-05-18 12:03:43 +0000841 {
David Turnerb1b47622002-05-21 21:17:43 +0000842 unsigned long v;
843 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000844
845
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000846 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000847 return 0;
848
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000849 /* Make sure the radix is something recognizable. Default to 10. */
850 switch ( base )
851 {
852 case 8:
853 dmap = odigits;
854 break;
855 case 16:
856 dmap = hdigits;
857 break;
858 default:
859 base = 10;
860 dmap = ddigits;
861 break;
David Turner993a8d02002-05-18 12:03:43 +0000862 }
863
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000864 /* Check for the special hex prefix. */
865 if ( *s == '0' &&
866 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
867 {
868 base = 16;
869 dmap = hdigits;
870 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000871 }
872
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000873 for ( v = 0; isdigok( dmap, *s ); s++ )
874 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000875
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000876 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000877 *end = s;
878
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000879 return v;
880 }
David Turner993a8d02002-05-18 12:03:43 +0000881
David Turner993a8d02002-05-18 12:03:43 +0000882
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000883 /* Routine to convert an ASCII string into an signed long integer. */
884 static long
885 _bdf_atol( char* s,
886 char** end,
887 int base )
888 {
David Turnerb1b47622002-05-21 21:17:43 +0000889 long v, neg;
890 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000891
892
893 if ( s == 0 || *s == 0 )
894 return 0;
895
896 /* Make sure the radix is something recognizable. Default to 10. */
897 switch ( base )
898 {
899 case 8:
900 dmap = odigits;
901 break;
902 case 16:
903 dmap = hdigits;
904 break;
905 default:
906 base = 10;
907 dmap = ddigits;
908 break;
909 }
910
911 /* Check for a minus sign. */
912 neg = 0;
913 if ( *s == '-' )
914 {
915 s++;
916 neg = 1;
917 }
918
919 /* Check for the special hex prefix. */
920 if ( *s == '0' &&
921 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
922 {
923 base = 16;
924 dmap = hdigits;
925 s += 2;
926 }
927
928 for ( v = 0; isdigok( dmap, *s ); s++ )
929 v = v * base + a2i[(int)*s];
930
931 if ( end != 0 )
932 *end = s;
933
934 return ( !neg ) ? v : -v;
935 }
936
937
938 /* Routine to convert an ASCII string into an signed short integer. */
939 static short
940 _bdf_atos( char* s,
941 char** end,
942 int base )
943 {
David Turnerb1b47622002-05-21 21:17:43 +0000944 short v, neg;
945 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000946
947
948 if ( s == 0 || *s == 0 )
949 return 0;
950
951 /* Make sure the radix is something recognizable. Default to 10. */
952 switch ( base )
953 {
954 case 8:
955 dmap = odigits;
956 break;
957 case 16:
958 dmap = hdigits;
959 break;
960 default:
961 base = 10;
962 dmap = ddigits;
963 break;
964 }
965
966 /* Check for a minus. */
967 neg = 0;
968 if ( *s == '-' )
969 {
970 s++;
971 neg = 1;
972 }
973
974 /* Check for the special hex prefix. */
975 if ( *s == '0' &&
976 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
977 {
978 base = 16;
979 dmap = hdigits;
980 s += 2;
981 }
982
983 for ( v = 0; isdigok( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +0000984 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000985
986 if ( end != 0 )
987 *end = s;
988
Werner Lemberg233302a2002-05-22 05:41:06 +0000989 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000990 }
991
992
993 /* Routine to compare two glyphs by encoding so they can be sorted. */
994 static int
995 by_encoding( const void* a,
996 const void* b )
997 {
998 bdf_glyph_t *c1, *c2;
999
1000
1001 c1 = (bdf_glyph_t *)a;
1002 c2 = (bdf_glyph_t *)b;
1003
1004 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001005 return -1;
David Turner68df4f72005-03-15 18:18:57 +00001006
1007 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001008 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001009
David Turner993a8d02002-05-18 12:03:43 +00001010 return 0;
David Turner993a8d02002-05-18 12:03:43 +00001011 }
1012
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001013
1014 static FT_Error
1015 bdf_create_property( char* name,
1016 int format,
1017 bdf_font_t* font )
1018 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001019 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001020 bdf_property_t* p;
1021 FT_Memory memory = font->memory;
1022 FT_Error error = BDF_Err_Ok;
1023
1024
Werner Lemberg96ddc672011-06-29 09:15:54 +02001025 /* First check whether the property has */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001026 /* already been added or not. If it has, then */
1027 /* simply ignore it. */
1028 if ( hash_lookup( name, &(font->proptbl) ) )
1029 goto Exit;
1030
David Turner68df4f72005-03-15 18:18:57 +00001031 if ( FT_RENEW_ARRAY( font->user_props,
1032 font->nuser_props,
1033 font->nuser_props + 1 ) )
1034 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001035
1036 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +00001037 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001038
suzuki toshiya704f4d72009-09-13 00:50:14 +09001039 n = ft_strlen( name ) + 1;
1040 if ( n > FT_ULONG_MAX )
1041 return BDF_Err_Invalid_Argument;
David Turner68df4f72005-03-15 18:18:57 +00001042
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001043 if ( FT_NEW_ARRAY( p->name, n ) )
1044 goto Exit;
1045
1046 FT_MEM_COPY( (char *)p->name, name, n );
1047
1048 p->format = format;
1049 p->builtin = 0;
1050
1051 n = _num_bdf_properties + font->nuser_props;
1052
suzuki toshiya704f4d72009-09-13 00:50:14 +09001053 error = hash_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001054 if ( error )
1055 goto Exit;
1056
1057 font->nuser_props++;
1058
1059 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001060 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001061 }
David Turner993a8d02002-05-18 12:03:43 +00001062
1063
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001064 FT_LOCAL_DEF( bdf_property_t * )
1065 bdf_get_property( char* name,
1066 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001067 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001068 hashnode hn;
1069 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001070
1071
1072 if ( name == 0 || *name == 0 )
1073 return 0;
1074
1075 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1076 return 0;
1077
suzuki toshiya704f4d72009-09-13 00:50:14 +09001078 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001079 if ( propid >= _num_bdf_properties )
1080 return font->user_props + ( propid - _num_bdf_properties );
1081
Werner Lemberg233302a2002-05-22 05:41:06 +00001082 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001083 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001084
1085
1086 /*************************************************************************/
1087 /* */
1088 /* BDF font file parsing flags and functions. */
1089 /* */
1090 /*************************************************************************/
1091
1092
1093 /* Parse flags. */
1094
1095#define _BDF_START 0x0001
1096#define _BDF_FONT_NAME 0x0002
1097#define _BDF_SIZE 0x0004
1098#define _BDF_FONT_BBX 0x0008
1099#define _BDF_PROPS 0x0010
1100#define _BDF_GLYPHS 0x0020
1101#define _BDF_GLYPH 0x0040
1102#define _BDF_ENCODING 0x0080
1103#define _BDF_SWIDTH 0x0100
1104#define _BDF_DWIDTH 0x0200
1105#define _BDF_BBX 0x0400
1106#define _BDF_BITMAP 0x0800
1107
1108#define _BDF_SWIDTH_ADJ 0x1000
1109
1110#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1111 _BDF_ENCODING | \
1112 _BDF_SWIDTH | \
1113 _BDF_DWIDTH | \
1114 _BDF_BBX | \
1115 _BDF_BITMAP )
1116
Werner Lembergf1c2b912006-01-13 14:53:28 +00001117#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1118#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001119
1120
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001121 static FT_Error
1122 _bdf_add_comment( bdf_font_t* font,
1123 char* comment,
1124 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001125 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001126 char* cp;
1127 FT_Memory memory = font->memory;
1128 FT_Error error = BDF_Err_Ok;
1129
1130
David Turner68df4f72005-03-15 18:18:57 +00001131 if ( FT_RENEW_ARRAY( font->comments,
1132 font->comments_len,
1133 font->comments_len + len + 1 ) )
1134 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001135
1136 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001137
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001138 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001139 cp[len] = '\n';
1140
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001141 font->comments_len += len + 1;
1142
1143 Exit:
1144 return error;
David Turner993a8d02002-05-18 12:03:43 +00001145 }
1146
David Turner993a8d02002-05-18 12:03:43 +00001147
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001148 /* Set the spacing from the font name if it exists, or set it to the */
1149 /* default specified in the options. */
1150 static FT_Error
1151 _bdf_set_default_spacing( bdf_font_t* font,
Werner Lemberge01406b2011-11-25 09:44:28 +01001152 bdf_options_t* opts,
1153 unsigned long lineno )
David Turner993a8d02002-05-18 12:03:43 +00001154 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001155 size_t len;
1156 char name[256];
1157 _bdf_list_t list;
1158 FT_Memory memory;
1159 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001160
David Turner993a8d02002-05-18 12:03:43 +00001161
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001162 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1163 {
1164 error = BDF_Err_Invalid_Argument;
1165 goto Exit;
1166 }
David Turner993a8d02002-05-18 12:03:43 +00001167
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001168 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001169
David Turner68df4f72005-03-15 18:18:57 +00001170 _bdf_list_init( &list, memory );
1171
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001172 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001173
suzuki toshiya704f4d72009-09-13 00:50:14 +09001174 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +00001175 /* Limit ourselves to 256 characters in the font name. */
1176 if ( len >= 256 )
1177 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001178 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
Werner Lemberga08b2172007-03-28 07:17:17 +00001179 error = BDF_Err_Invalid_Argument;
1180 goto Exit;
1181 }
1182
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001183 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001184
David Turner68df4f72005-03-15 18:18:57 +00001185 error = _bdf_list_split( &list, (char *)"-", name, len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001186 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001187 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001188
1189 if ( list.used == 15 )
1190 {
1191 switch ( list.field[11][0] )
1192 {
1193 case 'C':
1194 case 'c':
1195 font->spacing = BDF_CHARCELL;
1196 break;
1197 case 'M':
1198 case 'm':
1199 font->spacing = BDF_MONOWIDTH;
1200 break;
1201 case 'P':
1202 case 'p':
1203 font->spacing = BDF_PROPORTIONAL;
1204 break;
David Turner993a8d02002-05-18 12:03:43 +00001205 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001206 }
1207
David Turner68df4f72005-03-15 18:18:57 +00001208 Fail:
1209 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001210
1211 Exit:
1212 return error;
David Turner993a8d02002-05-18 12:03:43 +00001213 }
David Turner993a8d02002-05-18 12:03:43 +00001214
1215
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001216 /* Determine whether the property is an atom or not. If it is, then */
1217 /* clean it up so the double quotes are removed if they exist. */
1218 static int
1219 _bdf_is_atom( char* line,
1220 unsigned long linelen,
1221 char** name,
1222 char** value,
1223 bdf_font_t* font )
1224 {
1225 int hold;
1226 char *sp, *ep;
1227 bdf_property_t* p;
1228
David Turner993a8d02002-05-18 12:03:43 +00001229
1230 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001231
1232 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001233 ep++;
1234
1235 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001236 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001237 {
1238 hold = *ep;
1239 *ep = 0;
1240 }
1241
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001242 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001243
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001244 /* Restore the character that was saved before any return can happen. */
1245 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001246 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001247
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001248 /* If the property exists and is not an atom, just return here. */
1249 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001250 return 0;
1251
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001252 /* The property is an atom. Trim all leading and trailing whitespace */
1253 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001254 sp = ep;
1255 ep = line + linelen;
1256
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001257 /* Trim the leading whitespace if it exists. */
Werner Lemberg320d4972012-02-24 18:06:46 +01001258 if ( *sp )
1259 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001260 while ( *sp &&
1261 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001262 sp++;
1263
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001264 /* Trim the leading double quote if it exists. */
1265 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001266 sp++;
1267 *value = sp;
1268
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001269 /* Trim the trailing whitespace if it exists. */
1270 while ( ep > sp &&
1271 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001272 *--ep = 0;
1273
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001274 /* Trim the trailing double quote if it exists. */
1275 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001276 *--ep = 0;
1277
1278 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001279 }
David Turner993a8d02002-05-18 12:03:43 +00001280
1281
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001282 static FT_Error
Werner Lemberge01406b2011-11-25 09:44:28 +01001283 _bdf_add_property( bdf_font_t* font,
1284 char* name,
1285 char* value,
1286 unsigned long lineno )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001287 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001288 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001289 hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001290 bdf_property_t *prop, *fp;
1291 FT_Memory memory = font->memory;
1292 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001293
David Turner993a8d02002-05-18 12:03:43 +00001294
Werner Lemberg96ddc672011-06-29 09:15:54 +02001295 /* First, check whether the property already exists in the font. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001296 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001297 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001298 /* The property already exists in the font, so simply replace */
1299 /* the value of the property with the current value. */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001300 fp = font->props + hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001301
David Turnerb1b47622002-05-21 21:17:43 +00001302 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001303 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001304 case BDF_ATOM:
1305 /* Delete the current atom if it exists. */
1306 FT_FREE( fp->value.atom );
1307
David Turnerc0f9c4a2007-02-12 14:55:03 +00001308 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001309 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001310 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001311 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001312 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001313 break;
1314
1315 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001316 fp->value.l = _bdf_atol( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001317 break;
1318
1319 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001320 fp->value.ul = _bdf_atoul( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001321 break;
David Turnerd490e372002-05-28 23:40:37 +00001322
David Turnerb1b47622002-05-21 21:17:43 +00001323 default:
1324 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001325 }
David Turnerd490e372002-05-28 23:40:37 +00001326
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001327 goto Exit;
1328 }
1329
1330 /* See whether this property type exists yet or not. */
1331 /* If not, create it. */
1332 hn = hash_lookup( name, &(font->proptbl) );
1333 if ( hn == 0 )
1334 {
1335 error = bdf_create_property( name, BDF_ATOM, font );
1336 if ( error )
1337 goto Exit;
1338 hn = hash_lookup( name, &(font->proptbl) );
1339 }
1340
1341 /* Allocate another property if this is overflow. */
1342 if ( font->props_used == font->props_size )
1343 {
1344 if ( font->props_size == 0 )
1345 {
1346 if ( FT_NEW_ARRAY( font->props, 1 ) )
1347 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001348 }
1349 else
1350 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001351 if ( FT_RENEW_ARRAY( font->props,
1352 font->props_size,
1353 font->props_size + 1 ) )
1354 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001355 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001356
David Turner993a8d02002-05-18 12:03:43 +00001357 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001358 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001359 font->props_size++;
1360 }
1361
suzuki toshiya704f4d72009-09-13 00:50:14 +09001362 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001363 if ( propid >= _num_bdf_properties )
1364 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001365 else
David Turnerb1b47622002-05-21 21:17:43 +00001366 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001367
1368 fp = font->props + font->props_used;
1369
1370 fp->name = prop->name;
1371 fp->format = prop->format;
1372 fp->builtin = prop->builtin;
1373
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001374 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001375 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001376 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001377 fp->value.atom = 0;
1378 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001379 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001380 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001381 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001382 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001383 break;
David Turner993a8d02002-05-18 12:03:43 +00001384
1385 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001386 fp->value.l = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001387 break;
1388
1389 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001390 fp->value.ul = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001391 break;
David Turner993a8d02002-05-18 12:03:43 +00001392 }
1393
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001394 /* If the property happens to be a comment, then it doesn't need */
1395 /* to be added to the internal hash table. */
Werner Lemberg370aea82010-06-08 08:37:11 +02001396 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 )
1397 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001398 /* Add the property to the font property table. */
1399 error = hash_insert( fp->name,
suzuki toshiya704f4d72009-09-13 00:50:14 +09001400 font->props_used,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001401 (hashtable *)font->internal,
1402 memory );
1403 if ( error )
1404 goto Exit;
1405 }
David Turner993a8d02002-05-18 12:03:43 +00001406
1407 font->props_used++;
1408
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001409 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1410 /* property needs to be located if it exists in the property list, the */
1411 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1412 /* present, and the SPACING property should override the default */
1413 /* spacing. */
1414 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001415 font->default_char = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001416 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001417 font->font_ascent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001418 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001419 font->font_descent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001420 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001421 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001422 if ( !fp->value.atom )
1423 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001424 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lembergb66efef2009-03-12 08:07:49 +00001425 error = BDF_Err_Invalid_File_Format;
1426 goto Exit;
1427 }
1428
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001429 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001430 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001431 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001432 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001433 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001434 font->spacing = BDF_CHARCELL;
1435 }
1436
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001437 Exit:
1438 return error;
David Turner993a8d02002-05-18 12:03:43 +00001439 }
1440
David Turner993a8d02002-05-18 12:03:43 +00001441
David Turnerb1b47622002-05-21 21:17:43 +00001442 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001443 {
1444 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1445 };
1446
1447
1448 /* Actually parse the glyph info and bitmaps. */
1449 static FT_Error
1450 _bdf_parse_glyphs( char* line,
1451 unsigned long linelen,
1452 unsigned long lineno,
1453 void* call_data,
1454 void* client_data )
1455 {
1456 int c, mask_index;
1457 char* s;
1458 unsigned char* bp;
1459 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001460
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001461 _bdf_parse_t* p;
1462 bdf_glyph_t* glyph;
1463 bdf_font_t* font;
1464
1465 FT_Memory memory;
1466 FT_Error error = BDF_Err_Ok;
1467
Werner Lemberg319c00d2003-04-23 19:48:24 +00001468 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001469 FT_UNUSED( lineno ); /* only used in debug mode */
1470
1471
Werner Lemberg319c00d2003-04-23 19:48:24 +00001472 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001473
1474 font = p->font;
1475 memory = font->memory;
1476
1477 /* Check for a comment. */
1478 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1479 {
1480 linelen -= 7;
1481
1482 s = line + 7;
1483 if ( *s != 0 )
1484 {
1485 s++;
1486 linelen--;
1487 }
1488 error = _bdf_add_comment( p->font, s, linelen );
1489 goto Exit;
1490 }
1491
1492 /* The very first thing expected is the number of glyphs. */
1493 if ( !( p->flags & _BDF_GLYPHS ) )
1494 {
1495 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1496 {
1497 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1498 error = BDF_Err_Missing_Chars_Field;
1499 goto Exit;
1500 }
1501
David Turner68df4f72005-03-15 18:18:57 +00001502 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001503 if ( error )
1504 goto Exit;
1505 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1506
1507 /* Make sure the number of glyphs is non-zero. */
1508 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001509 font->glyphs_size = 64;
1510
Werner Lemberga08b2172007-03-28 07:17:17 +00001511 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1512 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001513 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001514 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001515 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberga08b2172007-03-28 07:17:17 +00001516 error = BDF_Err_Invalid_Argument;
1517 goto Exit;
1518 }
1519
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001520 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1521 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001522
David Turner993a8d02002-05-18 12:03:43 +00001523 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001524
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001525 goto Exit;
1526 }
1527
1528 /* Check for the ENDFONT field. */
1529 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1530 {
1531 /* Sort the glyphs by encoding. */
1532 ft_qsort( (char *)font->glyphs,
1533 font->glyphs_used,
1534 sizeof ( bdf_glyph_t ),
1535 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001536
1537 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001538
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001539 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001540 }
1541
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001542 /* Check for the ENDCHAR field. */
1543 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1544 {
1545 p->glyph_enc = 0;
1546 p->flags &= ~_BDF_GLYPH_BITS;
1547
1548 goto Exit;
1549 }
1550
Werner Lemberg96ddc672011-06-29 09:15:54 +02001551 /* Check whether a glyph is being scanned but should be */
1552 /* ignored because it is an unencoded glyph. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001553 if ( ( p->flags & _BDF_GLYPH ) &&
1554 p->glyph_enc == -1 &&
1555 p->opts->keep_unencoded == 0 )
1556 goto Exit;
1557
1558 /* Check for the STARTCHAR field. */
1559 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1560 {
1561 /* Set the character name in the parse info first until the */
1562 /* encoding can be checked for an unencoded character. */
1563 FT_FREE( p->glyph_name );
1564
David Turner68df4f72005-03-15 18:18:57 +00001565 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001566 if ( error )
1567 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001568
David Turner68df4f72005-03-15 18:18:57 +00001569 _bdf_list_shift( &p->list, 1 );
1570
1571 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001572
Werner Lembergba03af62007-05-30 13:57:02 +00001573 if ( !s )
1574 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001575 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lembergba03af62007-05-30 13:57:02 +00001576 error = BDF_Err_Invalid_File_Format;
1577 goto Exit;
1578 }
1579
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001580 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1581 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001582
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001583 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1584
1585 p->flags |= _BDF_GLYPH;
1586
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001587 FT_TRACE4(( DBGMSG1, lineno, s ));
1588
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001589 goto Exit;
1590 }
1591
1592 /* Check for the ENCODING field. */
1593 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1594 {
1595 if ( !( p->flags & _BDF_GLYPH ) )
1596 {
1597 /* Missing STARTCHAR field. */
1598 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1599 error = BDF_Err_Missing_Startchar_Field;
1600 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001601 }
1602
David Turner68df4f72005-03-15 18:18:57 +00001603 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001604 if ( error )
1605 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001606
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001607 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001608
Werner Lemberg28dd2c42012-02-26 06:18:58 +01001609 /* Normalize negative encoding values. The specification only */
1610 /* allows -1, but we can be more generous here. */
1611 if ( p->glyph_enc < -1 )
1612 p->glyph_enc = -1;
1613
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001614 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1615
Werner Lemberged54e432011-11-27 16:39:53 +01001616 /* Check that the encoding is in the Unicode range because */
1617 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lemberg96ddc672011-06-29 09:15:54 +02001618 if ( p->glyph_enc > 0 &&
1619 (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
David Turner481838e2006-02-23 12:40:14 +00001620 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001621 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
David Turner481838e2006-02-23 12:40:14 +00001622 error = BDF_Err_Invalid_File_Format;
1623 goto Exit;
1624 }
1625
Werner Lemberg96ddc672011-06-29 09:15:54 +02001626 /* Check whether this encoding has already been encountered. */
1627 /* If it has then change it to unencoded so it gets added if */
1628 /* indicated. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001629 if ( p->glyph_enc >= 0 )
1630 {
1631 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1632 {
1633 /* Emit a message saying a glyph has been moved to the */
1634 /* unencoded area. */
1635 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1636 p->glyph_enc, p->glyph_name ));
1637 p->glyph_enc = -1;
1638 font->modified = 1;
1639 }
1640 else
1641 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1642 }
1643
1644 if ( p->glyph_enc >= 0 )
1645 {
1646 /* Make sure there are enough glyphs allocated in case the */
1647 /* number of characters happen to be wrong. */
1648 if ( font->glyphs_used == font->glyphs_size )
1649 {
1650 if ( FT_RENEW_ARRAY( font->glyphs,
1651 font->glyphs_size,
1652 font->glyphs_size + 64 ) )
1653 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001654
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001655 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001656 }
1657
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001658 glyph = font->glyphs + font->glyphs_used++;
1659 glyph->name = p->glyph_name;
1660 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001661
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001662 /* Reset the initial glyph info. */
1663 p->glyph_name = 0;
1664 }
1665 else
1666 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001667 /* Unencoded glyph. Check whether it should */
1668 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001669 if ( p->opts->keep_unencoded != 0 )
1670 {
1671 /* Allocate the next unencoded glyph. */
1672 if ( font->unencoded_used == font->unencoded_size )
1673 {
David Turner68df4f72005-03-15 18:18:57 +00001674 if ( FT_RENEW_ARRAY( font->unencoded ,
1675 font->unencoded_size,
1676 font->unencoded_size + 4 ) )
1677 goto Exit;
1678
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001679 font->unencoded_size += 4;
1680 }
1681
1682 glyph = font->unencoded + font->unencoded_used;
1683 glyph->name = p->glyph_name;
1684 glyph->encoding = font->unencoded_used++;
1685 }
1686 else
1687 /* Free up the glyph name if the unencoded shouldn't be */
1688 /* kept. */
1689 FT_FREE( p->glyph_name );
1690
1691 p->glyph_name = 0;
1692 }
1693
1694 /* Clear the flags that might be added when width and height are */
1695 /* checked for consistency. */
1696 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1697
1698 p->flags |= _BDF_ENCODING;
1699
1700 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001701 }
1702
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001703 /* Point at the glyph being constructed. */
1704 if ( p->glyph_enc == -1 )
1705 glyph = font->unencoded + ( font->unencoded_used - 1 );
1706 else
1707 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001708
Werner Lemberg96ddc672011-06-29 09:15:54 +02001709 /* Check whether a bitmap is being constructed. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001710 if ( p->flags & _BDF_BITMAP )
1711 {
1712 /* If there are more rows than are specified in the glyph metrics, */
1713 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001714 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001715 {
1716 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1717 {
1718 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1719 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001720 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001721 }
1722
1723 goto Exit;
1724 }
1725
1726 /* Only collect the number of nibbles indicated by the glyph */
1727 /* metrics. If there are more columns, they are simply ignored. */
1728 nibbles = glyph->bpr << 1;
1729 bp = glyph->bitmap + p->row * glyph->bpr;
1730
David Turnerb698eed2006-02-23 14:50:13 +00001731 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001732 {
1733 c = line[i];
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001734 if ( !c )
1735 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001736 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001737 if ( i + 1 < nibbles && ( i & 1 ) )
1738 *++bp = 0;
1739 }
1740
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001741 /* If any line has not enough columns, */
1742 /* indicate they have been padded with zero bits. */
1743 if ( i < nibbles &&
1744 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1745 {
1746 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
1747 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1748 font->modified = 1;
1749 }
1750
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001751 /* Remove possible garbage at the right. */
1752 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001753 if ( glyph->bbx.width )
1754 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001755
1756 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001757 if ( i == nibbles &&
1758 ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001759 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1760 {
1761 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1762 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1763 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001764 }
1765
1766 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001767 goto Exit;
1768 }
David Turner993a8d02002-05-18 12:03:43 +00001769
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001770 /* Expect the SWIDTH (scalable width) field next. */
1771 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1772 {
1773 if ( !( p->flags & _BDF_ENCODING ) )
1774 {
1775 /* Missing ENCODING field. */
1776 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1777 error = BDF_Err_Missing_Encoding_Field;
1778 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001779 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001780
David Turner68df4f72005-03-15 18:18:57 +00001781 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001782 if ( error )
1783 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001784
David Turnerb1b47622002-05-21 21:17:43 +00001785 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001786 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001787
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001788 goto Exit;
1789 }
David Turner993a8d02002-05-18 12:03:43 +00001790
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001791 /* Expect the DWIDTH (scalable width) field next. */
1792 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1793 {
David Turner68df4f72005-03-15 18:18:57 +00001794 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001795 if ( error )
1796 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001797
David Turnerb1b47622002-05-21 21:17:43 +00001798 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001799
1800 if ( !( p->flags & _BDF_SWIDTH ) )
1801 {
1802 /* Missing SWIDTH field. Emit an auto correction message and set */
1803 /* the scalable width from the device width. */
1804 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1805
Werner Lemberg02d4d592002-05-28 22:38:05 +00001806 glyph->swidth = (unsigned short)FT_MulDiv(
1807 glyph->dwidth, 72000L,
1808 (FT_Long)( font->point_size *
1809 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001810 }
1811
1812 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001813 goto Exit;
1814 }
David Turner993a8d02002-05-18 12:03:43 +00001815
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001816 /* Expect the BBX field next. */
1817 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1818 {
David Turner68df4f72005-03-15 18:18:57 +00001819 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001820 if ( error )
1821 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001822
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001823 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1824 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1825 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1826 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1827
1828 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001829 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1830 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001831
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001832 /* Determine the overall font bounding box as the characters are */
1833 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001834 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1835 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001836
David Turnerb1b47622002-05-21 21:17:43 +00001837 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001838
Werner Lembergdfa46192004-03-05 09:26:24 +00001839 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1840 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1841 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001842
1843 if ( !( p->flags & _BDF_DWIDTH ) )
1844 {
1845 /* Missing DWIDTH field. Emit an auto correction message and set */
1846 /* the device width to the glyph width. */
1847 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1848 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001849 }
1850
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001851 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1852 /* value if necessary. */
1853 if ( p->opts->correct_metrics != 0 )
1854 {
1855 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001856 unsigned short sw = (unsigned short)FT_MulDiv(
1857 glyph->dwidth, 72000L,
1858 (FT_Long)( font->point_size *
1859 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001860
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001861
1862 if ( sw != glyph->swidth )
1863 {
1864 glyph->swidth = sw;
1865
1866 if ( p->glyph_enc == -1 )
1867 _bdf_set_glyph_modified( font->umod,
1868 font->unencoded_used - 1 );
1869 else
1870 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1871
1872 p->flags |= _BDF_SWIDTH_ADJ;
1873 font->modified = 1;
1874 }
David Turner993a8d02002-05-18 12:03:43 +00001875 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001876
David Turner993a8d02002-05-18 12:03:43 +00001877 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001878 goto Exit;
1879 }
David Turner993a8d02002-05-18 12:03:43 +00001880
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001881 /* And finally, gather up the bitmap. */
1882 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1883 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001884 unsigned long bitmap_size;
1885
1886
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001887 if ( !( p->flags & _BDF_BBX ) )
1888 {
1889 /* Missing BBX field. */
1890 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1891 error = BDF_Err_Missing_Bbx_Field;
1892 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001893 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001894
1895 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001896 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001897
1898 bitmap_size = glyph->bpr * glyph->bbx.height;
1899 if ( bitmap_size > 0xFFFFU )
1900 {
1901 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1902 error = BDF_Err_Bbx_Too_Big;
1903 goto Exit;
1904 }
1905 else
1906 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001907
1908 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1909 goto Exit;
1910
1911 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001912 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001913
1914 goto Exit;
1915 }
1916
Werner Lemberge01406b2011-11-25 09:44:28 +01001917 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001918 error = BDF_Err_Invalid_File_Format;
1919
1920 Exit:
Werner Lembergf4c94d42010-06-19 16:08:31 +02001921 if ( error && ( p->flags & _BDF_GLYPH ) )
1922 FT_FREE( p->glyph_name );
1923
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001924 return error;
David Turner993a8d02002-05-18 12:03:43 +00001925 }
1926
David Turner993a8d02002-05-18 12:03:43 +00001927
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001928 /* Load the font properties. */
1929 static FT_Error
1930 _bdf_parse_properties( char* line,
1931 unsigned long linelen,
1932 unsigned long lineno,
1933 void* call_data,
1934 void* client_data )
1935 {
1936 unsigned long vlen;
1937 _bdf_line_func_t* next;
1938 _bdf_parse_t* p;
1939 char* name;
1940 char* value;
1941 char nbuf[128];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001942 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001943
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001944 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001945
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001946
1947 next = (_bdf_line_func_t *)call_data;
1948 p = (_bdf_parse_t *) client_data;
1949
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001950 /* Check for the end of the properties. */
1951 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1952 {
1953 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1954 /* encountered yet, then make sure they are added as properties and */
1955 /* make sure they are set from the font bounding box info. */
1956 /* */
1957 /* This is *always* done regardless of the options, because X11 */
1958 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001959 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001960 {
1961 p->font->font_ascent = p->font->bbx.ascent;
1962 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001963 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
1964 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001965 if ( error )
1966 goto Exit;
1967
1968 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1969 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001970 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001971
Werner Lemberg428c2e42003-04-25 05:35:04 +00001972 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001973 {
1974 p->font->font_descent = p->font->bbx.descent;
1975 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001976 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
1977 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001978 if ( error )
1979 goto Exit;
1980
1981 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1982 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001983 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001984
David Turner993a8d02002-05-18 12:03:43 +00001985 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001986 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001987
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001988 goto Exit;
1989 }
David Turner993a8d02002-05-18 12:03:43 +00001990
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001991 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1992 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1993 goto Exit;
1994
1995 /* Handle COMMENT fields and properties in a special way to preserve */
1996 /* the spacing. */
1997 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1998 {
David Turner993a8d02002-05-18 12:03:43 +00001999 name = value = line;
2000 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002001 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00002002 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01002003 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002004 if ( error )
2005 goto Exit;
2006 }
2007 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
2008 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002009 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002010 if ( error )
2011 goto Exit;
2012 }
2013 else
2014 {
David Turner68df4f72005-03-15 18:18:57 +00002015 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002016 if ( error )
2017 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002018 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002019
David Turner68df4f72005-03-15 18:18:57 +00002020 _bdf_list_shift( &p->list, 1 );
2021 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002022
Werner Lemberge01406b2011-11-25 09:44:28 +01002023 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002024 if ( error )
2025 goto Exit;
2026 }
2027
2028 Exit:
2029 return error;
David Turner993a8d02002-05-18 12:03:43 +00002030 }
2031
David Turner993a8d02002-05-18 12:03:43 +00002032
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002033 /* Load the font header. */
2034 static FT_Error
2035 _bdf_parse_start( char* line,
2036 unsigned long linelen,
2037 unsigned long lineno,
2038 void* call_data,
2039 void* client_data )
2040 {
2041 unsigned long slen;
2042 _bdf_line_func_t* next;
2043 _bdf_parse_t* p;
2044 bdf_font_t* font;
2045 char *s;
David Turner993a8d02002-05-18 12:03:43 +00002046
David Turnerd490e372002-05-28 23:40:37 +00002047 FT_Memory memory = NULL;
2048 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002049
2050 FT_UNUSED( lineno ); /* only used in debug mode */
2051
2052
2053 next = (_bdf_line_func_t *)call_data;
2054 p = (_bdf_parse_t *) client_data;
2055
2056 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00002057 memory = p->font->memory;
2058
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002059 /* Check for a comment. This is done to handle those fonts that have */
2060 /* comments before the STARTFONT line for some reason. */
2061 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2062 {
2063 if ( p->opts->keep_comments != 0 && p->font != 0 )
2064 {
2065 linelen -= 7;
2066
2067 s = line + 7;
2068 if ( *s != 0 )
2069 {
2070 s++;
2071 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002072 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002073
2074 error = _bdf_add_comment( p->font, s, linelen );
2075 if ( error )
2076 goto Exit;
2077 /* here font is not defined! */
2078 }
2079
2080 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002081 }
2082
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002083 if ( !( p->flags & _BDF_START ) )
2084 {
2085 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002086
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002087 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2088 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01002089 /* we don't emit an error message since this code gets */
2090 /* explicitly caught one level higher */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002091 error = BDF_Err_Missing_Startfont_Field;
2092 goto Exit;
2093 }
David Turner993a8d02002-05-18 12:03:43 +00002094
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002095 p->flags = _BDF_START;
2096 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002097
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002098 if ( FT_NEW( font ) )
2099 goto Exit;
2100 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002101
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002102 font->memory = p->memory;
2103 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002104
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002105 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09002106 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002107 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002108
David Turner993a8d02002-05-18 12:03:43 +00002109
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002110 error = hash_init( &(font->proptbl), memory );
2111 if ( error )
2112 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002113 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002114 i < _num_bdf_properties; i++, prop++ )
2115 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09002116 error = hash_insert( prop->name, i,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002117 &(font->proptbl), memory );
2118 if ( error )
2119 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002120 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002121 }
2122
2123 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2124 goto Exit;
2125 error = hash_init( (hashtable *)p->font->internal,memory );
2126 if ( error )
2127 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002128 p->font->spacing = p->opts->font_spacing;
2129 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002130
2131 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002132 }
2133
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002134 /* Check for the start of the properties. */
2135 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2136 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002137 if ( !( p->flags & _BDF_FONT_BBX ) )
Werner Lembergfb690292010-06-23 10:00:52 +02002138 {
2139 /* Missing the FONTBOUNDINGBOX field. */
2140 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2141 error = BDF_Err_Missing_Fontboundingbox_Field;
2142 goto Exit;
2143 }
2144
David Turner68df4f72005-03-15 18:18:57 +00002145 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002146 if ( error )
2147 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00002148 /* at this point, `p->font' can't be NULL */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002149 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2150
2151 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2152 goto Exit;
2153
2154 p->flags |= _BDF_PROPS;
2155 *next = _bdf_parse_properties;
2156
2157 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002158 }
2159
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002160 /* Check for the FONTBOUNDINGBOX field. */
2161 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2162 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002163 if ( !( p->flags & _BDF_SIZE ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002164 {
2165 /* Missing the SIZE field. */
2166 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2167 error = BDF_Err_Missing_Size_Field;
2168 goto Exit;
2169 }
2170
David Turner68df4f72005-03-15 18:18:57 +00002171 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002172 if ( error )
2173 goto Exit;
2174
2175 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2176 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2177
2178 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2179 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2180
David Turnerd490e372002-05-28 23:40:37 +00002181 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002182 p->font->bbx.y_offset );
2183
2184 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002185
2186 p->flags |= _BDF_FONT_BBX;
2187
2188 goto Exit;
2189 }
2190
2191 /* The next thing to check for is the FONT field. */
2192 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2193 {
David Turner68df4f72005-03-15 18:18:57 +00002194 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002195 if ( error )
2196 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002197 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002198
David Turner68df4f72005-03-15 18:18:57 +00002199 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002200
2201 if ( !s )
2202 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002203 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg5b591e42007-06-01 22:16:43 +00002204 error = BDF_Err_Invalid_File_Format;
2205 goto Exit;
2206 }
2207
Werner Lembergfb690292010-06-23 10:00:52 +02002208 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2209 FT_FREE( p->font->name );
2210
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002211 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2212 goto Exit;
2213 FT_MEM_COPY( p->font->name, s, slen + 1 );
2214
2215 /* If the font name is an XLFD name, set the spacing to the one in */
2216 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002217 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002218 if ( error )
2219 goto Exit;
2220
2221 p->flags |= _BDF_FONT_NAME;
2222
2223 goto Exit;
2224 }
2225
2226 /* Check for the SIZE field. */
2227 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2228 {
2229 if ( !( p->flags & _BDF_FONT_NAME ) )
2230 {
2231 /* Missing the FONT field. */
2232 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2233 error = BDF_Err_Missing_Font_Field;
2234 goto Exit;
2235 }
2236
David Turner68df4f72005-03-15 18:18:57 +00002237 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002238 if ( error )
2239 goto Exit;
2240
2241 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2242 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2243 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2244
2245 /* Check for the bits per pixel field. */
2246 if ( p->list.used == 5 )
2247 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002248 unsigned short bitcount, i, shift;
2249
2250
2251 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2252
2253 /* Only values 1, 2, 4, 8 are allowed. */
2254 shift = p->font->bpp;
2255 bitcount = 0;
2256 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002257 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002258 if ( shift & 1 )
2259 bitcount = i;
2260 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002261 }
David Turner993a8d02002-05-18 12:03:43 +00002262
Werner Lembergbd8e3242002-06-12 08:43:58 +00002263 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002264
2265 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002266 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002267 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002268 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002269 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002270 }
2271 }
2272 else
2273 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002274
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002275 p->flags |= _BDF_SIZE;
2276
2277 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002278 }
2279
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002280 /* Check for the CHARS field -- font properties are optional */
2281 if ( ft_memcmp( line, "CHARS", 5 ) == 0 )
2282 {
2283 char nbuf[128];
2284
2285
2286 if ( !( p->flags & _BDF_FONT_BBX ) )
2287 {
2288 /* Missing the FONTBOUNDINGBOX field. */
2289 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2290 error = BDF_Err_Missing_Fontboundingbox_Field;
2291 goto Exit;
2292 }
2293
2294 /* Add the two standard X11 properties which are required */
2295 /* for compiling fonts. */
2296 p->font->font_ascent = p->font->bbx.ascent;
2297 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002298 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2299 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002300 if ( error )
2301 goto Exit;
2302 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2303
2304 p->font->font_descent = p->font->bbx.descent;
2305 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002306 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2307 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002308 if ( error )
2309 goto Exit;
2310 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2311
2312 p->font->modified = 1;
2313
2314 *next = _bdf_parse_glyphs;
2315
2316 /* A special return value. */
2317 error = -1;
2318 goto Exit;
2319 }
2320
Werner Lemberge01406b2011-11-25 09:44:28 +01002321 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002322 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002323
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002324 Exit:
2325 return error;
2326 }
David Turner993a8d02002-05-18 12:03:43 +00002327
2328
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002329 /*************************************************************************/
2330 /* */
2331 /* API. */
2332 /* */
2333 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002334
David Turner993a8d02002-05-18 12:03:43 +00002335
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002336 FT_LOCAL_DEF( FT_Error )
2337 bdf_load_font( FT_Stream stream,
2338 FT_Memory extmemory,
2339 bdf_options_t* opts,
2340 bdf_font_t* *font )
2341 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002342 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002343 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002344
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002345 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002346 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002347
2348
David Turner68df4f72005-03-15 18:18:57 +00002349 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002350 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002351
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002352 memory = NULL;
2353 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2354 p->minlb = 32767;
2355 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002356
David Turner68df4f72005-03-15 18:18:57 +00002357 _bdf_list_init( &p->list, extmemory );
2358
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002359 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002360 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002361 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002362 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002363
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002364 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002365 {
2366 /* If the font is not proportional, set the font's monowidth */
2367 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002368 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002369
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002370 if ( p->font->spacing != BDF_PROPORTIONAL )
2371 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002372
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002373 /* If the number of glyphs loaded is not that of the original count, */
2374 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002375 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002376 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002377 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2378 p->font->glyphs_used + p->font->unencoded_used ));
2379 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002380 }
2381
2382 /* Once the font has been loaded, adjust the overall font metrics if */
2383 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002384 if ( p->opts->correct_metrics != 0 &&
2385 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002386 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002387 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002388 {
2389 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002390 p->font->bbx.width, p->maxrb - p->minlb ));
2391 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2392 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002393 }
2394
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002395 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002396 {
2397 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002398 p->font->bbx.x_offset, p->minlb ));
2399 p->font->bbx.x_offset = p->minlb;
2400 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002401 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002402
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002403 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002404 {
2405 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002406 p->font->bbx.ascent, p->maxas ));
2407 p->font->bbx.ascent = p->maxas;
2408 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002409 }
2410
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002411 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002412 {
2413 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002414 p->font->bbx.descent, p->maxds ));
2415 p->font->bbx.descent = p->maxds;
2416 p->font->bbx.y_offset = (short)( -p->maxds );
2417 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002418 }
2419
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002420 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002421 {
2422 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002423 p->font->bbx.height, p->maxas + p->maxds ));
2424 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002425 }
2426
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002427 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002428 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2429 }
David Turner993a8d02002-05-18 12:03:43 +00002430 }
2431
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002432 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002433 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002434 /* The ENDFONT field was never reached or did not exist. */
2435 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002436 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002437 /* Error happened while parsing header. */
2438 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2439 error = BDF_Err_Corrupted_Font_Header;
2440 goto Exit;
2441 }
2442 else
2443 {
2444 /* Error happened when parsing glyphs. */
2445 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2446 error = BDF_Err_Corrupted_Font_Glyphs;
2447 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002448 }
David Turner993a8d02002-05-18 12:03:43 +00002449 }
2450
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002451 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002452 {
2453 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002454 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002455
Werner Lemberg370aea82010-06-08 08:37:11 +02002456 if ( p->font->comments_len > 0 )
2457 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002458 if ( FT_RENEW_ARRAY( p->font->comments,
2459 p->font->comments_len,
2460 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002461 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002462
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002463 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002464 }
David Turner993a8d02002-05-18 12:03:43 +00002465 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002466 else if ( error == BDF_Err_Ok )
2467 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002468
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002469 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002470
2471 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002472 if ( p )
2473 {
David Turner68df4f72005-03-15 18:18:57 +00002474 _bdf_list_done( &p->list );
2475
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002476 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002477
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002478 FT_FREE( p );
2479 }
2480
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002481 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002482
2483 Fail:
2484 bdf_free_font( p->font );
2485
2486 memory = extmemory;
2487
2488 FT_FREE( p->font );
2489
2490 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002491 }
David Turner993a8d02002-05-18 12:03:43 +00002492
2493
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002494 FT_LOCAL_DEF( void )
2495 bdf_free_font( bdf_font_t* font )
2496 {
2497 bdf_property_t* prop;
2498 unsigned long i;
2499 bdf_glyph_t* glyphs;
2500 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002501
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002502
2503 if ( font == 0 )
2504 return;
David Turner993a8d02002-05-18 12:03:43 +00002505
2506 memory = font->memory;
2507
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002508 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002509
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002510 /* Free up the internal hash table of property names. */
2511 if ( font->internal )
2512 {
2513 hash_free( (hashtable *)font->internal, memory );
2514 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002515 }
2516
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002517 /* Free up the comment info. */
2518 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002519
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002520 /* Free up the properties. */
2521 for ( i = 0; i < font->props_size; i++ )
2522 {
2523 if ( font->props[i].format == BDF_ATOM )
2524 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002525 }
2526
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002527 FT_FREE( font->props );
2528
2529 /* Free up the character info. */
2530 for ( i = 0, glyphs = font->glyphs;
2531 i < font->glyphs_used; i++, glyphs++ )
2532 {
2533 FT_FREE( glyphs->name );
2534 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002535 }
2536
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002537 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2538 i++, glyphs++ )
2539 {
2540 FT_FREE( glyphs->name );
2541 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002542 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002543
2544 FT_FREE( font->glyphs );
2545 FT_FREE( font->unencoded );
2546
2547 /* Free up the overflow storage if it was used. */
2548 for ( i = 0, glyphs = font->overflow.glyphs;
2549 i < font->overflow.glyphs_used; i++, glyphs++ )
2550 {
2551 FT_FREE( glyphs->name );
2552 FT_FREE( glyphs->bitmap );
2553 }
2554
2555 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002556
2557 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002558 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002559
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002560 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002561 for ( prop = font->user_props, i = 0;
2562 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002563 {
2564 FT_FREE( prop->name );
2565 if ( prop->format == BDF_ATOM )
2566 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002567 }
David Turner993a8d02002-05-18 12:03:43 +00002568
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002569 FT_FREE( font->user_props );
2570
2571 /* FREE( font ); */ /* XXX Fixme */
2572 }
David Turner993a8d02002-05-18 12:03:43 +00002573
2574
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002575 FT_LOCAL_DEF( bdf_property_t * )
2576 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002577 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002578 {
2579 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002580
David Turner993a8d02002-05-18 12:03:43 +00002581
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002582 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002583 return 0;
2584
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002585 hn = hash_lookup( name, (hashtable *)font->internal );
2586
suzuki toshiya704f4d72009-09-13 00:50:14 +09002587 return hn ? ( font->props + hn->data ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002588 }
2589
2590
2591/* END */