blob: 9206479ebe9e49fc5ac0cbe3d5bda1c5cde0b0dd [file] [log] [blame]
David Turner993a8d02002-05-18 12:03:43 +00001/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
Werner Lemberg059bc332013-03-14 10:27:35 +01003 * Copyright 2001-2013
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;
523 char *fp, *dp;
524
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 {
534 fp = list->field[i];
535 while ( *fp )
536 dp[j++] = *fp++;
537
538 if ( i + 1 < list->used )
539 dp[j++] = (char)c;
540 }
Werner Lembergf4c94d42010-06-19 16:08:31 +0200541 if ( dp != empty )
542 dp[j] = 0;
David Turner68df4f72005-03-15 18:18:57 +0000543
544 *alen = j;
545 return dp;
546 }
547
548
Werner Lemberg03242f52012-02-26 06:52:56 +0100549 /* The code below ensures that we have at least 4 + 1 `field' */
550 /* elements in `list' (which are possibly NULL) so that we */
551 /* don't have to check the number of fields in most cases. */
552
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000553 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000554 _bdf_list_split( _bdf_list_t* list,
555 char* separators,
556 char* line,
557 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000558 {
559 int mult, final_empty;
560 char *sp, *ep, *end;
561 char seps[32];
Werner Lemberge3c93012013-03-14 11:21:17 +0100562 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000563
564
565 /* Initialize the list. */
566 list->used = 0;
Werner Lembergd9c16592012-03-01 15:15:00 +0100567 if ( list->size )
568 {
569 list->field[0] = (char*)empty;
570 list->field[1] = (char*)empty;
571 list->field[2] = (char*)empty;
572 list->field[3] = (char*)empty;
Werner Lemberg649c6732012-03-16 21:12:41 +0100573 list->field[4] = (char*)empty;
Werner Lembergd9c16592012-03-01 15:15:00 +0100574 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000575
576 /* If the line is empty, then simply return. */
577 if ( linelen == 0 || line[0] == 0 )
578 goto Exit;
579
580 /* In the original code, if the `separators' parameter is NULL or */
581 /* empty, the list is split into individual bytes. We don't need */
582 /* this, so an error is signaled. */
583 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000584 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100585 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000586 goto Exit;
587 }
588
589 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000590 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000591
592 /* If the very last character of the separator string is a plus, then */
593 /* set the `mult' flag to indicate that multiple separators should be */
594 /* collapsed into one. */
595 for ( mult = 0, sp = separators; sp && *sp; sp++ )
596 {
597 if ( *sp == '+' && *( sp + 1 ) == 0 )
598 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000599 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000600 setsbit( seps, *sp );
601 }
602
603 /* Break the line up into fields. */
604 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
605 sp < end && *sp; )
606 {
607 /* Collect everything that is not a separator. */
608 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
609 ;
610
611 /* Resize the list if necessary. */
612 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000613 {
Werner Lembergebf55852005-03-16 01:49:54 +0000614 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000615 if ( error )
616 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000617 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000618
619 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000620 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000621
622 sp = ep;
623
624 if ( mult )
625 {
626 /* If multiple separators should be collapsed, do it now by */
627 /* setting all the separator characters to 0. */
628 for ( ; *ep && sbitset( seps, *ep ); ep++ )
629 *ep = 0;
630 }
631 else if ( *ep != 0 )
632 /* Don't collapse multiple separators by making them 0, so just */
633 /* make the one encountered 0. */
634 *ep++ = 0;
635
636 final_empty = ( ep > sp && *ep == 0 );
637 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000638 }
639
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000640 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000641 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000642 {
Werner Lembergebf55852005-03-16 01:49:54 +0000643 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000644 if ( error )
645 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000646 }
647
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000648 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000649 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000650
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000651 list->field[list->used] = 0;
652
653 Exit:
654 return error;
David Turner993a8d02002-05-18 12:03:43 +0000655 }
656
David Turner993a8d02002-05-18 12:03:43 +0000657
David Turner68df4f72005-03-15 18:18:57 +0000658#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000659
Werner Lembergebf55852005-03-16 01:49:54 +0000660
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000661 static FT_Error
662 _bdf_readstream( FT_Stream stream,
663 _bdf_line_func_t callback,
664 void* client_data,
665 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000666 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000667 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000668 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900669 int refill, hold, to_skip;
670 ptrdiff_t bytes, start, end, cursor, avail;
Werner Lemberg059bc332013-03-14 10:27:35 +0100671 char* buf = 0;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000672 FT_Memory memory = stream->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100673 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000674
David Turner993a8d02002-05-18 12:03:43 +0000675
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000676 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000677 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100678 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000679 goto Exit;
680 }
David Turner993a8d02002-05-18 12:03:43 +0000681
Werner Lembergebf55852005-03-16 01:49:54 +0000682 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000683 buf_size = 1024;
684
685 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000686 goto Exit;
687
Werner Lembergebf55852005-03-16 01:49:54 +0000688 cb = callback;
689 lineno = 1;
690 buf[0] = 0;
691 start = 0;
692 end = 0;
693 avail = 0;
694 cursor = 0;
695 refill = 1;
696 to_skip = NO_SKIP;
697 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000698
David Turner68df4f72005-03-15 18:18:57 +0000699 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000700 {
David Turner68df4f72005-03-15 18:18:57 +0000701 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000702 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +0200703 bytes = (ptrdiff_t)FT_Stream_TryRead(
704 stream, (FT_Byte*)buf + cursor,
705 (FT_ULong)( buf_size - cursor ) );
David Turner68df4f72005-03-15 18:18:57 +0000706 avail = cursor + bytes;
707 cursor = 0;
708 refill = 0;
709 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000710
David Turner68df4f72005-03-15 18:18:57 +0000711 end = start;
712
Werner Lembergebf55852005-03-16 01:49:54 +0000713 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000714 if ( start < avail && buf[start] == to_skip )
715 {
716 start += 1;
717 to_skip = NO_SKIP;
718 continue;
719 }
720
721 /* try to find the end of the line */
722 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
723 end++;
724
Werner Lembergebf55852005-03-16 01:49:54 +0000725 /* if we hit the end of the buffer, try shifting its content */
726 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000727 if ( end >= avail )
728 {
729 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
730 break; /* ignore it then exit */
731
732 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000733 {
Werner Lembergebf55852005-03-16 01:49:54 +0000734 /* this line is definitely too long; try resizing the input */
735 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000736 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000737
Werner Lembergebf55852005-03-16 01:49:54 +0000738
739 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000740 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100741 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +0100742 error = FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +0000743 goto Exit;
744 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000745
Werner Lembergebf55852005-03-16 01:49:54 +0000746 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000747 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
748 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000749
David Turner68df4f72005-03-15 18:18:57 +0000750 cursor = buf_size;
751 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000752 }
753 else
754 {
David Turner68df4f72005-03-15 18:18:57 +0000755 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000756
Werner Lemberg04e547b2013-04-03 07:37:56 +0200757 FT_MEM_MOVE( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000758
David Turner68df4f72005-03-15 18:18:57 +0000759 cursor = bytes;
760 avail -= bytes;
761 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000762 }
David Turner68df4f72005-03-15 18:18:57 +0000763 refill = 1;
764 continue;
David Turner993a8d02002-05-18 12:03:43 +0000765 }
David Turner68df4f72005-03-15 18:18:57 +0000766
767 /* Temporarily NUL-terminate the line. */
768 hold = buf[end];
769 buf[end] = 0;
770
771 /* XXX: Use encoding independent value for 0x1a */
772 if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
773 {
Werner Lemberga9f6f852012-12-17 09:08:09 +0100774 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergebf55852005-03-16 01:49:54 +0000775 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200776 /* Redo if we have encountered CHARS without properties. */
777 if ( error == -1 )
Werner Lemberga9f6f852012-12-17 09:08:09 +0100778 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200779 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000780 if ( error )
781 break;
782 }
783
784 lineno += 1;
785 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000786 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000787
788 if ( hold == '\n' )
789 to_skip = '\r';
790 else if ( hold == '\r' )
791 to_skip = '\n';
792 else
793 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000794 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000795
David Turner68df4f72005-03-15 18:18:57 +0000796 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000797
798 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000799 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000800 return error;
David Turner993a8d02002-05-18 12:03:43 +0000801 }
David Turner993a8d02002-05-18 12:03:43 +0000802
803
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000804 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000805
David Turnerb1b47622002-05-21 21:17:43 +0000806 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000807 {
David Turner993a8d02002-05-18 12:03:43 +0000808 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
809 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
811 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
812 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
813 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
814 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
815 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
816 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
817 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
818 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000819 };
David Turner993a8d02002-05-18 12:03:43 +0000820
David Turnerb1b47622002-05-21 21:17:43 +0000821 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000822 {
David Turner993a8d02002-05-18 12:03:43 +0000823 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
825 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
826 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000827 };
David Turner993a8d02002-05-18 12:03:43 +0000828
David Turnerb1b47622002-05-21 21:17:43 +0000829 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000830 {
David Turner993a8d02002-05-18 12:03:43 +0000831 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
832 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
833 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
834 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000835 };
David Turner993a8d02002-05-18 12:03:43 +0000836
David Turnerb1b47622002-05-21 21:17:43 +0000837 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000838 {
David Turner993a8d02002-05-18 12:03:43 +0000839 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
840 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
841 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
842 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000843 };
David Turner993a8d02002-05-18 12:03:43 +0000844
David Turner993a8d02002-05-18 12:03:43 +0000845
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000846 /* Routine to convert an ASCII string into an unsigned long integer. */
847 static unsigned long
848 _bdf_atoul( char* s,
849 char** end,
850 int base )
David Turner993a8d02002-05-18 12:03:43 +0000851 {
David Turnerb1b47622002-05-21 21:17:43 +0000852 unsigned long v;
853 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000854
855
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000856 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000857 return 0;
858
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000859 /* Make sure the radix is something recognizable. Default to 10. */
860 switch ( base )
861 {
862 case 8:
863 dmap = odigits;
864 break;
865 case 16:
866 dmap = hdigits;
867 break;
868 default:
869 base = 10;
870 dmap = ddigits;
871 break;
David Turner993a8d02002-05-18 12:03:43 +0000872 }
873
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000874 /* Check for the special hex prefix. */
875 if ( *s == '0' &&
876 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
877 {
878 base = 16;
879 dmap = hdigits;
880 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000881 }
882
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +0100883 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000884 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000885
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000886 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000887 *end = s;
888
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000889 return v;
890 }
David Turner993a8d02002-05-18 12:03:43 +0000891
David Turner993a8d02002-05-18 12:03:43 +0000892
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000893 /* Routine to convert an ASCII string into an signed long integer. */
894 static long
895 _bdf_atol( char* s,
896 char** end,
897 int base )
898 {
David Turnerb1b47622002-05-21 21:17:43 +0000899 long v, neg;
900 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000901
902
903 if ( s == 0 || *s == 0 )
904 return 0;
905
906 /* Make sure the radix is something recognizable. Default to 10. */
907 switch ( base )
908 {
909 case 8:
910 dmap = odigits;
911 break;
912 case 16:
913 dmap = hdigits;
914 break;
915 default:
916 base = 10;
917 dmap = ddigits;
918 break;
919 }
920
921 /* Check for a minus sign. */
922 neg = 0;
923 if ( *s == '-' )
924 {
925 s++;
926 neg = 1;
927 }
928
929 /* Check for the special hex prefix. */
930 if ( *s == '0' &&
931 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
932 {
933 base = 16;
934 dmap = hdigits;
935 s += 2;
936 }
937
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +0100938 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000939 v = v * base + a2i[(int)*s];
940
941 if ( end != 0 )
942 *end = s;
943
944 return ( !neg ) ? v : -v;
945 }
946
947
948 /* Routine to convert an ASCII string into an signed short integer. */
949 static short
950 _bdf_atos( char* s,
951 char** end,
952 int base )
953 {
David Turnerb1b47622002-05-21 21:17:43 +0000954 short v, neg;
955 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000956
957
958 if ( s == 0 || *s == 0 )
959 return 0;
960
961 /* Make sure the radix is something recognizable. Default to 10. */
962 switch ( base )
963 {
964 case 8:
965 dmap = odigits;
966 break;
967 case 16:
968 dmap = hdigits;
969 break;
970 default:
971 base = 10;
972 dmap = ddigits;
973 break;
974 }
975
976 /* Check for a minus. */
977 neg = 0;
978 if ( *s == '-' )
979 {
980 s++;
981 neg = 1;
982 }
983
984 /* Check for the special hex prefix. */
985 if ( *s == '0' &&
986 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
987 {
988 base = 16;
989 dmap = hdigits;
990 s += 2;
991 }
992
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +0100993 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +0000994 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000995
996 if ( end != 0 )
997 *end = s;
998
Werner Lemberg233302a2002-05-22 05:41:06 +0000999 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001000 }
1001
1002
1003 /* Routine to compare two glyphs by encoding so they can be sorted. */
1004 static int
1005 by_encoding( const void* a,
1006 const void* b )
1007 {
1008 bdf_glyph_t *c1, *c2;
1009
1010
1011 c1 = (bdf_glyph_t *)a;
1012 c2 = (bdf_glyph_t *)b;
1013
1014 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001015 return -1;
David Turner68df4f72005-03-15 18:18:57 +00001016
1017 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001018 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001019
David Turner993a8d02002-05-18 12:03:43 +00001020 return 0;
David Turner993a8d02002-05-18 12:03:43 +00001021 }
1022
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001023
1024 static FT_Error
1025 bdf_create_property( char* name,
1026 int format,
1027 bdf_font_t* font )
1028 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001029 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001030 bdf_property_t* p;
1031 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001032 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001033
1034
Werner Lemberg96ddc672011-06-29 09:15:54 +02001035 /* First check whether the property has */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001036 /* already been added or not. If it has, then */
1037 /* simply ignore it. */
1038 if ( hash_lookup( name, &(font->proptbl) ) )
1039 goto Exit;
1040
David Turner68df4f72005-03-15 18:18:57 +00001041 if ( FT_RENEW_ARRAY( font->user_props,
1042 font->nuser_props,
1043 font->nuser_props + 1 ) )
1044 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001045
1046 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +00001047 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001048
suzuki toshiya704f4d72009-09-13 00:50:14 +09001049 n = ft_strlen( name ) + 1;
1050 if ( n > FT_ULONG_MAX )
Werner Lemberg059bc332013-03-14 10:27:35 +01001051 return FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +00001052
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001053 if ( FT_NEW_ARRAY( p->name, n ) )
1054 goto Exit;
1055
1056 FT_MEM_COPY( (char *)p->name, name, n );
1057
1058 p->format = format;
1059 p->builtin = 0;
1060
1061 n = _num_bdf_properties + font->nuser_props;
1062
suzuki toshiya704f4d72009-09-13 00:50:14 +09001063 error = hash_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001064 if ( error )
1065 goto Exit;
1066
1067 font->nuser_props++;
1068
1069 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001070 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001071 }
David Turner993a8d02002-05-18 12:03:43 +00001072
1073
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001074 FT_LOCAL_DEF( bdf_property_t * )
1075 bdf_get_property( char* name,
1076 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001077 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001078 hashnode hn;
1079 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001080
1081
1082 if ( name == 0 || *name == 0 )
1083 return 0;
1084
1085 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1086 return 0;
1087
suzuki toshiya704f4d72009-09-13 00:50:14 +09001088 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001089 if ( propid >= _num_bdf_properties )
1090 return font->user_props + ( propid - _num_bdf_properties );
1091
Werner Lemberg233302a2002-05-22 05:41:06 +00001092 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001093 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001094
1095
1096 /*************************************************************************/
1097 /* */
1098 /* BDF font file parsing flags and functions. */
1099 /* */
1100 /*************************************************************************/
1101
1102
1103 /* Parse flags. */
1104
1105#define _BDF_START 0x0001
1106#define _BDF_FONT_NAME 0x0002
1107#define _BDF_SIZE 0x0004
1108#define _BDF_FONT_BBX 0x0008
1109#define _BDF_PROPS 0x0010
1110#define _BDF_GLYPHS 0x0020
1111#define _BDF_GLYPH 0x0040
1112#define _BDF_ENCODING 0x0080
1113#define _BDF_SWIDTH 0x0100
1114#define _BDF_DWIDTH 0x0200
1115#define _BDF_BBX 0x0400
1116#define _BDF_BITMAP 0x0800
1117
1118#define _BDF_SWIDTH_ADJ 0x1000
1119
1120#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1121 _BDF_ENCODING | \
1122 _BDF_SWIDTH | \
1123 _BDF_DWIDTH | \
1124 _BDF_BBX | \
1125 _BDF_BITMAP )
1126
Werner Lembergf1c2b912006-01-13 14:53:28 +00001127#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1128#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001129
1130
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001131 static FT_Error
1132 _bdf_add_comment( bdf_font_t* font,
1133 char* comment,
1134 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001135 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001136 char* cp;
1137 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001138 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001139
1140
David Turner68df4f72005-03-15 18:18:57 +00001141 if ( FT_RENEW_ARRAY( font->comments,
1142 font->comments_len,
1143 font->comments_len + len + 1 ) )
1144 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001145
1146 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001147
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001148 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001149 cp[len] = '\n';
1150
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001151 font->comments_len += len + 1;
1152
1153 Exit:
1154 return error;
David Turner993a8d02002-05-18 12:03:43 +00001155 }
1156
David Turner993a8d02002-05-18 12:03:43 +00001157
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001158 /* Set the spacing from the font name if it exists, or set it to the */
1159 /* default specified in the options. */
1160 static FT_Error
1161 _bdf_set_default_spacing( bdf_font_t* font,
Werner Lemberge01406b2011-11-25 09:44:28 +01001162 bdf_options_t* opts,
1163 unsigned long lineno )
David Turner993a8d02002-05-18 12:03:43 +00001164 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001165 size_t len;
1166 char name[256];
1167 _bdf_list_t list;
1168 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001169 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001170
David Turner993a8d02002-05-18 12:03:43 +00001171
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001172 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1173 {
Werner Lemberg059bc332013-03-14 10:27:35 +01001174 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001175 goto Exit;
1176 }
David Turner993a8d02002-05-18 12:03:43 +00001177
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001178 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001179
David Turner68df4f72005-03-15 18:18:57 +00001180 _bdf_list_init( &list, memory );
1181
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001182 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001183
suzuki toshiya704f4d72009-09-13 00:50:14 +09001184 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +00001185 /* Limit ourselves to 256 characters in the font name. */
1186 if ( len >= 256 )
1187 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001188 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001189 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001190 goto Exit;
1191 }
1192
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001193 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001194
David Turner68df4f72005-03-15 18:18:57 +00001195 error = _bdf_list_split( &list, (char *)"-", name, len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001196 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001197 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001198
1199 if ( list.used == 15 )
1200 {
1201 switch ( list.field[11][0] )
1202 {
1203 case 'C':
1204 case 'c':
1205 font->spacing = BDF_CHARCELL;
1206 break;
1207 case 'M':
1208 case 'm':
1209 font->spacing = BDF_MONOWIDTH;
1210 break;
1211 case 'P':
1212 case 'p':
1213 font->spacing = BDF_PROPORTIONAL;
1214 break;
David Turner993a8d02002-05-18 12:03:43 +00001215 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001216 }
1217
David Turner68df4f72005-03-15 18:18:57 +00001218 Fail:
1219 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001220
1221 Exit:
1222 return error;
David Turner993a8d02002-05-18 12:03:43 +00001223 }
David Turner993a8d02002-05-18 12:03:43 +00001224
1225
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001226 /* Determine whether the property is an atom or not. If it is, then */
1227 /* clean it up so the double quotes are removed if they exist. */
1228 static int
1229 _bdf_is_atom( char* line,
1230 unsigned long linelen,
1231 char** name,
1232 char** value,
1233 bdf_font_t* font )
1234 {
1235 int hold;
1236 char *sp, *ep;
1237 bdf_property_t* p;
1238
David Turner993a8d02002-05-18 12:03:43 +00001239
1240 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001241
1242 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001243 ep++;
1244
1245 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001246 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001247 {
1248 hold = *ep;
1249 *ep = 0;
1250 }
1251
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001252 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001253
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001254 /* Restore the character that was saved before any return can happen. */
1255 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001256 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001257
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001258 /* If the property exists and is not an atom, just return here. */
1259 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001260 return 0;
1261
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001262 /* The property is an atom. Trim all leading and trailing whitespace */
1263 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001264 sp = ep;
1265 ep = line + linelen;
1266
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001267 /* Trim the leading whitespace if it exists. */
Werner Lemberg320d4972012-02-24 18:06:46 +01001268 if ( *sp )
1269 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001270 while ( *sp &&
1271 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001272 sp++;
1273
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001274 /* Trim the leading double quote if it exists. */
1275 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001276 sp++;
1277 *value = sp;
1278
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001279 /* Trim the trailing whitespace if it exists. */
1280 while ( ep > sp &&
1281 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001282 *--ep = 0;
1283
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001284 /* Trim the trailing double quote if it exists. */
1285 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001286 *--ep = 0;
1287
1288 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001289 }
David Turner993a8d02002-05-18 12:03:43 +00001290
1291
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001292 static FT_Error
Werner Lemberge01406b2011-11-25 09:44:28 +01001293 _bdf_add_property( bdf_font_t* font,
1294 char* name,
1295 char* value,
1296 unsigned long lineno )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001297 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001298 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001299 hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001300 bdf_property_t *prop, *fp;
1301 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001302 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001303
David Turner993a8d02002-05-18 12:03:43 +00001304
Werner Lemberg96ddc672011-06-29 09:15:54 +02001305 /* First, check whether the property already exists in the font. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001306 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001307 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001308 /* The property already exists in the font, so simply replace */
1309 /* the value of the property with the current value. */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001310 fp = font->props + hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001311
David Turnerb1b47622002-05-21 21:17:43 +00001312 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001313 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001314 case BDF_ATOM:
1315 /* Delete the current atom if it exists. */
1316 FT_FREE( fp->value.atom );
1317
David Turnerc0f9c4a2007-02-12 14:55:03 +00001318 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001319 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001320 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001321 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001322 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001323 break;
1324
1325 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001326 fp->value.l = _bdf_atol( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001327 break;
1328
1329 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001330 fp->value.ul = _bdf_atoul( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001331 break;
David Turnerd490e372002-05-28 23:40:37 +00001332
David Turnerb1b47622002-05-21 21:17:43 +00001333 default:
1334 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001335 }
David Turnerd490e372002-05-28 23:40:37 +00001336
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001337 goto Exit;
1338 }
1339
1340 /* See whether this property type exists yet or not. */
1341 /* If not, create it. */
1342 hn = hash_lookup( name, &(font->proptbl) );
1343 if ( hn == 0 )
1344 {
1345 error = bdf_create_property( name, BDF_ATOM, font );
1346 if ( error )
1347 goto Exit;
1348 hn = hash_lookup( name, &(font->proptbl) );
1349 }
1350
1351 /* Allocate another property if this is overflow. */
1352 if ( font->props_used == font->props_size )
1353 {
1354 if ( font->props_size == 0 )
1355 {
1356 if ( FT_NEW_ARRAY( font->props, 1 ) )
1357 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001358 }
1359 else
1360 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001361 if ( FT_RENEW_ARRAY( font->props,
1362 font->props_size,
1363 font->props_size + 1 ) )
1364 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001365 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001366
David Turner993a8d02002-05-18 12:03:43 +00001367 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001368 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001369 font->props_size++;
1370 }
1371
suzuki toshiya704f4d72009-09-13 00:50:14 +09001372 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001373 if ( propid >= _num_bdf_properties )
1374 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001375 else
David Turnerb1b47622002-05-21 21:17:43 +00001376 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001377
1378 fp = font->props + font->props_used;
1379
1380 fp->name = prop->name;
1381 fp->format = prop->format;
1382 fp->builtin = prop->builtin;
1383
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001384 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001385 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001386 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001387 fp->value.atom = 0;
1388 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001389 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001390 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001391 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001392 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001393 break;
David Turner993a8d02002-05-18 12:03:43 +00001394
1395 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001396 fp->value.l = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001397 break;
1398
1399 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001400 fp->value.ul = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001401 break;
David Turner993a8d02002-05-18 12:03:43 +00001402 }
1403
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001404 /* If the property happens to be a comment, then it doesn't need */
1405 /* to be added to the internal hash table. */
Werner Lemberg370aea82010-06-08 08:37:11 +02001406 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 )
1407 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001408 /* Add the property to the font property table. */
1409 error = hash_insert( fp->name,
suzuki toshiya704f4d72009-09-13 00:50:14 +09001410 font->props_used,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001411 (hashtable *)font->internal,
1412 memory );
1413 if ( error )
1414 goto Exit;
1415 }
David Turner993a8d02002-05-18 12:03:43 +00001416
1417 font->props_used++;
1418
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001419 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1420 /* property needs to be located if it exists in the property list, the */
1421 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1422 /* present, and the SPACING property should override the default */
1423 /* spacing. */
1424 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001425 font->default_char = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001426 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001427 font->font_ascent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001428 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001429 font->font_descent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001430 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001431 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001432 if ( !fp->value.atom )
1433 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001434 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001435 error = FT_THROW( Invalid_File_Format );
Werner Lembergb66efef2009-03-12 08:07:49 +00001436 goto Exit;
1437 }
1438
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001439 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001440 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001441 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001442 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001443 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001444 font->spacing = BDF_CHARCELL;
1445 }
1446
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001447 Exit:
1448 return error;
David Turner993a8d02002-05-18 12:03:43 +00001449 }
1450
David Turner993a8d02002-05-18 12:03:43 +00001451
David Turnerb1b47622002-05-21 21:17:43 +00001452 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001453 {
1454 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1455 };
1456
1457
1458 /* Actually parse the glyph info and bitmaps. */
1459 static FT_Error
1460 _bdf_parse_glyphs( char* line,
1461 unsigned long linelen,
1462 unsigned long lineno,
1463 void* call_data,
1464 void* client_data )
1465 {
1466 int c, mask_index;
1467 char* s;
1468 unsigned char* bp;
1469 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001470
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001471 _bdf_parse_t* p;
1472 bdf_glyph_t* glyph;
1473 bdf_font_t* font;
1474
1475 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001476 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001477
Werner Lemberg319c00d2003-04-23 19:48:24 +00001478 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001479 FT_UNUSED( lineno ); /* only used in debug mode */
1480
1481
Werner Lemberg319c00d2003-04-23 19:48:24 +00001482 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001483
1484 font = p->font;
1485 memory = font->memory;
1486
1487 /* Check for a comment. */
1488 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1489 {
1490 linelen -= 7;
1491
1492 s = line + 7;
1493 if ( *s != 0 )
1494 {
1495 s++;
1496 linelen--;
1497 }
1498 error = _bdf_add_comment( p->font, s, linelen );
1499 goto Exit;
1500 }
1501
1502 /* The very first thing expected is the number of glyphs. */
1503 if ( !( p->flags & _BDF_GLYPHS ) )
1504 {
1505 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1506 {
1507 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001508 error = FT_THROW( Missing_Chars_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001509 goto Exit;
1510 }
1511
David Turner68df4f72005-03-15 18:18:57 +00001512 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001513 if ( error )
1514 goto Exit;
1515 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1516
1517 /* Make sure the number of glyphs is non-zero. */
1518 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001519 font->glyphs_size = 64;
1520
Werner Lemberga08b2172007-03-28 07:17:17 +00001521 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1522 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001523 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001524 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001525 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001526 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001527 goto Exit;
1528 }
1529
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001530 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1531 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001532
David Turner993a8d02002-05-18 12:03:43 +00001533 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001534
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001535 goto Exit;
1536 }
1537
1538 /* Check for the ENDFONT field. */
1539 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1540 {
1541 /* Sort the glyphs by encoding. */
1542 ft_qsort( (char *)font->glyphs,
1543 font->glyphs_used,
1544 sizeof ( bdf_glyph_t ),
1545 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001546
1547 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001548
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001549 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001550 }
1551
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001552 /* Check for the ENDCHAR field. */
1553 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1554 {
1555 p->glyph_enc = 0;
1556 p->flags &= ~_BDF_GLYPH_BITS;
1557
1558 goto Exit;
1559 }
1560
Werner Lemberg96ddc672011-06-29 09:15:54 +02001561 /* Check whether a glyph is being scanned but should be */
1562 /* ignored because it is an unencoded glyph. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001563 if ( ( p->flags & _BDF_GLYPH ) &&
1564 p->glyph_enc == -1 &&
1565 p->opts->keep_unencoded == 0 )
1566 goto Exit;
1567
1568 /* Check for the STARTCHAR field. */
1569 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1570 {
1571 /* Set the character name in the parse info first until the */
1572 /* encoding can be checked for an unencoded character. */
1573 FT_FREE( p->glyph_name );
1574
David Turner68df4f72005-03-15 18:18:57 +00001575 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001576 if ( error )
1577 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001578
David Turner68df4f72005-03-15 18:18:57 +00001579 _bdf_list_shift( &p->list, 1 );
1580
1581 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001582
Werner Lembergba03af62007-05-30 13:57:02 +00001583 if ( !s )
1584 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001585 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001586 error = FT_THROW( Invalid_File_Format );
Werner Lembergba03af62007-05-30 13:57:02 +00001587 goto Exit;
1588 }
1589
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001590 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1591 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001592
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001593 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1594
1595 p->flags |= _BDF_GLYPH;
1596
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001597 FT_TRACE4(( DBGMSG1, lineno, s ));
1598
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001599 goto Exit;
1600 }
1601
1602 /* Check for the ENCODING field. */
1603 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1604 {
1605 if ( !( p->flags & _BDF_GLYPH ) )
1606 {
1607 /* Missing STARTCHAR field. */
1608 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001609 error = FT_THROW( Missing_Startchar_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001610 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001611 }
1612
David Turner68df4f72005-03-15 18:18:57 +00001613 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001614 if ( error )
1615 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001616
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001617 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001618
Werner Lemberg28dd2c42012-02-26 06:18:58 +01001619 /* Normalize negative encoding values. The specification only */
1620 /* allows -1, but we can be more generous here. */
1621 if ( p->glyph_enc < -1 )
1622 p->glyph_enc = -1;
1623
Werner Lemberg03242f52012-02-26 06:52:56 +01001624 /* Check for alternative encoding format. */
1625 if ( p->glyph_enc == -1 && p->list.used > 2 )
1626 p->glyph_enc = _bdf_atol( p->list.field[2], 0, 10 );
1627
Werner Lemberg7f2e4f42012-12-15 09:39:41 +01001628 if ( p->glyph_enc < -1 )
1629 p->glyph_enc = -1;
1630
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001631 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1632
Werner Lemberged54e432011-11-27 16:39:53 +01001633 /* Check that the encoding is in the Unicode range because */
1634 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lemberg07bdb6e2012-12-15 02:02:23 +01001635 if ( p->glyph_enc > 0 &&
1636 (size_t)p->glyph_enc >= sizeof ( p->have ) /
1637 sizeof ( unsigned long ) * 32 )
David Turner481838e2006-02-23 12:40:14 +00001638 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001639 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001640 error = FT_THROW( Invalid_File_Format );
David Turner481838e2006-02-23 12:40:14 +00001641 goto Exit;
1642 }
1643
Werner Lemberg96ddc672011-06-29 09:15:54 +02001644 /* Check whether this encoding has already been encountered. */
1645 /* If it has then change it to unencoded so it gets added if */
1646 /* indicated. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001647 if ( p->glyph_enc >= 0 )
1648 {
1649 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1650 {
1651 /* Emit a message saying a glyph has been moved to the */
1652 /* unencoded area. */
1653 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1654 p->glyph_enc, p->glyph_name ));
1655 p->glyph_enc = -1;
1656 font->modified = 1;
1657 }
1658 else
1659 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1660 }
1661
1662 if ( p->glyph_enc >= 0 )
1663 {
1664 /* Make sure there are enough glyphs allocated in case the */
1665 /* number of characters happen to be wrong. */
1666 if ( font->glyphs_used == font->glyphs_size )
1667 {
1668 if ( FT_RENEW_ARRAY( font->glyphs,
1669 font->glyphs_size,
1670 font->glyphs_size + 64 ) )
1671 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001672
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001673 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001674 }
1675
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001676 glyph = font->glyphs + font->glyphs_used++;
1677 glyph->name = p->glyph_name;
1678 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001679
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001680 /* Reset the initial glyph info. */
1681 p->glyph_name = 0;
1682 }
1683 else
1684 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001685 /* Unencoded glyph. Check whether it should */
1686 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001687 if ( p->opts->keep_unencoded != 0 )
1688 {
1689 /* Allocate the next unencoded glyph. */
1690 if ( font->unencoded_used == font->unencoded_size )
1691 {
David Turner68df4f72005-03-15 18:18:57 +00001692 if ( FT_RENEW_ARRAY( font->unencoded ,
1693 font->unencoded_size,
1694 font->unencoded_size + 4 ) )
1695 goto Exit;
1696
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001697 font->unencoded_size += 4;
1698 }
1699
1700 glyph = font->unencoded + font->unencoded_used;
1701 glyph->name = p->glyph_name;
1702 glyph->encoding = font->unencoded_used++;
1703 }
1704 else
1705 /* Free up the glyph name if the unencoded shouldn't be */
1706 /* kept. */
1707 FT_FREE( p->glyph_name );
1708
1709 p->glyph_name = 0;
1710 }
1711
1712 /* Clear the flags that might be added when width and height are */
1713 /* checked for consistency. */
1714 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1715
1716 p->flags |= _BDF_ENCODING;
1717
1718 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001719 }
1720
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001721 /* Point at the glyph being constructed. */
1722 if ( p->glyph_enc == -1 )
1723 glyph = font->unencoded + ( font->unencoded_used - 1 );
1724 else
1725 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001726
Werner Lemberg96ddc672011-06-29 09:15:54 +02001727 /* Check whether a bitmap is being constructed. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001728 if ( p->flags & _BDF_BITMAP )
1729 {
1730 /* If there are more rows than are specified in the glyph metrics, */
1731 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001732 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001733 {
1734 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1735 {
1736 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1737 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001738 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001739 }
1740
1741 goto Exit;
1742 }
1743
1744 /* Only collect the number of nibbles indicated by the glyph */
1745 /* metrics. If there are more columns, they are simply ignored. */
1746 nibbles = glyph->bpr << 1;
1747 bp = glyph->bitmap + p->row * glyph->bpr;
1748
David Turnerb698eed2006-02-23 14:50:13 +00001749 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001750 {
1751 c = line[i];
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001752 if ( !sbitset( hdigits, c ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001753 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001754 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001755 if ( i + 1 < nibbles && ( i & 1 ) )
1756 *++bp = 0;
1757 }
1758
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001759 /* If any line has not enough columns, */
1760 /* indicate they have been padded with zero bits. */
1761 if ( i < nibbles &&
1762 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1763 {
1764 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
1765 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1766 font->modified = 1;
1767 }
1768
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001769 /* Remove possible garbage at the right. */
1770 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001771 if ( glyph->bbx.width )
1772 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001773
1774 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001775 if ( i == nibbles &&
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001776 sbitset( hdigits, line[nibbles] ) &&
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001777 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001778 {
1779 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1780 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1781 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001782 }
1783
1784 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001785 goto Exit;
1786 }
David Turner993a8d02002-05-18 12:03:43 +00001787
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001788 /* Expect the SWIDTH (scalable width) field next. */
1789 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1790 {
1791 if ( !( p->flags & _BDF_ENCODING ) )
Werner Lemberg4086fb72012-03-01 08:55:40 +01001792 goto Missing_Encoding;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001793
David Turner68df4f72005-03-15 18:18:57 +00001794 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001795 if ( error )
1796 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001797
David Turnerb1b47622002-05-21 21:17:43 +00001798 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001799 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001800
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001801 goto Exit;
1802 }
David Turner993a8d02002-05-18 12:03:43 +00001803
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001804 /* Expect the DWIDTH (scalable width) field next. */
1805 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1806 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001807 if ( !( p->flags & _BDF_ENCODING ) )
1808 goto Missing_Encoding;
1809
David Turner68df4f72005-03-15 18:18:57 +00001810 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001811 if ( error )
1812 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001813
David Turnerb1b47622002-05-21 21:17:43 +00001814 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001815
1816 if ( !( p->flags & _BDF_SWIDTH ) )
1817 {
1818 /* Missing SWIDTH field. Emit an auto correction message and set */
1819 /* the scalable width from the device width. */
1820 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1821
Werner Lemberg02d4d592002-05-28 22:38:05 +00001822 glyph->swidth = (unsigned short)FT_MulDiv(
1823 glyph->dwidth, 72000L,
1824 (FT_Long)( font->point_size *
1825 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001826 }
1827
1828 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001829 goto Exit;
1830 }
David Turner993a8d02002-05-18 12:03:43 +00001831
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001832 /* Expect the BBX field next. */
1833 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1834 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001835 if ( !( p->flags & _BDF_ENCODING ) )
1836 goto Missing_Encoding;
1837
David Turner68df4f72005-03-15 18:18:57 +00001838 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001839 if ( error )
1840 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001841
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001842 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1843 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1844 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1845 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1846
1847 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001848 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1849 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001850
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001851 /* Determine the overall font bounding box as the characters are */
1852 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001853 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1854 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001855
David Turnerb1b47622002-05-21 21:17:43 +00001856 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001857
Werner Lembergdfa46192004-03-05 09:26:24 +00001858 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1859 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1860 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001861
1862 if ( !( p->flags & _BDF_DWIDTH ) )
1863 {
1864 /* Missing DWIDTH field. Emit an auto correction message and set */
1865 /* the device width to the glyph width. */
1866 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1867 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001868 }
1869
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001870 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1871 /* value if necessary. */
1872 if ( p->opts->correct_metrics != 0 )
1873 {
1874 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001875 unsigned short sw = (unsigned short)FT_MulDiv(
1876 glyph->dwidth, 72000L,
1877 (FT_Long)( font->point_size *
1878 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001879
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001880
1881 if ( sw != glyph->swidth )
1882 {
1883 glyph->swidth = sw;
1884
1885 if ( p->glyph_enc == -1 )
1886 _bdf_set_glyph_modified( font->umod,
1887 font->unencoded_used - 1 );
1888 else
1889 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1890
1891 p->flags |= _BDF_SWIDTH_ADJ;
1892 font->modified = 1;
1893 }
David Turner993a8d02002-05-18 12:03:43 +00001894 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001895
David Turner993a8d02002-05-18 12:03:43 +00001896 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001897 goto Exit;
1898 }
David Turner993a8d02002-05-18 12:03:43 +00001899
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001900 /* And finally, gather up the bitmap. */
1901 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1902 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001903 unsigned long bitmap_size;
1904
1905
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001906 if ( !( p->flags & _BDF_BBX ) )
1907 {
1908 /* Missing BBX field. */
1909 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001910 error = FT_THROW( Missing_Bbx_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001911 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001912 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001913
1914 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001915 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001916
1917 bitmap_size = glyph->bpr * glyph->bbx.height;
Werner Lembergc4cad302012-03-08 20:11:37 +01001918 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
Werner Lemberg26170df2006-03-26 07:19:07 +00001919 {
1920 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001921 error = FT_THROW( Bbx_Too_Big );
Werner Lemberg26170df2006-03-26 07:19:07 +00001922 goto Exit;
1923 }
1924 else
1925 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001926
1927 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1928 goto Exit;
1929
1930 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001931 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001932
1933 goto Exit;
1934 }
1935
Werner Lemberge01406b2011-11-25 09:44:28 +01001936 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001937 error = FT_THROW( Invalid_File_Format );
Werner Lemberg4086fb72012-03-01 08:55:40 +01001938 goto Exit;
1939
1940 Missing_Encoding:
1941 /* Missing ENCODING field. */
1942 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001943 error = FT_THROW( Missing_Encoding_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001944
1945 Exit:
Werner Lembergf4c94d42010-06-19 16:08:31 +02001946 if ( error && ( p->flags & _BDF_GLYPH ) )
1947 FT_FREE( p->glyph_name );
1948
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001949 return error;
David Turner993a8d02002-05-18 12:03:43 +00001950 }
1951
David Turner993a8d02002-05-18 12:03:43 +00001952
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001953 /* Load the font properties. */
1954 static FT_Error
1955 _bdf_parse_properties( char* line,
1956 unsigned long linelen,
1957 unsigned long lineno,
1958 void* call_data,
1959 void* client_data )
1960 {
1961 unsigned long vlen;
1962 _bdf_line_func_t* next;
1963 _bdf_parse_t* p;
1964 char* name;
1965 char* value;
1966 char nbuf[128];
Werner Lemberge3c93012013-03-14 11:21:17 +01001967 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001968
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001969 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001970
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001971
1972 next = (_bdf_line_func_t *)call_data;
1973 p = (_bdf_parse_t *) client_data;
1974
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001975 /* Check for the end of the properties. */
1976 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1977 {
1978 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1979 /* encountered yet, then make sure they are added as properties and */
1980 /* make sure they are set from the font bounding box info. */
1981 /* */
1982 /* This is *always* done regardless of the options, because X11 */
1983 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001984 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001985 {
1986 p->font->font_ascent = p->font->bbx.ascent;
1987 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001988 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
1989 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001990 if ( error )
1991 goto Exit;
1992
1993 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1994 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001995 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001996
Werner Lemberg428c2e42003-04-25 05:35:04 +00001997 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001998 {
1999 p->font->font_descent = p->font->bbx.descent;
2000 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002001 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2002 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002003 if ( error )
2004 goto Exit;
2005
2006 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2007 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002008 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002009
David Turner993a8d02002-05-18 12:03:43 +00002010 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002011 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00002012
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002013 goto Exit;
2014 }
David Turner993a8d02002-05-18 12:03:43 +00002015
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002016 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
2017 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
2018 goto Exit;
2019
2020 /* Handle COMMENT fields and properties in a special way to preserve */
2021 /* the spacing. */
2022 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2023 {
David Turner993a8d02002-05-18 12:03:43 +00002024 name = value = line;
2025 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002026 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00002027 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01002028 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002029 if ( error )
2030 goto Exit;
2031 }
2032 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
2033 {
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
2039 {
David Turner68df4f72005-03-15 18:18:57 +00002040 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002041 if ( error )
2042 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002043 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002044
David Turner68df4f72005-03-15 18:18:57 +00002045 _bdf_list_shift( &p->list, 1 );
2046 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002047
Werner Lemberge01406b2011-11-25 09:44:28 +01002048 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002049 if ( error )
2050 goto Exit;
2051 }
2052
2053 Exit:
2054 return error;
David Turner993a8d02002-05-18 12:03:43 +00002055 }
2056
David Turner993a8d02002-05-18 12:03:43 +00002057
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002058 /* Load the font header. */
2059 static FT_Error
2060 _bdf_parse_start( char* line,
2061 unsigned long linelen,
2062 unsigned long lineno,
2063 void* call_data,
2064 void* client_data )
2065 {
2066 unsigned long slen;
2067 _bdf_line_func_t* next;
2068 _bdf_parse_t* p;
2069 bdf_font_t* font;
2070 char *s;
David Turner993a8d02002-05-18 12:03:43 +00002071
David Turnerd490e372002-05-28 23:40:37 +00002072 FT_Memory memory = NULL;
Werner Lemberge3c93012013-03-14 11:21:17 +01002073 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002074
2075 FT_UNUSED( lineno ); /* only used in debug mode */
2076
2077
2078 next = (_bdf_line_func_t *)call_data;
2079 p = (_bdf_parse_t *) client_data;
2080
2081 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00002082 memory = p->font->memory;
2083
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002084 /* Check for a comment. This is done to handle those fonts that have */
2085 /* comments before the STARTFONT line for some reason. */
2086 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2087 {
2088 if ( p->opts->keep_comments != 0 && p->font != 0 )
2089 {
2090 linelen -= 7;
2091
2092 s = line + 7;
2093 if ( *s != 0 )
2094 {
2095 s++;
2096 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002097 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002098
2099 error = _bdf_add_comment( p->font, s, linelen );
2100 if ( error )
2101 goto Exit;
2102 /* here font is not defined! */
2103 }
2104
2105 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002106 }
2107
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002108 if ( !( p->flags & _BDF_START ) )
2109 {
2110 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002111
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002112 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2113 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01002114 /* we don't emit an error message since this code gets */
2115 /* explicitly caught one level higher */
Werner Lemberg059bc332013-03-14 10:27:35 +01002116 error = FT_THROW( Missing_Startfont_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002117 goto Exit;
2118 }
David Turner993a8d02002-05-18 12:03:43 +00002119
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002120 p->flags = _BDF_START;
2121 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002122
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002123 if ( FT_NEW( font ) )
2124 goto Exit;
2125 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002126
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002127 font->memory = p->memory;
2128 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002129
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002130 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09002131 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002132 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002133
David Turner993a8d02002-05-18 12:03:43 +00002134
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002135 error = hash_init( &(font->proptbl), memory );
2136 if ( error )
2137 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002138 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002139 i < _num_bdf_properties; i++, prop++ )
2140 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09002141 error = hash_insert( prop->name, i,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002142 &(font->proptbl), memory );
2143 if ( error )
2144 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002145 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002146 }
2147
2148 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2149 goto Exit;
2150 error = hash_init( (hashtable *)p->font->internal,memory );
2151 if ( error )
2152 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002153 p->font->spacing = p->opts->font_spacing;
2154 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002155
2156 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002157 }
2158
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002159 /* Check for the start of the properties. */
2160 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2161 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002162 if ( !( p->flags & _BDF_FONT_BBX ) )
Werner Lembergfb690292010-06-23 10:00:52 +02002163 {
2164 /* Missing the FONTBOUNDINGBOX field. */
2165 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002166 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergfb690292010-06-23 10:00:52 +02002167 goto Exit;
2168 }
2169
David Turner68df4f72005-03-15 18:18:57 +00002170 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002171 if ( error )
2172 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00002173 /* at this point, `p->font' can't be NULL */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002174 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2175
2176 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
Werner Lemberg9b6b5752012-12-15 01:34:41 +01002177 {
2178 p->font->props_size = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002179 goto Exit;
Werner Lemberg9b6b5752012-12-15 01:34:41 +01002180 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002181
2182 p->flags |= _BDF_PROPS;
2183 *next = _bdf_parse_properties;
2184
2185 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002186 }
2187
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002188 /* Check for the FONTBOUNDINGBOX field. */
2189 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2190 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002191 if ( !( p->flags & _BDF_SIZE ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002192 {
2193 /* Missing the SIZE field. */
2194 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002195 error = FT_THROW( Missing_Size_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002196 goto Exit;
2197 }
2198
David Turner68df4f72005-03-15 18:18:57 +00002199 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002200 if ( error )
2201 goto Exit;
2202
2203 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2204 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2205
2206 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2207 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2208
David Turnerd490e372002-05-28 23:40:37 +00002209 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002210 p->font->bbx.y_offset );
2211
2212 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002213
2214 p->flags |= _BDF_FONT_BBX;
2215
2216 goto Exit;
2217 }
2218
2219 /* The next thing to check for is the FONT field. */
2220 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2221 {
David Turner68df4f72005-03-15 18:18:57 +00002222 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002223 if ( error )
2224 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002225 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002226
David Turner68df4f72005-03-15 18:18:57 +00002227 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002228
2229 if ( !s )
2230 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002231 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002232 error = FT_THROW( Invalid_File_Format );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002233 goto Exit;
2234 }
2235
Werner Lembergfb690292010-06-23 10:00:52 +02002236 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2237 FT_FREE( p->font->name );
2238
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002239 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2240 goto Exit;
2241 FT_MEM_COPY( p->font->name, s, slen + 1 );
2242
2243 /* If the font name is an XLFD name, set the spacing to the one in */
2244 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002245 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002246 if ( error )
2247 goto Exit;
2248
2249 p->flags |= _BDF_FONT_NAME;
2250
2251 goto Exit;
2252 }
2253
2254 /* Check for the SIZE field. */
2255 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2256 {
2257 if ( !( p->flags & _BDF_FONT_NAME ) )
2258 {
2259 /* Missing the FONT field. */
2260 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002261 error = FT_THROW( Missing_Font_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002262 goto Exit;
2263 }
2264
David Turner68df4f72005-03-15 18:18:57 +00002265 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002266 if ( error )
2267 goto Exit;
2268
2269 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2270 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2271 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2272
2273 /* Check for the bits per pixel field. */
2274 if ( p->list.used == 5 )
2275 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002276 unsigned short bitcount, i, shift;
2277
2278
2279 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2280
2281 /* Only values 1, 2, 4, 8 are allowed. */
2282 shift = p->font->bpp;
2283 bitcount = 0;
2284 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002285 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002286 if ( shift & 1 )
2287 bitcount = i;
2288 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002289 }
David Turner993a8d02002-05-18 12:03:43 +00002290
Werner Lembergbd8e3242002-06-12 08:43:58 +00002291 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002292
2293 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002294 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002295 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002296 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002297 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002298 }
2299 }
2300 else
2301 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002302
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002303 p->flags |= _BDF_SIZE;
2304
2305 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002306 }
2307
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002308 /* Check for the CHARS field -- font properties are optional */
2309 if ( ft_memcmp( line, "CHARS", 5 ) == 0 )
2310 {
2311 char nbuf[128];
2312
2313
2314 if ( !( p->flags & _BDF_FONT_BBX ) )
2315 {
2316 /* Missing the FONTBOUNDINGBOX field. */
2317 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002318 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002319 goto Exit;
2320 }
2321
2322 /* Add the two standard X11 properties which are required */
2323 /* for compiling fonts. */
2324 p->font->font_ascent = p->font->bbx.ascent;
2325 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002326 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2327 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002328 if ( error )
2329 goto Exit;
2330 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2331
2332 p->font->font_descent = p->font->bbx.descent;
2333 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002334 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2335 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002336 if ( error )
2337 goto Exit;
2338 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2339
2340 p->font->modified = 1;
2341
2342 *next = _bdf_parse_glyphs;
2343
2344 /* A special return value. */
2345 error = -1;
2346 goto Exit;
2347 }
2348
Werner Lemberge01406b2011-11-25 09:44:28 +01002349 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002350 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002351
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002352 Exit:
2353 return error;
2354 }
David Turner993a8d02002-05-18 12:03:43 +00002355
2356
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002357 /*************************************************************************/
2358 /* */
2359 /* API. */
2360 /* */
2361 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002362
David Turner993a8d02002-05-18 12:03:43 +00002363
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002364 FT_LOCAL_DEF( FT_Error )
2365 bdf_load_font( FT_Stream stream,
2366 FT_Memory extmemory,
2367 bdf_options_t* opts,
2368 bdf_font_t* *font )
2369 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002370 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002371 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002372
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002373 FT_Memory memory = extmemory;
Werner Lemberge3c93012013-03-14 11:21:17 +01002374 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002375
2376
David Turner68df4f72005-03-15 18:18:57 +00002377 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002378 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002379
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002380 memory = NULL;
2381 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2382 p->minlb = 32767;
2383 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002384
David Turner68df4f72005-03-15 18:18:57 +00002385 _bdf_list_init( &p->list, extmemory );
2386
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002387 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002388 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002389 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002390 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002391
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002392 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002393 {
2394 /* If the font is not proportional, set the font's monowidth */
2395 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002396 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002397
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002398 if ( p->font->spacing != BDF_PROPORTIONAL )
2399 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002400
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002401 /* If the number of glyphs loaded is not that of the original count, */
2402 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002403 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002404 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002405 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2406 p->font->glyphs_used + p->font->unencoded_used ));
2407 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002408 }
2409
2410 /* Once the font has been loaded, adjust the overall font metrics if */
2411 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002412 if ( p->opts->correct_metrics != 0 &&
2413 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002414 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002415 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002416 {
2417 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002418 p->font->bbx.width, p->maxrb - p->minlb ));
2419 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2420 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002421 }
2422
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002423 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002424 {
2425 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002426 p->font->bbx.x_offset, p->minlb ));
2427 p->font->bbx.x_offset = p->minlb;
2428 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002429 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002430
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002431 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002432 {
2433 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002434 p->font->bbx.ascent, p->maxas ));
2435 p->font->bbx.ascent = p->maxas;
2436 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002437 }
2438
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002439 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002440 {
2441 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002442 p->font->bbx.descent, p->maxds ));
2443 p->font->bbx.descent = p->maxds;
2444 p->font->bbx.y_offset = (short)( -p->maxds );
2445 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002446 }
2447
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002448 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002449 {
2450 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002451 p->font->bbx.height, p->maxas + p->maxds ));
2452 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002453 }
2454
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002455 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002456 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2457 }
David Turner993a8d02002-05-18 12:03:43 +00002458 }
2459
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002460 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002461 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002462 /* The ENDFONT field was never reached or did not exist. */
2463 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002464 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002465 /* Error happened while parsing header. */
2466 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002467 error = FT_THROW( Corrupted_Font_Header );
Werner Lemberge01406b2011-11-25 09:44:28 +01002468 goto Exit;
2469 }
2470 else
2471 {
2472 /* Error happened when parsing glyphs. */
2473 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002474 error = FT_THROW( Corrupted_Font_Glyphs );
Werner Lemberge01406b2011-11-25 09:44:28 +01002475 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002476 }
David Turner993a8d02002-05-18 12:03:43 +00002477 }
2478
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002479 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002480 {
2481 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002482 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002483
Werner Lemberg370aea82010-06-08 08:37:11 +02002484 if ( p->font->comments_len > 0 )
2485 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002486 if ( FT_RENEW_ARRAY( p->font->comments,
2487 p->font->comments_len,
2488 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002489 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002490
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002491 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002492 }
David Turner993a8d02002-05-18 12:03:43 +00002493 }
Werner Lemberge3c93012013-03-14 11:21:17 +01002494 else if ( error == FT_Err_Ok )
Werner Lemberg059bc332013-03-14 10:27:35 +01002495 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002496
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002497 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002498
2499 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002500 if ( p )
2501 {
David Turner68df4f72005-03-15 18:18:57 +00002502 _bdf_list_done( &p->list );
2503
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002504 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002505
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002506 FT_FREE( p );
2507 }
2508
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002509 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002510
2511 Fail:
2512 bdf_free_font( p->font );
2513
2514 memory = extmemory;
2515
2516 FT_FREE( p->font );
2517
2518 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002519 }
David Turner993a8d02002-05-18 12:03:43 +00002520
2521
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002522 FT_LOCAL_DEF( void )
2523 bdf_free_font( bdf_font_t* font )
2524 {
2525 bdf_property_t* prop;
2526 unsigned long i;
2527 bdf_glyph_t* glyphs;
2528 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002529
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002530
2531 if ( font == 0 )
2532 return;
David Turner993a8d02002-05-18 12:03:43 +00002533
2534 memory = font->memory;
2535
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002536 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002537
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002538 /* Free up the internal hash table of property names. */
2539 if ( font->internal )
2540 {
2541 hash_free( (hashtable *)font->internal, memory );
2542 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002543 }
2544
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002545 /* Free up the comment info. */
2546 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002547
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002548 /* Free up the properties. */
2549 for ( i = 0; i < font->props_size; i++ )
2550 {
2551 if ( font->props[i].format == BDF_ATOM )
2552 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002553 }
2554
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002555 FT_FREE( font->props );
2556
2557 /* Free up the character info. */
2558 for ( i = 0, glyphs = font->glyphs;
2559 i < font->glyphs_used; i++, glyphs++ )
2560 {
2561 FT_FREE( glyphs->name );
2562 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002563 }
2564
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002565 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2566 i++, glyphs++ )
2567 {
2568 FT_FREE( glyphs->name );
2569 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002570 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002571
2572 FT_FREE( font->glyphs );
2573 FT_FREE( font->unencoded );
2574
2575 /* Free up the overflow storage if it was used. */
2576 for ( i = 0, glyphs = font->overflow.glyphs;
2577 i < font->overflow.glyphs_used; i++, glyphs++ )
2578 {
2579 FT_FREE( glyphs->name );
2580 FT_FREE( glyphs->bitmap );
2581 }
2582
2583 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002584
2585 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002586 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002587
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002588 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002589 for ( prop = font->user_props, i = 0;
2590 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002591 {
2592 FT_FREE( prop->name );
2593 if ( prop->format == BDF_ATOM )
2594 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002595 }
David Turner993a8d02002-05-18 12:03:43 +00002596
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002597 FT_FREE( font->user_props );
2598
2599 /* FREE( font ); */ /* XXX Fixme */
2600 }
David Turner993a8d02002-05-18 12:03:43 +00002601
2602
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002603 FT_LOCAL_DEF( bdf_property_t * )
2604 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002605 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002606 {
2607 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002608
David Turner993a8d02002-05-18 12:03:43 +00002609
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002610 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002611 return 0;
2612
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002613 hn = hash_lookup( name, (hashtable *)font->internal );
2614
suzuki toshiya704f4d72009-09-13 00:50:14 +09002615 return hn ? ( font->props + hn->data ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002616 }
2617
2618
2619/* END */