blob: c9e231ea10ec0f0f72e52f5e9defa667c1aeb76f [file] [log] [blame]
David Turner993a8d02002-05-18 12:03:43 +00001/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
Sean McBride7be2a942014-02-08 13:55:38 +01003 * Copyright 2001-2014
Werner Lemberg442bfb82007-02-12 21:44:10 +00004 * Francesco Zappa Nardelli
David Turner993a8d02002-05-18 12:03:43 +00005 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
Werner Lemberg7cf4d372002-05-21 14:13:01 +000025 /*************************************************************************/
26 /* */
27 /* This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 */
28 /* */
29 /* taken from Mark Leisher's xmbdfed package */
30 /* */
31 /*************************************************************************/
32
David Turner993a8d02002-05-18 12:03:43 +000033
34#include <ft2build.h>
35
Werner Lemberg02d4d592002-05-28 22:38:05 +000036#include FT_FREETYPE_H
David Turner993a8d02002-05-18 12:03:43 +000037#include FT_INTERNAL_DEBUG_H
38#include FT_INTERNAL_STREAM_H
39#include FT_INTERNAL_OBJECTS_H
40
41#include "bdf.h"
David Turner993a8d02002-05-18 12:03:43 +000042#include "bdferror.h"
43
David Turner993a8d02002-05-18 12:03:43 +000044
Werner Lemberg7cf4d372002-05-21 14:13:01 +000045 /*************************************************************************/
46 /* */
47 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
48 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
49 /* messages during execution. */
50 /* */
51#undef FT_COMPONENT
52#define FT_COMPONENT trace_bdflib
David Turner993a8d02002-05-18 12:03:43 +000053
David Turner993a8d02002-05-18 12:03:43 +000054
Werner Lemberg7cf4d372002-05-21 14:13:01 +000055 /*************************************************************************/
56 /* */
57 /* Default BDF font options. */
58 /* */
59 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000060
David Turner993a8d02002-05-18 12:03:43 +000061
David Turnerb1b47622002-05-21 21:17:43 +000062 static const bdf_options_t _bdf_opts =
Werner Lemberg7cf4d372002-05-21 14:13:01 +000063 {
David Turner993a8d02002-05-18 12:03:43 +000064 1, /* Correct metrics. */
65 1, /* Preserve unencoded glyphs. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000066 0, /* Preserve comments. */
67 BDF_PROPORTIONAL /* Default spacing. */
68 };
David Turner993a8d02002-05-18 12:03:43 +000069
David Turner993a8d02002-05-18 12:03:43 +000070
Werner Lemberg7cf4d372002-05-21 14:13:01 +000071 /*************************************************************************/
72 /* */
73 /* Builtin BDF font properties. */
74 /* */
75 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000076
Werner Lemberg7cf4d372002-05-21 14:13:01 +000077 /* List of most properties that might appear in a font. Doesn't include */
78 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
David Turner993a8d02002-05-18 12:03:43 +000079
David Turnerb1b47622002-05-21 21:17:43 +000080 static const bdf_property_t _bdf_properties[] =
David Turner993a8d02002-05-18 12:03:43 +000081 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +000082 { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
83 { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
84 { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
85 { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
86 { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
87 { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
88 { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
89 { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
90 { (char *)"COMMENT", BDF_ATOM, 1, { 0 } },
91 { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } },
92 { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
93 { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } },
94 { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
95 { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } },
96 { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } },
97 { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } },
98 { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
99 { (char *)"FONT", BDF_ATOM, 1, { 0 } },
100 { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
101 { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
102 { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
103 { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } },
104 { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } },
105 { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
106 { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } },
107 { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } },
108 { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } },
109 { (char *)"NOTICE", BDF_ATOM, 1, { 0 } },
110 { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
111 { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } },
112 { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
113 { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
114 { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
115 { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
116 { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
117 { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
118 { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
119 { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
120 { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
121 { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
122 { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
123 { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
124 { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
125 { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
126 { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
127 { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
128 { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
129 { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
130 { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
131 { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
132 { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
133 { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
134 { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
135 { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
136 { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
137 { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
138 { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
139 { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
140 { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
141 { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
142 { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
143 { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } },
144 { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
145 { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
146 { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
147 { (char *)"SLANT", BDF_ATOM, 1, { 0 } },
148 { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
149 { (char *)"SPACING", BDF_ATOM, 1, { 0 } },
150 { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
151 { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
152 { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
153 { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
154 { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
155 { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
156 { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
157 { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
158 { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
159 { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
160 { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } },
161 { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
162 { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } },
163 { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
164 { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
165 };
David Turner993a8d02002-05-18 12:03:43 +0000166
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000167 static const unsigned long
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000168 _num_bdf_properties = sizeof ( _bdf_properties ) /
169 sizeof ( _bdf_properties[0] );
David Turner993a8d02002-05-18 12:03:43 +0000170
171
Werner Lemberge01406b2011-11-25 09:44:28 +0100172 /* Auto correction messages. */
173#define ACMSG1 "FONT_ASCENT property missing. " \
174 "Added `FONT_ASCENT %hd'.\n"
175#define ACMSG2 "FONT_DESCENT property missing. " \
176 "Added `FONT_DESCENT %hd'.\n"
177#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
178#define ACMSG4 "Font left bearing != actual left bearing. " \
179 "Old: %hd New: %hd.\n"
180#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
181#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
182#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
183#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
184#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
185#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
186#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
187#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
188#define ACMSG13 "Glyph %ld extra rows removed.\n"
189#define ACMSG14 "Glyph %ld extra columns removed.\n"
190#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
Werner Lemberg0b1c0c62012-02-25 10:23:04 +0100191#define ACMSG16 "Glyph %ld missing columns padded with zero bits.\n"
Werner Lemberge01406b2011-11-25 09:44:28 +0100192
193 /* Error messages. */
194#define ERRMSG1 "[line %ld] Missing `%s' line.\n"
195#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
196#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
197#define ERRMSG4 "[line %ld] BBX too big.\n"
198#define ERRMSG5 "[line %ld] `%s' value too big.\n"
199#define ERRMSG6 "[line %ld] Input line too long.\n"
200#define ERRMSG7 "[line %ld] Font name too long.\n"
201#define ERRMSG8 "[line %ld] Invalid `%s' value.\n"
202#define ERRMSG9 "[line %ld] Invalid keyword.\n"
203
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +0100204 /* Debug messages. */
205#define DBGMSG1 " [%6ld] %s" /* no \n */
206#define DBGMSG2 " (0x%lX)\n"
207
Werner Lemberge01406b2011-11-25 09:44:28 +0100208
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000209 /*************************************************************************/
210 /* */
211 /* Hash table utilities for the properties. */
212 /* */
213 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +0000214
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000215 /* XXX: Replace this with FreeType's hash functions */
David Turner993a8d02002-05-18 12:03:43 +0000216
David Turner993a8d02002-05-18 12:03:43 +0000217
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000218#define INITIAL_HT_SIZE 241
219
220 typedef void
221 (*hash_free_func)( hashnode node );
222
223 static hashnode*
Werner Lemberg428c2e42003-04-25 05:35:04 +0000224 hash_bucket( const char* key,
225 hashtable* ht )
David Turner993a8d02002-05-18 12:03:43 +0000226 {
Werner Lemberg428c2e42003-04-25 05:35:04 +0000227 const char* kp = key;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000228 unsigned long res = 0;
229 hashnode* bp = ht->table, *ndp;
230
231
232 /* Mocklisp hash function. */
233 while ( *kp )
234 res = ( res << 5 ) - res + *kp++;
235
236 ndp = bp + ( res % ht->size );
237 while ( *ndp )
David Turner993a8d02002-05-18 12:03:43 +0000238 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000239 kp = (*ndp)->key;
240 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
241 break;
242 ndp--;
243 if ( ndp < bp )
244 ndp = bp + ( ht->size - 1 );
David Turner993a8d02002-05-18 12:03:43 +0000245 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000246
247 return ndp;
David Turner993a8d02002-05-18 12:03:43 +0000248 }
David Turner993a8d02002-05-18 12:03:43 +0000249
250
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000251 static FT_Error
252 hash_rehash( hashtable* ht,
253 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000254 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000255 hashnode* obp = ht->table, *bp, *nbp;
David Turner993a8d02002-05-18 12:03:43 +0000256 int i, sz = ht->size;
Werner Lemberge3c93012013-03-14 11:21:17 +0100257 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000258
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000259
260 ht->size <<= 1;
261 ht->limit = ht->size / 3;
262
263 if ( FT_NEW_ARRAY( ht->table, ht->size ) )
264 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000265
266 for ( i = 0, bp = obp; i < sz; i++, bp++ )
David Turner993a8d02002-05-18 12:03:43 +0000267 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000268 if ( *bp )
269 {
270 nbp = hash_bucket( (*bp)->key, ht );
271 *nbp = *bp;
272 }
David Turner993a8d02002-05-18 12:03:43 +0000273 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000274 FT_FREE( obp );
275
276 Exit:
277 return error;
David Turner993a8d02002-05-18 12:03:43 +0000278 }
David Turner993a8d02002-05-18 12:03:43 +0000279
280
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000281 static FT_Error
282 hash_init( hashtable* ht,
283 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000284 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100285 int sz = INITIAL_HT_SIZE;
Werner Lemberge3c93012013-03-14 11:21:17 +0100286 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000287
David Turner993a8d02002-05-18 12:03:43 +0000288
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000289 ht->size = sz;
290 ht->limit = sz / 3;
291 ht->used = 0;
David Turner993a8d02002-05-18 12:03:43 +0000292
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000293 if ( FT_NEW_ARRAY( ht->table, sz ) )
294 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000295
296 Exit:
297 return error;
David Turner993a8d02002-05-18 12:03:43 +0000298 }
David Turner993a8d02002-05-18 12:03:43 +0000299
300
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000301 static void
302 hash_free( hashtable* ht,
303 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000304 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000305 if ( ht != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000306 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000307 int i, sz = ht->size;
308 hashnode* bp = ht->table;
David Turner993a8d02002-05-18 12:03:43 +0000309
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000310
311 for ( i = 0; i < sz; i++, bp++ )
312 FT_FREE( *bp );
313
314 FT_FREE( ht->table );
315 }
David Turner993a8d02002-05-18 12:03:43 +0000316 }
317
David Turner993a8d02002-05-18 12:03:43 +0000318
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000319 static FT_Error
320 hash_insert( char* key,
suzuki toshiya704f4d72009-09-13 00:50:14 +0900321 size_t data,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000322 hashtable* ht,
323 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000324 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100325 hashnode nn;
326 hashnode* bp = hash_bucket( key, ht );
Werner Lemberge3c93012013-03-14 11:21:17 +0100327 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000328
329
330 nn = *bp;
331 if ( !nn )
332 {
333 if ( FT_NEW( nn ) )
334 goto Exit;
335 *bp = nn;
336
337 nn->key = key;
338 nn->data = data;
339
340 if ( ht->used >= ht->limit )
341 {
342 error = hash_rehash( ht, memory );
343 if ( error )
344 goto Exit;
345 }
346 ht->used++;
347 }
David Turner993a8d02002-05-18 12:03:43 +0000348 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000349 nn->data = data;
350
351 Exit:
352 return error;
David Turner993a8d02002-05-18 12:03:43 +0000353 }
354
David Turner993a8d02002-05-18 12:03:43 +0000355
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000356 static hashnode
Werner Lemberg428c2e42003-04-25 05:35:04 +0000357 hash_lookup( const char* key,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000358 hashtable* ht )
359 {
360 hashnode *np = hash_bucket( key, ht );
361
362
363 return *np;
364 }
365
366
367 /*************************************************************************/
368 /* */
369 /* Utility types and functions. */
370 /* */
371 /*************************************************************************/
372
373
374 /* Function type for parsing lines of a BDF font. */
375
376 typedef FT_Error
377 (*_bdf_line_func_t)( char* line,
378 unsigned long linelen,
379 unsigned long lineno,
380 void* call_data,
381 void* client_data );
382
383
384 /* List structure for splitting lines into fields. */
385
386 typedef struct _bdf_list_t_
387 {
388 char** field;
389 unsigned long size;
390 unsigned long used;
David Turner68df4f72005-03-15 18:18:57 +0000391 FT_Memory memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000392
393 } _bdf_list_t;
394
395
396 /* Structure used while loading BDF fonts. */
397
398 typedef struct _bdf_parse_t_
399 {
400 unsigned long flags;
401 unsigned long cnt;
402 unsigned long row;
403
404 short minlb;
405 short maxlb;
406 short maxrb;
407 short maxas;
408 short maxds;
409
410 short rbearing;
411
412 char* glyph_name;
413 long glyph_enc;
414
415 bdf_font_t* font;
416 bdf_options_t* opts;
417
Werner Lemberged54e432011-11-27 16:39:53 +0100418 unsigned long have[34816]; /* must be in sync with `nmod' and `umod' */
419 /* arrays from `bdf_font_t' structure */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000420 _bdf_list_t list;
421
422 FT_Memory memory;
423
424 } _bdf_parse_t;
425
426
Werner Lemberga08b2172007-03-28 07:17:17 +0000427#define setsbit( m, cc ) \
428 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
429#define sbitset( m, cc ) \
430 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000431
432
David Turner68df4f72005-03-15 18:18:57 +0000433 static void
434 _bdf_list_init( _bdf_list_t* list,
435 FT_Memory memory )
436 {
Werner Lembergebf55852005-03-16 01:49:54 +0000437 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000438 list->memory = memory;
439 }
440
Werner Lembergebf55852005-03-16 01:49:54 +0000441
David Turner68df4f72005-03-15 18:18:57 +0000442 static void
443 _bdf_list_done( _bdf_list_t* list )
444 {
445 FT_Memory memory = list->memory;
446
Werner Lembergebf55852005-03-16 01:49:54 +0000447
David Turner68df4f72005-03-15 18:18:57 +0000448 if ( memory )
449 {
450 FT_FREE( list->field );
Werner Lembergebf55852005-03-16 01:49:54 +0000451 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000452 }
453 }
454
455
456 static FT_Error
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900457 _bdf_list_ensure( _bdf_list_t* list,
458 unsigned long num_items ) /* same as _bdf_list_t.used */
David Turner68df4f72005-03-15 18:18:57 +0000459 {
Werner Lemberge3c93012013-03-14 11:21:17 +0100460 FT_Error error = FT_Err_Ok;
Werner Lembergebf55852005-03-16 01:49:54 +0000461
David Turner68df4f72005-03-15 18:18:57 +0000462
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900463 if ( num_items > list->size )
David Turner68df4f72005-03-15 18:18:57 +0000464 {
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900465 unsigned long oldsize = list->size; /* same as _bdf_list_t.size */
Werner Lembergcee5d592012-03-01 09:26:03 +0100466 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 5;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900467 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
468 FT_Memory memory = list->memory;
David Turner68df4f72005-03-15 18:18:57 +0000469
Werner Lembergebf55852005-03-16 01:49:54 +0000470
David Turner68df4f72005-03-15 18:18:57 +0000471 if ( oldsize == bigsize )
472 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100473 error = FT_THROW( Out_Of_Memory );
David Turner68df4f72005-03-15 18:18:57 +0000474 goto Exit;
475 }
476 else if ( newsize < oldsize || newsize > bigsize )
477 newsize = bigsize;
478
479 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
480 goto Exit;
481
482 list->size = newsize;
483 }
Werner Lembergebf55852005-03-16 01:49:54 +0000484
David Turner68df4f72005-03-15 18:18:57 +0000485 Exit:
486 return error;
487 }
488
489
490 static void
491 _bdf_list_shift( _bdf_list_t* list,
492 unsigned long n )
493 {
494 unsigned long i, u;
495
496
497 if ( list == 0 || list->used == 0 || n == 0 )
498 return;
499
500 if ( n >= list->used )
501 {
502 list->used = 0;
503 return;
504 }
505
506 for ( u = n, i = 0; u < list->used; i++, u++ )
507 list->field[i] = list->field[u];
508 list->used -= n;
509 }
510
511
Werner Lembergf4c94d42010-06-19 16:08:31 +0200512 /* An empty string for empty fields. */
513
514 static const char empty[1] = { 0 }; /* XXX eliminate this */
515
516
David Turner68df4f72005-03-15 18:18:57 +0000517 static char *
518 _bdf_list_join( _bdf_list_t* list,
519 int c,
520 unsigned long *alen )
521 {
522 unsigned long i, j;
Werner Lembergdc624ca2013-06-04 10:30:48 +0200523 char* dp;
David Turner68df4f72005-03-15 18:18:57 +0000524
525
526 *alen = 0;
527
528 if ( list == 0 || list->used == 0 )
529 return 0;
530
531 dp = list->field[0];
532 for ( i = j = 0; i < list->used; i++ )
533 {
Werner Lembergdc624ca2013-06-04 10:30:48 +0200534 char* fp = list->field[i];
535
536
David Turner68df4f72005-03-15 18:18:57 +0000537 while ( *fp )
538 dp[j++] = *fp++;
539
540 if ( i + 1 < list->used )
541 dp[j++] = (char)c;
542 }
Werner Lembergf4c94d42010-06-19 16:08:31 +0200543 if ( dp != empty )
544 dp[j] = 0;
David Turner68df4f72005-03-15 18:18:57 +0000545
546 *alen = j;
547 return dp;
548 }
549
550
Werner Lemberg03242f52012-02-26 06:52:56 +0100551 /* The code below ensures that we have at least 4 + 1 `field' */
552 /* elements in `list' (which are possibly NULL) so that we */
553 /* don't have to check the number of fields in most cases. */
554
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000555 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000556 _bdf_list_split( _bdf_list_t* list,
557 char* separators,
558 char* line,
559 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000560 {
561 int mult, final_empty;
562 char *sp, *ep, *end;
563 char seps[32];
Werner Lemberge3c93012013-03-14 11:21:17 +0100564 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000565
566
567 /* Initialize the list. */
568 list->used = 0;
Werner Lembergd9c16592012-03-01 15:15:00 +0100569 if ( list->size )
570 {
571 list->field[0] = (char*)empty;
572 list->field[1] = (char*)empty;
573 list->field[2] = (char*)empty;
574 list->field[3] = (char*)empty;
Werner Lemberg649c6732012-03-16 21:12:41 +0100575 list->field[4] = (char*)empty;
Werner Lembergd9c16592012-03-01 15:15:00 +0100576 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000577
578 /* If the line is empty, then simply return. */
579 if ( linelen == 0 || line[0] == 0 )
580 goto Exit;
581
582 /* In the original code, if the `separators' parameter is NULL or */
583 /* empty, the list is split into individual bytes. We don't need */
584 /* this, so an error is signaled. */
585 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000586 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100587 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000588 goto Exit;
589 }
590
591 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000592 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000593
594 /* If the very last character of the separator string is a plus, then */
595 /* set the `mult' flag to indicate that multiple separators should be */
596 /* collapsed into one. */
597 for ( mult = 0, sp = separators; sp && *sp; sp++ )
598 {
599 if ( *sp == '+' && *( sp + 1 ) == 0 )
600 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000601 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000602 setsbit( seps, *sp );
603 }
604
605 /* Break the line up into fields. */
606 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
607 sp < end && *sp; )
608 {
609 /* Collect everything that is not a separator. */
610 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
611 ;
612
613 /* Resize the list if necessary. */
614 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000615 {
Werner Lembergebf55852005-03-16 01:49:54 +0000616 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000617 if ( error )
618 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000619 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000620
621 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000622 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000623
624 sp = ep;
625
626 if ( mult )
627 {
628 /* If multiple separators should be collapsed, do it now by */
629 /* setting all the separator characters to 0. */
630 for ( ; *ep && sbitset( seps, *ep ); ep++ )
631 *ep = 0;
632 }
633 else if ( *ep != 0 )
634 /* Don't collapse multiple separators by making them 0, so just */
635 /* make the one encountered 0. */
636 *ep++ = 0;
637
638 final_empty = ( ep > sp && *ep == 0 );
639 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000640 }
641
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000642 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000643 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000644 {
Werner Lembergebf55852005-03-16 01:49:54 +0000645 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000646 if ( error )
647 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000648 }
649
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000650 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000651 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000652
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000653 list->field[list->used] = 0;
654
655 Exit:
656 return error;
David Turner993a8d02002-05-18 12:03:43 +0000657 }
658
David Turner993a8d02002-05-18 12:03:43 +0000659
David Turner68df4f72005-03-15 18:18:57 +0000660#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000661
Werner Lembergebf55852005-03-16 01:49:54 +0000662
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000663 static FT_Error
664 _bdf_readstream( FT_Stream stream,
665 _bdf_line_func_t callback,
666 void* client_data,
667 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000668 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000669 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000670 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900671 int refill, hold, to_skip;
672 ptrdiff_t bytes, start, end, cursor, avail;
Werner Lemberg059bc332013-03-14 10:27:35 +0100673 char* buf = 0;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000674 FT_Memory memory = stream->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100675 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000676
David Turner993a8d02002-05-18 12:03:43 +0000677
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000678 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000679 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100680 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000681 goto Exit;
682 }
David Turner993a8d02002-05-18 12:03:43 +0000683
Werner Lembergebf55852005-03-16 01:49:54 +0000684 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000685 buf_size = 1024;
686
687 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000688 goto Exit;
689
Werner Lembergebf55852005-03-16 01:49:54 +0000690 cb = callback;
691 lineno = 1;
692 buf[0] = 0;
693 start = 0;
694 end = 0;
695 avail = 0;
696 cursor = 0;
697 refill = 1;
698 to_skip = NO_SKIP;
699 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000700
David Turner68df4f72005-03-15 18:18:57 +0000701 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000702 {
David Turner68df4f72005-03-15 18:18:57 +0000703 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000704 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +0200705 bytes = (ptrdiff_t)FT_Stream_TryRead(
706 stream, (FT_Byte*)buf + cursor,
707 (FT_ULong)( buf_size - cursor ) );
David Turner68df4f72005-03-15 18:18:57 +0000708 avail = cursor + bytes;
709 cursor = 0;
710 refill = 0;
711 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000712
David Turner68df4f72005-03-15 18:18:57 +0000713 end = start;
714
Werner Lembergebf55852005-03-16 01:49:54 +0000715 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000716 if ( start < avail && buf[start] == to_skip )
717 {
718 start += 1;
719 to_skip = NO_SKIP;
720 continue;
721 }
722
723 /* try to find the end of the line */
724 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
725 end++;
726
Werner Lembergebf55852005-03-16 01:49:54 +0000727 /* if we hit the end of the buffer, try shifting its content */
728 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000729 if ( end >= avail )
730 {
731 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
732 break; /* ignore it then exit */
733
734 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000735 {
Werner Lembergebf55852005-03-16 01:49:54 +0000736 /* this line is definitely too long; try resizing the input */
737 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000738 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000739
Werner Lembergebf55852005-03-16 01:49:54 +0000740
741 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000742 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100743 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +0100744 error = FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +0000745 goto Exit;
746 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000747
Werner Lembergebf55852005-03-16 01:49:54 +0000748 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000749 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
750 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000751
David Turner68df4f72005-03-15 18:18:57 +0000752 cursor = buf_size;
753 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000754 }
755 else
756 {
David Turner68df4f72005-03-15 18:18:57 +0000757 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000758
Werner Lemberg04e547b2013-04-03 07:37:56 +0200759 FT_MEM_MOVE( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000760
David Turner68df4f72005-03-15 18:18:57 +0000761 cursor = bytes;
762 avail -= bytes;
763 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000764 }
David Turner68df4f72005-03-15 18:18:57 +0000765 refill = 1;
766 continue;
David Turner993a8d02002-05-18 12:03:43 +0000767 }
David Turner68df4f72005-03-15 18:18:57 +0000768
769 /* Temporarily NUL-terminate the line. */
770 hold = buf[end];
771 buf[end] = 0;
772
773 /* XXX: Use encoding independent value for 0x1a */
774 if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
775 {
Werner Lemberga9f6f852012-12-17 09:08:09 +0100776 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergebf55852005-03-16 01:49:54 +0000777 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200778 /* Redo if we have encountered CHARS without properties. */
779 if ( error == -1 )
Werner Lemberga9f6f852012-12-17 09:08:09 +0100780 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200781 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000782 if ( error )
783 break;
784 }
785
786 lineno += 1;
787 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000788 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000789
790 if ( hold == '\n' )
791 to_skip = '\r';
792 else if ( hold == '\r' )
793 to_skip = '\n';
794 else
795 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000796 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000797
David Turner68df4f72005-03-15 18:18:57 +0000798 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000799
800 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000801 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000802 return error;
David Turner993a8d02002-05-18 12:03:43 +0000803 }
David Turner993a8d02002-05-18 12:03:43 +0000804
805
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000806 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000807
David Turnerb1b47622002-05-21 21:17:43 +0000808 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000809 {
David Turner993a8d02002-05-18 12:03:43 +0000810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
811 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
812 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
813 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
814 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
815 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
816 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
817 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
818 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
819 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
820 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 odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000824 {
David Turner993a8d02002-05-18 12:03:43 +0000825 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
826 0x00, 0x00, 0x00, 0x00, 0x00, 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 Turnerb1b47622002-05-21 21:17:43 +0000831 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000832 {
David Turner993a8d02002-05-18 12:03:43 +0000833 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
834 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
835 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
836 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000837 };
David Turner993a8d02002-05-18 12:03:43 +0000838
David Turnerb1b47622002-05-21 21:17:43 +0000839 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000840 {
David Turner993a8d02002-05-18 12:03:43 +0000841 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
842 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
843 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
844 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000845 };
David Turner993a8d02002-05-18 12:03:43 +0000846
David Turner993a8d02002-05-18 12:03:43 +0000847
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000848 /* Routine to convert an ASCII string into an unsigned long integer. */
849 static unsigned long
850 _bdf_atoul( char* s,
851 char** end,
852 int base )
David Turner993a8d02002-05-18 12:03:43 +0000853 {
David Turnerb1b47622002-05-21 21:17:43 +0000854 unsigned long v;
855 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000856
857
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000858 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000859 return 0;
860
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000861 /* Make sure the radix is something recognizable. Default to 10. */
862 switch ( base )
863 {
864 case 8:
865 dmap = odigits;
866 break;
867 case 16:
868 dmap = hdigits;
869 break;
870 default:
871 base = 10;
872 dmap = ddigits;
873 break;
David Turner993a8d02002-05-18 12:03:43 +0000874 }
875
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000876 /* Check for the special hex prefix. */
877 if ( *s == '0' &&
878 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
879 {
880 base = 16;
881 dmap = hdigits;
882 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000883 }
884
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +0100885 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000886 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000887
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000888 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000889 *end = s;
890
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000891 return v;
892 }
David Turner993a8d02002-05-18 12:03:43 +0000893
David Turner993a8d02002-05-18 12:03:43 +0000894
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000895 /* Routine to convert an ASCII string into an signed long integer. */
896 static long
897 _bdf_atol( char* s,
898 char** end,
899 int base )
900 {
David Turnerb1b47622002-05-21 21:17:43 +0000901 long v, neg;
902 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000903
904
905 if ( s == 0 || *s == 0 )
906 return 0;
907
908 /* Make sure the radix is something recognizable. Default to 10. */
909 switch ( base )
910 {
911 case 8:
912 dmap = odigits;
913 break;
914 case 16:
915 dmap = hdigits;
916 break;
917 default:
918 base = 10;
919 dmap = ddigits;
920 break;
921 }
922
923 /* Check for a minus sign. */
924 neg = 0;
925 if ( *s == '-' )
926 {
927 s++;
928 neg = 1;
929 }
930
931 /* Check for the special hex prefix. */
932 if ( *s == '0' &&
933 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
934 {
935 base = 16;
936 dmap = hdigits;
937 s += 2;
938 }
939
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +0100940 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000941 v = v * base + a2i[(int)*s];
942
943 if ( end != 0 )
944 *end = s;
945
946 return ( !neg ) ? v : -v;
947 }
948
949
950 /* Routine to convert an ASCII string into an signed short integer. */
951 static short
952 _bdf_atos( char* s,
953 char** end,
954 int base )
955 {
David Turnerb1b47622002-05-21 21:17:43 +0000956 short v, neg;
957 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000958
959
960 if ( s == 0 || *s == 0 )
961 return 0;
962
963 /* Make sure the radix is something recognizable. Default to 10. */
964 switch ( base )
965 {
966 case 8:
967 dmap = odigits;
968 break;
969 case 16:
970 dmap = hdigits;
971 break;
972 default:
973 base = 10;
974 dmap = ddigits;
975 break;
976 }
977
978 /* Check for a minus. */
979 neg = 0;
980 if ( *s == '-' )
981 {
982 s++;
983 neg = 1;
984 }
985
986 /* Check for the special hex prefix. */
987 if ( *s == '0' &&
988 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
989 {
990 base = 16;
991 dmap = hdigits;
992 s += 2;
993 }
994
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +0100995 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +0000996 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000997
998 if ( end != 0 )
999 *end = s;
1000
Werner Lemberg233302a2002-05-22 05:41:06 +00001001 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001002 }
1003
1004
1005 /* Routine to compare two glyphs by encoding so they can be sorted. */
1006 static int
1007 by_encoding( const void* a,
1008 const void* b )
1009 {
1010 bdf_glyph_t *c1, *c2;
1011
1012
1013 c1 = (bdf_glyph_t *)a;
1014 c2 = (bdf_glyph_t *)b;
1015
1016 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001017 return -1;
David Turner68df4f72005-03-15 18:18:57 +00001018
1019 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001020 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001021
David Turner993a8d02002-05-18 12:03:43 +00001022 return 0;
David Turner993a8d02002-05-18 12:03:43 +00001023 }
1024
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001025
1026 static FT_Error
1027 bdf_create_property( char* name,
1028 int format,
1029 bdf_font_t* font )
1030 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001031 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001032 bdf_property_t* p;
1033 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001034 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001035
1036
Werner Lemberg96ddc672011-06-29 09:15:54 +02001037 /* First check whether the property has */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001038 /* already been added or not. If it has, then */
1039 /* simply ignore it. */
1040 if ( hash_lookup( name, &(font->proptbl) ) )
1041 goto Exit;
1042
David Turner68df4f72005-03-15 18:18:57 +00001043 if ( FT_RENEW_ARRAY( font->user_props,
1044 font->nuser_props,
1045 font->nuser_props + 1 ) )
1046 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001047
1048 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +00001049 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001050
suzuki toshiya704f4d72009-09-13 00:50:14 +09001051 n = ft_strlen( name ) + 1;
1052 if ( n > FT_ULONG_MAX )
Werner Lemberg059bc332013-03-14 10:27:35 +01001053 return FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +00001054
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001055 if ( FT_NEW_ARRAY( p->name, n ) )
1056 goto Exit;
1057
1058 FT_MEM_COPY( (char *)p->name, name, n );
1059
1060 p->format = format;
1061 p->builtin = 0;
1062
1063 n = _num_bdf_properties + font->nuser_props;
1064
suzuki toshiya704f4d72009-09-13 00:50:14 +09001065 error = hash_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001066 if ( error )
1067 goto Exit;
1068
1069 font->nuser_props++;
1070
1071 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001072 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001073 }
David Turner993a8d02002-05-18 12:03:43 +00001074
1075
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001076 FT_LOCAL_DEF( bdf_property_t * )
1077 bdf_get_property( char* name,
1078 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001079 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001080 hashnode hn;
1081 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001082
1083
1084 if ( name == 0 || *name == 0 )
1085 return 0;
1086
1087 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1088 return 0;
1089
suzuki toshiya704f4d72009-09-13 00:50:14 +09001090 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001091 if ( propid >= _num_bdf_properties )
1092 return font->user_props + ( propid - _num_bdf_properties );
1093
Werner Lemberg233302a2002-05-22 05:41:06 +00001094 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001095 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001096
1097
1098 /*************************************************************************/
1099 /* */
1100 /* BDF font file parsing flags and functions. */
1101 /* */
1102 /*************************************************************************/
1103
1104
1105 /* Parse flags. */
1106
1107#define _BDF_START 0x0001
1108#define _BDF_FONT_NAME 0x0002
1109#define _BDF_SIZE 0x0004
1110#define _BDF_FONT_BBX 0x0008
1111#define _BDF_PROPS 0x0010
1112#define _BDF_GLYPHS 0x0020
1113#define _BDF_GLYPH 0x0040
1114#define _BDF_ENCODING 0x0080
1115#define _BDF_SWIDTH 0x0100
1116#define _BDF_DWIDTH 0x0200
1117#define _BDF_BBX 0x0400
1118#define _BDF_BITMAP 0x0800
1119
1120#define _BDF_SWIDTH_ADJ 0x1000
1121
1122#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1123 _BDF_ENCODING | \
1124 _BDF_SWIDTH | \
1125 _BDF_DWIDTH | \
1126 _BDF_BBX | \
1127 _BDF_BITMAP )
1128
Werner Lembergf1c2b912006-01-13 14:53:28 +00001129#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1130#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001131
1132
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001133 static FT_Error
1134 _bdf_add_comment( bdf_font_t* font,
1135 char* comment,
1136 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001137 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001138 char* cp;
1139 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001140 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001141
1142
David Turner68df4f72005-03-15 18:18:57 +00001143 if ( FT_RENEW_ARRAY( font->comments,
1144 font->comments_len,
1145 font->comments_len + len + 1 ) )
1146 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001147
1148 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001149
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001150 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001151 cp[len] = '\n';
1152
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001153 font->comments_len += len + 1;
1154
1155 Exit:
1156 return error;
David Turner993a8d02002-05-18 12:03:43 +00001157 }
1158
David Turner993a8d02002-05-18 12:03:43 +00001159
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001160 /* Set the spacing from the font name if it exists, or set it to the */
1161 /* default specified in the options. */
1162 static FT_Error
1163 _bdf_set_default_spacing( bdf_font_t* font,
Werner Lemberge01406b2011-11-25 09:44:28 +01001164 bdf_options_t* opts,
1165 unsigned long lineno )
David Turner993a8d02002-05-18 12:03:43 +00001166 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001167 size_t len;
1168 char name[256];
1169 _bdf_list_t list;
1170 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001171 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001172
Dave Arnoldc3782492013-06-05 19:57:55 +02001173 FT_UNUSED( lineno ); /* only used in debug mode */
1174
David Turner993a8d02002-05-18 12:03:43 +00001175
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001176 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1177 {
Werner Lemberg059bc332013-03-14 10:27:35 +01001178 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001179 goto Exit;
1180 }
David Turner993a8d02002-05-18 12:03:43 +00001181
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001182 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001183
David Turner68df4f72005-03-15 18:18:57 +00001184 _bdf_list_init( &list, memory );
1185
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001186 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001187
suzuki toshiya704f4d72009-09-13 00:50:14 +09001188 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +00001189 /* Limit ourselves to 256 characters in the font name. */
1190 if ( len >= 256 )
1191 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001192 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001193 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001194 goto Exit;
1195 }
1196
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001197 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001198
Werner Lembergbadf3172013-06-06 09:16:38 +02001199 error = _bdf_list_split( &list, (char *)"-", name, (unsigned long)len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001200 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001201 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001202
1203 if ( list.used == 15 )
1204 {
1205 switch ( list.field[11][0] )
1206 {
1207 case 'C':
1208 case 'c':
1209 font->spacing = BDF_CHARCELL;
1210 break;
1211 case 'M':
1212 case 'm':
1213 font->spacing = BDF_MONOWIDTH;
1214 break;
1215 case 'P':
1216 case 'p':
1217 font->spacing = BDF_PROPORTIONAL;
1218 break;
David Turner993a8d02002-05-18 12:03:43 +00001219 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001220 }
1221
David Turner68df4f72005-03-15 18:18:57 +00001222 Fail:
1223 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001224
1225 Exit:
1226 return error;
David Turner993a8d02002-05-18 12:03:43 +00001227 }
David Turner993a8d02002-05-18 12:03:43 +00001228
1229
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001230 /* Determine whether the property is an atom or not. If it is, then */
1231 /* clean it up so the double quotes are removed if they exist. */
1232 static int
1233 _bdf_is_atom( char* line,
1234 unsigned long linelen,
1235 char** name,
1236 char** value,
1237 bdf_font_t* font )
1238 {
1239 int hold;
1240 char *sp, *ep;
1241 bdf_property_t* p;
1242
David Turner993a8d02002-05-18 12:03:43 +00001243
1244 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001245
1246 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001247 ep++;
1248
1249 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001250 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001251 {
1252 hold = *ep;
1253 *ep = 0;
1254 }
1255
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001256 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001257
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001258 /* Restore the character that was saved before any return can happen. */
1259 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001260 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001261
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001262 /* If the property exists and is not an atom, just return here. */
1263 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001264 return 0;
1265
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001266 /* The property is an atom. Trim all leading and trailing whitespace */
1267 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001268 sp = ep;
1269 ep = line + linelen;
1270
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001271 /* Trim the leading whitespace if it exists. */
Werner Lemberg320d4972012-02-24 18:06:46 +01001272 if ( *sp )
1273 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001274 while ( *sp &&
1275 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001276 sp++;
1277
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001278 /* Trim the leading double quote if it exists. */
1279 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001280 sp++;
1281 *value = sp;
1282
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001283 /* Trim the trailing whitespace if it exists. */
1284 while ( ep > sp &&
1285 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001286 *--ep = 0;
1287
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001288 /* Trim the trailing double quote if it exists. */
1289 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001290 *--ep = 0;
1291
1292 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001293 }
David Turner993a8d02002-05-18 12:03:43 +00001294
1295
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001296 static FT_Error
Werner Lemberge01406b2011-11-25 09:44:28 +01001297 _bdf_add_property( bdf_font_t* font,
1298 char* name,
1299 char* value,
1300 unsigned long lineno )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001301 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001302 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001303 hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001304 bdf_property_t *prop, *fp;
1305 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001306 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001307
Dave Arnoldc3782492013-06-05 19:57:55 +02001308 FT_UNUSED( lineno ); /* only used in debug mode */
1309
David Turner993a8d02002-05-18 12:03:43 +00001310
Werner Lemberg96ddc672011-06-29 09:15:54 +02001311 /* First, check whether the property already exists in the font. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001312 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001313 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001314 /* The property already exists in the font, so simply replace */
1315 /* the value of the property with the current value. */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001316 fp = font->props + hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001317
David Turnerb1b47622002-05-21 21:17:43 +00001318 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001319 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001320 case BDF_ATOM:
1321 /* Delete the current atom if it exists. */
1322 FT_FREE( fp->value.atom );
1323
David Turnerc0f9c4a2007-02-12 14:55:03 +00001324 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001325 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001326 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001327 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001328 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001329 break;
1330
1331 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001332 fp->value.l = _bdf_atol( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001333 break;
1334
1335 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001336 fp->value.ul = _bdf_atoul( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001337 break;
David Turnerd490e372002-05-28 23:40:37 +00001338
David Turnerb1b47622002-05-21 21:17:43 +00001339 default:
1340 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001341 }
David Turnerd490e372002-05-28 23:40:37 +00001342
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001343 goto Exit;
1344 }
1345
1346 /* See whether this property type exists yet or not. */
1347 /* If not, create it. */
1348 hn = hash_lookup( name, &(font->proptbl) );
1349 if ( hn == 0 )
1350 {
1351 error = bdf_create_property( name, BDF_ATOM, font );
1352 if ( error )
1353 goto Exit;
1354 hn = hash_lookup( name, &(font->proptbl) );
1355 }
1356
1357 /* Allocate another property if this is overflow. */
1358 if ( font->props_used == font->props_size )
1359 {
1360 if ( font->props_size == 0 )
1361 {
1362 if ( FT_NEW_ARRAY( font->props, 1 ) )
1363 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001364 }
1365 else
1366 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001367 if ( FT_RENEW_ARRAY( font->props,
1368 font->props_size,
1369 font->props_size + 1 ) )
1370 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001371 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001372
David Turner993a8d02002-05-18 12:03:43 +00001373 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001374 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001375 font->props_size++;
1376 }
1377
suzuki toshiya704f4d72009-09-13 00:50:14 +09001378 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001379 if ( propid >= _num_bdf_properties )
1380 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001381 else
David Turnerb1b47622002-05-21 21:17:43 +00001382 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001383
1384 fp = font->props + font->props_used;
1385
1386 fp->name = prop->name;
1387 fp->format = prop->format;
1388 fp->builtin = prop->builtin;
1389
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001390 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001391 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001392 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001393 fp->value.atom = 0;
1394 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001395 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001396 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001397 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001398 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001399 break;
David Turner993a8d02002-05-18 12:03:43 +00001400
1401 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001402 fp->value.l = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001403 break;
1404
1405 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001406 fp->value.ul = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001407 break;
David Turner993a8d02002-05-18 12:03:43 +00001408 }
1409
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001410 /* If the property happens to be a comment, then it doesn't need */
1411 /* to be added to the internal hash table. */
Werner Lemberg370aea82010-06-08 08:37:11 +02001412 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 )
1413 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001414 /* Add the property to the font property table. */
1415 error = hash_insert( fp->name,
suzuki toshiya704f4d72009-09-13 00:50:14 +09001416 font->props_used,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001417 (hashtable *)font->internal,
1418 memory );
1419 if ( error )
1420 goto Exit;
1421 }
David Turner993a8d02002-05-18 12:03:43 +00001422
1423 font->props_used++;
1424
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001425 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1426 /* property needs to be located if it exists in the property list, the */
1427 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1428 /* present, and the SPACING property should override the default */
1429 /* spacing. */
1430 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001431 font->default_char = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001432 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001433 font->font_ascent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001434 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001435 font->font_descent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001436 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001437 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001438 if ( !fp->value.atom )
1439 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001440 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001441 error = FT_THROW( Invalid_File_Format );
Werner Lembergb66efef2009-03-12 08:07:49 +00001442 goto Exit;
1443 }
1444
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001445 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001446 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001447 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001448 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001449 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001450 font->spacing = BDF_CHARCELL;
1451 }
1452
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001453 Exit:
1454 return error;
David Turner993a8d02002-05-18 12:03:43 +00001455 }
1456
David Turner993a8d02002-05-18 12:03:43 +00001457
David Turnerb1b47622002-05-21 21:17:43 +00001458 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001459 {
1460 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1461 };
1462
1463
1464 /* Actually parse the glyph info and bitmaps. */
1465 static FT_Error
1466 _bdf_parse_glyphs( char* line,
1467 unsigned long linelen,
1468 unsigned long lineno,
1469 void* call_data,
1470 void* client_data )
1471 {
1472 int c, mask_index;
1473 char* s;
1474 unsigned char* bp;
1475 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001476
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001477 _bdf_parse_t* p;
1478 bdf_glyph_t* glyph;
1479 bdf_font_t* font;
1480
1481 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001482 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001483
Werner Lemberg319c00d2003-04-23 19:48:24 +00001484 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001485 FT_UNUSED( lineno ); /* only used in debug mode */
1486
1487
Werner Lemberg319c00d2003-04-23 19:48:24 +00001488 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001489
1490 font = p->font;
1491 memory = font->memory;
1492
1493 /* Check for a comment. */
1494 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1495 {
1496 linelen -= 7;
1497
1498 s = line + 7;
1499 if ( *s != 0 )
1500 {
1501 s++;
1502 linelen--;
1503 }
1504 error = _bdf_add_comment( p->font, s, linelen );
1505 goto Exit;
1506 }
1507
1508 /* The very first thing expected is the number of glyphs. */
1509 if ( !( p->flags & _BDF_GLYPHS ) )
1510 {
1511 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1512 {
1513 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001514 error = FT_THROW( Missing_Chars_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001515 goto Exit;
1516 }
1517
David Turner68df4f72005-03-15 18:18:57 +00001518 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001519 if ( error )
1520 goto Exit;
1521 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1522
1523 /* Make sure the number of glyphs is non-zero. */
1524 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001525 font->glyphs_size = 64;
1526
Werner Lemberga08b2172007-03-28 07:17:17 +00001527 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1528 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001529 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001530 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001531 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001532 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001533 goto Exit;
1534 }
1535
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001536 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1537 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001538
David Turner993a8d02002-05-18 12:03:43 +00001539 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001540
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001541 goto Exit;
1542 }
1543
1544 /* Check for the ENDFONT field. */
1545 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1546 {
1547 /* Sort the glyphs by encoding. */
1548 ft_qsort( (char *)font->glyphs,
1549 font->glyphs_used,
1550 sizeof ( bdf_glyph_t ),
1551 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001552
1553 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001554
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001555 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001556 }
1557
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001558 /* Check for the ENDCHAR field. */
1559 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1560 {
1561 p->glyph_enc = 0;
1562 p->flags &= ~_BDF_GLYPH_BITS;
1563
1564 goto Exit;
1565 }
1566
Werner Lemberg96ddc672011-06-29 09:15:54 +02001567 /* Check whether a glyph is being scanned but should be */
1568 /* ignored because it is an unencoded glyph. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001569 if ( ( p->flags & _BDF_GLYPH ) &&
1570 p->glyph_enc == -1 &&
1571 p->opts->keep_unencoded == 0 )
1572 goto Exit;
1573
1574 /* Check for the STARTCHAR field. */
1575 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1576 {
1577 /* Set the character name in the parse info first until the */
1578 /* encoding can be checked for an unencoded character. */
1579 FT_FREE( p->glyph_name );
1580
David Turner68df4f72005-03-15 18:18:57 +00001581 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001582 if ( error )
1583 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001584
David Turner68df4f72005-03-15 18:18:57 +00001585 _bdf_list_shift( &p->list, 1 );
1586
1587 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001588
Werner Lembergba03af62007-05-30 13:57:02 +00001589 if ( !s )
1590 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001591 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001592 error = FT_THROW( Invalid_File_Format );
Werner Lembergba03af62007-05-30 13:57:02 +00001593 goto Exit;
1594 }
1595
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001596 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1597 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001598
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001599 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1600
1601 p->flags |= _BDF_GLYPH;
1602
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001603 FT_TRACE4(( DBGMSG1, lineno, s ));
1604
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001605 goto Exit;
1606 }
1607
1608 /* Check for the ENCODING field. */
1609 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1610 {
1611 if ( !( p->flags & _BDF_GLYPH ) )
1612 {
1613 /* Missing STARTCHAR field. */
1614 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001615 error = FT_THROW( Missing_Startchar_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001616 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001617 }
1618
David Turner68df4f72005-03-15 18:18:57 +00001619 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001620 if ( error )
1621 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001622
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001623 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001624
Werner Lemberg28dd2c42012-02-26 06:18:58 +01001625 /* Normalize negative encoding values. The specification only */
1626 /* allows -1, but we can be more generous here. */
1627 if ( p->glyph_enc < -1 )
1628 p->glyph_enc = -1;
1629
Werner Lemberg03242f52012-02-26 06:52:56 +01001630 /* Check for alternative encoding format. */
1631 if ( p->glyph_enc == -1 && p->list.used > 2 )
1632 p->glyph_enc = _bdf_atol( p->list.field[2], 0, 10 );
1633
Werner Lemberg7f2e4f42012-12-15 09:39:41 +01001634 if ( p->glyph_enc < -1 )
1635 p->glyph_enc = -1;
1636
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001637 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1638
Werner Lemberged54e432011-11-27 16:39:53 +01001639 /* Check that the encoding is in the Unicode range because */
1640 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lemberg07bdb6e2012-12-15 02:02:23 +01001641 if ( p->glyph_enc > 0 &&
1642 (size_t)p->glyph_enc >= sizeof ( p->have ) /
1643 sizeof ( unsigned long ) * 32 )
David Turner481838e2006-02-23 12:40:14 +00001644 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001645 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001646 error = FT_THROW( Invalid_File_Format );
David Turner481838e2006-02-23 12:40:14 +00001647 goto Exit;
1648 }
1649
Werner Lemberg96ddc672011-06-29 09:15:54 +02001650 /* Check whether this encoding has already been encountered. */
1651 /* If it has then change it to unencoded so it gets added if */
1652 /* indicated. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001653 if ( p->glyph_enc >= 0 )
1654 {
1655 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1656 {
1657 /* Emit a message saying a glyph has been moved to the */
1658 /* unencoded area. */
1659 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1660 p->glyph_enc, p->glyph_name ));
1661 p->glyph_enc = -1;
1662 font->modified = 1;
1663 }
1664 else
1665 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1666 }
1667
1668 if ( p->glyph_enc >= 0 )
1669 {
1670 /* Make sure there are enough glyphs allocated in case the */
1671 /* number of characters happen to be wrong. */
1672 if ( font->glyphs_used == font->glyphs_size )
1673 {
1674 if ( FT_RENEW_ARRAY( font->glyphs,
1675 font->glyphs_size,
1676 font->glyphs_size + 64 ) )
1677 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001678
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001679 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001680 }
1681
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001682 glyph = font->glyphs + font->glyphs_used++;
1683 glyph->name = p->glyph_name;
1684 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001685
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001686 /* Reset the initial glyph info. */
1687 p->glyph_name = 0;
1688 }
1689 else
1690 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001691 /* Unencoded glyph. Check whether it should */
1692 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001693 if ( p->opts->keep_unencoded != 0 )
1694 {
1695 /* Allocate the next unencoded glyph. */
1696 if ( font->unencoded_used == font->unencoded_size )
1697 {
David Turner68df4f72005-03-15 18:18:57 +00001698 if ( FT_RENEW_ARRAY( font->unencoded ,
1699 font->unencoded_size,
1700 font->unencoded_size + 4 ) )
1701 goto Exit;
1702
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001703 font->unencoded_size += 4;
1704 }
1705
1706 glyph = font->unencoded + font->unencoded_used;
1707 glyph->name = p->glyph_name;
1708 glyph->encoding = font->unencoded_used++;
1709 }
1710 else
1711 /* Free up the glyph name if the unencoded shouldn't be */
1712 /* kept. */
1713 FT_FREE( p->glyph_name );
1714
1715 p->glyph_name = 0;
1716 }
1717
1718 /* Clear the flags that might be added when width and height are */
1719 /* checked for consistency. */
1720 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1721
1722 p->flags |= _BDF_ENCODING;
1723
1724 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001725 }
1726
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001727 /* Point at the glyph being constructed. */
1728 if ( p->glyph_enc == -1 )
1729 glyph = font->unencoded + ( font->unencoded_used - 1 );
1730 else
1731 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001732
Werner Lemberg96ddc672011-06-29 09:15:54 +02001733 /* Check whether a bitmap is being constructed. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001734 if ( p->flags & _BDF_BITMAP )
1735 {
1736 /* If there are more rows than are specified in the glyph metrics, */
1737 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001738 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001739 {
1740 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1741 {
1742 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1743 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001744 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001745 }
1746
1747 goto Exit;
1748 }
1749
1750 /* Only collect the number of nibbles indicated by the glyph */
1751 /* metrics. If there are more columns, they are simply ignored. */
1752 nibbles = glyph->bpr << 1;
1753 bp = glyph->bitmap + p->row * glyph->bpr;
1754
David Turnerb698eed2006-02-23 14:50:13 +00001755 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001756 {
1757 c = line[i];
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001758 if ( !sbitset( hdigits, c ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001759 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001760 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001761 if ( i + 1 < nibbles && ( i & 1 ) )
1762 *++bp = 0;
1763 }
1764
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001765 /* If any line has not enough columns, */
1766 /* indicate they have been padded with zero bits. */
1767 if ( i < nibbles &&
1768 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1769 {
1770 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
1771 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1772 font->modified = 1;
1773 }
1774
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001775 /* Remove possible garbage at the right. */
1776 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001777 if ( glyph->bbx.width )
1778 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001779
1780 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001781 if ( i == nibbles &&
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001782 sbitset( hdigits, line[nibbles] ) &&
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001783 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001784 {
1785 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1786 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1787 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001788 }
1789
1790 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001791 goto Exit;
1792 }
David Turner993a8d02002-05-18 12:03:43 +00001793
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001794 /* Expect the SWIDTH (scalable width) field next. */
1795 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1796 {
1797 if ( !( p->flags & _BDF_ENCODING ) )
Werner Lemberg4086fb72012-03-01 08:55:40 +01001798 goto Missing_Encoding;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001799
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 Turner68df4f72005-03-15 18:18:57 +00001803
David Turnerb1b47622002-05-21 21:17:43 +00001804 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001805 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001806
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001807 goto Exit;
1808 }
David Turner993a8d02002-05-18 12:03:43 +00001809
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001810 /* Expect the DWIDTH (scalable width) field next. */
1811 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1812 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001813 if ( !( p->flags & _BDF_ENCODING ) )
1814 goto Missing_Encoding;
1815
David Turner68df4f72005-03-15 18:18:57 +00001816 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001817 if ( error )
1818 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001819
David Turnerb1b47622002-05-21 21:17:43 +00001820 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001821
1822 if ( !( p->flags & _BDF_SWIDTH ) )
1823 {
1824 /* Missing SWIDTH field. Emit an auto correction message and set */
1825 /* the scalable width from the device width. */
1826 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1827
Werner Lemberg02d4d592002-05-28 22:38:05 +00001828 glyph->swidth = (unsigned short)FT_MulDiv(
1829 glyph->dwidth, 72000L,
1830 (FT_Long)( font->point_size *
1831 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001832 }
1833
1834 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001835 goto Exit;
1836 }
David Turner993a8d02002-05-18 12:03:43 +00001837
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001838 /* Expect the BBX field next. */
1839 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1840 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001841 if ( !( p->flags & _BDF_ENCODING ) )
1842 goto Missing_Encoding;
1843
David Turner68df4f72005-03-15 18:18:57 +00001844 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001845 if ( error )
1846 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001847
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001848 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1849 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1850 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1851 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1852
1853 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001854 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1855 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001856
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001857 /* Determine the overall font bounding box as the characters are */
1858 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001859 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1860 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001861
David Turnerb1b47622002-05-21 21:17:43 +00001862 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001863
Werner Lembergdfa46192004-03-05 09:26:24 +00001864 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1865 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1866 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001867
1868 if ( !( p->flags & _BDF_DWIDTH ) )
1869 {
1870 /* Missing DWIDTH field. Emit an auto correction message and set */
1871 /* the device width to the glyph width. */
1872 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1873 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001874 }
1875
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001876 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1877 /* value if necessary. */
1878 if ( p->opts->correct_metrics != 0 )
1879 {
1880 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001881 unsigned short sw = (unsigned short)FT_MulDiv(
1882 glyph->dwidth, 72000L,
1883 (FT_Long)( font->point_size *
1884 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001885
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001886
1887 if ( sw != glyph->swidth )
1888 {
1889 glyph->swidth = sw;
1890
1891 if ( p->glyph_enc == -1 )
1892 _bdf_set_glyph_modified( font->umod,
1893 font->unencoded_used - 1 );
1894 else
1895 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1896
1897 p->flags |= _BDF_SWIDTH_ADJ;
1898 font->modified = 1;
1899 }
David Turner993a8d02002-05-18 12:03:43 +00001900 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001901
David Turner993a8d02002-05-18 12:03:43 +00001902 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001903 goto Exit;
1904 }
David Turner993a8d02002-05-18 12:03:43 +00001905
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001906 /* And finally, gather up the bitmap. */
1907 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1908 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001909 unsigned long bitmap_size;
1910
1911
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001912 if ( !( p->flags & _BDF_BBX ) )
1913 {
1914 /* Missing BBX field. */
1915 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001916 error = FT_THROW( Missing_Bbx_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001917 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001918 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001919
1920 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001921 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001922
1923 bitmap_size = glyph->bpr * glyph->bbx.height;
Werner Lembergc4cad302012-03-08 20:11:37 +01001924 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
Werner Lemberg26170df2006-03-26 07:19:07 +00001925 {
1926 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001927 error = FT_THROW( Bbx_Too_Big );
Werner Lemberg26170df2006-03-26 07:19:07 +00001928 goto Exit;
1929 }
1930 else
1931 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001932
1933 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1934 goto Exit;
1935
1936 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001937 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001938
1939 goto Exit;
1940 }
1941
Werner Lemberge01406b2011-11-25 09:44:28 +01001942 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001943 error = FT_THROW( Invalid_File_Format );
Werner Lemberg4086fb72012-03-01 08:55:40 +01001944 goto Exit;
1945
1946 Missing_Encoding:
1947 /* Missing ENCODING field. */
1948 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001949 error = FT_THROW( Missing_Encoding_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001950
1951 Exit:
Werner Lembergf4c94d42010-06-19 16:08:31 +02001952 if ( error && ( p->flags & _BDF_GLYPH ) )
1953 FT_FREE( p->glyph_name );
1954
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001955 return error;
David Turner993a8d02002-05-18 12:03:43 +00001956 }
1957
David Turner993a8d02002-05-18 12:03:43 +00001958
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001959 /* Load the font properties. */
1960 static FT_Error
1961 _bdf_parse_properties( char* line,
1962 unsigned long linelen,
1963 unsigned long lineno,
1964 void* call_data,
1965 void* client_data )
1966 {
1967 unsigned long vlen;
1968 _bdf_line_func_t* next;
1969 _bdf_parse_t* p;
1970 char* name;
1971 char* value;
1972 char nbuf[128];
Werner Lemberge3c93012013-03-14 11:21:17 +01001973 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001974
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001975 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001976
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001977
1978 next = (_bdf_line_func_t *)call_data;
1979 p = (_bdf_parse_t *) client_data;
1980
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001981 /* Check for the end of the properties. */
1982 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1983 {
1984 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1985 /* encountered yet, then make sure they are added as properties and */
1986 /* make sure they are set from the font bounding box info. */
1987 /* */
1988 /* This is *always* done regardless of the options, because X11 */
1989 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001990 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001991 {
1992 p->font->font_ascent = p->font->bbx.ascent;
1993 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001994 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
1995 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001996 if ( error )
1997 goto Exit;
1998
1999 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2000 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002001 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002002
Werner Lemberg428c2e42003-04-25 05:35:04 +00002003 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002004 {
2005 p->font->font_descent = p->font->bbx.descent;
2006 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002007 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2008 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002009 if ( error )
2010 goto Exit;
2011
2012 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2013 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002014 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002015
David Turner993a8d02002-05-18 12:03:43 +00002016 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002017 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00002018
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002019 goto Exit;
2020 }
David Turner993a8d02002-05-18 12:03:43 +00002021
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002022 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
2023 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
2024 goto Exit;
2025
2026 /* Handle COMMENT fields and properties in a special way to preserve */
2027 /* the spacing. */
2028 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2029 {
David Turner993a8d02002-05-18 12:03:43 +00002030 name = value = line;
2031 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002032 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00002033 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01002034 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002035 if ( error )
2036 goto Exit;
2037 }
2038 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
2039 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002040 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002041 if ( error )
2042 goto Exit;
2043 }
2044 else
2045 {
David Turner68df4f72005-03-15 18:18:57 +00002046 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002047 if ( error )
2048 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002049 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002050
David Turner68df4f72005-03-15 18:18:57 +00002051 _bdf_list_shift( &p->list, 1 );
2052 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002053
Werner Lemberge01406b2011-11-25 09:44:28 +01002054 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002055 if ( error )
2056 goto Exit;
2057 }
2058
2059 Exit:
2060 return error;
David Turner993a8d02002-05-18 12:03:43 +00002061 }
2062
David Turner993a8d02002-05-18 12:03:43 +00002063
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002064 /* Load the font header. */
2065 static FT_Error
2066 _bdf_parse_start( char* line,
2067 unsigned long linelen,
2068 unsigned long lineno,
2069 void* call_data,
2070 void* client_data )
2071 {
2072 unsigned long slen;
2073 _bdf_line_func_t* next;
2074 _bdf_parse_t* p;
2075 bdf_font_t* font;
2076 char *s;
David Turner993a8d02002-05-18 12:03:43 +00002077
David Turnerd490e372002-05-28 23:40:37 +00002078 FT_Memory memory = NULL;
Werner Lemberge3c93012013-03-14 11:21:17 +01002079 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002080
2081 FT_UNUSED( lineno ); /* only used in debug mode */
2082
2083
2084 next = (_bdf_line_func_t *)call_data;
2085 p = (_bdf_parse_t *) client_data;
2086
2087 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00002088 memory = p->font->memory;
2089
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002090 /* Check for a comment. This is done to handle those fonts that have */
2091 /* comments before the STARTFONT line for some reason. */
2092 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2093 {
2094 if ( p->opts->keep_comments != 0 && p->font != 0 )
2095 {
2096 linelen -= 7;
2097
2098 s = line + 7;
2099 if ( *s != 0 )
2100 {
2101 s++;
2102 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002103 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002104
2105 error = _bdf_add_comment( p->font, s, linelen );
2106 if ( error )
2107 goto Exit;
2108 /* here font is not defined! */
2109 }
2110
2111 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002112 }
2113
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002114 if ( !( p->flags & _BDF_START ) )
2115 {
2116 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002117
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002118 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2119 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01002120 /* we don't emit an error message since this code gets */
2121 /* explicitly caught one level higher */
Werner Lemberg059bc332013-03-14 10:27:35 +01002122 error = FT_THROW( Missing_Startfont_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002123 goto Exit;
2124 }
David Turner993a8d02002-05-18 12:03:43 +00002125
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002126 p->flags = _BDF_START;
2127 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002128
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002129 if ( FT_NEW( font ) )
2130 goto Exit;
2131 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002132
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002133 font->memory = p->memory;
2134 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002135
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002136 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09002137 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002138 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002139
David Turner993a8d02002-05-18 12:03:43 +00002140
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002141 error = hash_init( &(font->proptbl), memory );
2142 if ( error )
2143 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002144 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002145 i < _num_bdf_properties; i++, prop++ )
2146 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09002147 error = hash_insert( prop->name, i,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002148 &(font->proptbl), memory );
2149 if ( error )
2150 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002151 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002152 }
2153
2154 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2155 goto Exit;
2156 error = hash_init( (hashtable *)p->font->internal,memory );
2157 if ( error )
2158 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002159 p->font->spacing = p->opts->font_spacing;
2160 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002161
2162 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002163 }
2164
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002165 /* Check for the start of the properties. */
2166 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2167 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002168 if ( !( p->flags & _BDF_FONT_BBX ) )
Werner Lembergfb690292010-06-23 10:00:52 +02002169 {
2170 /* Missing the FONTBOUNDINGBOX field. */
2171 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002172 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergfb690292010-06-23 10:00:52 +02002173 goto Exit;
2174 }
2175
David Turner68df4f72005-03-15 18:18:57 +00002176 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002177 if ( error )
2178 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00002179 /* at this point, `p->font' can't be NULL */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002180 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2181
2182 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
Werner Lemberg9b6b5752012-12-15 01:34:41 +01002183 {
2184 p->font->props_size = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002185 goto Exit;
Werner Lemberg9b6b5752012-12-15 01:34:41 +01002186 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002187
2188 p->flags |= _BDF_PROPS;
2189 *next = _bdf_parse_properties;
2190
2191 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002192 }
2193
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002194 /* Check for the FONTBOUNDINGBOX field. */
2195 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2196 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002197 if ( !( p->flags & _BDF_SIZE ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002198 {
2199 /* Missing the SIZE field. */
2200 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002201 error = FT_THROW( Missing_Size_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002202 goto Exit;
2203 }
2204
David Turner68df4f72005-03-15 18:18:57 +00002205 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002206 if ( error )
2207 goto Exit;
2208
2209 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2210 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2211
2212 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2213 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2214
David Turnerd490e372002-05-28 23:40:37 +00002215 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002216 p->font->bbx.y_offset );
2217
2218 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002219
2220 p->flags |= _BDF_FONT_BBX;
2221
2222 goto Exit;
2223 }
2224
2225 /* The next thing to check for is the FONT field. */
2226 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2227 {
David Turner68df4f72005-03-15 18:18:57 +00002228 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002229 if ( error )
2230 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002231 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002232
David Turner68df4f72005-03-15 18:18:57 +00002233 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002234
2235 if ( !s )
2236 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002237 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002238 error = FT_THROW( Invalid_File_Format );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002239 goto Exit;
2240 }
2241
Werner Lembergfb690292010-06-23 10:00:52 +02002242 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2243 FT_FREE( p->font->name );
2244
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002245 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2246 goto Exit;
2247 FT_MEM_COPY( p->font->name, s, slen + 1 );
2248
2249 /* If the font name is an XLFD name, set the spacing to the one in */
2250 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002251 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002252 if ( error )
2253 goto Exit;
2254
2255 p->flags |= _BDF_FONT_NAME;
2256
2257 goto Exit;
2258 }
2259
2260 /* Check for the SIZE field. */
2261 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2262 {
2263 if ( !( p->flags & _BDF_FONT_NAME ) )
2264 {
2265 /* Missing the FONT field. */
2266 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002267 error = FT_THROW( Missing_Font_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002268 goto Exit;
2269 }
2270
David Turner68df4f72005-03-15 18:18:57 +00002271 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002272 if ( error )
2273 goto Exit;
2274
2275 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2276 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2277 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2278
2279 /* Check for the bits per pixel field. */
2280 if ( p->list.used == 5 )
2281 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002282 unsigned short bitcount, i, shift;
2283
2284
2285 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2286
2287 /* Only values 1, 2, 4, 8 are allowed. */
2288 shift = p->font->bpp;
2289 bitcount = 0;
2290 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002291 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002292 if ( shift & 1 )
2293 bitcount = i;
2294 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002295 }
David Turner993a8d02002-05-18 12:03:43 +00002296
Werner Lembergbd8e3242002-06-12 08:43:58 +00002297 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002298
2299 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002300 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002301 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002302 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002303 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002304 }
2305 }
2306 else
2307 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002308
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002309 p->flags |= _BDF_SIZE;
2310
2311 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002312 }
2313
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002314 /* Check for the CHARS field -- font properties are optional */
2315 if ( ft_memcmp( line, "CHARS", 5 ) == 0 )
2316 {
2317 char nbuf[128];
2318
2319
2320 if ( !( p->flags & _BDF_FONT_BBX ) )
2321 {
2322 /* Missing the FONTBOUNDINGBOX field. */
2323 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002324 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002325 goto Exit;
2326 }
2327
2328 /* Add the two standard X11 properties which are required */
2329 /* for compiling fonts. */
2330 p->font->font_ascent = p->font->bbx.ascent;
2331 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002332 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2333 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002334 if ( error )
2335 goto Exit;
2336 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2337
2338 p->font->font_descent = p->font->bbx.descent;
2339 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002340 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2341 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002342 if ( error )
2343 goto Exit;
2344 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2345
2346 p->font->modified = 1;
2347
2348 *next = _bdf_parse_glyphs;
2349
2350 /* A special return value. */
2351 error = -1;
2352 goto Exit;
2353 }
2354
Werner Lemberge01406b2011-11-25 09:44:28 +01002355 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002356 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002357
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002358 Exit:
2359 return error;
2360 }
David Turner993a8d02002-05-18 12:03:43 +00002361
2362
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002363 /*************************************************************************/
2364 /* */
2365 /* API. */
2366 /* */
2367 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002368
David Turner993a8d02002-05-18 12:03:43 +00002369
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002370 FT_LOCAL_DEF( FT_Error )
2371 bdf_load_font( FT_Stream stream,
2372 FT_Memory extmemory,
2373 bdf_options_t* opts,
2374 bdf_font_t* *font )
2375 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002376 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002377 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002378
Sean McBride7be2a942014-02-08 13:55:38 +01002379 FT_Memory memory = extmemory; /* needed for FT_NEW */
2380 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002381
2382
David Turner68df4f72005-03-15 18:18:57 +00002383 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002384 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002385
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002386 memory = NULL;
2387 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2388 p->minlb = 32767;
2389 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002390
David Turner68df4f72005-03-15 18:18:57 +00002391 _bdf_list_init( &p->list, extmemory );
2392
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002393 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002394 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002395 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002396 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002397
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002398 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002399 {
2400 /* If the font is not proportional, set the font's monowidth */
2401 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002402 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002403
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002404 if ( p->font->spacing != BDF_PROPORTIONAL )
2405 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002406
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002407 /* If the number of glyphs loaded is not that of the original count, */
2408 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002409 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002410 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002411 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2412 p->font->glyphs_used + p->font->unencoded_used ));
2413 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002414 }
2415
2416 /* Once the font has been loaded, adjust the overall font metrics if */
2417 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002418 if ( p->opts->correct_metrics != 0 &&
2419 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002420 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002421 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002422 {
2423 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002424 p->font->bbx.width, p->maxrb - p->minlb ));
2425 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2426 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002427 }
2428
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002429 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002430 {
2431 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002432 p->font->bbx.x_offset, p->minlb ));
2433 p->font->bbx.x_offset = p->minlb;
2434 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002435 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002436
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002437 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002438 {
2439 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002440 p->font->bbx.ascent, p->maxas ));
2441 p->font->bbx.ascent = p->maxas;
2442 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002443 }
2444
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002445 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002446 {
2447 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002448 p->font->bbx.descent, p->maxds ));
2449 p->font->bbx.descent = p->maxds;
2450 p->font->bbx.y_offset = (short)( -p->maxds );
2451 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002452 }
2453
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002454 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002455 {
2456 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002457 p->font->bbx.height, p->maxas + p->maxds ));
2458 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002459 }
2460
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002461 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002462 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2463 }
David Turner993a8d02002-05-18 12:03:43 +00002464 }
2465
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002466 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002467 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002468 /* The ENDFONT field was never reached or did not exist. */
2469 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002470 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002471 /* Error happened while parsing header. */
2472 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002473 error = FT_THROW( Corrupted_Font_Header );
Werner Lemberge01406b2011-11-25 09:44:28 +01002474 goto Exit;
2475 }
2476 else
2477 {
2478 /* Error happened when parsing glyphs. */
2479 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002480 error = FT_THROW( Corrupted_Font_Glyphs );
Werner Lemberge01406b2011-11-25 09:44:28 +01002481 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002482 }
David Turner993a8d02002-05-18 12:03:43 +00002483 }
2484
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002485 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002486 {
2487 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002488 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002489
Werner Lemberg370aea82010-06-08 08:37:11 +02002490 if ( p->font->comments_len > 0 )
2491 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002492 if ( FT_RENEW_ARRAY( p->font->comments,
2493 p->font->comments_len,
2494 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002495 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002496
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002497 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002498 }
David Turner993a8d02002-05-18 12:03:43 +00002499 }
Werner Lemberge3c93012013-03-14 11:21:17 +01002500 else if ( error == FT_Err_Ok )
Werner Lemberg059bc332013-03-14 10:27:35 +01002501 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002502
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002503 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002504
2505 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002506 if ( p )
2507 {
David Turner68df4f72005-03-15 18:18:57 +00002508 _bdf_list_done( &p->list );
2509
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002510 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002511
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002512 FT_FREE( p );
2513 }
2514
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002515 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002516
2517 Fail:
2518 bdf_free_font( p->font );
2519
2520 memory = extmemory;
2521
2522 FT_FREE( p->font );
2523
2524 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002525 }
David Turner993a8d02002-05-18 12:03:43 +00002526
2527
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002528 FT_LOCAL_DEF( void )
2529 bdf_free_font( bdf_font_t* font )
2530 {
2531 bdf_property_t* prop;
2532 unsigned long i;
2533 bdf_glyph_t* glyphs;
2534 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002535
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002536
2537 if ( font == 0 )
2538 return;
David Turner993a8d02002-05-18 12:03:43 +00002539
2540 memory = font->memory;
2541
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002542 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002543
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002544 /* Free up the internal hash table of property names. */
2545 if ( font->internal )
2546 {
2547 hash_free( (hashtable *)font->internal, memory );
2548 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002549 }
2550
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002551 /* Free up the comment info. */
2552 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002553
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002554 /* Free up the properties. */
2555 for ( i = 0; i < font->props_size; i++ )
2556 {
2557 if ( font->props[i].format == BDF_ATOM )
2558 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002559 }
2560
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002561 FT_FREE( font->props );
2562
2563 /* Free up the character info. */
2564 for ( i = 0, glyphs = font->glyphs;
2565 i < font->glyphs_used; i++, glyphs++ )
2566 {
2567 FT_FREE( glyphs->name );
2568 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002569 }
2570
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002571 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2572 i++, glyphs++ )
2573 {
2574 FT_FREE( glyphs->name );
2575 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002576 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002577
2578 FT_FREE( font->glyphs );
2579 FT_FREE( font->unencoded );
2580
2581 /* Free up the overflow storage if it was used. */
2582 for ( i = 0, glyphs = font->overflow.glyphs;
2583 i < font->overflow.glyphs_used; i++, glyphs++ )
2584 {
2585 FT_FREE( glyphs->name );
2586 FT_FREE( glyphs->bitmap );
2587 }
2588
2589 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002590
2591 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002592 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002593
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002594 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002595 for ( prop = font->user_props, i = 0;
2596 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002597 {
2598 FT_FREE( prop->name );
2599 if ( prop->format == BDF_ATOM )
2600 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002601 }
David Turner993a8d02002-05-18 12:03:43 +00002602
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002603 FT_FREE( font->user_props );
2604
2605 /* FREE( font ); */ /* XXX Fixme */
2606 }
David Turner993a8d02002-05-18 12:03:43 +00002607
2608
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002609 FT_LOCAL_DEF( bdf_property_t * )
2610 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002611 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002612 {
2613 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002614
David Turner993a8d02002-05-18 12:03:43 +00002615
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002616 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002617 return 0;
2618
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002619 hn = hash_lookup( name, (hashtable *)font->internal );
2620
suzuki toshiya704f4d72009-09-13 00:50:14 +09002621 return hn ? ( font->props + hn->data ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002622 }
2623
2624
2625/* END */