blob: e027567167797b425894e58c86fd078a72145fee [file] [log] [blame]
David Turner993a8d02002-05-18 12:03:43 +00001/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
Werner Lemberg320d4972012-02-24 18:06:46 +01003 * Copyright 2001-2012
Werner Lemberg442bfb82007-02-12 21:44:10 +00004 * Francesco Zappa Nardelli
David Turner993a8d02002-05-18 12:03:43 +00005 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
Werner Lemberg7cf4d372002-05-21 14:13:01 +000025 /*************************************************************************/
26 /* */
27 /* This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 */
28 /* */
29 /* taken from Mark Leisher's xmbdfed package */
30 /* */
31 /*************************************************************************/
32
David Turner993a8d02002-05-18 12:03:43 +000033
34#include <ft2build.h>
35
Werner Lemberg02d4d592002-05-28 22:38:05 +000036#include FT_FREETYPE_H
David Turner993a8d02002-05-18 12:03:43 +000037#include FT_INTERNAL_DEBUG_H
38#include FT_INTERNAL_STREAM_H
39#include FT_INTERNAL_OBJECTS_H
40
41#include "bdf.h"
David Turner993a8d02002-05-18 12:03:43 +000042#include "bdferror.h"
43
David Turner993a8d02002-05-18 12:03:43 +000044
Werner Lemberg7cf4d372002-05-21 14:13:01 +000045 /*************************************************************************/
46 /* */
47 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
48 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
49 /* messages during execution. */
50 /* */
51#undef FT_COMPONENT
52#define FT_COMPONENT trace_bdflib
David Turner993a8d02002-05-18 12:03:43 +000053
David Turner993a8d02002-05-18 12:03:43 +000054
Werner Lemberg7cf4d372002-05-21 14:13:01 +000055 /*************************************************************************/
56 /* */
57 /* Default BDF font options. */
58 /* */
59 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000060
David Turner993a8d02002-05-18 12:03:43 +000061
David Turnerb1b47622002-05-21 21:17:43 +000062 static const bdf_options_t _bdf_opts =
Werner Lemberg7cf4d372002-05-21 14:13:01 +000063 {
David Turner993a8d02002-05-18 12:03:43 +000064 1, /* Correct metrics. */
65 1, /* Preserve unencoded glyphs. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000066 0, /* Preserve comments. */
67 BDF_PROPORTIONAL /* Default spacing. */
68 };
David Turner993a8d02002-05-18 12:03:43 +000069
David Turner993a8d02002-05-18 12:03:43 +000070
Werner Lemberg7cf4d372002-05-21 14:13:01 +000071 /*************************************************************************/
72 /* */
73 /* Builtin BDF font properties. */
74 /* */
75 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000076
Werner Lemberg7cf4d372002-05-21 14:13:01 +000077 /* List of most properties that might appear in a font. Doesn't include */
78 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
David Turner993a8d02002-05-18 12:03:43 +000079
David Turnerb1b47622002-05-21 21:17:43 +000080 static const bdf_property_t _bdf_properties[] =
David Turner993a8d02002-05-18 12:03:43 +000081 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +000082 { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
83 { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
84 { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
85 { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
86 { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
87 { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
88 { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
89 { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
90 { (char *)"COMMENT", BDF_ATOM, 1, { 0 } },
91 { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } },
92 { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
93 { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } },
94 { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
95 { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } },
96 { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } },
97 { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } },
98 { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
99 { (char *)"FONT", BDF_ATOM, 1, { 0 } },
100 { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
101 { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
102 { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
103 { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } },
104 { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } },
105 { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
106 { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } },
107 { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } },
108 { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } },
109 { (char *)"NOTICE", BDF_ATOM, 1, { 0 } },
110 { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
111 { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } },
112 { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
113 { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
114 { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
115 { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
116 { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
117 { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
118 { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
119 { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
120 { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
121 { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
122 { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
123 { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
124 { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
125 { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
126 { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
127 { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
128 { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
129 { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
130 { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
131 { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
132 { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
133 { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
134 { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
135 { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
136 { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
137 { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
138 { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
139 { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
140 { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
141 { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
142 { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
143 { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } },
144 { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
145 { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
146 { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
147 { (char *)"SLANT", BDF_ATOM, 1, { 0 } },
148 { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
149 { (char *)"SPACING", BDF_ATOM, 1, { 0 } },
150 { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
151 { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
152 { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
153 { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
154 { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
155 { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
156 { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
157 { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
158 { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
159 { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
160 { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } },
161 { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
162 { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } },
163 { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
164 { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
165 };
David Turner993a8d02002-05-18 12:03:43 +0000166
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000167 static const unsigned long
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000168 _num_bdf_properties = sizeof ( _bdf_properties ) /
169 sizeof ( _bdf_properties[0] );
David Turner993a8d02002-05-18 12:03:43 +0000170
171
Werner Lemberge01406b2011-11-25 09:44:28 +0100172 /* Auto correction messages. */
173#define ACMSG1 "FONT_ASCENT property missing. " \
174 "Added `FONT_ASCENT %hd'.\n"
175#define ACMSG2 "FONT_DESCENT property missing. " \
176 "Added `FONT_DESCENT %hd'.\n"
177#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
178#define ACMSG4 "Font left bearing != actual left bearing. " \
179 "Old: %hd New: %hd.\n"
180#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
181#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
182#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
183#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
184#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
185#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
186#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
187#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
188#define ACMSG13 "Glyph %ld extra rows removed.\n"
189#define ACMSG14 "Glyph %ld extra columns removed.\n"
190#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
Werner Lemberg0b1c0c62012-02-25 10:23:04 +0100191#define ACMSG16 "Glyph %ld missing columns padded with zero bits.\n"
Werner Lemberge01406b2011-11-25 09:44:28 +0100192
193 /* Error messages. */
194#define ERRMSG1 "[line %ld] Missing `%s' line.\n"
195#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
196#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
197#define ERRMSG4 "[line %ld] BBX too big.\n"
198#define ERRMSG5 "[line %ld] `%s' value too big.\n"
199#define ERRMSG6 "[line %ld] Input line too long.\n"
200#define ERRMSG7 "[line %ld] Font name too long.\n"
201#define ERRMSG8 "[line %ld] Invalid `%s' value.\n"
202#define ERRMSG9 "[line %ld] Invalid keyword.\n"
203
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +0100204 /* Debug messages. */
205#define DBGMSG1 " [%6ld] %s" /* no \n */
206#define DBGMSG2 " (0x%lX)\n"
207
Werner Lemberge01406b2011-11-25 09:44:28 +0100208
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000209 /*************************************************************************/
210 /* */
211 /* Hash table utilities for the properties. */
212 /* */
213 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +0000214
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000215 /* XXX: Replace this with FreeType's hash functions */
David Turner993a8d02002-05-18 12:03:43 +0000216
David Turner993a8d02002-05-18 12:03:43 +0000217
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000218#define INITIAL_HT_SIZE 241
219
220 typedef void
221 (*hash_free_func)( hashnode node );
222
223 static hashnode*
Werner Lemberg428c2e42003-04-25 05:35:04 +0000224 hash_bucket( const char* key,
225 hashtable* ht )
David Turner993a8d02002-05-18 12:03:43 +0000226 {
Werner Lemberg428c2e42003-04-25 05:35:04 +0000227 const char* kp = key;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000228 unsigned long res = 0;
229 hashnode* bp = ht->table, *ndp;
230
231
232 /* Mocklisp hash function. */
233 while ( *kp )
234 res = ( res << 5 ) - res + *kp++;
235
236 ndp = bp + ( res % ht->size );
237 while ( *ndp )
David Turner993a8d02002-05-18 12:03:43 +0000238 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000239 kp = (*ndp)->key;
240 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
241 break;
242 ndp--;
243 if ( ndp < bp )
244 ndp = bp + ( ht->size - 1 );
David Turner993a8d02002-05-18 12:03:43 +0000245 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000246
247 return ndp;
David Turner993a8d02002-05-18 12:03:43 +0000248 }
David Turner993a8d02002-05-18 12:03:43 +0000249
250
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000251 static FT_Error
252 hash_rehash( hashtable* ht,
253 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000254 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000255 hashnode* obp = ht->table, *bp, *nbp;
David Turner993a8d02002-05-18 12:03:43 +0000256 int i, sz = ht->size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000257 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000258
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000259
260 ht->size <<= 1;
261 ht->limit = ht->size / 3;
262
263 if ( FT_NEW_ARRAY( ht->table, ht->size ) )
264 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000265
266 for ( i = 0, bp = obp; i < sz; i++, bp++ )
David Turner993a8d02002-05-18 12:03:43 +0000267 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000268 if ( *bp )
269 {
270 nbp = hash_bucket( (*bp)->key, ht );
271 *nbp = *bp;
272 }
David Turner993a8d02002-05-18 12:03:43 +0000273 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000274 FT_FREE( obp );
275
276 Exit:
277 return error;
David Turner993a8d02002-05-18 12:03:43 +0000278 }
David Turner993a8d02002-05-18 12:03:43 +0000279
280
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000281 static FT_Error
282 hash_init( hashtable* ht,
283 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000284 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000285 int sz = INITIAL_HT_SIZE;
286 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000287
David Turner993a8d02002-05-18 12:03:43 +0000288
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000289 ht->size = sz;
290 ht->limit = sz / 3;
291 ht->used = 0;
David Turner993a8d02002-05-18 12:03:43 +0000292
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000293 if ( FT_NEW_ARRAY( ht->table, sz ) )
294 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000295
296 Exit:
297 return error;
David Turner993a8d02002-05-18 12:03:43 +0000298 }
David Turner993a8d02002-05-18 12:03:43 +0000299
300
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000301 static void
302 hash_free( hashtable* ht,
303 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000304 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000305 if ( ht != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000306 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000307 int i, sz = ht->size;
308 hashnode* bp = ht->table;
David Turner993a8d02002-05-18 12:03:43 +0000309
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000310
311 for ( i = 0; i < sz; i++, bp++ )
312 FT_FREE( *bp );
313
314 FT_FREE( ht->table );
315 }
David Turner993a8d02002-05-18 12:03:43 +0000316 }
317
David Turner993a8d02002-05-18 12:03:43 +0000318
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000319 static FT_Error
320 hash_insert( char* key,
suzuki toshiya704f4d72009-09-13 00:50:14 +0900321 size_t data,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000322 hashtable* ht,
323 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000324 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000325 hashnode nn, *bp = hash_bucket( key, ht );
326 FT_Error error = BDF_Err_Ok;
327
328
329 nn = *bp;
330 if ( !nn )
331 {
332 if ( FT_NEW( nn ) )
333 goto Exit;
334 *bp = nn;
335
336 nn->key = key;
337 nn->data = data;
338
339 if ( ht->used >= ht->limit )
340 {
341 error = hash_rehash( ht, memory );
342 if ( error )
343 goto Exit;
344 }
345 ht->used++;
346 }
David Turner993a8d02002-05-18 12:03:43 +0000347 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000348 nn->data = data;
349
350 Exit:
351 return error;
David Turner993a8d02002-05-18 12:03:43 +0000352 }
353
David Turner993a8d02002-05-18 12:03:43 +0000354
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000355 static hashnode
Werner Lemberg428c2e42003-04-25 05:35:04 +0000356 hash_lookup( const char* key,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000357 hashtable* ht )
358 {
359 hashnode *np = hash_bucket( key, ht );
360
361
362 return *np;
363 }
364
365
366 /*************************************************************************/
367 /* */
368 /* Utility types and functions. */
369 /* */
370 /*************************************************************************/
371
372
373 /* Function type for parsing lines of a BDF font. */
374
375 typedef FT_Error
376 (*_bdf_line_func_t)( char* line,
377 unsigned long linelen,
378 unsigned long lineno,
379 void* call_data,
380 void* client_data );
381
382
383 /* List structure for splitting lines into fields. */
384
385 typedef struct _bdf_list_t_
386 {
387 char** field;
388 unsigned long size;
389 unsigned long used;
David Turner68df4f72005-03-15 18:18:57 +0000390 FT_Memory memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000391
392 } _bdf_list_t;
393
394
395 /* Structure used while loading BDF fonts. */
396
397 typedef struct _bdf_parse_t_
398 {
399 unsigned long flags;
400 unsigned long cnt;
401 unsigned long row;
402
403 short minlb;
404 short maxlb;
405 short maxrb;
406 short maxas;
407 short maxds;
408
409 short rbearing;
410
411 char* glyph_name;
412 long glyph_enc;
413
414 bdf_font_t* font;
415 bdf_options_t* opts;
416
Werner Lemberged54e432011-11-27 16:39:53 +0100417 unsigned long have[34816]; /* must be in sync with `nmod' and `umod' */
418 /* arrays from `bdf_font_t' structure */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000419 _bdf_list_t list;
420
421 FT_Memory memory;
422
423 } _bdf_parse_t;
424
425
Werner Lemberga08b2172007-03-28 07:17:17 +0000426#define setsbit( m, cc ) \
427 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
428#define sbitset( m, cc ) \
429 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000430
431
David Turner68df4f72005-03-15 18:18:57 +0000432 static void
433 _bdf_list_init( _bdf_list_t* list,
434 FT_Memory memory )
435 {
Werner Lembergebf55852005-03-16 01:49:54 +0000436 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000437 list->memory = memory;
438 }
439
Werner Lembergebf55852005-03-16 01:49:54 +0000440
David Turner68df4f72005-03-15 18:18:57 +0000441 static void
442 _bdf_list_done( _bdf_list_t* list )
443 {
444 FT_Memory memory = list->memory;
445
Werner Lembergebf55852005-03-16 01:49:54 +0000446
David Turner68df4f72005-03-15 18:18:57 +0000447 if ( memory )
448 {
449 FT_FREE( list->field );
Werner Lembergebf55852005-03-16 01:49:54 +0000450 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000451 }
452 }
453
454
455 static FT_Error
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900456 _bdf_list_ensure( _bdf_list_t* list,
457 unsigned long num_items ) /* same as _bdf_list_t.used */
David Turner68df4f72005-03-15 18:18:57 +0000458 {
Werner Lembergebf55852005-03-16 01:49:54 +0000459 FT_Error error = BDF_Err_Ok;
460
David Turner68df4f72005-03-15 18:18:57 +0000461
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900462 if ( num_items > list->size )
David Turner68df4f72005-03-15 18:18:57 +0000463 {
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900464 unsigned long oldsize = list->size; /* same as _bdf_list_t.size */
Werner Lembergcee5d592012-03-01 09:26:03 +0100465 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 5;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900466 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
467 FT_Memory memory = list->memory;
David Turner68df4f72005-03-15 18:18:57 +0000468
Werner Lembergebf55852005-03-16 01:49:54 +0000469
David Turner68df4f72005-03-15 18:18:57 +0000470 if ( oldsize == bigsize )
471 {
Werner Lembergebf55852005-03-16 01:49:54 +0000472 error = BDF_Err_Out_Of_Memory;
David Turner68df4f72005-03-15 18:18:57 +0000473 goto Exit;
474 }
475 else if ( newsize < oldsize || newsize > bigsize )
476 newsize = bigsize;
477
478 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
479 goto Exit;
480
481 list->size = newsize;
482 }
Werner Lembergebf55852005-03-16 01:49:54 +0000483
David Turner68df4f72005-03-15 18:18:57 +0000484 Exit:
485 return error;
486 }
487
488
489 static void
490 _bdf_list_shift( _bdf_list_t* list,
491 unsigned long n )
492 {
493 unsigned long i, u;
494
495
496 if ( list == 0 || list->used == 0 || n == 0 )
497 return;
498
499 if ( n >= list->used )
500 {
501 list->used = 0;
502 return;
503 }
504
505 for ( u = n, i = 0; u < list->used; i++, u++ )
506 list->field[i] = list->field[u];
507 list->used -= n;
508 }
509
510
Werner Lembergf4c94d42010-06-19 16:08:31 +0200511 /* An empty string for empty fields. */
512
513 static const char empty[1] = { 0 }; /* XXX eliminate this */
514
515
David Turner68df4f72005-03-15 18:18:57 +0000516 static char *
517 _bdf_list_join( _bdf_list_t* list,
518 int c,
519 unsigned long *alen )
520 {
521 unsigned long i, j;
522 char *fp, *dp;
523
524
525 *alen = 0;
526
527 if ( list == 0 || list->used == 0 )
528 return 0;
529
530 dp = list->field[0];
531 for ( i = j = 0; i < list->used; i++ )
532 {
533 fp = list->field[i];
534 while ( *fp )
535 dp[j++] = *fp++;
536
537 if ( i + 1 < list->used )
538 dp[j++] = (char)c;
539 }
Werner Lembergf4c94d42010-06-19 16:08:31 +0200540 if ( dp != empty )
541 dp[j] = 0;
David Turner68df4f72005-03-15 18:18:57 +0000542
543 *alen = j;
544 return dp;
545 }
546
547
Werner Lemberg03242f52012-02-26 06:52:56 +0100548 /* The code below ensures that we have at least 4 + 1 `field' */
549 /* elements in `list' (which are possibly NULL) so that we */
550 /* don't have to check the number of fields in most cases. */
551
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000552 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000553 _bdf_list_split( _bdf_list_t* list,
554 char* separators,
555 char* line,
556 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000557 {
558 int mult, final_empty;
559 char *sp, *ep, *end;
560 char seps[32];
561 FT_Error error = BDF_Err_Ok;
562
563
564 /* Initialize the list. */
565 list->used = 0;
Werner Lembergd9c16592012-03-01 15:15:00 +0100566 if ( list->size )
567 {
568 list->field[0] = (char*)empty;
569 list->field[1] = (char*)empty;
570 list->field[2] = (char*)empty;
571 list->field[3] = (char*)empty;
Werner Lemberg649c6732012-03-16 21:12:41 +0100572 list->field[4] = (char*)empty;
Werner Lembergd9c16592012-03-01 15:15:00 +0100573 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000574
575 /* If the line is empty, then simply return. */
576 if ( linelen == 0 || line[0] == 0 )
577 goto Exit;
578
579 /* In the original code, if the `separators' parameter is NULL or */
580 /* empty, the list is split into individual bytes. We don't need */
581 /* this, so an error is signaled. */
582 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000583 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000584 error = BDF_Err_Invalid_Argument;
585 goto Exit;
586 }
587
588 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000589 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000590
591 /* If the very last character of the separator string is a plus, then */
592 /* set the `mult' flag to indicate that multiple separators should be */
593 /* collapsed into one. */
594 for ( mult = 0, sp = separators; sp && *sp; sp++ )
595 {
596 if ( *sp == '+' && *( sp + 1 ) == 0 )
597 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000598 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000599 setsbit( seps, *sp );
600 }
601
602 /* Break the line up into fields. */
603 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
604 sp < end && *sp; )
605 {
606 /* Collect everything that is not a separator. */
607 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
608 ;
609
610 /* Resize the list if necessary. */
611 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000612 {
Werner Lembergebf55852005-03-16 01:49:54 +0000613 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000614 if ( error )
615 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000616 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000617
618 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000619 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000620
621 sp = ep;
622
623 if ( mult )
624 {
625 /* If multiple separators should be collapsed, do it now by */
626 /* setting all the separator characters to 0. */
627 for ( ; *ep && sbitset( seps, *ep ); ep++ )
628 *ep = 0;
629 }
630 else if ( *ep != 0 )
631 /* Don't collapse multiple separators by making them 0, so just */
632 /* make the one encountered 0. */
633 *ep++ = 0;
634
635 final_empty = ( ep > sp && *ep == 0 );
636 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000637 }
638
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000639 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000640 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000641 {
Werner Lembergebf55852005-03-16 01:49:54 +0000642 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000643 if ( error )
644 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000645 }
646
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000647 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000648 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000649
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000650 list->field[list->used] = 0;
651
652 Exit:
653 return error;
David Turner993a8d02002-05-18 12:03:43 +0000654 }
655
David Turner993a8d02002-05-18 12:03:43 +0000656
David Turner68df4f72005-03-15 18:18:57 +0000657#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000658
Werner Lembergebf55852005-03-16 01:49:54 +0000659
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000660 static FT_Error
661 _bdf_readstream( FT_Stream stream,
662 _bdf_line_func_t callback,
663 void* client_data,
664 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000665 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000666 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000667 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900668 int refill, hold, to_skip;
669 ptrdiff_t bytes, start, end, cursor, avail;
David Turner68df4f72005-03-15 18:18:57 +0000670 char* buf = 0;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000671 FT_Memory memory = stream->memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000672 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000673
David Turner993a8d02002-05-18 12:03:43 +0000674
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000675 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000676 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000677 error = BDF_Err_Invalid_Argument;
678 goto Exit;
679 }
David Turner993a8d02002-05-18 12:03:43 +0000680
Werner Lembergebf55852005-03-16 01:49:54 +0000681 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000682 buf_size = 1024;
683
684 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000685 goto Exit;
686
Werner Lembergebf55852005-03-16 01:49:54 +0000687 cb = callback;
688 lineno = 1;
689 buf[0] = 0;
690 start = 0;
691 end = 0;
692 avail = 0;
693 cursor = 0;
694 refill = 1;
695 to_skip = NO_SKIP;
696 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000697
David Turner68df4f72005-03-15 18:18:57 +0000698 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000699 {
David Turner68df4f72005-03-15 18:18:57 +0000700 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000701 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +0200702 bytes = (ptrdiff_t)FT_Stream_TryRead(
703 stream, (FT_Byte*)buf + cursor,
704 (FT_ULong)( buf_size - cursor ) );
David Turner68df4f72005-03-15 18:18:57 +0000705 avail = cursor + bytes;
706 cursor = 0;
707 refill = 0;
708 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000709
David Turner68df4f72005-03-15 18:18:57 +0000710 end = start;
711
Werner Lembergebf55852005-03-16 01:49:54 +0000712 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000713 if ( start < avail && buf[start] == to_skip )
714 {
715 start += 1;
716 to_skip = NO_SKIP;
717 continue;
718 }
719
720 /* try to find the end of the line */
721 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
722 end++;
723
Werner Lembergebf55852005-03-16 01:49:54 +0000724 /* if we hit the end of the buffer, try shifting its content */
725 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000726 if ( end >= avail )
727 {
728 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
729 break; /* ignore it then exit */
730
731 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000732 {
Werner Lembergebf55852005-03-16 01:49:54 +0000733 /* this line is definitely too long; try resizing the input */
734 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000735 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000736
Werner Lembergebf55852005-03-16 01:49:54 +0000737
738 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000739 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100740 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
David Turner68df4f72005-03-15 18:18:57 +0000741 error = BDF_Err_Invalid_Argument;
742 goto Exit;
743 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000744
Werner Lembergebf55852005-03-16 01:49:54 +0000745 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000746 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
747 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000748
David Turner68df4f72005-03-15 18:18:57 +0000749 cursor = buf_size;
750 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000751 }
752 else
753 {
David Turner68df4f72005-03-15 18:18:57 +0000754 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000755
Werner Lembergebf55852005-03-16 01:49:54 +0000756 FT_MEM_COPY( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000757
David Turner68df4f72005-03-15 18:18:57 +0000758 cursor = bytes;
759 avail -= bytes;
760 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000761 }
David Turner68df4f72005-03-15 18:18:57 +0000762 refill = 1;
763 continue;
David Turner993a8d02002-05-18 12:03:43 +0000764 }
David Turner68df4f72005-03-15 18:18:57 +0000765
766 /* Temporarily NUL-terminate the line. */
767 hold = buf[end];
768 buf[end] = 0;
769
770 /* XXX: Use encoding independent value for 0x1a */
771 if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
772 {
Werner Lembergebf55852005-03-16 01:49:54 +0000773 error = (*cb)( buf + start, end - start, lineno,
774 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200775 /* Redo if we have encountered CHARS without properties. */
776 if ( error == -1 )
777 error = (*cb)( buf + start, end - start, lineno,
778 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000779 if ( error )
780 break;
781 }
782
783 lineno += 1;
784 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000785 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000786
787 if ( hold == '\n' )
788 to_skip = '\r';
789 else if ( hold == '\r' )
790 to_skip = '\n';
791 else
792 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000793 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000794
David Turner68df4f72005-03-15 18:18:57 +0000795 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000796
797 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000798 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000799 return error;
David Turner993a8d02002-05-18 12:03:43 +0000800 }
David Turner993a8d02002-05-18 12:03:43 +0000801
802
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000803 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000804
David Turnerb1b47622002-05-21 21:17:43 +0000805 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000806 {
David Turner993a8d02002-05-18 12:03:43 +0000807 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
808 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
809 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
811 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
812 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
813 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
814 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
815 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
816 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
817 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000818 };
David Turner993a8d02002-05-18 12:03:43 +0000819
David Turnerb1b47622002-05-21 21:17:43 +0000820 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000821 {
David Turner993a8d02002-05-18 12:03:43 +0000822 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
823 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
825 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000826 };
David Turner993a8d02002-05-18 12:03:43 +0000827
David Turnerb1b47622002-05-21 21:17:43 +0000828 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000829 {
David Turner993a8d02002-05-18 12:03:43 +0000830 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
831 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
832 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
833 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000834 };
David Turner993a8d02002-05-18 12:03:43 +0000835
David Turnerb1b47622002-05-21 21:17:43 +0000836 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000837 {
David Turner993a8d02002-05-18 12:03:43 +0000838 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
839 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
840 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
841 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000842 };
David Turner993a8d02002-05-18 12:03:43 +0000843
David Turner993a8d02002-05-18 12:03:43 +0000844
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000845#define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
David Turner993a8d02002-05-18 12:03:43 +0000846
David Turner993a8d02002-05-18 12:03:43 +0000847
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000848 /* Routine to convert an ASCII string into an unsigned long integer. */
849 static unsigned long
850 _bdf_atoul( char* s,
851 char** end,
852 int base )
David Turner993a8d02002-05-18 12:03:43 +0000853 {
David Turnerb1b47622002-05-21 21:17:43 +0000854 unsigned long v;
855 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000856
857
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000858 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000859 return 0;
860
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000861 /* Make sure the radix is something recognizable. Default to 10. */
862 switch ( base )
863 {
864 case 8:
865 dmap = odigits;
866 break;
867 case 16:
868 dmap = hdigits;
869 break;
870 default:
871 base = 10;
872 dmap = ddigits;
873 break;
David Turner993a8d02002-05-18 12:03:43 +0000874 }
875
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000876 /* Check for the special hex prefix. */
877 if ( *s == '0' &&
878 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
879 {
880 base = 16;
881 dmap = hdigits;
882 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000883 }
884
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000885 for ( v = 0; isdigok( dmap, *s ); s++ )
886 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000887
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000888 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000889 *end = s;
890
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000891 return v;
892 }
David Turner993a8d02002-05-18 12:03:43 +0000893
David Turner993a8d02002-05-18 12:03:43 +0000894
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000895 /* Routine to convert an ASCII string into an signed long integer. */
896 static long
897 _bdf_atol( char* s,
898 char** end,
899 int base )
900 {
David Turnerb1b47622002-05-21 21:17:43 +0000901 long v, neg;
902 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000903
904
905 if ( s == 0 || *s == 0 )
906 return 0;
907
908 /* Make sure the radix is something recognizable. Default to 10. */
909 switch ( base )
910 {
911 case 8:
912 dmap = odigits;
913 break;
914 case 16:
915 dmap = hdigits;
916 break;
917 default:
918 base = 10;
919 dmap = ddigits;
920 break;
921 }
922
923 /* Check for a minus sign. */
924 neg = 0;
925 if ( *s == '-' )
926 {
927 s++;
928 neg = 1;
929 }
930
931 /* Check for the special hex prefix. */
932 if ( *s == '0' &&
933 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
934 {
935 base = 16;
936 dmap = hdigits;
937 s += 2;
938 }
939
940 for ( v = 0; isdigok( dmap, *s ); s++ )
941 v = v * base + a2i[(int)*s];
942
943 if ( end != 0 )
944 *end = s;
945
946 return ( !neg ) ? v : -v;
947 }
948
949
950 /* Routine to convert an ASCII string into an signed short integer. */
951 static short
952 _bdf_atos( char* s,
953 char** end,
954 int base )
955 {
David Turnerb1b47622002-05-21 21:17:43 +0000956 short v, neg;
957 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000958
959
960 if ( s == 0 || *s == 0 )
961 return 0;
962
963 /* Make sure the radix is something recognizable. Default to 10. */
964 switch ( base )
965 {
966 case 8:
967 dmap = odigits;
968 break;
969 case 16:
970 dmap = hdigits;
971 break;
972 default:
973 base = 10;
974 dmap = ddigits;
975 break;
976 }
977
978 /* Check for a minus. */
979 neg = 0;
980 if ( *s == '-' )
981 {
982 s++;
983 neg = 1;
984 }
985
986 /* Check for the special hex prefix. */
987 if ( *s == '0' &&
988 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
989 {
990 base = 16;
991 dmap = hdigits;
992 s += 2;
993 }
994
995 for ( v = 0; isdigok( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +0000996 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000997
998 if ( end != 0 )
999 *end = s;
1000
Werner Lemberg233302a2002-05-22 05:41:06 +00001001 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001002 }
1003
1004
1005 /* Routine to compare two glyphs by encoding so they can be sorted. */
1006 static int
1007 by_encoding( const void* a,
1008 const void* b )
1009 {
1010 bdf_glyph_t *c1, *c2;
1011
1012
1013 c1 = (bdf_glyph_t *)a;
1014 c2 = (bdf_glyph_t *)b;
1015
1016 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001017 return -1;
David Turner68df4f72005-03-15 18:18:57 +00001018
1019 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001020 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001021
David Turner993a8d02002-05-18 12:03:43 +00001022 return 0;
David Turner993a8d02002-05-18 12:03:43 +00001023 }
1024
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001025
1026 static FT_Error
1027 bdf_create_property( char* name,
1028 int format,
1029 bdf_font_t* font )
1030 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001031 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001032 bdf_property_t* p;
1033 FT_Memory memory = font->memory;
1034 FT_Error error = BDF_Err_Ok;
1035
1036
Werner Lemberg96ddc672011-06-29 09:15:54 +02001037 /* First check whether the property has */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001038 /* already been added or not. If it has, then */
1039 /* simply ignore it. */
1040 if ( hash_lookup( name, &(font->proptbl) ) )
1041 goto Exit;
1042
David Turner68df4f72005-03-15 18:18:57 +00001043 if ( FT_RENEW_ARRAY( font->user_props,
1044 font->nuser_props,
1045 font->nuser_props + 1 ) )
1046 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001047
1048 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +00001049 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001050
suzuki toshiya704f4d72009-09-13 00:50:14 +09001051 n = ft_strlen( name ) + 1;
1052 if ( n > FT_ULONG_MAX )
1053 return BDF_Err_Invalid_Argument;
David Turner68df4f72005-03-15 18:18:57 +00001054
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001055 if ( FT_NEW_ARRAY( p->name, n ) )
1056 goto Exit;
1057
1058 FT_MEM_COPY( (char *)p->name, name, n );
1059
1060 p->format = format;
1061 p->builtin = 0;
1062
1063 n = _num_bdf_properties + font->nuser_props;
1064
suzuki toshiya704f4d72009-09-13 00:50:14 +09001065 error = hash_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001066 if ( error )
1067 goto Exit;
1068
1069 font->nuser_props++;
1070
1071 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001072 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001073 }
David Turner993a8d02002-05-18 12:03:43 +00001074
1075
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001076 FT_LOCAL_DEF( bdf_property_t * )
1077 bdf_get_property( char* name,
1078 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001079 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001080 hashnode hn;
1081 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001082
1083
1084 if ( name == 0 || *name == 0 )
1085 return 0;
1086
1087 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1088 return 0;
1089
suzuki toshiya704f4d72009-09-13 00:50:14 +09001090 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001091 if ( propid >= _num_bdf_properties )
1092 return font->user_props + ( propid - _num_bdf_properties );
1093
Werner Lemberg233302a2002-05-22 05:41:06 +00001094 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001095 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001096
1097
1098 /*************************************************************************/
1099 /* */
1100 /* BDF font file parsing flags and functions. */
1101 /* */
1102 /*************************************************************************/
1103
1104
1105 /* Parse flags. */
1106
1107#define _BDF_START 0x0001
1108#define _BDF_FONT_NAME 0x0002
1109#define _BDF_SIZE 0x0004
1110#define _BDF_FONT_BBX 0x0008
1111#define _BDF_PROPS 0x0010
1112#define _BDF_GLYPHS 0x0020
1113#define _BDF_GLYPH 0x0040
1114#define _BDF_ENCODING 0x0080
1115#define _BDF_SWIDTH 0x0100
1116#define _BDF_DWIDTH 0x0200
1117#define _BDF_BBX 0x0400
1118#define _BDF_BITMAP 0x0800
1119
1120#define _BDF_SWIDTH_ADJ 0x1000
1121
1122#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1123 _BDF_ENCODING | \
1124 _BDF_SWIDTH | \
1125 _BDF_DWIDTH | \
1126 _BDF_BBX | \
1127 _BDF_BITMAP )
1128
Werner Lembergf1c2b912006-01-13 14:53:28 +00001129#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1130#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001131
1132
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001133 static FT_Error
1134 _bdf_add_comment( bdf_font_t* font,
1135 char* comment,
1136 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001137 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001138 char* cp;
1139 FT_Memory memory = font->memory;
1140 FT_Error error = BDF_Err_Ok;
1141
1142
David Turner68df4f72005-03-15 18:18:57 +00001143 if ( FT_RENEW_ARRAY( font->comments,
1144 font->comments_len,
1145 font->comments_len + len + 1 ) )
1146 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001147
1148 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001149
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001150 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001151 cp[len] = '\n';
1152
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001153 font->comments_len += len + 1;
1154
1155 Exit:
1156 return error;
David Turner993a8d02002-05-18 12:03:43 +00001157 }
1158
David Turner993a8d02002-05-18 12:03:43 +00001159
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001160 /* Set the spacing from the font name if it exists, or set it to the */
1161 /* default specified in the options. */
1162 static FT_Error
1163 _bdf_set_default_spacing( bdf_font_t* font,
Werner Lemberge01406b2011-11-25 09:44:28 +01001164 bdf_options_t* opts,
1165 unsigned long lineno )
David Turner993a8d02002-05-18 12:03:43 +00001166 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001167 size_t len;
1168 char name[256];
1169 _bdf_list_t list;
1170 FT_Memory memory;
1171 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001172
David Turner993a8d02002-05-18 12:03:43 +00001173
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001174 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1175 {
1176 error = BDF_Err_Invalid_Argument;
1177 goto Exit;
1178 }
David Turner993a8d02002-05-18 12:03:43 +00001179
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001180 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001181
David Turner68df4f72005-03-15 18:18:57 +00001182 _bdf_list_init( &list, memory );
1183
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001184 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001185
suzuki toshiya704f4d72009-09-13 00:50:14 +09001186 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +00001187 /* Limit ourselves to 256 characters in the font name. */
1188 if ( len >= 256 )
1189 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001190 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
Werner Lemberga08b2172007-03-28 07:17:17 +00001191 error = BDF_Err_Invalid_Argument;
1192 goto Exit;
1193 }
1194
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001195 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001196
David Turner68df4f72005-03-15 18:18:57 +00001197 error = _bdf_list_split( &list, (char *)"-", name, len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001198 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001199 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001200
1201 if ( list.used == 15 )
1202 {
1203 switch ( list.field[11][0] )
1204 {
1205 case 'C':
1206 case 'c':
1207 font->spacing = BDF_CHARCELL;
1208 break;
1209 case 'M':
1210 case 'm':
1211 font->spacing = BDF_MONOWIDTH;
1212 break;
1213 case 'P':
1214 case 'p':
1215 font->spacing = BDF_PROPORTIONAL;
1216 break;
David Turner993a8d02002-05-18 12:03:43 +00001217 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001218 }
1219
David Turner68df4f72005-03-15 18:18:57 +00001220 Fail:
1221 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001222
1223 Exit:
1224 return error;
David Turner993a8d02002-05-18 12:03:43 +00001225 }
David Turner993a8d02002-05-18 12:03:43 +00001226
1227
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001228 /* Determine whether the property is an atom or not. If it is, then */
1229 /* clean it up so the double quotes are removed if they exist. */
1230 static int
1231 _bdf_is_atom( char* line,
1232 unsigned long linelen,
1233 char** name,
1234 char** value,
1235 bdf_font_t* font )
1236 {
1237 int hold;
1238 char *sp, *ep;
1239 bdf_property_t* p;
1240
David Turner993a8d02002-05-18 12:03:43 +00001241
1242 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001243
1244 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001245 ep++;
1246
1247 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001248 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001249 {
1250 hold = *ep;
1251 *ep = 0;
1252 }
1253
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001254 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001255
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001256 /* Restore the character that was saved before any return can happen. */
1257 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001258 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001259
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001260 /* If the property exists and is not an atom, just return here. */
1261 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001262 return 0;
1263
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001264 /* The property is an atom. Trim all leading and trailing whitespace */
1265 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001266 sp = ep;
1267 ep = line + linelen;
1268
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001269 /* Trim the leading whitespace if it exists. */
Werner Lemberg320d4972012-02-24 18:06:46 +01001270 if ( *sp )
1271 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001272 while ( *sp &&
1273 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001274 sp++;
1275
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001276 /* Trim the leading double quote if it exists. */
1277 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001278 sp++;
1279 *value = sp;
1280
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001281 /* Trim the trailing whitespace if it exists. */
1282 while ( ep > sp &&
1283 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001284 *--ep = 0;
1285
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001286 /* Trim the trailing double quote if it exists. */
1287 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001288 *--ep = 0;
1289
1290 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001291 }
David Turner993a8d02002-05-18 12:03:43 +00001292
1293
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001294 static FT_Error
Werner Lemberge01406b2011-11-25 09:44:28 +01001295 _bdf_add_property( bdf_font_t* font,
1296 char* name,
1297 char* value,
1298 unsigned long lineno )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001299 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001300 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001301 hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001302 bdf_property_t *prop, *fp;
1303 FT_Memory memory = font->memory;
1304 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001305
David Turner993a8d02002-05-18 12:03:43 +00001306
Werner Lemberg96ddc672011-06-29 09:15:54 +02001307 /* First, check whether the property already exists in the font. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001308 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001309 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001310 /* The property already exists in the font, so simply replace */
1311 /* the value of the property with the current value. */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001312 fp = font->props + hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001313
David Turnerb1b47622002-05-21 21:17:43 +00001314 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001315 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001316 case BDF_ATOM:
1317 /* Delete the current atom if it exists. */
1318 FT_FREE( fp->value.atom );
1319
David Turnerc0f9c4a2007-02-12 14:55:03 +00001320 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001321 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001322 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001323 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001324 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001325 break;
1326
1327 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001328 fp->value.l = _bdf_atol( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001329 break;
1330
1331 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001332 fp->value.ul = _bdf_atoul( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001333 break;
David Turnerd490e372002-05-28 23:40:37 +00001334
David Turnerb1b47622002-05-21 21:17:43 +00001335 default:
1336 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001337 }
David Turnerd490e372002-05-28 23:40:37 +00001338
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001339 goto Exit;
1340 }
1341
1342 /* See whether this property type exists yet or not. */
1343 /* If not, create it. */
1344 hn = hash_lookup( name, &(font->proptbl) );
1345 if ( hn == 0 )
1346 {
1347 error = bdf_create_property( name, BDF_ATOM, font );
1348 if ( error )
1349 goto Exit;
1350 hn = hash_lookup( name, &(font->proptbl) );
1351 }
1352
1353 /* Allocate another property if this is overflow. */
1354 if ( font->props_used == font->props_size )
1355 {
1356 if ( font->props_size == 0 )
1357 {
1358 if ( FT_NEW_ARRAY( font->props, 1 ) )
1359 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001360 }
1361 else
1362 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001363 if ( FT_RENEW_ARRAY( font->props,
1364 font->props_size,
1365 font->props_size + 1 ) )
1366 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001367 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001368
David Turner993a8d02002-05-18 12:03:43 +00001369 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001370 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001371 font->props_size++;
1372 }
1373
suzuki toshiya704f4d72009-09-13 00:50:14 +09001374 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001375 if ( propid >= _num_bdf_properties )
1376 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001377 else
David Turnerb1b47622002-05-21 21:17:43 +00001378 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001379
1380 fp = font->props + font->props_used;
1381
1382 fp->name = prop->name;
1383 fp->format = prop->format;
1384 fp->builtin = prop->builtin;
1385
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001386 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001387 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001388 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001389 fp->value.atom = 0;
1390 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001391 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001392 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001393 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001394 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001395 break;
David Turner993a8d02002-05-18 12:03:43 +00001396
1397 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001398 fp->value.l = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001399 break;
1400
1401 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001402 fp->value.ul = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001403 break;
David Turner993a8d02002-05-18 12:03:43 +00001404 }
1405
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001406 /* If the property happens to be a comment, then it doesn't need */
1407 /* to be added to the internal hash table. */
Werner Lemberg370aea82010-06-08 08:37:11 +02001408 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 )
1409 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001410 /* Add the property to the font property table. */
1411 error = hash_insert( fp->name,
suzuki toshiya704f4d72009-09-13 00:50:14 +09001412 font->props_used,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001413 (hashtable *)font->internal,
1414 memory );
1415 if ( error )
1416 goto Exit;
1417 }
David Turner993a8d02002-05-18 12:03:43 +00001418
1419 font->props_used++;
1420
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001421 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1422 /* property needs to be located if it exists in the property list, the */
1423 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1424 /* present, and the SPACING property should override the default */
1425 /* spacing. */
1426 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001427 font->default_char = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001428 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001429 font->font_ascent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001430 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001431 font->font_descent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001432 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001433 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001434 if ( !fp->value.atom )
1435 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001436 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lembergb66efef2009-03-12 08:07:49 +00001437 error = BDF_Err_Invalid_File_Format;
1438 goto Exit;
1439 }
1440
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001441 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001442 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001443 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001444 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001445 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001446 font->spacing = BDF_CHARCELL;
1447 }
1448
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001449 Exit:
1450 return error;
David Turner993a8d02002-05-18 12:03:43 +00001451 }
1452
David Turner993a8d02002-05-18 12:03:43 +00001453
David Turnerb1b47622002-05-21 21:17:43 +00001454 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001455 {
1456 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1457 };
1458
1459
1460 /* Actually parse the glyph info and bitmaps. */
1461 static FT_Error
1462 _bdf_parse_glyphs( char* line,
1463 unsigned long linelen,
1464 unsigned long lineno,
1465 void* call_data,
1466 void* client_data )
1467 {
1468 int c, mask_index;
1469 char* s;
1470 unsigned char* bp;
1471 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001472
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001473 _bdf_parse_t* p;
1474 bdf_glyph_t* glyph;
1475 bdf_font_t* font;
1476
1477 FT_Memory memory;
1478 FT_Error error = BDF_Err_Ok;
1479
Werner Lemberg319c00d2003-04-23 19:48:24 +00001480 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001481 FT_UNUSED( lineno ); /* only used in debug mode */
1482
1483
Werner Lemberg319c00d2003-04-23 19:48:24 +00001484 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001485
1486 font = p->font;
1487 memory = font->memory;
1488
1489 /* Check for a comment. */
1490 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1491 {
1492 linelen -= 7;
1493
1494 s = line + 7;
1495 if ( *s != 0 )
1496 {
1497 s++;
1498 linelen--;
1499 }
1500 error = _bdf_add_comment( p->font, s, linelen );
1501 goto Exit;
1502 }
1503
1504 /* The very first thing expected is the number of glyphs. */
1505 if ( !( p->flags & _BDF_GLYPHS ) )
1506 {
1507 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1508 {
1509 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1510 error = BDF_Err_Missing_Chars_Field;
1511 goto Exit;
1512 }
1513
David Turner68df4f72005-03-15 18:18:57 +00001514 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001515 if ( error )
1516 goto Exit;
1517 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1518
1519 /* Make sure the number of glyphs is non-zero. */
1520 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001521 font->glyphs_size = 64;
1522
Werner Lemberga08b2172007-03-28 07:17:17 +00001523 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1524 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001525 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001526 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001527 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberga08b2172007-03-28 07:17:17 +00001528 error = BDF_Err_Invalid_Argument;
1529 goto Exit;
1530 }
1531
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001532 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1533 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001534
David Turner993a8d02002-05-18 12:03:43 +00001535 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001536
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001537 goto Exit;
1538 }
1539
1540 /* Check for the ENDFONT field. */
1541 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1542 {
1543 /* Sort the glyphs by encoding. */
1544 ft_qsort( (char *)font->glyphs,
1545 font->glyphs_used,
1546 sizeof ( bdf_glyph_t ),
1547 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001548
1549 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001550
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001551 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001552 }
1553
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001554 /* Check for the ENDCHAR field. */
1555 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1556 {
1557 p->glyph_enc = 0;
1558 p->flags &= ~_BDF_GLYPH_BITS;
1559
1560 goto Exit;
1561 }
1562
Werner Lemberg96ddc672011-06-29 09:15:54 +02001563 /* Check whether a glyph is being scanned but should be */
1564 /* ignored because it is an unencoded glyph. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001565 if ( ( p->flags & _BDF_GLYPH ) &&
1566 p->glyph_enc == -1 &&
1567 p->opts->keep_unencoded == 0 )
1568 goto Exit;
1569
1570 /* Check for the STARTCHAR field. */
1571 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1572 {
1573 /* Set the character name in the parse info first until the */
1574 /* encoding can be checked for an unencoded character. */
1575 FT_FREE( p->glyph_name );
1576
David Turner68df4f72005-03-15 18:18:57 +00001577 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001578 if ( error )
1579 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001580
David Turner68df4f72005-03-15 18:18:57 +00001581 _bdf_list_shift( &p->list, 1 );
1582
1583 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001584
Werner Lembergba03af62007-05-30 13:57:02 +00001585 if ( !s )
1586 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001587 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lembergba03af62007-05-30 13:57:02 +00001588 error = BDF_Err_Invalid_File_Format;
1589 goto Exit;
1590 }
1591
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001592 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1593 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001594
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001595 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1596
1597 p->flags |= _BDF_GLYPH;
1598
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001599 FT_TRACE4(( DBGMSG1, lineno, s ));
1600
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001601 goto Exit;
1602 }
1603
1604 /* Check for the ENCODING field. */
1605 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1606 {
1607 if ( !( p->flags & _BDF_GLYPH ) )
1608 {
1609 /* Missing STARTCHAR field. */
1610 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1611 error = BDF_Err_Missing_Startchar_Field;
1612 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001613 }
1614
David Turner68df4f72005-03-15 18:18:57 +00001615 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001616 if ( error )
1617 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001618
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001619 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001620
Werner Lemberg28dd2c42012-02-26 06:18:58 +01001621 /* Normalize negative encoding values. The specification only */
1622 /* allows -1, but we can be more generous here. */
1623 if ( p->glyph_enc < -1 )
1624 p->glyph_enc = -1;
1625
Werner Lemberg03242f52012-02-26 06:52:56 +01001626 /* Check for alternative encoding format. */
1627 if ( p->glyph_enc == -1 && p->list.used > 2 )
1628 p->glyph_enc = _bdf_atol( p->list.field[2], 0, 10 );
1629
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001630 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1631
Werner Lemberged54e432011-11-27 16:39:53 +01001632 /* Check that the encoding is in the Unicode range because */
1633 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lemberg96ddc672011-06-29 09:15:54 +02001634 if ( p->glyph_enc > 0 &&
1635 (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
David Turner481838e2006-02-23 12:40:14 +00001636 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001637 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
David Turner481838e2006-02-23 12:40:14 +00001638 error = BDF_Err_Invalid_File_Format;
1639 goto Exit;
1640 }
1641
Werner Lemberg96ddc672011-06-29 09:15:54 +02001642 /* Check whether this encoding has already been encountered. */
1643 /* If it has then change it to unencoded so it gets added if */
1644 /* indicated. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001645 if ( p->glyph_enc >= 0 )
1646 {
1647 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1648 {
1649 /* Emit a message saying a glyph has been moved to the */
1650 /* unencoded area. */
1651 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1652 p->glyph_enc, p->glyph_name ));
1653 p->glyph_enc = -1;
1654 font->modified = 1;
1655 }
1656 else
1657 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1658 }
1659
1660 if ( p->glyph_enc >= 0 )
1661 {
1662 /* Make sure there are enough glyphs allocated in case the */
1663 /* number of characters happen to be wrong. */
1664 if ( font->glyphs_used == font->glyphs_size )
1665 {
1666 if ( FT_RENEW_ARRAY( font->glyphs,
1667 font->glyphs_size,
1668 font->glyphs_size + 64 ) )
1669 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001670
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001671 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001672 }
1673
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001674 glyph = font->glyphs + font->glyphs_used++;
1675 glyph->name = p->glyph_name;
1676 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001677
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001678 /* Reset the initial glyph info. */
1679 p->glyph_name = 0;
1680 }
1681 else
1682 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001683 /* Unencoded glyph. Check whether it should */
1684 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001685 if ( p->opts->keep_unencoded != 0 )
1686 {
1687 /* Allocate the next unencoded glyph. */
1688 if ( font->unencoded_used == font->unencoded_size )
1689 {
David Turner68df4f72005-03-15 18:18:57 +00001690 if ( FT_RENEW_ARRAY( font->unencoded ,
1691 font->unencoded_size,
1692 font->unencoded_size + 4 ) )
1693 goto Exit;
1694
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001695 font->unencoded_size += 4;
1696 }
1697
1698 glyph = font->unencoded + font->unencoded_used;
1699 glyph->name = p->glyph_name;
1700 glyph->encoding = font->unencoded_used++;
1701 }
1702 else
1703 /* Free up the glyph name if the unencoded shouldn't be */
1704 /* kept. */
1705 FT_FREE( p->glyph_name );
1706
1707 p->glyph_name = 0;
1708 }
1709
1710 /* Clear the flags that might be added when width and height are */
1711 /* checked for consistency. */
1712 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1713
1714 p->flags |= _BDF_ENCODING;
1715
1716 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001717 }
1718
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001719 /* Point at the glyph being constructed. */
1720 if ( p->glyph_enc == -1 )
1721 glyph = font->unencoded + ( font->unencoded_used - 1 );
1722 else
1723 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001724
Werner Lemberg96ddc672011-06-29 09:15:54 +02001725 /* Check whether a bitmap is being constructed. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001726 if ( p->flags & _BDF_BITMAP )
1727 {
1728 /* If there are more rows than are specified in the glyph metrics, */
1729 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001730 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001731 {
1732 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1733 {
1734 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1735 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001736 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001737 }
1738
1739 goto Exit;
1740 }
1741
1742 /* Only collect the number of nibbles indicated by the glyph */
1743 /* metrics. If there are more columns, they are simply ignored. */
1744 nibbles = glyph->bpr << 1;
1745 bp = glyph->bitmap + p->row * glyph->bpr;
1746
David Turnerb698eed2006-02-23 14:50:13 +00001747 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001748 {
1749 c = line[i];
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001750 if ( !isdigok( hdigits, c ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001751 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001752 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001753 if ( i + 1 < nibbles && ( i & 1 ) )
1754 *++bp = 0;
1755 }
1756
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001757 /* If any line has not enough columns, */
1758 /* indicate they have been padded with zero bits. */
1759 if ( i < nibbles &&
1760 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1761 {
1762 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
1763 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1764 font->modified = 1;
1765 }
1766
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001767 /* Remove possible garbage at the right. */
1768 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001769 if ( glyph->bbx.width )
1770 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001771
1772 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001773 if ( i == nibbles &&
1774 isdigok( hdigits, line[nibbles] ) &&
1775 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001776 {
1777 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1778 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1779 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001780 }
1781
1782 p->row++;
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 SWIDTH (scalable width) field next. */
1787 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1788 {
1789 if ( !( p->flags & _BDF_ENCODING ) )
Werner Lemberg4086fb72012-03-01 08:55:40 +01001790 goto Missing_Encoding;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001791
David Turner68df4f72005-03-15 18:18:57 +00001792 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001793 if ( error )
1794 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001795
David Turnerb1b47622002-05-21 21:17:43 +00001796 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001797 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001798
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001799 goto Exit;
1800 }
David Turner993a8d02002-05-18 12:03:43 +00001801
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001802 /* Expect the DWIDTH (scalable width) field next. */
1803 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1804 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001805 if ( !( p->flags & _BDF_ENCODING ) )
1806 goto Missing_Encoding;
1807
David Turner68df4f72005-03-15 18:18:57 +00001808 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001809 if ( error )
1810 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001811
David Turnerb1b47622002-05-21 21:17:43 +00001812 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001813
1814 if ( !( p->flags & _BDF_SWIDTH ) )
1815 {
1816 /* Missing SWIDTH field. Emit an auto correction message and set */
1817 /* the scalable width from the device width. */
1818 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1819
Werner Lemberg02d4d592002-05-28 22:38:05 +00001820 glyph->swidth = (unsigned short)FT_MulDiv(
1821 glyph->dwidth, 72000L,
1822 (FT_Long)( font->point_size *
1823 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001824 }
1825
1826 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001827 goto Exit;
1828 }
David Turner993a8d02002-05-18 12:03:43 +00001829
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001830 /* Expect the BBX field next. */
1831 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1832 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001833 if ( !( p->flags & _BDF_ENCODING ) )
1834 goto Missing_Encoding;
1835
David Turner68df4f72005-03-15 18:18:57 +00001836 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001837 if ( error )
1838 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001839
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001840 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1841 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1842 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1843 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1844
1845 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001846 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1847 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001848
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001849 /* Determine the overall font bounding box as the characters are */
1850 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001851 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1852 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001853
David Turnerb1b47622002-05-21 21:17:43 +00001854 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001855
Werner Lembergdfa46192004-03-05 09:26:24 +00001856 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1857 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1858 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001859
1860 if ( !( p->flags & _BDF_DWIDTH ) )
1861 {
1862 /* Missing DWIDTH field. Emit an auto correction message and set */
1863 /* the device width to the glyph width. */
1864 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1865 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001866 }
1867
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001868 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1869 /* value if necessary. */
1870 if ( p->opts->correct_metrics != 0 )
1871 {
1872 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001873 unsigned short sw = (unsigned short)FT_MulDiv(
1874 glyph->dwidth, 72000L,
1875 (FT_Long)( font->point_size *
1876 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001877
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001878
1879 if ( sw != glyph->swidth )
1880 {
1881 glyph->swidth = sw;
1882
1883 if ( p->glyph_enc == -1 )
1884 _bdf_set_glyph_modified( font->umod,
1885 font->unencoded_used - 1 );
1886 else
1887 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1888
1889 p->flags |= _BDF_SWIDTH_ADJ;
1890 font->modified = 1;
1891 }
David Turner993a8d02002-05-18 12:03:43 +00001892 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001893
David Turner993a8d02002-05-18 12:03:43 +00001894 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001895 goto Exit;
1896 }
David Turner993a8d02002-05-18 12:03:43 +00001897
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001898 /* And finally, gather up the bitmap. */
1899 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1900 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001901 unsigned long bitmap_size;
1902
1903
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001904 if ( !( p->flags & _BDF_BBX ) )
1905 {
1906 /* Missing BBX field. */
1907 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1908 error = BDF_Err_Missing_Bbx_Field;
1909 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001910 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001911
1912 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001913 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001914
1915 bitmap_size = glyph->bpr * glyph->bbx.height;
Werner Lembergc4cad302012-03-08 20:11:37 +01001916 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
Werner Lemberg26170df2006-03-26 07:19:07 +00001917 {
1918 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1919 error = BDF_Err_Bbx_Too_Big;
1920 goto Exit;
1921 }
1922 else
1923 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001924
1925 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1926 goto Exit;
1927
1928 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001929 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001930
1931 goto Exit;
1932 }
1933
Werner Lemberge01406b2011-11-25 09:44:28 +01001934 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001935 error = BDF_Err_Invalid_File_Format;
Werner Lemberg4086fb72012-03-01 08:55:40 +01001936 goto Exit;
1937
1938 Missing_Encoding:
1939 /* Missing ENCODING field. */
1940 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1941 error = BDF_Err_Missing_Encoding_Field;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001942
1943 Exit:
Werner Lembergf4c94d42010-06-19 16:08:31 +02001944 if ( error && ( p->flags & _BDF_GLYPH ) )
1945 FT_FREE( p->glyph_name );
1946
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001947 return error;
David Turner993a8d02002-05-18 12:03:43 +00001948 }
1949
David Turner993a8d02002-05-18 12:03:43 +00001950
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001951 /* Load the font properties. */
1952 static FT_Error
1953 _bdf_parse_properties( char* line,
1954 unsigned long linelen,
1955 unsigned long lineno,
1956 void* call_data,
1957 void* client_data )
1958 {
1959 unsigned long vlen;
1960 _bdf_line_func_t* next;
1961 _bdf_parse_t* p;
1962 char* name;
1963 char* value;
1964 char nbuf[128];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001965 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001966
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001967 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001968
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001969
1970 next = (_bdf_line_func_t *)call_data;
1971 p = (_bdf_parse_t *) client_data;
1972
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001973 /* Check for the end of the properties. */
1974 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1975 {
1976 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1977 /* encountered yet, then make sure they are added as properties and */
1978 /* make sure they are set from the font bounding box info. */
1979 /* */
1980 /* This is *always* done regardless of the options, because X11 */
1981 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001982 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001983 {
1984 p->font->font_ascent = p->font->bbx.ascent;
1985 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001986 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
1987 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001988 if ( error )
1989 goto Exit;
1990
1991 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1992 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001993 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001994
Werner Lemberg428c2e42003-04-25 05:35:04 +00001995 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001996 {
1997 p->font->font_descent = p->font->bbx.descent;
1998 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001999 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2000 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002001 if ( error )
2002 goto Exit;
2003
2004 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2005 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002006 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002007
David Turner993a8d02002-05-18 12:03:43 +00002008 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002009 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00002010
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002011 goto Exit;
2012 }
David Turner993a8d02002-05-18 12:03:43 +00002013
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002014 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
2015 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
2016 goto Exit;
2017
2018 /* Handle COMMENT fields and properties in a special way to preserve */
2019 /* the spacing. */
2020 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2021 {
David Turner993a8d02002-05-18 12:03:43 +00002022 name = value = line;
2023 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002024 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00002025 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01002026 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002027 if ( error )
2028 goto Exit;
2029 }
2030 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
2031 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002032 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002033 if ( error )
2034 goto Exit;
2035 }
2036 else
2037 {
David Turner68df4f72005-03-15 18:18:57 +00002038 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002039 if ( error )
2040 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002041 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002042
David Turner68df4f72005-03-15 18:18:57 +00002043 _bdf_list_shift( &p->list, 1 );
2044 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002045
Werner Lemberge01406b2011-11-25 09:44:28 +01002046 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002047 if ( error )
2048 goto Exit;
2049 }
2050
2051 Exit:
2052 return error;
David Turner993a8d02002-05-18 12:03:43 +00002053 }
2054
David Turner993a8d02002-05-18 12:03:43 +00002055
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002056 /* Load the font header. */
2057 static FT_Error
2058 _bdf_parse_start( char* line,
2059 unsigned long linelen,
2060 unsigned long lineno,
2061 void* call_data,
2062 void* client_data )
2063 {
2064 unsigned long slen;
2065 _bdf_line_func_t* next;
2066 _bdf_parse_t* p;
2067 bdf_font_t* font;
2068 char *s;
David Turner993a8d02002-05-18 12:03:43 +00002069
David Turnerd490e372002-05-28 23:40:37 +00002070 FT_Memory memory = NULL;
2071 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002072
2073 FT_UNUSED( lineno ); /* only used in debug mode */
2074
2075
2076 next = (_bdf_line_func_t *)call_data;
2077 p = (_bdf_parse_t *) client_data;
2078
2079 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00002080 memory = p->font->memory;
2081
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002082 /* Check for a comment. This is done to handle those fonts that have */
2083 /* comments before the STARTFONT line for some reason. */
2084 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2085 {
2086 if ( p->opts->keep_comments != 0 && p->font != 0 )
2087 {
2088 linelen -= 7;
2089
2090 s = line + 7;
2091 if ( *s != 0 )
2092 {
2093 s++;
2094 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002095 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002096
2097 error = _bdf_add_comment( p->font, s, linelen );
2098 if ( error )
2099 goto Exit;
2100 /* here font is not defined! */
2101 }
2102
2103 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002104 }
2105
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002106 if ( !( p->flags & _BDF_START ) )
2107 {
2108 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002109
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002110 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2111 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01002112 /* we don't emit an error message since this code gets */
2113 /* explicitly caught one level higher */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002114 error = BDF_Err_Missing_Startfont_Field;
2115 goto Exit;
2116 }
David Turner993a8d02002-05-18 12:03:43 +00002117
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002118 p->flags = _BDF_START;
2119 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002120
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002121 if ( FT_NEW( font ) )
2122 goto Exit;
2123 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002124
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002125 font->memory = p->memory;
2126 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002127
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002128 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09002129 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002130 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002131
David Turner993a8d02002-05-18 12:03:43 +00002132
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002133 error = hash_init( &(font->proptbl), memory );
2134 if ( error )
2135 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002136 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002137 i < _num_bdf_properties; i++, prop++ )
2138 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09002139 error = hash_insert( prop->name, i,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002140 &(font->proptbl), memory );
2141 if ( error )
2142 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002143 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002144 }
2145
2146 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2147 goto Exit;
2148 error = hash_init( (hashtable *)p->font->internal,memory );
2149 if ( error )
2150 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002151 p->font->spacing = p->opts->font_spacing;
2152 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002153
2154 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002155 }
2156
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002157 /* Check for the start of the properties. */
2158 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2159 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002160 if ( !( p->flags & _BDF_FONT_BBX ) )
Werner Lembergfb690292010-06-23 10:00:52 +02002161 {
2162 /* Missing the FONTBOUNDINGBOX field. */
2163 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2164 error = BDF_Err_Missing_Fontboundingbox_Field;
2165 goto Exit;
2166 }
2167
David Turner68df4f72005-03-15 18:18:57 +00002168 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002169 if ( error )
2170 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00002171 /* at this point, `p->font' can't be NULL */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002172 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2173
2174 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2175 goto Exit;
2176
2177 p->flags |= _BDF_PROPS;
2178 *next = _bdf_parse_properties;
2179
2180 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002181 }
2182
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002183 /* Check for the FONTBOUNDINGBOX field. */
2184 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2185 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002186 if ( !( p->flags & _BDF_SIZE ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002187 {
2188 /* Missing the SIZE field. */
2189 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2190 error = BDF_Err_Missing_Size_Field;
2191 goto Exit;
2192 }
2193
David Turner68df4f72005-03-15 18:18:57 +00002194 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002195 if ( error )
2196 goto Exit;
2197
2198 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2199 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2200
2201 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2202 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2203
David Turnerd490e372002-05-28 23:40:37 +00002204 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002205 p->font->bbx.y_offset );
2206
2207 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002208
2209 p->flags |= _BDF_FONT_BBX;
2210
2211 goto Exit;
2212 }
2213
2214 /* The next thing to check for is the FONT field. */
2215 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2216 {
David Turner68df4f72005-03-15 18:18:57 +00002217 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002218 if ( error )
2219 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002220 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002221
David Turner68df4f72005-03-15 18:18:57 +00002222 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002223
2224 if ( !s )
2225 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002226 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg5b591e42007-06-01 22:16:43 +00002227 error = BDF_Err_Invalid_File_Format;
2228 goto Exit;
2229 }
2230
Werner Lembergfb690292010-06-23 10:00:52 +02002231 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2232 FT_FREE( p->font->name );
2233
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002234 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2235 goto Exit;
2236 FT_MEM_COPY( p->font->name, s, slen + 1 );
2237
2238 /* If the font name is an XLFD name, set the spacing to the one in */
2239 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002240 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002241 if ( error )
2242 goto Exit;
2243
2244 p->flags |= _BDF_FONT_NAME;
2245
2246 goto Exit;
2247 }
2248
2249 /* Check for the SIZE field. */
2250 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2251 {
2252 if ( !( p->flags & _BDF_FONT_NAME ) )
2253 {
2254 /* Missing the FONT field. */
2255 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2256 error = BDF_Err_Missing_Font_Field;
2257 goto Exit;
2258 }
2259
David Turner68df4f72005-03-15 18:18:57 +00002260 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002261 if ( error )
2262 goto Exit;
2263
2264 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2265 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2266 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2267
2268 /* Check for the bits per pixel field. */
2269 if ( p->list.used == 5 )
2270 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002271 unsigned short bitcount, i, shift;
2272
2273
2274 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2275
2276 /* Only values 1, 2, 4, 8 are allowed. */
2277 shift = p->font->bpp;
2278 bitcount = 0;
2279 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002280 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002281 if ( shift & 1 )
2282 bitcount = i;
2283 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002284 }
David Turner993a8d02002-05-18 12:03:43 +00002285
Werner Lembergbd8e3242002-06-12 08:43:58 +00002286 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002287
2288 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002289 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002290 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002291 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002292 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002293 }
2294 }
2295 else
2296 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002297
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002298 p->flags |= _BDF_SIZE;
2299
2300 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002301 }
2302
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002303 /* Check for the CHARS field -- font properties are optional */
2304 if ( ft_memcmp( line, "CHARS", 5 ) == 0 )
2305 {
2306 char nbuf[128];
2307
2308
2309 if ( !( p->flags & _BDF_FONT_BBX ) )
2310 {
2311 /* Missing the FONTBOUNDINGBOX field. */
2312 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2313 error = BDF_Err_Missing_Fontboundingbox_Field;
2314 goto Exit;
2315 }
2316
2317 /* Add the two standard X11 properties which are required */
2318 /* for compiling fonts. */
2319 p->font->font_ascent = p->font->bbx.ascent;
2320 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002321 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2322 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002323 if ( error )
2324 goto Exit;
2325 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2326
2327 p->font->font_descent = p->font->bbx.descent;
2328 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002329 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2330 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002331 if ( error )
2332 goto Exit;
2333 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2334
2335 p->font->modified = 1;
2336
2337 *next = _bdf_parse_glyphs;
2338
2339 /* A special return value. */
2340 error = -1;
2341 goto Exit;
2342 }
2343
Werner Lemberge01406b2011-11-25 09:44:28 +01002344 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002345 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002346
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002347 Exit:
2348 return error;
2349 }
David Turner993a8d02002-05-18 12:03:43 +00002350
2351
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002352 /*************************************************************************/
2353 /* */
2354 /* API. */
2355 /* */
2356 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002357
David Turner993a8d02002-05-18 12:03:43 +00002358
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002359 FT_LOCAL_DEF( FT_Error )
2360 bdf_load_font( FT_Stream stream,
2361 FT_Memory extmemory,
2362 bdf_options_t* opts,
2363 bdf_font_t* *font )
2364 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002365 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002366 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002367
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002368 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002369 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002370
2371
David Turner68df4f72005-03-15 18:18:57 +00002372 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002373 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002374
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002375 memory = NULL;
2376 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2377 p->minlb = 32767;
2378 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002379
David Turner68df4f72005-03-15 18:18:57 +00002380 _bdf_list_init( &p->list, extmemory );
2381
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002382 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002383 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002384 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002385 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002386
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002387 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002388 {
2389 /* If the font is not proportional, set the font's monowidth */
2390 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002391 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002392
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002393 if ( p->font->spacing != BDF_PROPORTIONAL )
2394 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002395
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002396 /* If the number of glyphs loaded is not that of the original count, */
2397 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002398 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002399 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002400 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2401 p->font->glyphs_used + p->font->unencoded_used ));
2402 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002403 }
2404
2405 /* Once the font has been loaded, adjust the overall font metrics if */
2406 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002407 if ( p->opts->correct_metrics != 0 &&
2408 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002409 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002410 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002411 {
2412 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002413 p->font->bbx.width, p->maxrb - p->minlb ));
2414 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2415 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002416 }
2417
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002418 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002419 {
2420 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002421 p->font->bbx.x_offset, p->minlb ));
2422 p->font->bbx.x_offset = p->minlb;
2423 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002424 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002425
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002426 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002427 {
2428 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002429 p->font->bbx.ascent, p->maxas ));
2430 p->font->bbx.ascent = p->maxas;
2431 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002432 }
2433
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002434 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002435 {
2436 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002437 p->font->bbx.descent, p->maxds ));
2438 p->font->bbx.descent = p->maxds;
2439 p->font->bbx.y_offset = (short)( -p->maxds );
2440 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002441 }
2442
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002443 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002444 {
2445 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002446 p->font->bbx.height, p->maxas + p->maxds ));
2447 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002448 }
2449
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002450 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002451 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2452 }
David Turner993a8d02002-05-18 12:03:43 +00002453 }
2454
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002455 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002456 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002457 /* The ENDFONT field was never reached or did not exist. */
2458 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002459 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002460 /* Error happened while parsing header. */
2461 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2462 error = BDF_Err_Corrupted_Font_Header;
2463 goto Exit;
2464 }
2465 else
2466 {
2467 /* Error happened when parsing glyphs. */
2468 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2469 error = BDF_Err_Corrupted_Font_Glyphs;
2470 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002471 }
David Turner993a8d02002-05-18 12:03:43 +00002472 }
2473
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002474 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002475 {
2476 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002477 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002478
Werner Lemberg370aea82010-06-08 08:37:11 +02002479 if ( p->font->comments_len > 0 )
2480 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002481 if ( FT_RENEW_ARRAY( p->font->comments,
2482 p->font->comments_len,
2483 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002484 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002485
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002486 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002487 }
David Turner993a8d02002-05-18 12:03:43 +00002488 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002489 else if ( error == BDF_Err_Ok )
2490 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002491
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002492 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002493
2494 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002495 if ( p )
2496 {
David Turner68df4f72005-03-15 18:18:57 +00002497 _bdf_list_done( &p->list );
2498
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002499 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002500
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002501 FT_FREE( p );
2502 }
2503
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002504 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002505
2506 Fail:
2507 bdf_free_font( p->font );
2508
2509 memory = extmemory;
2510
2511 FT_FREE( p->font );
2512
2513 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002514 }
David Turner993a8d02002-05-18 12:03:43 +00002515
2516
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002517 FT_LOCAL_DEF( void )
2518 bdf_free_font( bdf_font_t* font )
2519 {
2520 bdf_property_t* prop;
2521 unsigned long i;
2522 bdf_glyph_t* glyphs;
2523 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002524
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002525
2526 if ( font == 0 )
2527 return;
David Turner993a8d02002-05-18 12:03:43 +00002528
2529 memory = font->memory;
2530
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002531 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002532
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002533 /* Free up the internal hash table of property names. */
2534 if ( font->internal )
2535 {
2536 hash_free( (hashtable *)font->internal, memory );
2537 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002538 }
2539
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002540 /* Free up the comment info. */
2541 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002542
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002543 /* Free up the properties. */
2544 for ( i = 0; i < font->props_size; i++ )
2545 {
2546 if ( font->props[i].format == BDF_ATOM )
2547 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002548 }
2549
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002550 FT_FREE( font->props );
2551
2552 /* Free up the character info. */
2553 for ( i = 0, glyphs = font->glyphs;
2554 i < font->glyphs_used; i++, glyphs++ )
2555 {
2556 FT_FREE( glyphs->name );
2557 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002558 }
2559
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002560 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2561 i++, glyphs++ )
2562 {
2563 FT_FREE( glyphs->name );
2564 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002565 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002566
2567 FT_FREE( font->glyphs );
2568 FT_FREE( font->unencoded );
2569
2570 /* Free up the overflow storage if it was used. */
2571 for ( i = 0, glyphs = font->overflow.glyphs;
2572 i < font->overflow.glyphs_used; i++, glyphs++ )
2573 {
2574 FT_FREE( glyphs->name );
2575 FT_FREE( glyphs->bitmap );
2576 }
2577
2578 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002579
2580 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002581 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002582
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002583 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002584 for ( prop = font->user_props, i = 0;
2585 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002586 {
2587 FT_FREE( prop->name );
2588 if ( prop->format == BDF_ATOM )
2589 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002590 }
David Turner993a8d02002-05-18 12:03:43 +00002591
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002592 FT_FREE( font->user_props );
2593
2594 /* FREE( font ); */ /* XXX Fixme */
2595 }
David Turner993a8d02002-05-18 12:03:43 +00002596
2597
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002598 FT_LOCAL_DEF( bdf_property_t * )
2599 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002600 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002601 {
2602 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002603
David Turner993a8d02002-05-18 12:03:43 +00002604
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002605 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002606 return 0;
2607
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002608 hn = hash_lookup( name, (hashtable *)font->internal );
2609
suzuki toshiya704f4d72009-09-13 00:50:14 +09002610 return hn ? ( font->props + hn->data ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002611 }
2612
2613
2614/* END */