blob: f2ca92df6e1e3a6b912e30c168dc4fe70147c846 [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 Lemberg6e0d4cd2011-11-27 09:21:03 +01001609 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1610
Werner Lemberged54e432011-11-27 16:39:53 +01001611 /* Check that the encoding is in the Unicode range because */
1612 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lemberg96ddc672011-06-29 09:15:54 +02001613 if ( p->glyph_enc > 0 &&
1614 (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
David Turner481838e2006-02-23 12:40:14 +00001615 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001616 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
David Turner481838e2006-02-23 12:40:14 +00001617 error = BDF_Err_Invalid_File_Format;
1618 goto Exit;
1619 }
1620
Werner Lemberg96ddc672011-06-29 09:15:54 +02001621 /* Check whether this encoding has already been encountered. */
1622 /* If it has then change it to unencoded so it gets added if */
1623 /* indicated. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001624 if ( p->glyph_enc >= 0 )
1625 {
1626 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1627 {
1628 /* Emit a message saying a glyph has been moved to the */
1629 /* unencoded area. */
1630 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1631 p->glyph_enc, p->glyph_name ));
1632 p->glyph_enc = -1;
1633 font->modified = 1;
1634 }
1635 else
1636 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1637 }
1638
1639 if ( p->glyph_enc >= 0 )
1640 {
1641 /* Make sure there are enough glyphs allocated in case the */
1642 /* number of characters happen to be wrong. */
1643 if ( font->glyphs_used == font->glyphs_size )
1644 {
1645 if ( FT_RENEW_ARRAY( font->glyphs,
1646 font->glyphs_size,
1647 font->glyphs_size + 64 ) )
1648 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001649
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001650 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001651 }
1652
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001653 glyph = font->glyphs + font->glyphs_used++;
1654 glyph->name = p->glyph_name;
1655 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001656
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001657 /* Reset the initial glyph info. */
1658 p->glyph_name = 0;
1659 }
1660 else
1661 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001662 /* Unencoded glyph. Check whether it should */
1663 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001664 if ( p->opts->keep_unencoded != 0 )
1665 {
1666 /* Allocate the next unencoded glyph. */
1667 if ( font->unencoded_used == font->unencoded_size )
1668 {
David Turner68df4f72005-03-15 18:18:57 +00001669 if ( FT_RENEW_ARRAY( font->unencoded ,
1670 font->unencoded_size,
1671 font->unencoded_size + 4 ) )
1672 goto Exit;
1673
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001674 font->unencoded_size += 4;
1675 }
1676
1677 glyph = font->unencoded + font->unencoded_used;
1678 glyph->name = p->glyph_name;
1679 glyph->encoding = font->unencoded_used++;
1680 }
1681 else
1682 /* Free up the glyph name if the unencoded shouldn't be */
1683 /* kept. */
1684 FT_FREE( p->glyph_name );
1685
1686 p->glyph_name = 0;
1687 }
1688
1689 /* Clear the flags that might be added when width and height are */
1690 /* checked for consistency. */
1691 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1692
1693 p->flags |= _BDF_ENCODING;
1694
1695 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001696 }
1697
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001698 /* Point at the glyph being constructed. */
1699 if ( p->glyph_enc == -1 )
1700 glyph = font->unencoded + ( font->unencoded_used - 1 );
1701 else
1702 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001703
Werner Lemberg96ddc672011-06-29 09:15:54 +02001704 /* Check whether a bitmap is being constructed. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001705 if ( p->flags & _BDF_BITMAP )
1706 {
1707 /* If there are more rows than are specified in the glyph metrics, */
1708 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001709 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001710 {
1711 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1712 {
1713 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1714 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001715 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001716 }
1717
1718 goto Exit;
1719 }
1720
1721 /* Only collect the number of nibbles indicated by the glyph */
1722 /* metrics. If there are more columns, they are simply ignored. */
1723 nibbles = glyph->bpr << 1;
1724 bp = glyph->bitmap + p->row * glyph->bpr;
1725
David Turnerb698eed2006-02-23 14:50:13 +00001726 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001727 {
1728 c = line[i];
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001729 if ( !c )
1730 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001731 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001732 if ( i + 1 < nibbles && ( i & 1 ) )
1733 *++bp = 0;
1734 }
1735
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001736 /* If any line has not enough columns, */
1737 /* indicate they have been padded with zero bits. */
1738 if ( i < nibbles &&
1739 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1740 {
1741 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
1742 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1743 font->modified = 1;
1744 }
1745
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001746 /* Remove possible garbage at the right. */
1747 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001748 if ( glyph->bbx.width )
1749 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001750
1751 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001752 if ( i == nibbles &&
1753 ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001754 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1755 {
1756 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1757 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1758 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001759 }
1760
1761 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001762 goto Exit;
1763 }
David Turner993a8d02002-05-18 12:03:43 +00001764
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001765 /* Expect the SWIDTH (scalable width) field next. */
1766 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1767 {
1768 if ( !( p->flags & _BDF_ENCODING ) )
1769 {
1770 /* Missing ENCODING field. */
1771 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1772 error = BDF_Err_Missing_Encoding_Field;
1773 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001774 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001775
David Turner68df4f72005-03-15 18:18:57 +00001776 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001777 if ( error )
1778 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001779
David Turnerb1b47622002-05-21 21:17:43 +00001780 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001781 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001782
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001783 goto Exit;
1784 }
David Turner993a8d02002-05-18 12:03:43 +00001785
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001786 /* Expect the DWIDTH (scalable width) field next. */
1787 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1788 {
David Turner68df4f72005-03-15 18:18:57 +00001789 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001790 if ( error )
1791 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001792
David Turnerb1b47622002-05-21 21:17:43 +00001793 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001794
1795 if ( !( p->flags & _BDF_SWIDTH ) )
1796 {
1797 /* Missing SWIDTH field. Emit an auto correction message and set */
1798 /* the scalable width from the device width. */
1799 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1800
Werner Lemberg02d4d592002-05-28 22:38:05 +00001801 glyph->swidth = (unsigned short)FT_MulDiv(
1802 glyph->dwidth, 72000L,
1803 (FT_Long)( font->point_size *
1804 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001805 }
1806
1807 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001808 goto Exit;
1809 }
David Turner993a8d02002-05-18 12:03:43 +00001810
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001811 /* Expect the BBX field next. */
1812 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1813 {
David Turner68df4f72005-03-15 18:18:57 +00001814 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001815 if ( error )
1816 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001817
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001818 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1819 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1820 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1821 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1822
1823 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001824 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1825 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001826
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001827 /* Determine the overall font bounding box as the characters are */
1828 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001829 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1830 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001831
David Turnerb1b47622002-05-21 21:17:43 +00001832 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001833
Werner Lembergdfa46192004-03-05 09:26:24 +00001834 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1835 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1836 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001837
1838 if ( !( p->flags & _BDF_DWIDTH ) )
1839 {
1840 /* Missing DWIDTH field. Emit an auto correction message and set */
1841 /* the device width to the glyph width. */
1842 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1843 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001844 }
1845
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001846 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1847 /* value if necessary. */
1848 if ( p->opts->correct_metrics != 0 )
1849 {
1850 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001851 unsigned short sw = (unsigned short)FT_MulDiv(
1852 glyph->dwidth, 72000L,
1853 (FT_Long)( font->point_size *
1854 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001855
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001856
1857 if ( sw != glyph->swidth )
1858 {
1859 glyph->swidth = sw;
1860
1861 if ( p->glyph_enc == -1 )
1862 _bdf_set_glyph_modified( font->umod,
1863 font->unencoded_used - 1 );
1864 else
1865 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1866
1867 p->flags |= _BDF_SWIDTH_ADJ;
1868 font->modified = 1;
1869 }
David Turner993a8d02002-05-18 12:03:43 +00001870 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001871
David Turner993a8d02002-05-18 12:03:43 +00001872 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001873 goto Exit;
1874 }
David Turner993a8d02002-05-18 12:03:43 +00001875
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001876 /* And finally, gather up the bitmap. */
1877 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1878 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001879 unsigned long bitmap_size;
1880
1881
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001882 if ( !( p->flags & _BDF_BBX ) )
1883 {
1884 /* Missing BBX field. */
1885 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1886 error = BDF_Err_Missing_Bbx_Field;
1887 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001888 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001889
1890 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001891 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001892
1893 bitmap_size = glyph->bpr * glyph->bbx.height;
1894 if ( bitmap_size > 0xFFFFU )
1895 {
1896 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1897 error = BDF_Err_Bbx_Too_Big;
1898 goto Exit;
1899 }
1900 else
1901 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001902
1903 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1904 goto Exit;
1905
1906 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001907 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001908
1909 goto Exit;
1910 }
1911
Werner Lemberge01406b2011-11-25 09:44:28 +01001912 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001913 error = BDF_Err_Invalid_File_Format;
1914
1915 Exit:
Werner Lembergf4c94d42010-06-19 16:08:31 +02001916 if ( error && ( p->flags & _BDF_GLYPH ) )
1917 FT_FREE( p->glyph_name );
1918
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001919 return error;
David Turner993a8d02002-05-18 12:03:43 +00001920 }
1921
David Turner993a8d02002-05-18 12:03:43 +00001922
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001923 /* Load the font properties. */
1924 static FT_Error
1925 _bdf_parse_properties( char* line,
1926 unsigned long linelen,
1927 unsigned long lineno,
1928 void* call_data,
1929 void* client_data )
1930 {
1931 unsigned long vlen;
1932 _bdf_line_func_t* next;
1933 _bdf_parse_t* p;
1934 char* name;
1935 char* value;
1936 char nbuf[128];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001937 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001938
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001939 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001940
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001941
1942 next = (_bdf_line_func_t *)call_data;
1943 p = (_bdf_parse_t *) client_data;
1944
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001945 /* Check for the end of the properties. */
1946 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1947 {
1948 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1949 /* encountered yet, then make sure they are added as properties and */
1950 /* make sure they are set from the font bounding box info. */
1951 /* */
1952 /* This is *always* done regardless of the options, because X11 */
1953 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001954 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001955 {
1956 p->font->font_ascent = p->font->bbx.ascent;
1957 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001958 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
1959 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001960 if ( error )
1961 goto Exit;
1962
1963 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1964 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001965 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001966
Werner Lemberg428c2e42003-04-25 05:35:04 +00001967 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001968 {
1969 p->font->font_descent = p->font->bbx.descent;
1970 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001971 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
1972 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001973 if ( error )
1974 goto Exit;
1975
1976 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1977 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001978 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001979
David Turner993a8d02002-05-18 12:03:43 +00001980 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001981 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001982
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001983 goto Exit;
1984 }
David Turner993a8d02002-05-18 12:03:43 +00001985
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001986 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1987 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1988 goto Exit;
1989
1990 /* Handle COMMENT fields and properties in a special way to preserve */
1991 /* the spacing. */
1992 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1993 {
David Turner993a8d02002-05-18 12:03:43 +00001994 name = value = line;
1995 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001996 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001997 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01001998 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001999 if ( error )
2000 goto Exit;
2001 }
2002 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
2003 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002004 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002005 if ( error )
2006 goto Exit;
2007 }
2008 else
2009 {
David Turner68df4f72005-03-15 18:18:57 +00002010 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002011 if ( error )
2012 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002013 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002014
David Turner68df4f72005-03-15 18:18:57 +00002015 _bdf_list_shift( &p->list, 1 );
2016 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002017
Werner Lemberge01406b2011-11-25 09:44:28 +01002018 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002019 if ( error )
2020 goto Exit;
2021 }
2022
2023 Exit:
2024 return error;
David Turner993a8d02002-05-18 12:03:43 +00002025 }
2026
David Turner993a8d02002-05-18 12:03:43 +00002027
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002028 /* Load the font header. */
2029 static FT_Error
2030 _bdf_parse_start( char* line,
2031 unsigned long linelen,
2032 unsigned long lineno,
2033 void* call_data,
2034 void* client_data )
2035 {
2036 unsigned long slen;
2037 _bdf_line_func_t* next;
2038 _bdf_parse_t* p;
2039 bdf_font_t* font;
2040 char *s;
David Turner993a8d02002-05-18 12:03:43 +00002041
David Turnerd490e372002-05-28 23:40:37 +00002042 FT_Memory memory = NULL;
2043 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002044
2045 FT_UNUSED( lineno ); /* only used in debug mode */
2046
2047
2048 next = (_bdf_line_func_t *)call_data;
2049 p = (_bdf_parse_t *) client_data;
2050
2051 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00002052 memory = p->font->memory;
2053
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002054 /* Check for a comment. This is done to handle those fonts that have */
2055 /* comments before the STARTFONT line for some reason. */
2056 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2057 {
2058 if ( p->opts->keep_comments != 0 && p->font != 0 )
2059 {
2060 linelen -= 7;
2061
2062 s = line + 7;
2063 if ( *s != 0 )
2064 {
2065 s++;
2066 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002067 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002068
2069 error = _bdf_add_comment( p->font, s, linelen );
2070 if ( error )
2071 goto Exit;
2072 /* here font is not defined! */
2073 }
2074
2075 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002076 }
2077
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002078 if ( !( p->flags & _BDF_START ) )
2079 {
2080 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002081
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002082 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2083 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01002084 /* we don't emit an error message since this code gets */
2085 /* explicitly caught one level higher */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002086 error = BDF_Err_Missing_Startfont_Field;
2087 goto Exit;
2088 }
David Turner993a8d02002-05-18 12:03:43 +00002089
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002090 p->flags = _BDF_START;
2091 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002092
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002093 if ( FT_NEW( font ) )
2094 goto Exit;
2095 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002096
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002097 font->memory = p->memory;
2098 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002099
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002100 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09002101 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002102 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002103
David Turner993a8d02002-05-18 12:03:43 +00002104
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002105 error = hash_init( &(font->proptbl), memory );
2106 if ( error )
2107 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002108 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002109 i < _num_bdf_properties; i++, prop++ )
2110 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09002111 error = hash_insert( prop->name, i,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002112 &(font->proptbl), memory );
2113 if ( error )
2114 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002115 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002116 }
2117
2118 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2119 goto Exit;
2120 error = hash_init( (hashtable *)p->font->internal,memory );
2121 if ( error )
2122 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002123 p->font->spacing = p->opts->font_spacing;
2124 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002125
2126 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002127 }
2128
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002129 /* Check for the start of the properties. */
2130 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2131 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002132 if ( !( p->flags & _BDF_FONT_BBX ) )
Werner Lembergfb690292010-06-23 10:00:52 +02002133 {
2134 /* Missing the FONTBOUNDINGBOX field. */
2135 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2136 error = BDF_Err_Missing_Fontboundingbox_Field;
2137 goto Exit;
2138 }
2139
David Turner68df4f72005-03-15 18:18:57 +00002140 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002141 if ( error )
2142 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00002143 /* at this point, `p->font' can't be NULL */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002144 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2145
2146 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2147 goto Exit;
2148
2149 p->flags |= _BDF_PROPS;
2150 *next = _bdf_parse_properties;
2151
2152 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002153 }
2154
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002155 /* Check for the FONTBOUNDINGBOX field. */
2156 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2157 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002158 if ( !( p->flags & _BDF_SIZE ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002159 {
2160 /* Missing the SIZE field. */
2161 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2162 error = BDF_Err_Missing_Size_Field;
2163 goto Exit;
2164 }
2165
David Turner68df4f72005-03-15 18:18:57 +00002166 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002167 if ( error )
2168 goto Exit;
2169
2170 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2171 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2172
2173 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2174 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2175
David Turnerd490e372002-05-28 23:40:37 +00002176 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002177 p->font->bbx.y_offset );
2178
2179 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002180
2181 p->flags |= _BDF_FONT_BBX;
2182
2183 goto Exit;
2184 }
2185
2186 /* The next thing to check for is the FONT field. */
2187 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2188 {
David Turner68df4f72005-03-15 18:18:57 +00002189 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002190 if ( error )
2191 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002192 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002193
David Turner68df4f72005-03-15 18:18:57 +00002194 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002195
2196 if ( !s )
2197 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002198 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg5b591e42007-06-01 22:16:43 +00002199 error = BDF_Err_Invalid_File_Format;
2200 goto Exit;
2201 }
2202
Werner Lembergfb690292010-06-23 10:00:52 +02002203 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2204 FT_FREE( p->font->name );
2205
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002206 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2207 goto Exit;
2208 FT_MEM_COPY( p->font->name, s, slen + 1 );
2209
2210 /* If the font name is an XLFD name, set the spacing to the one in */
2211 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002212 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002213 if ( error )
2214 goto Exit;
2215
2216 p->flags |= _BDF_FONT_NAME;
2217
2218 goto Exit;
2219 }
2220
2221 /* Check for the SIZE field. */
2222 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2223 {
2224 if ( !( p->flags & _BDF_FONT_NAME ) )
2225 {
2226 /* Missing the FONT field. */
2227 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2228 error = BDF_Err_Missing_Font_Field;
2229 goto Exit;
2230 }
2231
David Turner68df4f72005-03-15 18:18:57 +00002232 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002233 if ( error )
2234 goto Exit;
2235
2236 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2237 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2238 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2239
2240 /* Check for the bits per pixel field. */
2241 if ( p->list.used == 5 )
2242 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002243 unsigned short bitcount, i, shift;
2244
2245
2246 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2247
2248 /* Only values 1, 2, 4, 8 are allowed. */
2249 shift = p->font->bpp;
2250 bitcount = 0;
2251 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002252 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002253 if ( shift & 1 )
2254 bitcount = i;
2255 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002256 }
David Turner993a8d02002-05-18 12:03:43 +00002257
Werner Lembergbd8e3242002-06-12 08:43:58 +00002258 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002259
2260 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002261 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002262 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002263 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002264 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002265 }
2266 }
2267 else
2268 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002269
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002270 p->flags |= _BDF_SIZE;
2271
2272 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002273 }
2274
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002275 /* Check for the CHARS field -- font properties are optional */
2276 if ( ft_memcmp( line, "CHARS", 5 ) == 0 )
2277 {
2278 char nbuf[128];
2279
2280
2281 if ( !( p->flags & _BDF_FONT_BBX ) )
2282 {
2283 /* Missing the FONTBOUNDINGBOX field. */
2284 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2285 error = BDF_Err_Missing_Fontboundingbox_Field;
2286 goto Exit;
2287 }
2288
2289 /* Add the two standard X11 properties which are required */
2290 /* for compiling fonts. */
2291 p->font->font_ascent = p->font->bbx.ascent;
2292 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002293 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2294 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002295 if ( error )
2296 goto Exit;
2297 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2298
2299 p->font->font_descent = p->font->bbx.descent;
2300 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002301 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2302 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002303 if ( error )
2304 goto Exit;
2305 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2306
2307 p->font->modified = 1;
2308
2309 *next = _bdf_parse_glyphs;
2310
2311 /* A special return value. */
2312 error = -1;
2313 goto Exit;
2314 }
2315
Werner Lemberge01406b2011-11-25 09:44:28 +01002316 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002317 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002318
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002319 Exit:
2320 return error;
2321 }
David Turner993a8d02002-05-18 12:03:43 +00002322
2323
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002324 /*************************************************************************/
2325 /* */
2326 /* API. */
2327 /* */
2328 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002329
David Turner993a8d02002-05-18 12:03:43 +00002330
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002331 FT_LOCAL_DEF( FT_Error )
2332 bdf_load_font( FT_Stream stream,
2333 FT_Memory extmemory,
2334 bdf_options_t* opts,
2335 bdf_font_t* *font )
2336 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002337 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002338 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002339
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002340 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002341 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002342
2343
David Turner68df4f72005-03-15 18:18:57 +00002344 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002345 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002346
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002347 memory = NULL;
2348 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2349 p->minlb = 32767;
2350 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002351
David Turner68df4f72005-03-15 18:18:57 +00002352 _bdf_list_init( &p->list, extmemory );
2353
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002354 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002355 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002356 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002357 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002358
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002359 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002360 {
2361 /* If the font is not proportional, set the font's monowidth */
2362 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002363 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002364
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002365 if ( p->font->spacing != BDF_PROPORTIONAL )
2366 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002367
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002368 /* If the number of glyphs loaded is not that of the original count, */
2369 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002370 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002371 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002372 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2373 p->font->glyphs_used + p->font->unencoded_used ));
2374 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002375 }
2376
2377 /* Once the font has been loaded, adjust the overall font metrics if */
2378 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002379 if ( p->opts->correct_metrics != 0 &&
2380 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002381 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002382 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002383 {
2384 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002385 p->font->bbx.width, p->maxrb - p->minlb ));
2386 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2387 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002388 }
2389
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002390 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002391 {
2392 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002393 p->font->bbx.x_offset, p->minlb ));
2394 p->font->bbx.x_offset = p->minlb;
2395 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002396 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002397
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002398 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002399 {
2400 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002401 p->font->bbx.ascent, p->maxas ));
2402 p->font->bbx.ascent = p->maxas;
2403 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002404 }
2405
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002406 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002407 {
2408 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002409 p->font->bbx.descent, p->maxds ));
2410 p->font->bbx.descent = p->maxds;
2411 p->font->bbx.y_offset = (short)( -p->maxds );
2412 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002413 }
2414
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002415 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002416 {
2417 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002418 p->font->bbx.height, p->maxas + p->maxds ));
2419 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002420 }
2421
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002422 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002423 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2424 }
David Turner993a8d02002-05-18 12:03:43 +00002425 }
2426
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002427 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002428 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002429 /* The ENDFONT field was never reached or did not exist. */
2430 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002431 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002432 /* Error happened while parsing header. */
2433 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2434 error = BDF_Err_Corrupted_Font_Header;
2435 goto Exit;
2436 }
2437 else
2438 {
2439 /* Error happened when parsing glyphs. */
2440 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2441 error = BDF_Err_Corrupted_Font_Glyphs;
2442 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002443 }
David Turner993a8d02002-05-18 12:03:43 +00002444 }
2445
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002446 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002447 {
2448 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002449 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002450
Werner Lemberg370aea82010-06-08 08:37:11 +02002451 if ( p->font->comments_len > 0 )
2452 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002453 if ( FT_RENEW_ARRAY( p->font->comments,
2454 p->font->comments_len,
2455 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002456 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002457
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002458 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002459 }
David Turner993a8d02002-05-18 12:03:43 +00002460 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002461 else if ( error == BDF_Err_Ok )
2462 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002463
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002464 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002465
2466 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002467 if ( p )
2468 {
David Turner68df4f72005-03-15 18:18:57 +00002469 _bdf_list_done( &p->list );
2470
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002471 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002472
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002473 FT_FREE( p );
2474 }
2475
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002476 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002477
2478 Fail:
2479 bdf_free_font( p->font );
2480
2481 memory = extmemory;
2482
2483 FT_FREE( p->font );
2484
2485 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002486 }
David Turner993a8d02002-05-18 12:03:43 +00002487
2488
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002489 FT_LOCAL_DEF( void )
2490 bdf_free_font( bdf_font_t* font )
2491 {
2492 bdf_property_t* prop;
2493 unsigned long i;
2494 bdf_glyph_t* glyphs;
2495 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002496
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002497
2498 if ( font == 0 )
2499 return;
David Turner993a8d02002-05-18 12:03:43 +00002500
2501 memory = font->memory;
2502
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002503 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002504
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002505 /* Free up the internal hash table of property names. */
2506 if ( font->internal )
2507 {
2508 hash_free( (hashtable *)font->internal, memory );
2509 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002510 }
2511
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002512 /* Free up the comment info. */
2513 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002514
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002515 /* Free up the properties. */
2516 for ( i = 0; i < font->props_size; i++ )
2517 {
2518 if ( font->props[i].format == BDF_ATOM )
2519 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002520 }
2521
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002522 FT_FREE( font->props );
2523
2524 /* Free up the character info. */
2525 for ( i = 0, glyphs = font->glyphs;
2526 i < font->glyphs_used; i++, glyphs++ )
2527 {
2528 FT_FREE( glyphs->name );
2529 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002530 }
2531
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002532 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2533 i++, glyphs++ )
2534 {
2535 FT_FREE( glyphs->name );
2536 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002537 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002538
2539 FT_FREE( font->glyphs );
2540 FT_FREE( font->unencoded );
2541
2542 /* Free up the overflow storage if it was used. */
2543 for ( i = 0, glyphs = font->overflow.glyphs;
2544 i < font->overflow.glyphs_used; i++, glyphs++ )
2545 {
2546 FT_FREE( glyphs->name );
2547 FT_FREE( glyphs->bitmap );
2548 }
2549
2550 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002551
2552 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002553 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002554
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002555 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002556 for ( prop = font->user_props, i = 0;
2557 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002558 {
2559 FT_FREE( prop->name );
2560 if ( prop->format == BDF_ATOM )
2561 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002562 }
David Turner993a8d02002-05-18 12:03:43 +00002563
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002564 FT_FREE( font->user_props );
2565
2566 /* FREE( font ); */ /* XXX Fixme */
2567 }
David Turner993a8d02002-05-18 12:03:43 +00002568
2569
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002570 FT_LOCAL_DEF( bdf_property_t * )
2571 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002572 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002573 {
2574 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002575
David Turner993a8d02002-05-18 12:03:43 +00002576
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002577 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002578 return 0;
2579
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002580 hn = hash_lookup( name, (hashtable *)font->internal );
2581
suzuki toshiya704f4d72009-09-13 00:50:14 +09002582 return hn ? ( font->props + hn->data ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002583 }
2584
2585
2586/* END */