blob: 37ffc1ee3a0d17947e22566073dbbe1bdbf307cd [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"
191
192 /* Error messages. */
193#define ERRMSG1 "[line %ld] Missing `%s' line.\n"
194#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
195#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
196#define ERRMSG4 "[line %ld] BBX too big.\n"
197#define ERRMSG5 "[line %ld] `%s' value too big.\n"
198#define ERRMSG6 "[line %ld] Input line too long.\n"
199#define ERRMSG7 "[line %ld] Font name too long.\n"
200#define ERRMSG8 "[line %ld] Invalid `%s' value.\n"
201#define ERRMSG9 "[line %ld] Invalid keyword.\n"
202
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +0100203 /* Debug messages. */
204#define DBGMSG1 " [%6ld] %s" /* no \n */
205#define DBGMSG2 " (0x%lX)\n"
206
Werner Lemberge01406b2011-11-25 09:44:28 +0100207
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000208 /*************************************************************************/
209 /* */
210 /* Hash table utilities for the properties. */
211 /* */
212 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +0000213
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000214 /* XXX: Replace this with FreeType's hash functions */
David Turner993a8d02002-05-18 12:03:43 +0000215
David Turner993a8d02002-05-18 12:03:43 +0000216
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000217#define INITIAL_HT_SIZE 241
218
219 typedef void
220 (*hash_free_func)( hashnode node );
221
222 static hashnode*
Werner Lemberg428c2e42003-04-25 05:35:04 +0000223 hash_bucket( const char* key,
224 hashtable* ht )
David Turner993a8d02002-05-18 12:03:43 +0000225 {
Werner Lemberg428c2e42003-04-25 05:35:04 +0000226 const char* kp = key;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000227 unsigned long res = 0;
228 hashnode* bp = ht->table, *ndp;
229
230
231 /* Mocklisp hash function. */
232 while ( *kp )
233 res = ( res << 5 ) - res + *kp++;
234
235 ndp = bp + ( res % ht->size );
236 while ( *ndp )
David Turner993a8d02002-05-18 12:03:43 +0000237 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000238 kp = (*ndp)->key;
239 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
240 break;
241 ndp--;
242 if ( ndp < bp )
243 ndp = bp + ( ht->size - 1 );
David Turner993a8d02002-05-18 12:03:43 +0000244 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000245
246 return ndp;
David Turner993a8d02002-05-18 12:03:43 +0000247 }
David Turner993a8d02002-05-18 12:03:43 +0000248
249
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000250 static FT_Error
251 hash_rehash( hashtable* ht,
252 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000253 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000254 hashnode* obp = ht->table, *bp, *nbp;
David Turner993a8d02002-05-18 12:03:43 +0000255 int i, sz = ht->size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000256 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000257
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000258
259 ht->size <<= 1;
260 ht->limit = ht->size / 3;
261
262 if ( FT_NEW_ARRAY( ht->table, ht->size ) )
263 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000264
265 for ( i = 0, bp = obp; i < sz; i++, bp++ )
David Turner993a8d02002-05-18 12:03:43 +0000266 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000267 if ( *bp )
268 {
269 nbp = hash_bucket( (*bp)->key, ht );
270 *nbp = *bp;
271 }
David Turner993a8d02002-05-18 12:03:43 +0000272 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000273 FT_FREE( obp );
274
275 Exit:
276 return error;
David Turner993a8d02002-05-18 12:03:43 +0000277 }
David Turner993a8d02002-05-18 12:03:43 +0000278
279
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000280 static FT_Error
281 hash_init( hashtable* ht,
282 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000283 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000284 int sz = INITIAL_HT_SIZE;
285 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000286
David Turner993a8d02002-05-18 12:03:43 +0000287
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000288 ht->size = sz;
289 ht->limit = sz / 3;
290 ht->used = 0;
David Turner993a8d02002-05-18 12:03:43 +0000291
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000292 if ( FT_NEW_ARRAY( ht->table, sz ) )
293 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000294
295 Exit:
296 return error;
David Turner993a8d02002-05-18 12:03:43 +0000297 }
David Turner993a8d02002-05-18 12:03:43 +0000298
299
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000300 static void
301 hash_free( hashtable* ht,
302 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000303 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000304 if ( ht != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000305 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000306 int i, sz = ht->size;
307 hashnode* bp = ht->table;
David Turner993a8d02002-05-18 12:03:43 +0000308
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000309
310 for ( i = 0; i < sz; i++, bp++ )
311 FT_FREE( *bp );
312
313 FT_FREE( ht->table );
314 }
David Turner993a8d02002-05-18 12:03:43 +0000315 }
316
David Turner993a8d02002-05-18 12:03:43 +0000317
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000318 static FT_Error
319 hash_insert( char* key,
suzuki toshiya704f4d72009-09-13 00:50:14 +0900320 size_t data,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000321 hashtable* ht,
322 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000323 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000324 hashnode nn, *bp = hash_bucket( key, ht );
325 FT_Error error = BDF_Err_Ok;
326
327
328 nn = *bp;
329 if ( !nn )
330 {
331 if ( FT_NEW( nn ) )
332 goto Exit;
333 *bp = nn;
334
335 nn->key = key;
336 nn->data = data;
337
338 if ( ht->used >= ht->limit )
339 {
340 error = hash_rehash( ht, memory );
341 if ( error )
342 goto Exit;
343 }
344 ht->used++;
345 }
David Turner993a8d02002-05-18 12:03:43 +0000346 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000347 nn->data = data;
348
349 Exit:
350 return error;
David Turner993a8d02002-05-18 12:03:43 +0000351 }
352
David Turner993a8d02002-05-18 12:03:43 +0000353
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000354 static hashnode
Werner Lemberg428c2e42003-04-25 05:35:04 +0000355 hash_lookup( const char* key,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000356 hashtable* ht )
357 {
358 hashnode *np = hash_bucket( key, ht );
359
360
361 return *np;
362 }
363
364
365 /*************************************************************************/
366 /* */
367 /* Utility types and functions. */
368 /* */
369 /*************************************************************************/
370
371
372 /* Function type for parsing lines of a BDF font. */
373
374 typedef FT_Error
375 (*_bdf_line_func_t)( char* line,
376 unsigned long linelen,
377 unsigned long lineno,
378 void* call_data,
379 void* client_data );
380
381
382 /* List structure for splitting lines into fields. */
383
384 typedef struct _bdf_list_t_
385 {
386 char** field;
387 unsigned long size;
388 unsigned long used;
David Turner68df4f72005-03-15 18:18:57 +0000389 FT_Memory memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000390
391 } _bdf_list_t;
392
393
394 /* Structure used while loading BDF fonts. */
395
396 typedef struct _bdf_parse_t_
397 {
398 unsigned long flags;
399 unsigned long cnt;
400 unsigned long row;
401
402 short minlb;
403 short maxlb;
404 short maxrb;
405 short maxas;
406 short maxds;
407
408 short rbearing;
409
410 char* glyph_name;
411 long glyph_enc;
412
413 bdf_font_t* font;
414 bdf_options_t* opts;
415
Werner Lemberged54e432011-11-27 16:39:53 +0100416 unsigned long have[34816]; /* must be in sync with `nmod' and `umod' */
417 /* arrays from `bdf_font_t' structure */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000418 _bdf_list_t list;
419
420 FT_Memory memory;
421
422 } _bdf_parse_t;
423
424
Werner Lemberga08b2172007-03-28 07:17:17 +0000425#define setsbit( m, cc ) \
426 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
427#define sbitset( m, cc ) \
428 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000429
430
David Turner68df4f72005-03-15 18:18:57 +0000431 static void
432 _bdf_list_init( _bdf_list_t* list,
433 FT_Memory memory )
434 {
Werner Lembergebf55852005-03-16 01:49:54 +0000435 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000436 list->memory = memory;
437 }
438
Werner Lembergebf55852005-03-16 01:49:54 +0000439
David Turner68df4f72005-03-15 18:18:57 +0000440 static void
441 _bdf_list_done( _bdf_list_t* list )
442 {
443 FT_Memory memory = list->memory;
444
Werner Lembergebf55852005-03-16 01:49:54 +0000445
David Turner68df4f72005-03-15 18:18:57 +0000446 if ( memory )
447 {
448 FT_FREE( list->field );
Werner Lembergebf55852005-03-16 01:49:54 +0000449 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000450 }
451 }
452
453
454 static FT_Error
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900455 _bdf_list_ensure( _bdf_list_t* list,
456 unsigned long num_items ) /* same as _bdf_list_t.used */
David Turner68df4f72005-03-15 18:18:57 +0000457 {
Werner Lembergebf55852005-03-16 01:49:54 +0000458 FT_Error error = BDF_Err_Ok;
459
David Turner68df4f72005-03-15 18:18:57 +0000460
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900461 if ( num_items > list->size )
David Turner68df4f72005-03-15 18:18:57 +0000462 {
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900463 unsigned long oldsize = list->size; /* same as _bdf_list_t.size */
464 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 4;
465 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
466 FT_Memory memory = list->memory;
David Turner68df4f72005-03-15 18:18:57 +0000467
Werner Lembergebf55852005-03-16 01:49:54 +0000468
David Turner68df4f72005-03-15 18:18:57 +0000469 if ( oldsize == bigsize )
470 {
Werner Lembergebf55852005-03-16 01:49:54 +0000471 error = BDF_Err_Out_Of_Memory;
David Turner68df4f72005-03-15 18:18:57 +0000472 goto Exit;
473 }
474 else if ( newsize < oldsize || newsize > bigsize )
475 newsize = bigsize;
476
477 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
478 goto Exit;
479
480 list->size = newsize;
481 }
Werner Lembergebf55852005-03-16 01:49:54 +0000482
David Turner68df4f72005-03-15 18:18:57 +0000483 Exit:
484 return error;
485 }
486
487
488 static void
489 _bdf_list_shift( _bdf_list_t* list,
490 unsigned long n )
491 {
492 unsigned long i, u;
493
494
495 if ( list == 0 || list->used == 0 || n == 0 )
496 return;
497
498 if ( n >= list->used )
499 {
500 list->used = 0;
501 return;
502 }
503
504 for ( u = n, i = 0; u < list->used; i++, u++ )
505 list->field[i] = list->field[u];
506 list->used -= n;
507 }
508
509
Werner Lembergf4c94d42010-06-19 16:08:31 +0200510 /* An empty string for empty fields. */
511
512 static const char empty[1] = { 0 }; /* XXX eliminate this */
513
514
David Turner68df4f72005-03-15 18:18:57 +0000515 static char *
516 _bdf_list_join( _bdf_list_t* list,
517 int c,
518 unsigned long *alen )
519 {
520 unsigned long i, j;
521 char *fp, *dp;
522
523
524 *alen = 0;
525
526 if ( list == 0 || list->used == 0 )
527 return 0;
528
529 dp = list->field[0];
530 for ( i = j = 0; i < list->used; i++ )
531 {
532 fp = list->field[i];
533 while ( *fp )
534 dp[j++] = *fp++;
535
536 if ( i + 1 < list->used )
537 dp[j++] = (char)c;
538 }
Werner Lembergf4c94d42010-06-19 16:08:31 +0200539 if ( dp != empty )
540 dp[j] = 0;
David Turner68df4f72005-03-15 18:18:57 +0000541
542 *alen = j;
543 return dp;
544 }
545
546
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000547 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000548 _bdf_list_split( _bdf_list_t* list,
549 char* separators,
550 char* line,
551 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000552 {
553 int mult, final_empty;
554 char *sp, *ep, *end;
555 char seps[32];
556 FT_Error error = BDF_Err_Ok;
557
558
559 /* Initialize the list. */
560 list->used = 0;
561
562 /* If the line is empty, then simply return. */
563 if ( linelen == 0 || line[0] == 0 )
564 goto Exit;
565
566 /* In the original code, if the `separators' parameter is NULL or */
567 /* empty, the list is split into individual bytes. We don't need */
568 /* this, so an error is signaled. */
569 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000570 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000571 error = BDF_Err_Invalid_Argument;
572 goto Exit;
573 }
574
575 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000576 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000577
578 /* If the very last character of the separator string is a plus, then */
579 /* set the `mult' flag to indicate that multiple separators should be */
580 /* collapsed into one. */
581 for ( mult = 0, sp = separators; sp && *sp; sp++ )
582 {
583 if ( *sp == '+' && *( sp + 1 ) == 0 )
584 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000585 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000586 setsbit( seps, *sp );
587 }
588
589 /* Break the line up into fields. */
590 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
591 sp < end && *sp; )
592 {
593 /* Collect everything that is not a separator. */
594 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
595 ;
596
597 /* Resize the list if necessary. */
598 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000599 {
Werner Lembergebf55852005-03-16 01:49:54 +0000600 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000601 if ( error )
602 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000603 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000604
605 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000606 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000607
608 sp = ep;
609
610 if ( mult )
611 {
612 /* If multiple separators should be collapsed, do it now by */
613 /* setting all the separator characters to 0. */
614 for ( ; *ep && sbitset( seps, *ep ); ep++ )
615 *ep = 0;
616 }
617 else if ( *ep != 0 )
618 /* Don't collapse multiple separators by making them 0, so just */
619 /* make the one encountered 0. */
620 *ep++ = 0;
621
622 final_empty = ( ep > sp && *ep == 0 );
623 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000624 }
625
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000626 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000627 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000628 {
Werner Lembergebf55852005-03-16 01:49:54 +0000629 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000630 if ( error )
631 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000632 }
633
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000634 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000635 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000636
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000637 list->field[list->used] = 0;
638
639 Exit:
640 return error;
David Turner993a8d02002-05-18 12:03:43 +0000641 }
642
David Turner993a8d02002-05-18 12:03:43 +0000643
David Turner68df4f72005-03-15 18:18:57 +0000644#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000645
Werner Lembergebf55852005-03-16 01:49:54 +0000646
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000647 static FT_Error
648 _bdf_readstream( FT_Stream stream,
649 _bdf_line_func_t callback,
650 void* client_data,
651 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000652 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000653 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000654 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900655 int refill, hold, to_skip;
656 ptrdiff_t bytes, start, end, cursor, avail;
David Turner68df4f72005-03-15 18:18:57 +0000657 char* buf = 0;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000658 FT_Memory memory = stream->memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000659 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000660
David Turner993a8d02002-05-18 12:03:43 +0000661
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000662 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000663 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000664 error = BDF_Err_Invalid_Argument;
665 goto Exit;
666 }
David Turner993a8d02002-05-18 12:03:43 +0000667
Werner Lembergebf55852005-03-16 01:49:54 +0000668 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000669 buf_size = 1024;
670
671 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000672 goto Exit;
673
Werner Lembergebf55852005-03-16 01:49:54 +0000674 cb = callback;
675 lineno = 1;
676 buf[0] = 0;
677 start = 0;
678 end = 0;
679 avail = 0;
680 cursor = 0;
681 refill = 1;
682 to_skip = NO_SKIP;
683 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000684
David Turner68df4f72005-03-15 18:18:57 +0000685 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000686 {
David Turner68df4f72005-03-15 18:18:57 +0000687 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000688 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +0200689 bytes = (ptrdiff_t)FT_Stream_TryRead(
690 stream, (FT_Byte*)buf + cursor,
691 (FT_ULong)( buf_size - cursor ) );
David Turner68df4f72005-03-15 18:18:57 +0000692 avail = cursor + bytes;
693 cursor = 0;
694 refill = 0;
695 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000696
David Turner68df4f72005-03-15 18:18:57 +0000697 end = start;
698
Werner Lembergebf55852005-03-16 01:49:54 +0000699 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000700 if ( start < avail && buf[start] == to_skip )
701 {
702 start += 1;
703 to_skip = NO_SKIP;
704 continue;
705 }
706
707 /* try to find the end of the line */
708 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
709 end++;
710
Werner Lembergebf55852005-03-16 01:49:54 +0000711 /* if we hit the end of the buffer, try shifting its content */
712 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000713 if ( end >= avail )
714 {
715 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
716 break; /* ignore it then exit */
717
718 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000719 {
Werner Lembergebf55852005-03-16 01:49:54 +0000720 /* this line is definitely too long; try resizing the input */
721 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000722 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000723
Werner Lembergebf55852005-03-16 01:49:54 +0000724
725 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000726 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100727 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
David Turner68df4f72005-03-15 18:18:57 +0000728 error = BDF_Err_Invalid_Argument;
729 goto Exit;
730 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000731
Werner Lembergebf55852005-03-16 01:49:54 +0000732 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000733 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
734 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000735
David Turner68df4f72005-03-15 18:18:57 +0000736 cursor = buf_size;
737 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000738 }
739 else
740 {
David Turner68df4f72005-03-15 18:18:57 +0000741 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000742
Werner Lembergebf55852005-03-16 01:49:54 +0000743 FT_MEM_COPY( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000744
David Turner68df4f72005-03-15 18:18:57 +0000745 cursor = bytes;
746 avail -= bytes;
747 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000748 }
David Turner68df4f72005-03-15 18:18:57 +0000749 refill = 1;
750 continue;
David Turner993a8d02002-05-18 12:03:43 +0000751 }
David Turner68df4f72005-03-15 18:18:57 +0000752
753 /* Temporarily NUL-terminate the line. */
754 hold = buf[end];
755 buf[end] = 0;
756
757 /* XXX: Use encoding independent value for 0x1a */
758 if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
759 {
Werner Lembergebf55852005-03-16 01:49:54 +0000760 error = (*cb)( buf + start, end - start, lineno,
761 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200762 /* Redo if we have encountered CHARS without properties. */
763 if ( error == -1 )
764 error = (*cb)( buf + start, end - start, lineno,
765 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000766 if ( error )
767 break;
768 }
769
770 lineno += 1;
771 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000772 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000773
774 if ( hold == '\n' )
775 to_skip = '\r';
776 else if ( hold == '\r' )
777 to_skip = '\n';
778 else
779 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000780 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000781
David Turner68df4f72005-03-15 18:18:57 +0000782 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000783
784 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000785 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000786 return error;
David Turner993a8d02002-05-18 12:03:43 +0000787 }
David Turner993a8d02002-05-18 12:03:43 +0000788
789
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000790 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000791
David Turnerb1b47622002-05-21 21:17:43 +0000792 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000793 {
David Turner993a8d02002-05-18 12:03:43 +0000794 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
795 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
796 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
797 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
798 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
799 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
800 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
801 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
802 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
803 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
804 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000805 };
David Turner993a8d02002-05-18 12:03:43 +0000806
David Turnerb1b47622002-05-21 21:17:43 +0000807 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000808 {
David Turner993a8d02002-05-18 12:03:43 +0000809 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
811 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
812 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000813 };
David Turner993a8d02002-05-18 12:03:43 +0000814
David Turnerb1b47622002-05-21 21:17:43 +0000815 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000816 {
David Turner993a8d02002-05-18 12:03:43 +0000817 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
818 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
819 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
820 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000821 };
David Turner993a8d02002-05-18 12:03:43 +0000822
David Turnerb1b47622002-05-21 21:17:43 +0000823 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000824 {
David Turner993a8d02002-05-18 12:03:43 +0000825 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
826 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
827 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
828 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000829 };
David Turner993a8d02002-05-18 12:03:43 +0000830
David Turner993a8d02002-05-18 12:03:43 +0000831
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000832#define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
David Turner993a8d02002-05-18 12:03:43 +0000833
David Turner993a8d02002-05-18 12:03:43 +0000834
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000835 /* Routine to convert an ASCII string into an unsigned long integer. */
836 static unsigned long
837 _bdf_atoul( char* s,
838 char** end,
839 int base )
David Turner993a8d02002-05-18 12:03:43 +0000840 {
David Turnerb1b47622002-05-21 21:17:43 +0000841 unsigned long v;
842 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000843
844
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000845 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000846 return 0;
847
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000848 /* Make sure the radix is something recognizable. Default to 10. */
849 switch ( base )
850 {
851 case 8:
852 dmap = odigits;
853 break;
854 case 16:
855 dmap = hdigits;
856 break;
857 default:
858 base = 10;
859 dmap = ddigits;
860 break;
David Turner993a8d02002-05-18 12:03:43 +0000861 }
862
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000863 /* Check for the special hex prefix. */
864 if ( *s == '0' &&
865 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
866 {
867 base = 16;
868 dmap = hdigits;
869 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000870 }
871
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000872 for ( v = 0; isdigok( dmap, *s ); s++ )
873 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000874
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000875 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000876 *end = s;
877
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000878 return v;
879 }
David Turner993a8d02002-05-18 12:03:43 +0000880
David Turner993a8d02002-05-18 12:03:43 +0000881
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000882 /* Routine to convert an ASCII string into an signed long integer. */
883 static long
884 _bdf_atol( char* s,
885 char** end,
886 int base )
887 {
David Turnerb1b47622002-05-21 21:17:43 +0000888 long v, neg;
889 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000890
891
892 if ( s == 0 || *s == 0 )
893 return 0;
894
895 /* Make sure the radix is something recognizable. Default to 10. */
896 switch ( base )
897 {
898 case 8:
899 dmap = odigits;
900 break;
901 case 16:
902 dmap = hdigits;
903 break;
904 default:
905 base = 10;
906 dmap = ddigits;
907 break;
908 }
909
910 /* Check for a minus sign. */
911 neg = 0;
912 if ( *s == '-' )
913 {
914 s++;
915 neg = 1;
916 }
917
918 /* Check for the special hex prefix. */
919 if ( *s == '0' &&
920 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
921 {
922 base = 16;
923 dmap = hdigits;
924 s += 2;
925 }
926
927 for ( v = 0; isdigok( dmap, *s ); s++ )
928 v = v * base + a2i[(int)*s];
929
930 if ( end != 0 )
931 *end = s;
932
933 return ( !neg ) ? v : -v;
934 }
935
936
937 /* Routine to convert an ASCII string into an signed short integer. */
938 static short
939 _bdf_atos( char* s,
940 char** end,
941 int base )
942 {
David Turnerb1b47622002-05-21 21:17:43 +0000943 short v, neg;
944 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000945
946
947 if ( s == 0 || *s == 0 )
948 return 0;
949
950 /* Make sure the radix is something recognizable. Default to 10. */
951 switch ( base )
952 {
953 case 8:
954 dmap = odigits;
955 break;
956 case 16:
957 dmap = hdigits;
958 break;
959 default:
960 base = 10;
961 dmap = ddigits;
962 break;
963 }
964
965 /* Check for a minus. */
966 neg = 0;
967 if ( *s == '-' )
968 {
969 s++;
970 neg = 1;
971 }
972
973 /* Check for the special hex prefix. */
974 if ( *s == '0' &&
975 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
976 {
977 base = 16;
978 dmap = hdigits;
979 s += 2;
980 }
981
982 for ( v = 0; isdigok( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +0000983 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000984
985 if ( end != 0 )
986 *end = s;
987
Werner Lemberg233302a2002-05-22 05:41:06 +0000988 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000989 }
990
991
992 /* Routine to compare two glyphs by encoding so they can be sorted. */
993 static int
994 by_encoding( const void* a,
995 const void* b )
996 {
997 bdf_glyph_t *c1, *c2;
998
999
1000 c1 = (bdf_glyph_t *)a;
1001 c2 = (bdf_glyph_t *)b;
1002
1003 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001004 return -1;
David Turner68df4f72005-03-15 18:18:57 +00001005
1006 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001007 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001008
David Turner993a8d02002-05-18 12:03:43 +00001009 return 0;
David Turner993a8d02002-05-18 12:03:43 +00001010 }
1011
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001012
1013 static FT_Error
1014 bdf_create_property( char* name,
1015 int format,
1016 bdf_font_t* font )
1017 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001018 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001019 bdf_property_t* p;
1020 FT_Memory memory = font->memory;
1021 FT_Error error = BDF_Err_Ok;
1022
1023
Werner Lemberg96ddc672011-06-29 09:15:54 +02001024 /* First check whether the property has */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001025 /* already been added or not. If it has, then */
1026 /* simply ignore it. */
1027 if ( hash_lookup( name, &(font->proptbl) ) )
1028 goto Exit;
1029
David Turner68df4f72005-03-15 18:18:57 +00001030 if ( FT_RENEW_ARRAY( font->user_props,
1031 font->nuser_props,
1032 font->nuser_props + 1 ) )
1033 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001034
1035 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +00001036 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001037
suzuki toshiya704f4d72009-09-13 00:50:14 +09001038 n = ft_strlen( name ) + 1;
1039 if ( n > FT_ULONG_MAX )
1040 return BDF_Err_Invalid_Argument;
David Turner68df4f72005-03-15 18:18:57 +00001041
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001042 if ( FT_NEW_ARRAY( p->name, n ) )
1043 goto Exit;
1044
1045 FT_MEM_COPY( (char *)p->name, name, n );
1046
1047 p->format = format;
1048 p->builtin = 0;
1049
1050 n = _num_bdf_properties + font->nuser_props;
1051
suzuki toshiya704f4d72009-09-13 00:50:14 +09001052 error = hash_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001053 if ( error )
1054 goto Exit;
1055
1056 font->nuser_props++;
1057
1058 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001059 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001060 }
David Turner993a8d02002-05-18 12:03:43 +00001061
1062
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001063 FT_LOCAL_DEF( bdf_property_t * )
1064 bdf_get_property( char* name,
1065 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001066 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001067 hashnode hn;
1068 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001069
1070
1071 if ( name == 0 || *name == 0 )
1072 return 0;
1073
1074 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1075 return 0;
1076
suzuki toshiya704f4d72009-09-13 00:50:14 +09001077 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001078 if ( propid >= _num_bdf_properties )
1079 return font->user_props + ( propid - _num_bdf_properties );
1080
Werner Lemberg233302a2002-05-22 05:41:06 +00001081 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001082 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001083
1084
1085 /*************************************************************************/
1086 /* */
1087 /* BDF font file parsing flags and functions. */
1088 /* */
1089 /*************************************************************************/
1090
1091
1092 /* Parse flags. */
1093
1094#define _BDF_START 0x0001
1095#define _BDF_FONT_NAME 0x0002
1096#define _BDF_SIZE 0x0004
1097#define _BDF_FONT_BBX 0x0008
1098#define _BDF_PROPS 0x0010
1099#define _BDF_GLYPHS 0x0020
1100#define _BDF_GLYPH 0x0040
1101#define _BDF_ENCODING 0x0080
1102#define _BDF_SWIDTH 0x0100
1103#define _BDF_DWIDTH 0x0200
1104#define _BDF_BBX 0x0400
1105#define _BDF_BITMAP 0x0800
1106
1107#define _BDF_SWIDTH_ADJ 0x1000
1108
1109#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1110 _BDF_ENCODING | \
1111 _BDF_SWIDTH | \
1112 _BDF_DWIDTH | \
1113 _BDF_BBX | \
1114 _BDF_BITMAP )
1115
Werner Lembergf1c2b912006-01-13 14:53:28 +00001116#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1117#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001118
1119
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001120 static FT_Error
1121 _bdf_add_comment( bdf_font_t* font,
1122 char* comment,
1123 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001124 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001125 char* cp;
1126 FT_Memory memory = font->memory;
1127 FT_Error error = BDF_Err_Ok;
1128
1129
David Turner68df4f72005-03-15 18:18:57 +00001130 if ( FT_RENEW_ARRAY( font->comments,
1131 font->comments_len,
1132 font->comments_len + len + 1 ) )
1133 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001134
1135 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001136
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001137 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001138 cp[len] = '\n';
1139
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001140 font->comments_len += len + 1;
1141
1142 Exit:
1143 return error;
David Turner993a8d02002-05-18 12:03:43 +00001144 }
1145
David Turner993a8d02002-05-18 12:03:43 +00001146
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001147 /* Set the spacing from the font name if it exists, or set it to the */
1148 /* default specified in the options. */
1149 static FT_Error
1150 _bdf_set_default_spacing( bdf_font_t* font,
Werner Lemberge01406b2011-11-25 09:44:28 +01001151 bdf_options_t* opts,
1152 unsigned long lineno )
David Turner993a8d02002-05-18 12:03:43 +00001153 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001154 size_t len;
1155 char name[256];
1156 _bdf_list_t list;
1157 FT_Memory memory;
1158 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001159
David Turner993a8d02002-05-18 12:03:43 +00001160
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001161 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1162 {
1163 error = BDF_Err_Invalid_Argument;
1164 goto Exit;
1165 }
David Turner993a8d02002-05-18 12:03:43 +00001166
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001167 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001168
David Turner68df4f72005-03-15 18:18:57 +00001169 _bdf_list_init( &list, memory );
1170
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001171 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001172
suzuki toshiya704f4d72009-09-13 00:50:14 +09001173 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +00001174 /* Limit ourselves to 256 characters in the font name. */
1175 if ( len >= 256 )
1176 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001177 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
Werner Lemberga08b2172007-03-28 07:17:17 +00001178 error = BDF_Err_Invalid_Argument;
1179 goto Exit;
1180 }
1181
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001182 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001183
David Turner68df4f72005-03-15 18:18:57 +00001184 error = _bdf_list_split( &list, (char *)"-", name, len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001185 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001186 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001187
1188 if ( list.used == 15 )
1189 {
1190 switch ( list.field[11][0] )
1191 {
1192 case 'C':
1193 case 'c':
1194 font->spacing = BDF_CHARCELL;
1195 break;
1196 case 'M':
1197 case 'm':
1198 font->spacing = BDF_MONOWIDTH;
1199 break;
1200 case 'P':
1201 case 'p':
1202 font->spacing = BDF_PROPORTIONAL;
1203 break;
David Turner993a8d02002-05-18 12:03:43 +00001204 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001205 }
1206
David Turner68df4f72005-03-15 18:18:57 +00001207 Fail:
1208 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001209
1210 Exit:
1211 return error;
David Turner993a8d02002-05-18 12:03:43 +00001212 }
David Turner993a8d02002-05-18 12:03:43 +00001213
1214
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001215 /* Determine whether the property is an atom or not. If it is, then */
1216 /* clean it up so the double quotes are removed if they exist. */
1217 static int
1218 _bdf_is_atom( char* line,
1219 unsigned long linelen,
1220 char** name,
1221 char** value,
1222 bdf_font_t* font )
1223 {
1224 int hold;
1225 char *sp, *ep;
1226 bdf_property_t* p;
1227
David Turner993a8d02002-05-18 12:03:43 +00001228
1229 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001230
1231 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001232 ep++;
1233
1234 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001235 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001236 {
1237 hold = *ep;
1238 *ep = 0;
1239 }
1240
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001241 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001242
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001243 /* Restore the character that was saved before any return can happen. */
1244 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001245 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001246
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001247 /* If the property exists and is not an atom, just return here. */
1248 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001249 return 0;
1250
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001251 /* The property is an atom. Trim all leading and trailing whitespace */
1252 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001253 sp = ep;
1254 ep = line + linelen;
1255
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001256 /* Trim the leading whitespace if it exists. */
Werner Lemberg320d4972012-02-24 18:06:46 +01001257 if ( *sp )
1258 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001259 while ( *sp &&
1260 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001261 sp++;
1262
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001263 /* Trim the leading double quote if it exists. */
1264 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001265 sp++;
1266 *value = sp;
1267
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001268 /* Trim the trailing whitespace if it exists. */
1269 while ( ep > sp &&
1270 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001271 *--ep = 0;
1272
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001273 /* Trim the trailing double quote if it exists. */
1274 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001275 *--ep = 0;
1276
1277 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001278 }
David Turner993a8d02002-05-18 12:03:43 +00001279
1280
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001281 static FT_Error
Werner Lemberge01406b2011-11-25 09:44:28 +01001282 _bdf_add_property( bdf_font_t* font,
1283 char* name,
1284 char* value,
1285 unsigned long lineno )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001286 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001287 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001288 hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001289 bdf_property_t *prop, *fp;
1290 FT_Memory memory = font->memory;
1291 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001292
David Turner993a8d02002-05-18 12:03:43 +00001293
Werner Lemberg96ddc672011-06-29 09:15:54 +02001294 /* First, check whether the property already exists in the font. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001295 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001296 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001297 /* The property already exists in the font, so simply replace */
1298 /* the value of the property with the current value. */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001299 fp = font->props + hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001300
David Turnerb1b47622002-05-21 21:17:43 +00001301 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001302 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001303 case BDF_ATOM:
1304 /* Delete the current atom if it exists. */
1305 FT_FREE( fp->value.atom );
1306
David Turnerc0f9c4a2007-02-12 14:55:03 +00001307 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001308 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001309 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001310 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001311 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001312 break;
1313
1314 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001315 fp->value.l = _bdf_atol( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001316 break;
1317
1318 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001319 fp->value.ul = _bdf_atoul( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001320 break;
David Turnerd490e372002-05-28 23:40:37 +00001321
David Turnerb1b47622002-05-21 21:17:43 +00001322 default:
1323 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001324 }
David Turnerd490e372002-05-28 23:40:37 +00001325
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001326 goto Exit;
1327 }
1328
1329 /* See whether this property type exists yet or not. */
1330 /* If not, create it. */
1331 hn = hash_lookup( name, &(font->proptbl) );
1332 if ( hn == 0 )
1333 {
1334 error = bdf_create_property( name, BDF_ATOM, font );
1335 if ( error )
1336 goto Exit;
1337 hn = hash_lookup( name, &(font->proptbl) );
1338 }
1339
1340 /* Allocate another property if this is overflow. */
1341 if ( font->props_used == font->props_size )
1342 {
1343 if ( font->props_size == 0 )
1344 {
1345 if ( FT_NEW_ARRAY( font->props, 1 ) )
1346 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001347 }
1348 else
1349 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001350 if ( FT_RENEW_ARRAY( font->props,
1351 font->props_size,
1352 font->props_size + 1 ) )
1353 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001354 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001355
David Turner993a8d02002-05-18 12:03:43 +00001356 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001357 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001358 font->props_size++;
1359 }
1360
suzuki toshiya704f4d72009-09-13 00:50:14 +09001361 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001362 if ( propid >= _num_bdf_properties )
1363 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001364 else
David Turnerb1b47622002-05-21 21:17:43 +00001365 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001366
1367 fp = font->props + font->props_used;
1368
1369 fp->name = prop->name;
1370 fp->format = prop->format;
1371 fp->builtin = prop->builtin;
1372
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001373 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001374 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001375 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001376 fp->value.atom = 0;
1377 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001378 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001379 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001380 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001381 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001382 break;
David Turner993a8d02002-05-18 12:03:43 +00001383
1384 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001385 fp->value.l = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001386 break;
1387
1388 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001389 fp->value.ul = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001390 break;
David Turner993a8d02002-05-18 12:03:43 +00001391 }
1392
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001393 /* If the property happens to be a comment, then it doesn't need */
1394 /* to be added to the internal hash table. */
Werner Lemberg370aea82010-06-08 08:37:11 +02001395 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 )
1396 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001397 /* Add the property to the font property table. */
1398 error = hash_insert( fp->name,
suzuki toshiya704f4d72009-09-13 00:50:14 +09001399 font->props_used,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001400 (hashtable *)font->internal,
1401 memory );
1402 if ( error )
1403 goto Exit;
1404 }
David Turner993a8d02002-05-18 12:03:43 +00001405
1406 font->props_used++;
1407
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001408 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1409 /* property needs to be located if it exists in the property list, the */
1410 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1411 /* present, and the SPACING property should override the default */
1412 /* spacing. */
1413 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001414 font->default_char = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001415 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001416 font->font_ascent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001417 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001418 font->font_descent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001419 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001420 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001421 if ( !fp->value.atom )
1422 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001423 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lembergb66efef2009-03-12 08:07:49 +00001424 error = BDF_Err_Invalid_File_Format;
1425 goto Exit;
1426 }
1427
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001428 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001429 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001430 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001431 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001432 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001433 font->spacing = BDF_CHARCELL;
1434 }
1435
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001436 Exit:
1437 return error;
David Turner993a8d02002-05-18 12:03:43 +00001438 }
1439
David Turner993a8d02002-05-18 12:03:43 +00001440
David Turnerb1b47622002-05-21 21:17:43 +00001441 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001442 {
1443 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1444 };
1445
1446
1447 /* Actually parse the glyph info and bitmaps. */
1448 static FT_Error
1449 _bdf_parse_glyphs( char* line,
1450 unsigned long linelen,
1451 unsigned long lineno,
1452 void* call_data,
1453 void* client_data )
1454 {
1455 int c, mask_index;
1456 char* s;
1457 unsigned char* bp;
1458 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001459
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001460 _bdf_parse_t* p;
1461 bdf_glyph_t* glyph;
1462 bdf_font_t* font;
1463
1464 FT_Memory memory;
1465 FT_Error error = BDF_Err_Ok;
1466
Werner Lemberg319c00d2003-04-23 19:48:24 +00001467 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001468 FT_UNUSED( lineno ); /* only used in debug mode */
1469
1470
Werner Lemberg319c00d2003-04-23 19:48:24 +00001471 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001472
1473 font = p->font;
1474 memory = font->memory;
1475
1476 /* Check for a comment. */
1477 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1478 {
1479 linelen -= 7;
1480
1481 s = line + 7;
1482 if ( *s != 0 )
1483 {
1484 s++;
1485 linelen--;
1486 }
1487 error = _bdf_add_comment( p->font, s, linelen );
1488 goto Exit;
1489 }
1490
1491 /* The very first thing expected is the number of glyphs. */
1492 if ( !( p->flags & _BDF_GLYPHS ) )
1493 {
1494 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1495 {
1496 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1497 error = BDF_Err_Missing_Chars_Field;
1498 goto Exit;
1499 }
1500
David Turner68df4f72005-03-15 18:18:57 +00001501 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001502 if ( error )
1503 goto Exit;
1504 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1505
1506 /* Make sure the number of glyphs is non-zero. */
1507 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001508 font->glyphs_size = 64;
1509
Werner Lemberga08b2172007-03-28 07:17:17 +00001510 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1511 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001512 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001513 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001514 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberga08b2172007-03-28 07:17:17 +00001515 error = BDF_Err_Invalid_Argument;
1516 goto Exit;
1517 }
1518
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001519 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1520 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001521
David Turner993a8d02002-05-18 12:03:43 +00001522 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001523
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001524 goto Exit;
1525 }
1526
1527 /* Check for the ENDFONT field. */
1528 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1529 {
1530 /* Sort the glyphs by encoding. */
1531 ft_qsort( (char *)font->glyphs,
1532 font->glyphs_used,
1533 sizeof ( bdf_glyph_t ),
1534 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001535
1536 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001537
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001538 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001539 }
1540
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001541 /* Check for the ENDCHAR field. */
1542 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1543 {
1544 p->glyph_enc = 0;
1545 p->flags &= ~_BDF_GLYPH_BITS;
1546
1547 goto Exit;
1548 }
1549
Werner Lemberg96ddc672011-06-29 09:15:54 +02001550 /* Check whether a glyph is being scanned but should be */
1551 /* ignored because it is an unencoded glyph. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001552 if ( ( p->flags & _BDF_GLYPH ) &&
1553 p->glyph_enc == -1 &&
1554 p->opts->keep_unencoded == 0 )
1555 goto Exit;
1556
1557 /* Check for the STARTCHAR field. */
1558 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1559 {
1560 /* Set the character name in the parse info first until the */
1561 /* encoding can be checked for an unencoded character. */
1562 FT_FREE( p->glyph_name );
1563
David Turner68df4f72005-03-15 18:18:57 +00001564 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001565 if ( error )
1566 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001567
David Turner68df4f72005-03-15 18:18:57 +00001568 _bdf_list_shift( &p->list, 1 );
1569
1570 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001571
Werner Lembergba03af62007-05-30 13:57:02 +00001572 if ( !s )
1573 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001574 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lembergba03af62007-05-30 13:57:02 +00001575 error = BDF_Err_Invalid_File_Format;
1576 goto Exit;
1577 }
1578
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001579 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1580 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001581
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001582 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1583
1584 p->flags |= _BDF_GLYPH;
1585
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001586 FT_TRACE4(( DBGMSG1, lineno, s ));
1587
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001588 goto Exit;
1589 }
1590
1591 /* Check for the ENCODING field. */
1592 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1593 {
1594 if ( !( p->flags & _BDF_GLYPH ) )
1595 {
1596 /* Missing STARTCHAR field. */
1597 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1598 error = BDF_Err_Missing_Startchar_Field;
1599 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001600 }
1601
David Turner68df4f72005-03-15 18:18:57 +00001602 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001603 if ( error )
1604 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001605
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001606 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001607
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001608 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1609
Werner Lemberged54e432011-11-27 16:39:53 +01001610 /* Check that the encoding is in the Unicode range because */
1611 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lemberg96ddc672011-06-29 09:15:54 +02001612 if ( p->glyph_enc > 0 &&
1613 (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
David Turner481838e2006-02-23 12:40:14 +00001614 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001615 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
David Turner481838e2006-02-23 12:40:14 +00001616 error = BDF_Err_Invalid_File_Format;
1617 goto Exit;
1618 }
1619
Werner Lemberg96ddc672011-06-29 09:15:54 +02001620 /* Check whether this encoding has already been encountered. */
1621 /* If it has then change it to unencoded so it gets added if */
1622 /* indicated. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001623 if ( p->glyph_enc >= 0 )
1624 {
1625 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1626 {
1627 /* Emit a message saying a glyph has been moved to the */
1628 /* unencoded area. */
1629 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1630 p->glyph_enc, p->glyph_name ));
1631 p->glyph_enc = -1;
1632 font->modified = 1;
1633 }
1634 else
1635 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1636 }
1637
1638 if ( p->glyph_enc >= 0 )
1639 {
1640 /* Make sure there are enough glyphs allocated in case the */
1641 /* number of characters happen to be wrong. */
1642 if ( font->glyphs_used == font->glyphs_size )
1643 {
1644 if ( FT_RENEW_ARRAY( font->glyphs,
1645 font->glyphs_size,
1646 font->glyphs_size + 64 ) )
1647 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001648
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001649 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001650 }
1651
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001652 glyph = font->glyphs + font->glyphs_used++;
1653 glyph->name = p->glyph_name;
1654 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001655
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001656 /* Reset the initial glyph info. */
1657 p->glyph_name = 0;
1658 }
1659 else
1660 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001661 /* Unencoded glyph. Check whether it should */
1662 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001663 if ( p->opts->keep_unencoded != 0 )
1664 {
1665 /* Allocate the next unencoded glyph. */
1666 if ( font->unencoded_used == font->unencoded_size )
1667 {
David Turner68df4f72005-03-15 18:18:57 +00001668 if ( FT_RENEW_ARRAY( font->unencoded ,
1669 font->unencoded_size,
1670 font->unencoded_size + 4 ) )
1671 goto Exit;
1672
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001673 font->unencoded_size += 4;
1674 }
1675
1676 glyph = font->unencoded + font->unencoded_used;
1677 glyph->name = p->glyph_name;
1678 glyph->encoding = font->unencoded_used++;
1679 }
1680 else
1681 /* Free up the glyph name if the unencoded shouldn't be */
1682 /* kept. */
1683 FT_FREE( p->glyph_name );
1684
1685 p->glyph_name = 0;
1686 }
1687
1688 /* Clear the flags that might be added when width and height are */
1689 /* checked for consistency. */
1690 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1691
1692 p->flags |= _BDF_ENCODING;
1693
1694 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001695 }
1696
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001697 /* Point at the glyph being constructed. */
1698 if ( p->glyph_enc == -1 )
1699 glyph = font->unencoded + ( font->unencoded_used - 1 );
1700 else
1701 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001702
Werner Lemberg96ddc672011-06-29 09:15:54 +02001703 /* Check whether a bitmap is being constructed. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001704 if ( p->flags & _BDF_BITMAP )
1705 {
1706 /* If there are more rows than are specified in the glyph metrics, */
1707 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001708 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001709 {
1710 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1711 {
1712 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1713 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001714 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001715 }
1716
1717 goto Exit;
1718 }
1719
1720 /* Only collect the number of nibbles indicated by the glyph */
1721 /* metrics. If there are more columns, they are simply ignored. */
1722 nibbles = glyph->bpr << 1;
1723 bp = glyph->bitmap + p->row * glyph->bpr;
1724
David Turnerb698eed2006-02-23 14:50:13 +00001725 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001726 {
1727 c = line[i];
Werner Lemberg233302a2002-05-22 05:41:06 +00001728 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001729 if ( i + 1 < nibbles && ( i & 1 ) )
1730 *++bp = 0;
1731 }
1732
1733 /* Remove possible garbage at the right. */
1734 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001735 if ( glyph->bbx.width )
1736 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001737
1738 /* If any line has extra columns, indicate they have been removed. */
1739 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1740 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1741 {
1742 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1743 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1744 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001745 }
1746
1747 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001748 goto Exit;
1749 }
David Turner993a8d02002-05-18 12:03:43 +00001750
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001751 /* Expect the SWIDTH (scalable width) field next. */
1752 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1753 {
1754 if ( !( p->flags & _BDF_ENCODING ) )
1755 {
1756 /* Missing ENCODING field. */
1757 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1758 error = BDF_Err_Missing_Encoding_Field;
1759 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001760 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001761
David Turner68df4f72005-03-15 18:18:57 +00001762 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001763 if ( error )
1764 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001765
David Turnerb1b47622002-05-21 21:17:43 +00001766 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001767 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001768
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001769 goto Exit;
1770 }
David Turner993a8d02002-05-18 12:03:43 +00001771
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001772 /* Expect the DWIDTH (scalable width) field next. */
1773 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1774 {
David Turner68df4f72005-03-15 18:18:57 +00001775 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001776 if ( error )
1777 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001778
David Turnerb1b47622002-05-21 21:17:43 +00001779 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001780
1781 if ( !( p->flags & _BDF_SWIDTH ) )
1782 {
1783 /* Missing SWIDTH field. Emit an auto correction message and set */
1784 /* the scalable width from the device width. */
1785 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1786
Werner Lemberg02d4d592002-05-28 22:38:05 +00001787 glyph->swidth = (unsigned short)FT_MulDiv(
1788 glyph->dwidth, 72000L,
1789 (FT_Long)( font->point_size *
1790 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001791 }
1792
1793 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001794 goto Exit;
1795 }
David Turner993a8d02002-05-18 12:03:43 +00001796
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001797 /* Expect the BBX field next. */
1798 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1799 {
David Turner68df4f72005-03-15 18:18:57 +00001800 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001801 if ( error )
1802 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001803
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001804 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1805 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1806 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1807 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1808
1809 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001810 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1811 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001812
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001813 /* Determine the overall font bounding box as the characters are */
1814 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001815 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1816 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001817
David Turnerb1b47622002-05-21 21:17:43 +00001818 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001819
Werner Lembergdfa46192004-03-05 09:26:24 +00001820 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1821 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1822 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001823
1824 if ( !( p->flags & _BDF_DWIDTH ) )
1825 {
1826 /* Missing DWIDTH field. Emit an auto correction message and set */
1827 /* the device width to the glyph width. */
1828 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1829 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001830 }
1831
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001832 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1833 /* value if necessary. */
1834 if ( p->opts->correct_metrics != 0 )
1835 {
1836 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001837 unsigned short sw = (unsigned short)FT_MulDiv(
1838 glyph->dwidth, 72000L,
1839 (FT_Long)( font->point_size *
1840 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001841
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001842
1843 if ( sw != glyph->swidth )
1844 {
1845 glyph->swidth = sw;
1846
1847 if ( p->glyph_enc == -1 )
1848 _bdf_set_glyph_modified( font->umod,
1849 font->unencoded_used - 1 );
1850 else
1851 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1852
1853 p->flags |= _BDF_SWIDTH_ADJ;
1854 font->modified = 1;
1855 }
David Turner993a8d02002-05-18 12:03:43 +00001856 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001857
David Turner993a8d02002-05-18 12:03:43 +00001858 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001859 goto Exit;
1860 }
David Turner993a8d02002-05-18 12:03:43 +00001861
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001862 /* And finally, gather up the bitmap. */
1863 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1864 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001865 unsigned long bitmap_size;
1866
1867
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001868 if ( !( p->flags & _BDF_BBX ) )
1869 {
1870 /* Missing BBX field. */
1871 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1872 error = BDF_Err_Missing_Bbx_Field;
1873 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001874 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001875
1876 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001877 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001878
1879 bitmap_size = glyph->bpr * glyph->bbx.height;
1880 if ( bitmap_size > 0xFFFFU )
1881 {
1882 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1883 error = BDF_Err_Bbx_Too_Big;
1884 goto Exit;
1885 }
1886 else
1887 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001888
1889 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1890 goto Exit;
1891
1892 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001893 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001894
1895 goto Exit;
1896 }
1897
Werner Lemberge01406b2011-11-25 09:44:28 +01001898 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001899 error = BDF_Err_Invalid_File_Format;
1900
1901 Exit:
Werner Lembergf4c94d42010-06-19 16:08:31 +02001902 if ( error && ( p->flags & _BDF_GLYPH ) )
1903 FT_FREE( p->glyph_name );
1904
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001905 return error;
David Turner993a8d02002-05-18 12:03:43 +00001906 }
1907
David Turner993a8d02002-05-18 12:03:43 +00001908
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001909 /* Load the font properties. */
1910 static FT_Error
1911 _bdf_parse_properties( char* line,
1912 unsigned long linelen,
1913 unsigned long lineno,
1914 void* call_data,
1915 void* client_data )
1916 {
1917 unsigned long vlen;
1918 _bdf_line_func_t* next;
1919 _bdf_parse_t* p;
1920 char* name;
1921 char* value;
1922 char nbuf[128];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001923 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001924
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001925 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001926
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001927
1928 next = (_bdf_line_func_t *)call_data;
1929 p = (_bdf_parse_t *) client_data;
1930
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001931 /* Check for the end of the properties. */
1932 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1933 {
1934 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1935 /* encountered yet, then make sure they are added as properties and */
1936 /* make sure they are set from the font bounding box info. */
1937 /* */
1938 /* This is *always* done regardless of the options, because X11 */
1939 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001940 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001941 {
1942 p->font->font_ascent = p->font->bbx.ascent;
1943 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001944 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
1945 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001946 if ( error )
1947 goto Exit;
1948
1949 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1950 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001951 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001952
Werner Lemberg428c2e42003-04-25 05:35:04 +00001953 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001954 {
1955 p->font->font_descent = p->font->bbx.descent;
1956 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001957 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
1958 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001959 if ( error )
1960 goto Exit;
1961
1962 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1963 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001964 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001965
David Turner993a8d02002-05-18 12:03:43 +00001966 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001967 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001968
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001969 goto Exit;
1970 }
David Turner993a8d02002-05-18 12:03:43 +00001971
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001972 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1973 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1974 goto Exit;
1975
1976 /* Handle COMMENT fields and properties in a special way to preserve */
1977 /* the spacing. */
1978 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1979 {
David Turner993a8d02002-05-18 12:03:43 +00001980 name = value = line;
1981 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001982 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001983 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01001984 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001985 if ( error )
1986 goto Exit;
1987 }
1988 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1989 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001990 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001991 if ( error )
1992 goto Exit;
1993 }
1994 else
1995 {
David Turner68df4f72005-03-15 18:18:57 +00001996 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001997 if ( error )
1998 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001999 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002000
David Turner68df4f72005-03-15 18:18:57 +00002001 _bdf_list_shift( &p->list, 1 );
2002 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002003
Werner Lemberge01406b2011-11-25 09:44:28 +01002004 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002005 if ( error )
2006 goto Exit;
2007 }
2008
2009 Exit:
2010 return error;
David Turner993a8d02002-05-18 12:03:43 +00002011 }
2012
David Turner993a8d02002-05-18 12:03:43 +00002013
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002014 /* Load the font header. */
2015 static FT_Error
2016 _bdf_parse_start( char* line,
2017 unsigned long linelen,
2018 unsigned long lineno,
2019 void* call_data,
2020 void* client_data )
2021 {
2022 unsigned long slen;
2023 _bdf_line_func_t* next;
2024 _bdf_parse_t* p;
2025 bdf_font_t* font;
2026 char *s;
David Turner993a8d02002-05-18 12:03:43 +00002027
David Turnerd490e372002-05-28 23:40:37 +00002028 FT_Memory memory = NULL;
2029 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002030
2031 FT_UNUSED( lineno ); /* only used in debug mode */
2032
2033
2034 next = (_bdf_line_func_t *)call_data;
2035 p = (_bdf_parse_t *) client_data;
2036
2037 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00002038 memory = p->font->memory;
2039
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002040 /* Check for a comment. This is done to handle those fonts that have */
2041 /* comments before the STARTFONT line for some reason. */
2042 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2043 {
2044 if ( p->opts->keep_comments != 0 && p->font != 0 )
2045 {
2046 linelen -= 7;
2047
2048 s = line + 7;
2049 if ( *s != 0 )
2050 {
2051 s++;
2052 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002053 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002054
2055 error = _bdf_add_comment( p->font, s, linelen );
2056 if ( error )
2057 goto Exit;
2058 /* here font is not defined! */
2059 }
2060
2061 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002062 }
2063
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002064 if ( !( p->flags & _BDF_START ) )
2065 {
2066 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002067
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002068 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2069 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01002070 /* we don't emit an error message since this code gets */
2071 /* explicitly caught one level higher */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002072 error = BDF_Err_Missing_Startfont_Field;
2073 goto Exit;
2074 }
David Turner993a8d02002-05-18 12:03:43 +00002075
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002076 p->flags = _BDF_START;
2077 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002078
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002079 if ( FT_NEW( font ) )
2080 goto Exit;
2081 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002082
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002083 font->memory = p->memory;
2084 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002085
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002086 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09002087 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002088 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002089
David Turner993a8d02002-05-18 12:03:43 +00002090
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002091 error = hash_init( &(font->proptbl), memory );
2092 if ( error )
2093 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002094 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002095 i < _num_bdf_properties; i++, prop++ )
2096 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09002097 error = hash_insert( prop->name, i,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002098 &(font->proptbl), memory );
2099 if ( error )
2100 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002101 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002102 }
2103
2104 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2105 goto Exit;
2106 error = hash_init( (hashtable *)p->font->internal,memory );
2107 if ( error )
2108 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002109 p->font->spacing = p->opts->font_spacing;
2110 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002111
2112 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002113 }
2114
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002115 /* Check for the start of the properties. */
2116 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2117 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002118 if ( !( p->flags & _BDF_FONT_BBX ) )
Werner Lembergfb690292010-06-23 10:00:52 +02002119 {
2120 /* Missing the FONTBOUNDINGBOX field. */
2121 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2122 error = BDF_Err_Missing_Fontboundingbox_Field;
2123 goto Exit;
2124 }
2125
David Turner68df4f72005-03-15 18:18:57 +00002126 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002127 if ( error )
2128 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00002129 /* at this point, `p->font' can't be NULL */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002130 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2131
2132 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2133 goto Exit;
2134
2135 p->flags |= _BDF_PROPS;
2136 *next = _bdf_parse_properties;
2137
2138 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002139 }
2140
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002141 /* Check for the FONTBOUNDINGBOX field. */
2142 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2143 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002144 if ( !( p->flags & _BDF_SIZE ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002145 {
2146 /* Missing the SIZE field. */
2147 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2148 error = BDF_Err_Missing_Size_Field;
2149 goto Exit;
2150 }
2151
David Turner68df4f72005-03-15 18:18:57 +00002152 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002153 if ( error )
2154 goto Exit;
2155
2156 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2157 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2158
2159 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2160 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2161
David Turnerd490e372002-05-28 23:40:37 +00002162 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002163 p->font->bbx.y_offset );
2164
2165 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002166
2167 p->flags |= _BDF_FONT_BBX;
2168
2169 goto Exit;
2170 }
2171
2172 /* The next thing to check for is the FONT field. */
2173 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2174 {
David Turner68df4f72005-03-15 18:18:57 +00002175 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002176 if ( error )
2177 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002178 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002179
David Turner68df4f72005-03-15 18:18:57 +00002180 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002181
2182 if ( !s )
2183 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002184 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg5b591e42007-06-01 22:16:43 +00002185 error = BDF_Err_Invalid_File_Format;
2186 goto Exit;
2187 }
2188
Werner Lembergfb690292010-06-23 10:00:52 +02002189 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2190 FT_FREE( p->font->name );
2191
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002192 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2193 goto Exit;
2194 FT_MEM_COPY( p->font->name, s, slen + 1 );
2195
2196 /* If the font name is an XLFD name, set the spacing to the one in */
2197 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002198 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002199 if ( error )
2200 goto Exit;
2201
2202 p->flags |= _BDF_FONT_NAME;
2203
2204 goto Exit;
2205 }
2206
2207 /* Check for the SIZE field. */
2208 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2209 {
2210 if ( !( p->flags & _BDF_FONT_NAME ) )
2211 {
2212 /* Missing the FONT field. */
2213 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2214 error = BDF_Err_Missing_Font_Field;
2215 goto Exit;
2216 }
2217
David Turner68df4f72005-03-15 18:18:57 +00002218 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002219 if ( error )
2220 goto Exit;
2221
2222 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2223 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2224 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2225
2226 /* Check for the bits per pixel field. */
2227 if ( p->list.used == 5 )
2228 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002229 unsigned short bitcount, i, shift;
2230
2231
2232 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2233
2234 /* Only values 1, 2, 4, 8 are allowed. */
2235 shift = p->font->bpp;
2236 bitcount = 0;
2237 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002238 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002239 if ( shift & 1 )
2240 bitcount = i;
2241 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002242 }
David Turner993a8d02002-05-18 12:03:43 +00002243
Werner Lembergbd8e3242002-06-12 08:43:58 +00002244 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002245
2246 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002247 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002248 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002249 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002250 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002251 }
2252 }
2253 else
2254 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002255
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002256 p->flags |= _BDF_SIZE;
2257
2258 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002259 }
2260
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002261 /* Check for the CHARS field -- font properties are optional */
2262 if ( ft_memcmp( line, "CHARS", 5 ) == 0 )
2263 {
2264 char nbuf[128];
2265
2266
2267 if ( !( p->flags & _BDF_FONT_BBX ) )
2268 {
2269 /* Missing the FONTBOUNDINGBOX field. */
2270 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2271 error = BDF_Err_Missing_Fontboundingbox_Field;
2272 goto Exit;
2273 }
2274
2275 /* Add the two standard X11 properties which are required */
2276 /* for compiling fonts. */
2277 p->font->font_ascent = p->font->bbx.ascent;
2278 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002279 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2280 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002281 if ( error )
2282 goto Exit;
2283 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2284
2285 p->font->font_descent = p->font->bbx.descent;
2286 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002287 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2288 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002289 if ( error )
2290 goto Exit;
2291 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2292
2293 p->font->modified = 1;
2294
2295 *next = _bdf_parse_glyphs;
2296
2297 /* A special return value. */
2298 error = -1;
2299 goto Exit;
2300 }
2301
Werner Lemberge01406b2011-11-25 09:44:28 +01002302 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002303 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002304
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002305 Exit:
2306 return error;
2307 }
David Turner993a8d02002-05-18 12:03:43 +00002308
2309
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002310 /*************************************************************************/
2311 /* */
2312 /* API. */
2313 /* */
2314 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002315
David Turner993a8d02002-05-18 12:03:43 +00002316
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002317 FT_LOCAL_DEF( FT_Error )
2318 bdf_load_font( FT_Stream stream,
2319 FT_Memory extmemory,
2320 bdf_options_t* opts,
2321 bdf_font_t* *font )
2322 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002323 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002324 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002325
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002326 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002327 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002328
2329
David Turner68df4f72005-03-15 18:18:57 +00002330 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002331 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002332
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002333 memory = NULL;
2334 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2335 p->minlb = 32767;
2336 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002337
David Turner68df4f72005-03-15 18:18:57 +00002338 _bdf_list_init( &p->list, extmemory );
2339
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002340 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002341 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002342 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002343 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002344
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002345 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002346 {
2347 /* If the font is not proportional, set the font's monowidth */
2348 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002349 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002350
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002351 if ( p->font->spacing != BDF_PROPORTIONAL )
2352 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002353
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002354 /* If the number of glyphs loaded is not that of the original count, */
2355 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002356 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002357 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002358 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2359 p->font->glyphs_used + p->font->unencoded_used ));
2360 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002361 }
2362
2363 /* Once the font has been loaded, adjust the overall font metrics if */
2364 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002365 if ( p->opts->correct_metrics != 0 &&
2366 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002367 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002368 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002369 {
2370 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002371 p->font->bbx.width, p->maxrb - p->minlb ));
2372 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2373 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002374 }
2375
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002376 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002377 {
2378 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002379 p->font->bbx.x_offset, p->minlb ));
2380 p->font->bbx.x_offset = p->minlb;
2381 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002382 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002383
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002384 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002385 {
2386 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002387 p->font->bbx.ascent, p->maxas ));
2388 p->font->bbx.ascent = p->maxas;
2389 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002390 }
2391
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002392 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002393 {
2394 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002395 p->font->bbx.descent, p->maxds ));
2396 p->font->bbx.descent = p->maxds;
2397 p->font->bbx.y_offset = (short)( -p->maxds );
2398 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002399 }
2400
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002401 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002402 {
2403 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002404 p->font->bbx.height, p->maxas + p->maxds ));
2405 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002406 }
2407
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002408 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002409 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2410 }
David Turner993a8d02002-05-18 12:03:43 +00002411 }
2412
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002413 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002414 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002415 /* The ENDFONT field was never reached or did not exist. */
2416 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002417 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002418 /* Error happened while parsing header. */
2419 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2420 error = BDF_Err_Corrupted_Font_Header;
2421 goto Exit;
2422 }
2423 else
2424 {
2425 /* Error happened when parsing glyphs. */
2426 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2427 error = BDF_Err_Corrupted_Font_Glyphs;
2428 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002429 }
David Turner993a8d02002-05-18 12:03:43 +00002430 }
2431
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002432 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002433 {
2434 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002435 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002436
Werner Lemberg370aea82010-06-08 08:37:11 +02002437 if ( p->font->comments_len > 0 )
2438 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002439 if ( FT_RENEW_ARRAY( p->font->comments,
2440 p->font->comments_len,
2441 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002442 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002443
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002444 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002445 }
David Turner993a8d02002-05-18 12:03:43 +00002446 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002447 else if ( error == BDF_Err_Ok )
2448 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002449
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002450 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002451
2452 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002453 if ( p )
2454 {
David Turner68df4f72005-03-15 18:18:57 +00002455 _bdf_list_done( &p->list );
2456
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002457 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002458
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002459 FT_FREE( p );
2460 }
2461
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002462 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002463
2464 Fail:
2465 bdf_free_font( p->font );
2466
2467 memory = extmemory;
2468
2469 FT_FREE( p->font );
2470
2471 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002472 }
David Turner993a8d02002-05-18 12:03:43 +00002473
2474
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002475 FT_LOCAL_DEF( void )
2476 bdf_free_font( bdf_font_t* font )
2477 {
2478 bdf_property_t* prop;
2479 unsigned long i;
2480 bdf_glyph_t* glyphs;
2481 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002482
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002483
2484 if ( font == 0 )
2485 return;
David Turner993a8d02002-05-18 12:03:43 +00002486
2487 memory = font->memory;
2488
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002489 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002490
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002491 /* Free up the internal hash table of property names. */
2492 if ( font->internal )
2493 {
2494 hash_free( (hashtable *)font->internal, memory );
2495 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002496 }
2497
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002498 /* Free up the comment info. */
2499 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002500
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002501 /* Free up the properties. */
2502 for ( i = 0; i < font->props_size; i++ )
2503 {
2504 if ( font->props[i].format == BDF_ATOM )
2505 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002506 }
2507
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002508 FT_FREE( font->props );
2509
2510 /* Free up the character info. */
2511 for ( i = 0, glyphs = font->glyphs;
2512 i < font->glyphs_used; i++, glyphs++ )
2513 {
2514 FT_FREE( glyphs->name );
2515 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002516 }
2517
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002518 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2519 i++, glyphs++ )
2520 {
2521 FT_FREE( glyphs->name );
2522 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002523 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002524
2525 FT_FREE( font->glyphs );
2526 FT_FREE( font->unencoded );
2527
2528 /* Free up the overflow storage if it was used. */
2529 for ( i = 0, glyphs = font->overflow.glyphs;
2530 i < font->overflow.glyphs_used; i++, glyphs++ )
2531 {
2532 FT_FREE( glyphs->name );
2533 FT_FREE( glyphs->bitmap );
2534 }
2535
2536 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002537
2538 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002539 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002540
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002541 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002542 for ( prop = font->user_props, i = 0;
2543 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002544 {
2545 FT_FREE( prop->name );
2546 if ( prop->format == BDF_ATOM )
2547 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002548 }
David Turner993a8d02002-05-18 12:03:43 +00002549
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002550 FT_FREE( font->user_props );
2551
2552 /* FREE( font ); */ /* XXX Fixme */
2553 }
David Turner993a8d02002-05-18 12:03:43 +00002554
2555
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002556 FT_LOCAL_DEF( bdf_property_t * )
2557 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002558 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002559 {
2560 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002561
David Turner993a8d02002-05-18 12:03:43 +00002562
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002563 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002564 return 0;
2565
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002566 hn = hash_lookup( name, (hashtable *)font->internal );
2567
suzuki toshiya704f4d72009-09-13 00:50:14 +09002568 return hn ? ( font->props + hn->data ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002569 }
2570
2571
2572/* END */