blob: f132e08e973e06f7575eb8b24d3e651a9a837ab7 [file] [log] [blame]
David Turner993a8d02002-05-18 12:03:43 +00001/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
Werner Lemberg96ddc672011-06-29 09:15:54 +02003 * Copyright 2001-2011
Werner Lemberg442bfb82007-02-12 21:44:10 +00004 * Francesco Zappa Nardelli
David Turner993a8d02002-05-18 12:03:43 +00005 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
Werner Lemberg7cf4d372002-05-21 14:13:01 +000025 /*************************************************************************/
26 /* */
27 /* This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 */
28 /* */
29 /* taken from Mark Leisher's xmbdfed package */
30 /* */
31 /*************************************************************************/
32
David Turner993a8d02002-05-18 12:03:43 +000033
34#include <ft2build.h>
35
Werner Lemberg02d4d592002-05-28 22:38:05 +000036#include FT_FREETYPE_H
David Turner993a8d02002-05-18 12:03:43 +000037#include FT_INTERNAL_DEBUG_H
38#include FT_INTERNAL_STREAM_H
39#include FT_INTERNAL_OBJECTS_H
40
41#include "bdf.h"
David Turner993a8d02002-05-18 12:03:43 +000042#include "bdferror.h"
43
David Turner993a8d02002-05-18 12:03:43 +000044
Werner Lemberg7cf4d372002-05-21 14:13:01 +000045 /*************************************************************************/
46 /* */
47 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
48 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
49 /* messages during execution. */
50 /* */
51#undef FT_COMPONENT
52#define FT_COMPONENT trace_bdflib
David Turner993a8d02002-05-18 12:03:43 +000053
David Turner993a8d02002-05-18 12:03:43 +000054
Werner Lemberg7cf4d372002-05-21 14:13:01 +000055 /*************************************************************************/
56 /* */
57 /* Default BDF font options. */
58 /* */
59 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000060
David Turner993a8d02002-05-18 12:03:43 +000061
David Turnerb1b47622002-05-21 21:17:43 +000062 static const bdf_options_t _bdf_opts =
Werner Lemberg7cf4d372002-05-21 14:13:01 +000063 {
David Turner993a8d02002-05-18 12:03:43 +000064 1, /* Correct metrics. */
65 1, /* Preserve unencoded glyphs. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000066 0, /* Preserve comments. */
67 BDF_PROPORTIONAL /* Default spacing. */
68 };
David Turner993a8d02002-05-18 12:03:43 +000069
David Turner993a8d02002-05-18 12:03:43 +000070
Werner Lemberg7cf4d372002-05-21 14:13:01 +000071 /*************************************************************************/
72 /* */
73 /* Builtin BDF font properties. */
74 /* */
75 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000076
Werner Lemberg7cf4d372002-05-21 14:13:01 +000077 /* List of most properties that might appear in a font. Doesn't include */
78 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
David Turner993a8d02002-05-18 12:03:43 +000079
David Turnerb1b47622002-05-21 21:17:43 +000080 static const bdf_property_t _bdf_properties[] =
David Turner993a8d02002-05-18 12:03:43 +000081 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +000082 { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
83 { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
84 { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
85 { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
86 { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
87 { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
88 { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
89 { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
90 { (char *)"COMMENT", BDF_ATOM, 1, { 0 } },
91 { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } },
92 { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
93 { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } },
94 { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
95 { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } },
96 { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } },
97 { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } },
98 { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
99 { (char *)"FONT", BDF_ATOM, 1, { 0 } },
100 { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
101 { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
102 { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
103 { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } },
104 { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } },
105 { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
106 { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } },
107 { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } },
108 { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } },
109 { (char *)"NOTICE", BDF_ATOM, 1, { 0 } },
110 { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
111 { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } },
112 { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
113 { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
114 { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
115 { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
116 { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
117 { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
118 { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
119 { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
120 { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
121 { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
122 { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
123 { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
124 { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
125 { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
126 { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
127 { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
128 { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
129 { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
130 { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
131 { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
132 { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
133 { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
134 { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
135 { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
136 { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
137 { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
138 { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
139 { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
140 { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
141 { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
142 { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
143 { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } },
144 { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
145 { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
146 { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
147 { (char *)"SLANT", BDF_ATOM, 1, { 0 } },
148 { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
149 { (char *)"SPACING", BDF_ATOM, 1, { 0 } },
150 { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
151 { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
152 { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
153 { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
154 { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
155 { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
156 { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
157 { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
158 { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
159 { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
160 { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } },
161 { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
162 { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } },
163 { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
164 { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
165 };
David Turner993a8d02002-05-18 12:03:43 +0000166
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000167 static const unsigned long
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000168 _num_bdf_properties = sizeof ( _bdf_properties ) /
169 sizeof ( _bdf_properties[0] );
David Turner993a8d02002-05-18 12:03:43 +0000170
171
Werner Lemberge01406b2011-11-25 09:44:28 +0100172 /* Auto correction messages. */
173#define ACMSG1 "FONT_ASCENT property missing. " \
174 "Added `FONT_ASCENT %hd'.\n"
175#define ACMSG2 "FONT_DESCENT property missing. " \
176 "Added `FONT_DESCENT %hd'.\n"
177#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
178#define ACMSG4 "Font left bearing != actual left bearing. " \
179 "Old: %hd New: %hd.\n"
180#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
181#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
182#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
183#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
184#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
185#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
186#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
187#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
188#define ACMSG13 "Glyph %ld extra rows removed.\n"
189#define ACMSG14 "Glyph %ld extra columns removed.\n"
190#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
191
192 /* Error messages. */
193#define ERRMSG1 "[line %ld] Missing `%s' line.\n"
194#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
195#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
196#define ERRMSG4 "[line %ld] BBX too big.\n"
197#define ERRMSG5 "[line %ld] `%s' value too big.\n"
198#define ERRMSG6 "[line %ld] Input line too long.\n"
199#define ERRMSG7 "[line %ld] Font name too long.\n"
200#define ERRMSG8 "[line %ld] Invalid `%s' value.\n"
201#define ERRMSG9 "[line %ld] Invalid keyword.\n"
202
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +0100203 /* Debug messages. */
204#define DBGMSG1 " [%6ld] %s" /* no \n */
205#define DBGMSG2 " (0x%lX)\n"
206
Werner Lemberge01406b2011-11-25 09:44:28 +0100207
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000208 /*************************************************************************/
209 /* */
210 /* Hash table utilities for the properties. */
211 /* */
212 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +0000213
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000214 /* XXX: Replace this with FreeType's hash functions */
David Turner993a8d02002-05-18 12:03:43 +0000215
David Turner993a8d02002-05-18 12:03:43 +0000216
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000217#define INITIAL_HT_SIZE 241
218
219 typedef void
220 (*hash_free_func)( hashnode node );
221
222 static hashnode*
Werner Lemberg428c2e42003-04-25 05:35:04 +0000223 hash_bucket( const char* key,
224 hashtable* ht )
David Turner993a8d02002-05-18 12:03:43 +0000225 {
Werner Lemberg428c2e42003-04-25 05:35:04 +0000226 const char* kp = key;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000227 unsigned long res = 0;
228 hashnode* bp = ht->table, *ndp;
229
230
231 /* Mocklisp hash function. */
232 while ( *kp )
233 res = ( res << 5 ) - res + *kp++;
234
235 ndp = bp + ( res % ht->size );
236 while ( *ndp )
David Turner993a8d02002-05-18 12:03:43 +0000237 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000238 kp = (*ndp)->key;
239 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
240 break;
241 ndp--;
242 if ( ndp < bp )
243 ndp = bp + ( ht->size - 1 );
David Turner993a8d02002-05-18 12:03:43 +0000244 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000245
246 return ndp;
David Turner993a8d02002-05-18 12:03:43 +0000247 }
David Turner993a8d02002-05-18 12:03:43 +0000248
249
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000250 static FT_Error
251 hash_rehash( hashtable* ht,
252 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000253 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000254 hashnode* obp = ht->table, *bp, *nbp;
David Turner993a8d02002-05-18 12:03:43 +0000255 int i, sz = ht->size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000256 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000257
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000258
259 ht->size <<= 1;
260 ht->limit = ht->size / 3;
261
262 if ( FT_NEW_ARRAY( ht->table, ht->size ) )
263 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000264
265 for ( i = 0, bp = obp; i < sz; i++, bp++ )
David Turner993a8d02002-05-18 12:03:43 +0000266 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000267 if ( *bp )
268 {
269 nbp = hash_bucket( (*bp)->key, ht );
270 *nbp = *bp;
271 }
David Turner993a8d02002-05-18 12:03:43 +0000272 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000273 FT_FREE( obp );
274
275 Exit:
276 return error;
David Turner993a8d02002-05-18 12:03:43 +0000277 }
David Turner993a8d02002-05-18 12:03:43 +0000278
279
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000280 static FT_Error
281 hash_init( hashtable* ht,
282 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000283 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000284 int sz = INITIAL_HT_SIZE;
285 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000286
David Turner993a8d02002-05-18 12:03:43 +0000287
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000288 ht->size = sz;
289 ht->limit = sz / 3;
290 ht->used = 0;
David Turner993a8d02002-05-18 12:03:43 +0000291
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000292 if ( FT_NEW_ARRAY( ht->table, sz ) )
293 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000294
295 Exit:
296 return error;
David Turner993a8d02002-05-18 12:03:43 +0000297 }
David Turner993a8d02002-05-18 12:03:43 +0000298
299
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000300 static void
301 hash_free( hashtable* ht,
302 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000303 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000304 if ( ht != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000305 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000306 int i, sz = ht->size;
307 hashnode* bp = ht->table;
David Turner993a8d02002-05-18 12:03:43 +0000308
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000309
310 for ( i = 0; i < sz; i++, bp++ )
311 FT_FREE( *bp );
312
313 FT_FREE( ht->table );
314 }
David Turner993a8d02002-05-18 12:03:43 +0000315 }
316
David Turner993a8d02002-05-18 12:03:43 +0000317
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000318 static FT_Error
319 hash_insert( char* key,
suzuki toshiya704f4d72009-09-13 00:50:14 +0900320 size_t data,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000321 hashtable* ht,
322 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000323 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000324 hashnode nn, *bp = hash_bucket( key, ht );
325 FT_Error error = BDF_Err_Ok;
326
327
328 nn = *bp;
329 if ( !nn )
330 {
331 if ( FT_NEW( nn ) )
332 goto Exit;
333 *bp = nn;
334
335 nn->key = key;
336 nn->data = data;
337
338 if ( ht->used >= ht->limit )
339 {
340 error = hash_rehash( ht, memory );
341 if ( error )
342 goto Exit;
343 }
344 ht->used++;
345 }
David Turner993a8d02002-05-18 12:03:43 +0000346 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000347 nn->data = data;
348
349 Exit:
350 return error;
David Turner993a8d02002-05-18 12:03:43 +0000351 }
352
David Turner993a8d02002-05-18 12:03:43 +0000353
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000354 static hashnode
Werner Lemberg428c2e42003-04-25 05:35:04 +0000355 hash_lookup( const char* key,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000356 hashtable* ht )
357 {
358 hashnode *np = hash_bucket( key, ht );
359
360
361 return *np;
362 }
363
364
365 /*************************************************************************/
366 /* */
367 /* Utility types and functions. */
368 /* */
369 /*************************************************************************/
370
371
372 /* Function type for parsing lines of a BDF font. */
373
374 typedef FT_Error
375 (*_bdf_line_func_t)( char* line,
376 unsigned long linelen,
377 unsigned long lineno,
378 void* call_data,
379 void* client_data );
380
381
382 /* List structure for splitting lines into fields. */
383
384 typedef struct _bdf_list_t_
385 {
386 char** field;
387 unsigned long size;
388 unsigned long used;
David Turner68df4f72005-03-15 18:18:57 +0000389 FT_Memory memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000390
391 } _bdf_list_t;
392
393
394 /* Structure used while loading BDF fonts. */
395
396 typedef struct _bdf_parse_t_
397 {
398 unsigned long flags;
399 unsigned long cnt;
400 unsigned long row;
401
402 short minlb;
403 short maxlb;
404 short maxrb;
405 short maxas;
406 short maxds;
407
408 short rbearing;
409
410 char* glyph_name;
411 long glyph_enc;
412
413 bdf_font_t* font;
414 bdf_options_t* opts;
415
416 unsigned long have[2048];
417 _bdf_list_t list;
418
419 FT_Memory memory;
420
421 } _bdf_parse_t;
422
423
Werner Lemberga08b2172007-03-28 07:17:17 +0000424#define setsbit( m, cc ) \
425 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
426#define sbitset( m, cc ) \
427 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000428
429
David Turner68df4f72005-03-15 18:18:57 +0000430 static void
431 _bdf_list_init( _bdf_list_t* list,
432 FT_Memory memory )
433 {
Werner Lembergebf55852005-03-16 01:49:54 +0000434 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000435 list->memory = memory;
436 }
437
Werner Lembergebf55852005-03-16 01:49:54 +0000438
David Turner68df4f72005-03-15 18:18:57 +0000439 static void
440 _bdf_list_done( _bdf_list_t* list )
441 {
442 FT_Memory memory = list->memory;
443
Werner Lembergebf55852005-03-16 01:49:54 +0000444
David Turner68df4f72005-03-15 18:18:57 +0000445 if ( memory )
446 {
447 FT_FREE( list->field );
Werner Lembergebf55852005-03-16 01:49:54 +0000448 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000449 }
450 }
451
452
453 static FT_Error
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900454 _bdf_list_ensure( _bdf_list_t* list,
455 unsigned long num_items ) /* same as _bdf_list_t.used */
David Turner68df4f72005-03-15 18:18:57 +0000456 {
Werner Lembergebf55852005-03-16 01:49:54 +0000457 FT_Error error = BDF_Err_Ok;
458
David Turner68df4f72005-03-15 18:18:57 +0000459
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900460 if ( num_items > list->size )
David Turner68df4f72005-03-15 18:18:57 +0000461 {
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900462 unsigned long oldsize = list->size; /* same as _bdf_list_t.size */
463 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 4;
464 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
465 FT_Memory memory = list->memory;
David Turner68df4f72005-03-15 18:18:57 +0000466
Werner Lembergebf55852005-03-16 01:49:54 +0000467
David Turner68df4f72005-03-15 18:18:57 +0000468 if ( oldsize == bigsize )
469 {
Werner Lembergebf55852005-03-16 01:49:54 +0000470 error = BDF_Err_Out_Of_Memory;
David Turner68df4f72005-03-15 18:18:57 +0000471 goto Exit;
472 }
473 else if ( newsize < oldsize || newsize > bigsize )
474 newsize = bigsize;
475
476 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
477 goto Exit;
478
479 list->size = newsize;
480 }
Werner Lembergebf55852005-03-16 01:49:54 +0000481
David Turner68df4f72005-03-15 18:18:57 +0000482 Exit:
483 return error;
484 }
485
486
487 static void
488 _bdf_list_shift( _bdf_list_t* list,
489 unsigned long n )
490 {
491 unsigned long i, u;
492
493
494 if ( list == 0 || list->used == 0 || n == 0 )
495 return;
496
497 if ( n >= list->used )
498 {
499 list->used = 0;
500 return;
501 }
502
503 for ( u = n, i = 0; u < list->used; i++, u++ )
504 list->field[i] = list->field[u];
505 list->used -= n;
506 }
507
508
Werner Lembergf4c94d42010-06-19 16:08:31 +0200509 /* An empty string for empty fields. */
510
511 static const char empty[1] = { 0 }; /* XXX eliminate this */
512
513
David Turner68df4f72005-03-15 18:18:57 +0000514 static char *
515 _bdf_list_join( _bdf_list_t* list,
516 int c,
517 unsigned long *alen )
518 {
519 unsigned long i, j;
520 char *fp, *dp;
521
522
523 *alen = 0;
524
525 if ( list == 0 || list->used == 0 )
526 return 0;
527
528 dp = list->field[0];
529 for ( i = j = 0; i < list->used; i++ )
530 {
531 fp = list->field[i];
532 while ( *fp )
533 dp[j++] = *fp++;
534
535 if ( i + 1 < list->used )
536 dp[j++] = (char)c;
537 }
Werner Lembergf4c94d42010-06-19 16:08:31 +0200538 if ( dp != empty )
539 dp[j] = 0;
David Turner68df4f72005-03-15 18:18:57 +0000540
541 *alen = j;
542 return dp;
543 }
544
545
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000546 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000547 _bdf_list_split( _bdf_list_t* list,
548 char* separators,
549 char* line,
550 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000551 {
552 int mult, final_empty;
553 char *sp, *ep, *end;
554 char seps[32];
555 FT_Error error = BDF_Err_Ok;
556
557
558 /* Initialize the list. */
559 list->used = 0;
560
561 /* If the line is empty, then simply return. */
562 if ( linelen == 0 || line[0] == 0 )
563 goto Exit;
564
565 /* In the original code, if the `separators' parameter is NULL or */
566 /* empty, the list is split into individual bytes. We don't need */
567 /* this, so an error is signaled. */
568 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000569 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000570 error = BDF_Err_Invalid_Argument;
571 goto Exit;
572 }
573
574 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000575 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000576
577 /* If the very last character of the separator string is a plus, then */
578 /* set the `mult' flag to indicate that multiple separators should be */
579 /* collapsed into one. */
580 for ( mult = 0, sp = separators; sp && *sp; sp++ )
581 {
582 if ( *sp == '+' && *( sp + 1 ) == 0 )
583 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000584 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000585 setsbit( seps, *sp );
586 }
587
588 /* Break the line up into fields. */
589 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
590 sp < end && *sp; )
591 {
592 /* Collect everything that is not a separator. */
593 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
594 ;
595
596 /* Resize the list if necessary. */
597 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000598 {
Werner Lembergebf55852005-03-16 01:49:54 +0000599 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000600 if ( error )
601 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000602 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000603
604 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000605 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000606
607 sp = ep;
608
609 if ( mult )
610 {
611 /* If multiple separators should be collapsed, do it now by */
612 /* setting all the separator characters to 0. */
613 for ( ; *ep && sbitset( seps, *ep ); ep++ )
614 *ep = 0;
615 }
616 else if ( *ep != 0 )
617 /* Don't collapse multiple separators by making them 0, so just */
618 /* make the one encountered 0. */
619 *ep++ = 0;
620
621 final_empty = ( ep > sp && *ep == 0 );
622 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000623 }
624
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000625 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000626 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000627 {
Werner Lembergebf55852005-03-16 01:49:54 +0000628 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000629 if ( error )
630 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000631 }
632
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000633 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000634 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000635
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000636 list->field[list->used] = 0;
637
638 Exit:
639 return error;
David Turner993a8d02002-05-18 12:03:43 +0000640 }
641
David Turner993a8d02002-05-18 12:03:43 +0000642
David Turner68df4f72005-03-15 18:18:57 +0000643#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000644
Werner Lembergebf55852005-03-16 01:49:54 +0000645
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000646 static FT_Error
647 _bdf_readstream( FT_Stream stream,
648 _bdf_line_func_t callback,
649 void* client_data,
650 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000651 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000652 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000653 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900654 int refill, hold, to_skip;
655 ptrdiff_t bytes, start, end, cursor, avail;
David Turner68df4f72005-03-15 18:18:57 +0000656 char* buf = 0;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000657 FT_Memory memory = stream->memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000658 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000659
David Turner993a8d02002-05-18 12:03:43 +0000660
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000661 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000662 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000663 error = BDF_Err_Invalid_Argument;
664 goto Exit;
665 }
David Turner993a8d02002-05-18 12:03:43 +0000666
Werner Lembergebf55852005-03-16 01:49:54 +0000667 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000668 buf_size = 1024;
669
670 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000671 goto Exit;
672
Werner Lembergebf55852005-03-16 01:49:54 +0000673 cb = callback;
674 lineno = 1;
675 buf[0] = 0;
676 start = 0;
677 end = 0;
678 avail = 0;
679 cursor = 0;
680 refill = 1;
681 to_skip = NO_SKIP;
682 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000683
David Turner68df4f72005-03-15 18:18:57 +0000684 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000685 {
David Turner68df4f72005-03-15 18:18:57 +0000686 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000687 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +0200688 bytes = (ptrdiff_t)FT_Stream_TryRead(
689 stream, (FT_Byte*)buf + cursor,
690 (FT_ULong)( buf_size - cursor ) );
David Turner68df4f72005-03-15 18:18:57 +0000691 avail = cursor + bytes;
692 cursor = 0;
693 refill = 0;
694 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000695
David Turner68df4f72005-03-15 18:18:57 +0000696 end = start;
697
Werner Lembergebf55852005-03-16 01:49:54 +0000698 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000699 if ( start < avail && buf[start] == to_skip )
700 {
701 start += 1;
702 to_skip = NO_SKIP;
703 continue;
704 }
705
706 /* try to find the end of the line */
707 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
708 end++;
709
Werner Lembergebf55852005-03-16 01:49:54 +0000710 /* if we hit the end of the buffer, try shifting its content */
711 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000712 if ( end >= avail )
713 {
714 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
715 break; /* ignore it then exit */
716
717 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000718 {
Werner Lembergebf55852005-03-16 01:49:54 +0000719 /* this line is definitely too long; try resizing the input */
720 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000721 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000722
Werner Lembergebf55852005-03-16 01:49:54 +0000723
724 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000725 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100726 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
David Turner68df4f72005-03-15 18:18:57 +0000727 error = BDF_Err_Invalid_Argument;
728 goto Exit;
729 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000730
Werner Lembergebf55852005-03-16 01:49:54 +0000731 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000732 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
733 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000734
David Turner68df4f72005-03-15 18:18:57 +0000735 cursor = buf_size;
736 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000737 }
738 else
739 {
David Turner68df4f72005-03-15 18:18:57 +0000740 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000741
Werner Lembergebf55852005-03-16 01:49:54 +0000742 FT_MEM_COPY( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000743
David Turner68df4f72005-03-15 18:18:57 +0000744 cursor = bytes;
745 avail -= bytes;
746 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000747 }
David Turner68df4f72005-03-15 18:18:57 +0000748 refill = 1;
749 continue;
David Turner993a8d02002-05-18 12:03:43 +0000750 }
David Turner68df4f72005-03-15 18:18:57 +0000751
752 /* Temporarily NUL-terminate the line. */
753 hold = buf[end];
754 buf[end] = 0;
755
756 /* XXX: Use encoding independent value for 0x1a */
757 if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
758 {
Werner Lembergebf55852005-03-16 01:49:54 +0000759 error = (*cb)( buf + start, end - start, lineno,
760 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200761 /* Redo if we have encountered CHARS without properties. */
762 if ( error == -1 )
763 error = (*cb)( buf + start, end - start, lineno,
764 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000765 if ( error )
766 break;
767 }
768
769 lineno += 1;
770 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000771 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000772
773 if ( hold == '\n' )
774 to_skip = '\r';
775 else if ( hold == '\r' )
776 to_skip = '\n';
777 else
778 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000779 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000780
David Turner68df4f72005-03-15 18:18:57 +0000781 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000782
783 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000784 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000785 return error;
David Turner993a8d02002-05-18 12:03:43 +0000786 }
David Turner993a8d02002-05-18 12:03:43 +0000787
788
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000789 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000790
David Turnerb1b47622002-05-21 21:17:43 +0000791 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000792 {
David Turner993a8d02002-05-18 12:03:43 +0000793 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
794 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
795 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
796 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
797 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
798 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
799 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
800 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
801 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
802 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
803 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000804 };
David Turner993a8d02002-05-18 12:03:43 +0000805
David Turnerb1b47622002-05-21 21:17:43 +0000806 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000807 {
David Turner993a8d02002-05-18 12:03:43 +0000808 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
809 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
811 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000812 };
David Turner993a8d02002-05-18 12:03:43 +0000813
David Turnerb1b47622002-05-21 21:17:43 +0000814 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000815 {
David Turner993a8d02002-05-18 12:03:43 +0000816 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
817 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
818 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
819 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000820 };
David Turner993a8d02002-05-18 12:03:43 +0000821
David Turnerb1b47622002-05-21 21:17:43 +0000822 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000823 {
David Turner993a8d02002-05-18 12:03:43 +0000824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
825 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
826 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
827 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000828 };
David Turner993a8d02002-05-18 12:03:43 +0000829
David Turner993a8d02002-05-18 12:03:43 +0000830
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000831#define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
David Turner993a8d02002-05-18 12:03:43 +0000832
David Turner993a8d02002-05-18 12:03:43 +0000833
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000834 /* Routine to convert an ASCII string into an unsigned long integer. */
835 static unsigned long
836 _bdf_atoul( char* s,
837 char** end,
838 int base )
David Turner993a8d02002-05-18 12:03:43 +0000839 {
David Turnerb1b47622002-05-21 21:17:43 +0000840 unsigned long v;
841 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000842
843
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000844 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000845 return 0;
846
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000847 /* Make sure the radix is something recognizable. Default to 10. */
848 switch ( base )
849 {
850 case 8:
851 dmap = odigits;
852 break;
853 case 16:
854 dmap = hdigits;
855 break;
856 default:
857 base = 10;
858 dmap = ddigits;
859 break;
David Turner993a8d02002-05-18 12:03:43 +0000860 }
861
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000862 /* Check for the special hex prefix. */
863 if ( *s == '0' &&
864 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
865 {
866 base = 16;
867 dmap = hdigits;
868 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000869 }
870
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000871 for ( v = 0; isdigok( dmap, *s ); s++ )
872 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000873
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000874 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000875 *end = s;
876
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000877 return v;
878 }
David Turner993a8d02002-05-18 12:03:43 +0000879
David Turner993a8d02002-05-18 12:03:43 +0000880
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000881 /* Routine to convert an ASCII string into an signed long integer. */
882 static long
883 _bdf_atol( char* s,
884 char** end,
885 int base )
886 {
David Turnerb1b47622002-05-21 21:17:43 +0000887 long v, neg;
888 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000889
890
891 if ( s == 0 || *s == 0 )
892 return 0;
893
894 /* Make sure the radix is something recognizable. Default to 10. */
895 switch ( base )
896 {
897 case 8:
898 dmap = odigits;
899 break;
900 case 16:
901 dmap = hdigits;
902 break;
903 default:
904 base = 10;
905 dmap = ddigits;
906 break;
907 }
908
909 /* Check for a minus sign. */
910 neg = 0;
911 if ( *s == '-' )
912 {
913 s++;
914 neg = 1;
915 }
916
917 /* Check for the special hex prefix. */
918 if ( *s == '0' &&
919 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
920 {
921 base = 16;
922 dmap = hdigits;
923 s += 2;
924 }
925
926 for ( v = 0; isdigok( dmap, *s ); s++ )
927 v = v * base + a2i[(int)*s];
928
929 if ( end != 0 )
930 *end = s;
931
932 return ( !neg ) ? v : -v;
933 }
934
935
936 /* Routine to convert an ASCII string into an signed short integer. */
937 static short
938 _bdf_atos( char* s,
939 char** end,
940 int base )
941 {
David Turnerb1b47622002-05-21 21:17:43 +0000942 short v, neg;
943 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000944
945
946 if ( s == 0 || *s == 0 )
947 return 0;
948
949 /* Make sure the radix is something recognizable. Default to 10. */
950 switch ( base )
951 {
952 case 8:
953 dmap = odigits;
954 break;
955 case 16:
956 dmap = hdigits;
957 break;
958 default:
959 base = 10;
960 dmap = ddigits;
961 break;
962 }
963
964 /* Check for a minus. */
965 neg = 0;
966 if ( *s == '-' )
967 {
968 s++;
969 neg = 1;
970 }
971
972 /* Check for the special hex prefix. */
973 if ( *s == '0' &&
974 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
975 {
976 base = 16;
977 dmap = hdigits;
978 s += 2;
979 }
980
981 for ( v = 0; isdigok( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +0000982 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000983
984 if ( end != 0 )
985 *end = s;
986
Werner Lemberg233302a2002-05-22 05:41:06 +0000987 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000988 }
989
990
991 /* Routine to compare two glyphs by encoding so they can be sorted. */
992 static int
993 by_encoding( const void* a,
994 const void* b )
995 {
996 bdf_glyph_t *c1, *c2;
997
998
999 c1 = (bdf_glyph_t *)a;
1000 c2 = (bdf_glyph_t *)b;
1001
1002 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001003 return -1;
David Turner68df4f72005-03-15 18:18:57 +00001004
1005 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001006 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001007
David Turner993a8d02002-05-18 12:03:43 +00001008 return 0;
David Turner993a8d02002-05-18 12:03:43 +00001009 }
1010
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001011
1012 static FT_Error
1013 bdf_create_property( char* name,
1014 int format,
1015 bdf_font_t* font )
1016 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001017 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001018 bdf_property_t* p;
1019 FT_Memory memory = font->memory;
1020 FT_Error error = BDF_Err_Ok;
1021
1022
Werner Lemberg96ddc672011-06-29 09:15:54 +02001023 /* First check whether the property has */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001024 /* already been added or not. If it has, then */
1025 /* simply ignore it. */
1026 if ( hash_lookup( name, &(font->proptbl) ) )
1027 goto Exit;
1028
David Turner68df4f72005-03-15 18:18:57 +00001029 if ( FT_RENEW_ARRAY( font->user_props,
1030 font->nuser_props,
1031 font->nuser_props + 1 ) )
1032 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001033
1034 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +00001035 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001036
suzuki toshiya704f4d72009-09-13 00:50:14 +09001037 n = ft_strlen( name ) + 1;
1038 if ( n > FT_ULONG_MAX )
1039 return BDF_Err_Invalid_Argument;
David Turner68df4f72005-03-15 18:18:57 +00001040
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001041 if ( FT_NEW_ARRAY( p->name, n ) )
1042 goto Exit;
1043
1044 FT_MEM_COPY( (char *)p->name, name, n );
1045
1046 p->format = format;
1047 p->builtin = 0;
1048
1049 n = _num_bdf_properties + font->nuser_props;
1050
suzuki toshiya704f4d72009-09-13 00:50:14 +09001051 error = hash_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001052 if ( error )
1053 goto Exit;
1054
1055 font->nuser_props++;
1056
1057 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001058 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001059 }
David Turner993a8d02002-05-18 12:03:43 +00001060
1061
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001062 FT_LOCAL_DEF( bdf_property_t * )
1063 bdf_get_property( char* name,
1064 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001065 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001066 hashnode hn;
1067 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001068
1069
1070 if ( name == 0 || *name == 0 )
1071 return 0;
1072
1073 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1074 return 0;
1075
suzuki toshiya704f4d72009-09-13 00:50:14 +09001076 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001077 if ( propid >= _num_bdf_properties )
1078 return font->user_props + ( propid - _num_bdf_properties );
1079
Werner Lemberg233302a2002-05-22 05:41:06 +00001080 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001081 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001082
1083
1084 /*************************************************************************/
1085 /* */
1086 /* BDF font file parsing flags and functions. */
1087 /* */
1088 /*************************************************************************/
1089
1090
1091 /* Parse flags. */
1092
1093#define _BDF_START 0x0001
1094#define _BDF_FONT_NAME 0x0002
1095#define _BDF_SIZE 0x0004
1096#define _BDF_FONT_BBX 0x0008
1097#define _BDF_PROPS 0x0010
1098#define _BDF_GLYPHS 0x0020
1099#define _BDF_GLYPH 0x0040
1100#define _BDF_ENCODING 0x0080
1101#define _BDF_SWIDTH 0x0100
1102#define _BDF_DWIDTH 0x0200
1103#define _BDF_BBX 0x0400
1104#define _BDF_BITMAP 0x0800
1105
1106#define _BDF_SWIDTH_ADJ 0x1000
1107
1108#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1109 _BDF_ENCODING | \
1110 _BDF_SWIDTH | \
1111 _BDF_DWIDTH | \
1112 _BDF_BBX | \
1113 _BDF_BITMAP )
1114
Werner Lembergf1c2b912006-01-13 14:53:28 +00001115#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1116#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001117
1118
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001119 static FT_Error
1120 _bdf_add_comment( bdf_font_t* font,
1121 char* comment,
1122 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001123 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001124 char* cp;
1125 FT_Memory memory = font->memory;
1126 FT_Error error = BDF_Err_Ok;
1127
1128
David Turner68df4f72005-03-15 18:18:57 +00001129 if ( FT_RENEW_ARRAY( font->comments,
1130 font->comments_len,
1131 font->comments_len + len + 1 ) )
1132 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001133
1134 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001135
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001136 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001137 cp[len] = '\n';
1138
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001139 font->comments_len += len + 1;
1140
1141 Exit:
1142 return error;
David Turner993a8d02002-05-18 12:03:43 +00001143 }
1144
David Turner993a8d02002-05-18 12:03:43 +00001145
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001146 /* Set the spacing from the font name if it exists, or set it to the */
1147 /* default specified in the options. */
1148 static FT_Error
1149 _bdf_set_default_spacing( bdf_font_t* font,
Werner Lemberge01406b2011-11-25 09:44:28 +01001150 bdf_options_t* opts,
1151 unsigned long lineno )
David Turner993a8d02002-05-18 12:03:43 +00001152 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001153 size_t len;
1154 char name[256];
1155 _bdf_list_t list;
1156 FT_Memory memory;
1157 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001158
David Turner993a8d02002-05-18 12:03:43 +00001159
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001160 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1161 {
1162 error = BDF_Err_Invalid_Argument;
1163 goto Exit;
1164 }
David Turner993a8d02002-05-18 12:03:43 +00001165
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001166 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001167
David Turner68df4f72005-03-15 18:18:57 +00001168 _bdf_list_init( &list, memory );
1169
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001170 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001171
suzuki toshiya704f4d72009-09-13 00:50:14 +09001172 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +00001173 /* Limit ourselves to 256 characters in the font name. */
1174 if ( len >= 256 )
1175 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001176 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
Werner Lemberga08b2172007-03-28 07:17:17 +00001177 error = BDF_Err_Invalid_Argument;
1178 goto Exit;
1179 }
1180
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001181 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001182
David Turner68df4f72005-03-15 18:18:57 +00001183 error = _bdf_list_split( &list, (char *)"-", name, len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001184 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001185 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001186
1187 if ( list.used == 15 )
1188 {
1189 switch ( list.field[11][0] )
1190 {
1191 case 'C':
1192 case 'c':
1193 font->spacing = BDF_CHARCELL;
1194 break;
1195 case 'M':
1196 case 'm':
1197 font->spacing = BDF_MONOWIDTH;
1198 break;
1199 case 'P':
1200 case 'p':
1201 font->spacing = BDF_PROPORTIONAL;
1202 break;
David Turner993a8d02002-05-18 12:03:43 +00001203 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001204 }
1205
David Turner68df4f72005-03-15 18:18:57 +00001206 Fail:
1207 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001208
1209 Exit:
1210 return error;
David Turner993a8d02002-05-18 12:03:43 +00001211 }
David Turner993a8d02002-05-18 12:03:43 +00001212
1213
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001214 /* Determine whether the property is an atom or not. If it is, then */
1215 /* clean it up so the double quotes are removed if they exist. */
1216 static int
1217 _bdf_is_atom( char* line,
1218 unsigned long linelen,
1219 char** name,
1220 char** value,
1221 bdf_font_t* font )
1222 {
1223 int hold;
1224 char *sp, *ep;
1225 bdf_property_t* p;
1226
David Turner993a8d02002-05-18 12:03:43 +00001227
1228 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001229
1230 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001231 ep++;
1232
1233 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001234 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001235 {
1236 hold = *ep;
1237 *ep = 0;
1238 }
1239
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001240 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001241
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001242 /* Restore the character that was saved before any return can happen. */
1243 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001244 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001245
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001246 /* If the property exists and is not an atom, just return here. */
1247 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001248 return 0;
1249
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001250 /* The property is an atom. Trim all leading and trailing whitespace */
1251 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001252 sp = ep;
1253 ep = line + linelen;
1254
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001255 /* Trim the leading whitespace if it exists. */
David Turner993a8d02002-05-18 12:03:43 +00001256 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001257 while ( *sp &&
1258 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001259 sp++;
1260
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001261 /* Trim the leading double quote if it exists. */
1262 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001263 sp++;
1264 *value = sp;
1265
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001266 /* Trim the trailing whitespace if it exists. */
1267 while ( ep > sp &&
1268 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001269 *--ep = 0;
1270
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001271 /* Trim the trailing double quote if it exists. */
1272 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001273 *--ep = 0;
1274
1275 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001276 }
David Turner993a8d02002-05-18 12:03:43 +00001277
1278
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001279 static FT_Error
Werner Lemberge01406b2011-11-25 09:44:28 +01001280 _bdf_add_property( bdf_font_t* font,
1281 char* name,
1282 char* value,
1283 unsigned long lineno )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001284 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001285 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001286 hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001287 bdf_property_t *prop, *fp;
1288 FT_Memory memory = font->memory;
1289 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001290
David Turner993a8d02002-05-18 12:03:43 +00001291
Werner Lemberg96ddc672011-06-29 09:15:54 +02001292 /* First, check whether the property already exists in the font. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001293 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001294 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001295 /* The property already exists in the font, so simply replace */
1296 /* the value of the property with the current value. */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001297 fp = font->props + hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001298
David Turnerb1b47622002-05-21 21:17:43 +00001299 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001300 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001301 case BDF_ATOM:
1302 /* Delete the current atom if it exists. */
1303 FT_FREE( fp->value.atom );
1304
David Turnerc0f9c4a2007-02-12 14:55:03 +00001305 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001306 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001307 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001308 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001309 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001310 break;
1311
1312 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001313 fp->value.l = _bdf_atol( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001314 break;
1315
1316 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001317 fp->value.ul = _bdf_atoul( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001318 break;
David Turnerd490e372002-05-28 23:40:37 +00001319
David Turnerb1b47622002-05-21 21:17:43 +00001320 default:
1321 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001322 }
David Turnerd490e372002-05-28 23:40:37 +00001323
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001324 goto Exit;
1325 }
1326
1327 /* See whether this property type exists yet or not. */
1328 /* If not, create it. */
1329 hn = hash_lookup( name, &(font->proptbl) );
1330 if ( hn == 0 )
1331 {
1332 error = bdf_create_property( name, BDF_ATOM, font );
1333 if ( error )
1334 goto Exit;
1335 hn = hash_lookup( name, &(font->proptbl) );
1336 }
1337
1338 /* Allocate another property if this is overflow. */
1339 if ( font->props_used == font->props_size )
1340 {
1341 if ( font->props_size == 0 )
1342 {
1343 if ( FT_NEW_ARRAY( font->props, 1 ) )
1344 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001345 }
1346 else
1347 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001348 if ( FT_RENEW_ARRAY( font->props,
1349 font->props_size,
1350 font->props_size + 1 ) )
1351 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001352 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001353
David Turner993a8d02002-05-18 12:03:43 +00001354 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001355 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001356 font->props_size++;
1357 }
1358
suzuki toshiya704f4d72009-09-13 00:50:14 +09001359 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001360 if ( propid >= _num_bdf_properties )
1361 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001362 else
David Turnerb1b47622002-05-21 21:17:43 +00001363 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001364
1365 fp = font->props + font->props_used;
1366
1367 fp->name = prop->name;
1368 fp->format = prop->format;
1369 fp->builtin = prop->builtin;
1370
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001371 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001372 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001373 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001374 fp->value.atom = 0;
1375 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001376 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001377 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001378 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001379 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001380 break;
David Turner993a8d02002-05-18 12:03:43 +00001381
1382 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001383 fp->value.l = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001384 break;
1385
1386 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001387 fp->value.ul = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001388 break;
David Turner993a8d02002-05-18 12:03:43 +00001389 }
1390
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001391 /* If the property happens to be a comment, then it doesn't need */
1392 /* to be added to the internal hash table. */
Werner Lemberg370aea82010-06-08 08:37:11 +02001393 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 )
1394 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001395 /* Add the property to the font property table. */
1396 error = hash_insert( fp->name,
suzuki toshiya704f4d72009-09-13 00:50:14 +09001397 font->props_used,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001398 (hashtable *)font->internal,
1399 memory );
1400 if ( error )
1401 goto Exit;
1402 }
David Turner993a8d02002-05-18 12:03:43 +00001403
1404 font->props_used++;
1405
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001406 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1407 /* property needs to be located if it exists in the property list, the */
1408 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1409 /* present, and the SPACING property should override the default */
1410 /* spacing. */
1411 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001412 font->default_char = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001413 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001414 font->font_ascent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001415 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001416 font->font_descent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001417 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001418 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001419 if ( !fp->value.atom )
1420 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001421 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lembergb66efef2009-03-12 08:07:49 +00001422 error = BDF_Err_Invalid_File_Format;
1423 goto Exit;
1424 }
1425
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001426 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001427 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001428 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001429 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001430 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001431 font->spacing = BDF_CHARCELL;
1432 }
1433
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001434 Exit:
1435 return error;
David Turner993a8d02002-05-18 12:03:43 +00001436 }
1437
David Turner993a8d02002-05-18 12:03:43 +00001438
David Turnerb1b47622002-05-21 21:17:43 +00001439 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001440 {
1441 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1442 };
1443
1444
1445 /* Actually parse the glyph info and bitmaps. */
1446 static FT_Error
1447 _bdf_parse_glyphs( char* line,
1448 unsigned long linelen,
1449 unsigned long lineno,
1450 void* call_data,
1451 void* client_data )
1452 {
1453 int c, mask_index;
1454 char* s;
1455 unsigned char* bp;
1456 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001457
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001458 _bdf_parse_t* p;
1459 bdf_glyph_t* glyph;
1460 bdf_font_t* font;
1461
1462 FT_Memory memory;
1463 FT_Error error = BDF_Err_Ok;
1464
Werner Lemberg319c00d2003-04-23 19:48:24 +00001465 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001466 FT_UNUSED( lineno ); /* only used in debug mode */
1467
1468
Werner Lemberg319c00d2003-04-23 19:48:24 +00001469 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001470
1471 font = p->font;
1472 memory = font->memory;
1473
1474 /* Check for a comment. */
1475 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1476 {
1477 linelen -= 7;
1478
1479 s = line + 7;
1480 if ( *s != 0 )
1481 {
1482 s++;
1483 linelen--;
1484 }
1485 error = _bdf_add_comment( p->font, s, linelen );
1486 goto Exit;
1487 }
1488
1489 /* The very first thing expected is the number of glyphs. */
1490 if ( !( p->flags & _BDF_GLYPHS ) )
1491 {
1492 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1493 {
1494 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1495 error = BDF_Err_Missing_Chars_Field;
1496 goto Exit;
1497 }
1498
David Turner68df4f72005-03-15 18:18:57 +00001499 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001500 if ( error )
1501 goto Exit;
1502 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1503
1504 /* Make sure the number of glyphs is non-zero. */
1505 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001506 font->glyphs_size = 64;
1507
Werner Lemberga08b2172007-03-28 07:17:17 +00001508 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1509 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001510 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001511 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001512 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberga08b2172007-03-28 07:17:17 +00001513 error = BDF_Err_Invalid_Argument;
1514 goto Exit;
1515 }
1516
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001517 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1518 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001519
David Turner993a8d02002-05-18 12:03:43 +00001520 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001521
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001522 goto Exit;
1523 }
1524
1525 /* Check for the ENDFONT field. */
1526 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1527 {
1528 /* Sort the glyphs by encoding. */
1529 ft_qsort( (char *)font->glyphs,
1530 font->glyphs_used,
1531 sizeof ( bdf_glyph_t ),
1532 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001533
1534 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001535
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001536 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001537 }
1538
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001539 /* Check for the ENDCHAR field. */
1540 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1541 {
1542 p->glyph_enc = 0;
1543 p->flags &= ~_BDF_GLYPH_BITS;
1544
1545 goto Exit;
1546 }
1547
Werner Lemberg96ddc672011-06-29 09:15:54 +02001548 /* Check whether a glyph is being scanned but should be */
1549 /* ignored because it is an unencoded glyph. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001550 if ( ( p->flags & _BDF_GLYPH ) &&
1551 p->glyph_enc == -1 &&
1552 p->opts->keep_unencoded == 0 )
1553 goto Exit;
1554
1555 /* Check for the STARTCHAR field. */
1556 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1557 {
1558 /* Set the character name in the parse info first until the */
1559 /* encoding can be checked for an unencoded character. */
1560 FT_FREE( p->glyph_name );
1561
David Turner68df4f72005-03-15 18:18:57 +00001562 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001563 if ( error )
1564 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001565
David Turner68df4f72005-03-15 18:18:57 +00001566 _bdf_list_shift( &p->list, 1 );
1567
1568 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001569
Werner Lembergba03af62007-05-30 13:57:02 +00001570 if ( !s )
1571 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001572 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lembergba03af62007-05-30 13:57:02 +00001573 error = BDF_Err_Invalid_File_Format;
1574 goto Exit;
1575 }
1576
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001577 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1578 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001579
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001580 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1581
1582 p->flags |= _BDF_GLYPH;
1583
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001584 FT_TRACE4(( DBGMSG1, lineno, s ));
1585
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001586 goto Exit;
1587 }
1588
1589 /* Check for the ENCODING field. */
1590 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1591 {
1592 if ( !( p->flags & _BDF_GLYPH ) )
1593 {
1594 /* Missing STARTCHAR field. */
1595 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1596 error = BDF_Err_Missing_Startchar_Field;
1597 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001598 }
1599
David Turner68df4f72005-03-15 18:18:57 +00001600 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001601 if ( error )
1602 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001603
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001604 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001605
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001606 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1607
Werner Lemberg96ddc672011-06-29 09:15:54 +02001608 /* Check that the encoding is in the range [0,65536] because */
1609 /* otherwise p->have (a bitmap with static size) overflows. */
1610 if ( p->glyph_enc > 0 &&
1611 (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
David Turner481838e2006-02-23 12:40:14 +00001612 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001613 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
David Turner481838e2006-02-23 12:40:14 +00001614 error = BDF_Err_Invalid_File_Format;
1615 goto Exit;
1616 }
1617
Werner Lemberg96ddc672011-06-29 09:15:54 +02001618 /* Check whether this encoding has already been encountered. */
1619 /* If it has then change it to unencoded so it gets added if */
1620 /* indicated. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001621 if ( p->glyph_enc >= 0 )
1622 {
1623 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1624 {
1625 /* Emit a message saying a glyph has been moved to the */
1626 /* unencoded area. */
1627 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1628 p->glyph_enc, p->glyph_name ));
1629 p->glyph_enc = -1;
1630 font->modified = 1;
1631 }
1632 else
1633 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1634 }
1635
1636 if ( p->glyph_enc >= 0 )
1637 {
1638 /* Make sure there are enough glyphs allocated in case the */
1639 /* number of characters happen to be wrong. */
1640 if ( font->glyphs_used == font->glyphs_size )
1641 {
1642 if ( FT_RENEW_ARRAY( font->glyphs,
1643 font->glyphs_size,
1644 font->glyphs_size + 64 ) )
1645 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001646
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001647 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001648 }
1649
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001650 glyph = font->glyphs + font->glyphs_used++;
1651 glyph->name = p->glyph_name;
1652 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001653
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001654 /* Reset the initial glyph info. */
1655 p->glyph_name = 0;
1656 }
1657 else
1658 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001659 /* Unencoded glyph. Check whether it should */
1660 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001661 if ( p->opts->keep_unencoded != 0 )
1662 {
1663 /* Allocate the next unencoded glyph. */
1664 if ( font->unencoded_used == font->unencoded_size )
1665 {
David Turner68df4f72005-03-15 18:18:57 +00001666 if ( FT_RENEW_ARRAY( font->unencoded ,
1667 font->unencoded_size,
1668 font->unencoded_size + 4 ) )
1669 goto Exit;
1670
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001671 font->unencoded_size += 4;
1672 }
1673
1674 glyph = font->unencoded + font->unencoded_used;
1675 glyph->name = p->glyph_name;
1676 glyph->encoding = font->unencoded_used++;
1677 }
1678 else
1679 /* Free up the glyph name if the unencoded shouldn't be */
1680 /* kept. */
1681 FT_FREE( p->glyph_name );
1682
1683 p->glyph_name = 0;
1684 }
1685
1686 /* Clear the flags that might be added when width and height are */
1687 /* checked for consistency. */
1688 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1689
1690 p->flags |= _BDF_ENCODING;
1691
1692 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001693 }
1694
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001695 /* Point at the glyph being constructed. */
1696 if ( p->glyph_enc == -1 )
1697 glyph = font->unencoded + ( font->unencoded_used - 1 );
1698 else
1699 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001700
Werner Lemberg96ddc672011-06-29 09:15:54 +02001701 /* Check whether a bitmap is being constructed. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001702 if ( p->flags & _BDF_BITMAP )
1703 {
1704 /* If there are more rows than are specified in the glyph metrics, */
1705 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001706 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001707 {
1708 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1709 {
1710 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1711 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001712 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001713 }
1714
1715 goto Exit;
1716 }
1717
1718 /* Only collect the number of nibbles indicated by the glyph */
1719 /* metrics. If there are more columns, they are simply ignored. */
1720 nibbles = glyph->bpr << 1;
1721 bp = glyph->bitmap + p->row * glyph->bpr;
1722
David Turnerb698eed2006-02-23 14:50:13 +00001723 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001724 {
1725 c = line[i];
Werner Lemberg233302a2002-05-22 05:41:06 +00001726 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001727 if ( i + 1 < nibbles && ( i & 1 ) )
1728 *++bp = 0;
1729 }
1730
1731 /* Remove possible garbage at the right. */
1732 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001733 if ( glyph->bbx.width )
1734 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001735
1736 /* If any line has extra columns, indicate they have been removed. */
1737 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1738 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1739 {
1740 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1741 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1742 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001743 }
1744
1745 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001746 goto Exit;
1747 }
David Turner993a8d02002-05-18 12:03:43 +00001748
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001749 /* Expect the SWIDTH (scalable width) field next. */
1750 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1751 {
1752 if ( !( p->flags & _BDF_ENCODING ) )
1753 {
1754 /* Missing ENCODING field. */
1755 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1756 error = BDF_Err_Missing_Encoding_Field;
1757 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001758 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001759
David Turner68df4f72005-03-15 18:18:57 +00001760 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001761 if ( error )
1762 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001763
David Turnerb1b47622002-05-21 21:17:43 +00001764 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001765 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001766
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001767 goto Exit;
1768 }
David Turner993a8d02002-05-18 12:03:43 +00001769
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001770 /* Expect the DWIDTH (scalable width) field next. */
1771 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1772 {
David Turner68df4f72005-03-15 18:18:57 +00001773 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001774 if ( error )
1775 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001776
David Turnerb1b47622002-05-21 21:17:43 +00001777 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001778
1779 if ( !( p->flags & _BDF_SWIDTH ) )
1780 {
1781 /* Missing SWIDTH field. Emit an auto correction message and set */
1782 /* the scalable width from the device width. */
1783 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1784
Werner Lemberg02d4d592002-05-28 22:38:05 +00001785 glyph->swidth = (unsigned short)FT_MulDiv(
1786 glyph->dwidth, 72000L,
1787 (FT_Long)( font->point_size *
1788 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001789 }
1790
1791 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001792 goto Exit;
1793 }
David Turner993a8d02002-05-18 12:03:43 +00001794
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001795 /* Expect the BBX field next. */
1796 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1797 {
David Turner68df4f72005-03-15 18:18:57 +00001798 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001799 if ( error )
1800 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001801
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001802 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1803 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1804 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1805 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1806
1807 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001808 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1809 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001810
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001811 /* Determine the overall font bounding box as the characters are */
1812 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001813 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1814 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001815
David Turnerb1b47622002-05-21 21:17:43 +00001816 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001817
Werner Lembergdfa46192004-03-05 09:26:24 +00001818 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1819 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1820 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001821
1822 if ( !( p->flags & _BDF_DWIDTH ) )
1823 {
1824 /* Missing DWIDTH field. Emit an auto correction message and set */
1825 /* the device width to the glyph width. */
1826 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1827 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001828 }
1829
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001830 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1831 /* value if necessary. */
1832 if ( p->opts->correct_metrics != 0 )
1833 {
1834 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001835 unsigned short sw = (unsigned short)FT_MulDiv(
1836 glyph->dwidth, 72000L,
1837 (FT_Long)( font->point_size *
1838 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001839
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001840
1841 if ( sw != glyph->swidth )
1842 {
1843 glyph->swidth = sw;
1844
1845 if ( p->glyph_enc == -1 )
1846 _bdf_set_glyph_modified( font->umod,
1847 font->unencoded_used - 1 );
1848 else
1849 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1850
1851 p->flags |= _BDF_SWIDTH_ADJ;
1852 font->modified = 1;
1853 }
David Turner993a8d02002-05-18 12:03:43 +00001854 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001855
David Turner993a8d02002-05-18 12:03:43 +00001856 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001857 goto Exit;
1858 }
David Turner993a8d02002-05-18 12:03:43 +00001859
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001860 /* And finally, gather up the bitmap. */
1861 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1862 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001863 unsigned long bitmap_size;
1864
1865
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001866 if ( !( p->flags & _BDF_BBX ) )
1867 {
1868 /* Missing BBX field. */
1869 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1870 error = BDF_Err_Missing_Bbx_Field;
1871 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001872 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001873
1874 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001875 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001876
1877 bitmap_size = glyph->bpr * glyph->bbx.height;
1878 if ( bitmap_size > 0xFFFFU )
1879 {
1880 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1881 error = BDF_Err_Bbx_Too_Big;
1882 goto Exit;
1883 }
1884 else
1885 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001886
1887 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1888 goto Exit;
1889
1890 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001891 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001892
1893 goto Exit;
1894 }
1895
Werner Lemberge01406b2011-11-25 09:44:28 +01001896 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001897 error = BDF_Err_Invalid_File_Format;
1898
1899 Exit:
Werner Lembergf4c94d42010-06-19 16:08:31 +02001900 if ( error && ( p->flags & _BDF_GLYPH ) )
1901 FT_FREE( p->glyph_name );
1902
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001903 return error;
David Turner993a8d02002-05-18 12:03:43 +00001904 }
1905
David Turner993a8d02002-05-18 12:03:43 +00001906
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001907 /* Load the font properties. */
1908 static FT_Error
1909 _bdf_parse_properties( char* line,
1910 unsigned long linelen,
1911 unsigned long lineno,
1912 void* call_data,
1913 void* client_data )
1914 {
1915 unsigned long vlen;
1916 _bdf_line_func_t* next;
1917 _bdf_parse_t* p;
1918 char* name;
1919 char* value;
1920 char nbuf[128];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001921 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001922
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001923 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001924
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001925
1926 next = (_bdf_line_func_t *)call_data;
1927 p = (_bdf_parse_t *) client_data;
1928
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001929 /* Check for the end of the properties. */
1930 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1931 {
1932 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1933 /* encountered yet, then make sure they are added as properties and */
1934 /* make sure they are set from the font bounding box info. */
1935 /* */
1936 /* This is *always* done regardless of the options, because X11 */
1937 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001938 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001939 {
1940 p->font->font_ascent = p->font->bbx.ascent;
1941 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001942 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
1943 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001944 if ( error )
1945 goto Exit;
1946
1947 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1948 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001949 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001950
Werner Lemberg428c2e42003-04-25 05:35:04 +00001951 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001952 {
1953 p->font->font_descent = p->font->bbx.descent;
1954 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001955 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
1956 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001957 if ( error )
1958 goto Exit;
1959
1960 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1961 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001962 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001963
David Turner993a8d02002-05-18 12:03:43 +00001964 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001965 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001966
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001967 goto Exit;
1968 }
David Turner993a8d02002-05-18 12:03:43 +00001969
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001970 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1971 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1972 goto Exit;
1973
1974 /* Handle COMMENT fields and properties in a special way to preserve */
1975 /* the spacing. */
1976 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1977 {
David Turner993a8d02002-05-18 12:03:43 +00001978 name = value = line;
1979 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001980 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001981 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01001982 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001983 if ( error )
1984 goto Exit;
1985 }
1986 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1987 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001988 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001989 if ( error )
1990 goto Exit;
1991 }
1992 else
1993 {
David Turner68df4f72005-03-15 18:18:57 +00001994 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001995 if ( error )
1996 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001997 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001998
David Turner68df4f72005-03-15 18:18:57 +00001999 _bdf_list_shift( &p->list, 1 );
2000 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002001
Werner Lemberge01406b2011-11-25 09:44:28 +01002002 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002003 if ( error )
2004 goto Exit;
2005 }
2006
2007 Exit:
2008 return error;
David Turner993a8d02002-05-18 12:03:43 +00002009 }
2010
David Turner993a8d02002-05-18 12:03:43 +00002011
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002012 /* Load the font header. */
2013 static FT_Error
2014 _bdf_parse_start( char* line,
2015 unsigned long linelen,
2016 unsigned long lineno,
2017 void* call_data,
2018 void* client_data )
2019 {
2020 unsigned long slen;
2021 _bdf_line_func_t* next;
2022 _bdf_parse_t* p;
2023 bdf_font_t* font;
2024 char *s;
David Turner993a8d02002-05-18 12:03:43 +00002025
David Turnerd490e372002-05-28 23:40:37 +00002026 FT_Memory memory = NULL;
2027 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002028
2029 FT_UNUSED( lineno ); /* only used in debug mode */
2030
2031
2032 next = (_bdf_line_func_t *)call_data;
2033 p = (_bdf_parse_t *) client_data;
2034
2035 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00002036 memory = p->font->memory;
2037
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002038 /* Check for a comment. This is done to handle those fonts that have */
2039 /* comments before the STARTFONT line for some reason. */
2040 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2041 {
2042 if ( p->opts->keep_comments != 0 && p->font != 0 )
2043 {
2044 linelen -= 7;
2045
2046 s = line + 7;
2047 if ( *s != 0 )
2048 {
2049 s++;
2050 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002051 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002052
2053 error = _bdf_add_comment( p->font, s, linelen );
2054 if ( error )
2055 goto Exit;
2056 /* here font is not defined! */
2057 }
2058
2059 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002060 }
2061
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002062 if ( !( p->flags & _BDF_START ) )
2063 {
2064 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002065
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002066 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2067 {
2068 /* No STARTFONT field is a good indication of a problem. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002069 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "STARTFONT" ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002070 error = BDF_Err_Missing_Startfont_Field;
2071 goto Exit;
2072 }
David Turner993a8d02002-05-18 12:03:43 +00002073
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002074 p->flags = _BDF_START;
2075 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002076
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002077 if ( FT_NEW( font ) )
2078 goto Exit;
2079 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002080
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002081 font->memory = p->memory;
2082 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002083
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002084 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09002085 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002086 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002087
David Turner993a8d02002-05-18 12:03:43 +00002088
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002089 error = hash_init( &(font->proptbl), memory );
2090 if ( error )
2091 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002092 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002093 i < _num_bdf_properties; i++, prop++ )
2094 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09002095 error = hash_insert( prop->name, i,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002096 &(font->proptbl), memory );
2097 if ( error )
2098 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002099 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002100 }
2101
2102 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2103 goto Exit;
2104 error = hash_init( (hashtable *)p->font->internal,memory );
2105 if ( error )
2106 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002107 p->font->spacing = p->opts->font_spacing;
2108 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002109
2110 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002111 }
2112
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002113 /* Check for the start of the properties. */
2114 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2115 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002116 if ( !( p->flags & _BDF_FONT_BBX ) )
Werner Lembergfb690292010-06-23 10:00:52 +02002117 {
2118 /* Missing the FONTBOUNDINGBOX field. */
2119 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2120 error = BDF_Err_Missing_Fontboundingbox_Field;
2121 goto Exit;
2122 }
2123
David Turner68df4f72005-03-15 18:18:57 +00002124 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002125 if ( error )
2126 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00002127 /* at this point, `p->font' can't be NULL */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002128 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2129
2130 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2131 goto Exit;
2132
2133 p->flags |= _BDF_PROPS;
2134 *next = _bdf_parse_properties;
2135
2136 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002137 }
2138
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002139 /* Check for the FONTBOUNDINGBOX field. */
2140 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2141 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002142 if ( !( p->flags & _BDF_SIZE ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002143 {
2144 /* Missing the SIZE field. */
2145 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2146 error = BDF_Err_Missing_Size_Field;
2147 goto Exit;
2148 }
2149
David Turner68df4f72005-03-15 18:18:57 +00002150 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002151 if ( error )
2152 goto Exit;
2153
2154 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2155 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2156
2157 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2158 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2159
David Turnerd490e372002-05-28 23:40:37 +00002160 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002161 p->font->bbx.y_offset );
2162
2163 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002164
2165 p->flags |= _BDF_FONT_BBX;
2166
2167 goto Exit;
2168 }
2169
2170 /* The next thing to check for is the FONT field. */
2171 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2172 {
David Turner68df4f72005-03-15 18:18:57 +00002173 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002174 if ( error )
2175 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002176 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002177
David Turner68df4f72005-03-15 18:18:57 +00002178 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002179
2180 if ( !s )
2181 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002182 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg5b591e42007-06-01 22:16:43 +00002183 error = BDF_Err_Invalid_File_Format;
2184 goto Exit;
2185 }
2186
Werner Lembergfb690292010-06-23 10:00:52 +02002187 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2188 FT_FREE( p->font->name );
2189
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002190 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2191 goto Exit;
2192 FT_MEM_COPY( p->font->name, s, slen + 1 );
2193
2194 /* If the font name is an XLFD name, set the spacing to the one in */
2195 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002196 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002197 if ( error )
2198 goto Exit;
2199
2200 p->flags |= _BDF_FONT_NAME;
2201
2202 goto Exit;
2203 }
2204
2205 /* Check for the SIZE field. */
2206 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2207 {
2208 if ( !( p->flags & _BDF_FONT_NAME ) )
2209 {
2210 /* Missing the FONT field. */
2211 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2212 error = BDF_Err_Missing_Font_Field;
2213 goto Exit;
2214 }
2215
David Turner68df4f72005-03-15 18:18:57 +00002216 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002217 if ( error )
2218 goto Exit;
2219
2220 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2221 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2222 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2223
2224 /* Check for the bits per pixel field. */
2225 if ( p->list.used == 5 )
2226 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002227 unsigned short bitcount, i, shift;
2228
2229
2230 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2231
2232 /* Only values 1, 2, 4, 8 are allowed. */
2233 shift = p->font->bpp;
2234 bitcount = 0;
2235 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002236 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002237 if ( shift & 1 )
2238 bitcount = i;
2239 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002240 }
David Turner993a8d02002-05-18 12:03:43 +00002241
Werner Lembergbd8e3242002-06-12 08:43:58 +00002242 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002243
2244 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002245 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002246 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002247 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002248 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002249 }
2250 }
2251 else
2252 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002253
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002254 p->flags |= _BDF_SIZE;
2255
2256 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002257 }
2258
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002259 /* Check for the CHARS field -- font properties are optional */
2260 if ( ft_memcmp( line, "CHARS", 5 ) == 0 )
2261 {
2262 char nbuf[128];
2263
2264
2265 if ( !( p->flags & _BDF_FONT_BBX ) )
2266 {
2267 /* Missing the FONTBOUNDINGBOX field. */
2268 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2269 error = BDF_Err_Missing_Fontboundingbox_Field;
2270 goto Exit;
2271 }
2272
2273 /* Add the two standard X11 properties which are required */
2274 /* for compiling fonts. */
2275 p->font->font_ascent = p->font->bbx.ascent;
2276 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002277 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2278 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002279 if ( error )
2280 goto Exit;
2281 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2282
2283 p->font->font_descent = p->font->bbx.descent;
2284 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002285 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2286 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002287 if ( error )
2288 goto Exit;
2289 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2290
2291 p->font->modified = 1;
2292
2293 *next = _bdf_parse_glyphs;
2294
2295 /* A special return value. */
2296 error = -1;
2297 goto Exit;
2298 }
2299
Werner Lemberge01406b2011-11-25 09:44:28 +01002300 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002301 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002302
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002303 Exit:
2304 return error;
2305 }
David Turner993a8d02002-05-18 12:03:43 +00002306
2307
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002308 /*************************************************************************/
2309 /* */
2310 /* API. */
2311 /* */
2312 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002313
David Turner993a8d02002-05-18 12:03:43 +00002314
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002315 FT_LOCAL_DEF( FT_Error )
2316 bdf_load_font( FT_Stream stream,
2317 FT_Memory extmemory,
2318 bdf_options_t* opts,
2319 bdf_font_t* *font )
2320 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002321 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002322 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002323
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002324 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002325 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002326
2327
David Turner68df4f72005-03-15 18:18:57 +00002328 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002329 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002330
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002331 memory = NULL;
2332 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2333 p->minlb = 32767;
2334 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002335
David Turner68df4f72005-03-15 18:18:57 +00002336 _bdf_list_init( &p->list, extmemory );
2337
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002338 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002339 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002340 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002341 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002342
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002343 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002344 {
2345 /* If the font is not proportional, set the font's monowidth */
2346 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002347 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002348
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002349 if ( p->font->spacing != BDF_PROPORTIONAL )
2350 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002351
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002352 /* If the number of glyphs loaded is not that of the original count, */
2353 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002354 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002355 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002356 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2357 p->font->glyphs_used + p->font->unencoded_used ));
2358 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002359 }
2360
2361 /* Once the font has been loaded, adjust the overall font metrics if */
2362 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002363 if ( p->opts->correct_metrics != 0 &&
2364 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002365 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002366 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002367 {
2368 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002369 p->font->bbx.width, p->maxrb - p->minlb ));
2370 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2371 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002372 }
2373
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002374 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002375 {
2376 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002377 p->font->bbx.x_offset, p->minlb ));
2378 p->font->bbx.x_offset = p->minlb;
2379 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002380 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002381
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002382 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002383 {
2384 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002385 p->font->bbx.ascent, p->maxas ));
2386 p->font->bbx.ascent = p->maxas;
2387 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002388 }
2389
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002390 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002391 {
2392 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002393 p->font->bbx.descent, p->maxds ));
2394 p->font->bbx.descent = p->maxds;
2395 p->font->bbx.y_offset = (short)( -p->maxds );
2396 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002397 }
2398
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002399 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002400 {
2401 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002402 p->font->bbx.height, p->maxas + p->maxds ));
2403 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002404 }
2405
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002406 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002407 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2408 }
David Turner993a8d02002-05-18 12:03:43 +00002409 }
2410
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002411 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002412 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002413 /* The ENDFONT field was never reached or did not exist. */
2414 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002415 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002416 /* Error happened while parsing header. */
2417 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2418 error = BDF_Err_Corrupted_Font_Header;
2419 goto Exit;
2420 }
2421 else
2422 {
2423 /* Error happened when parsing glyphs. */
2424 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2425 error = BDF_Err_Corrupted_Font_Glyphs;
2426 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002427 }
David Turner993a8d02002-05-18 12:03:43 +00002428 }
2429
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002430 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002431 {
2432 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002433 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002434
Werner Lemberg370aea82010-06-08 08:37:11 +02002435 if ( p->font->comments_len > 0 )
2436 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002437 if ( FT_RENEW_ARRAY( p->font->comments,
2438 p->font->comments_len,
2439 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002440 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002441
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002442 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002443 }
David Turner993a8d02002-05-18 12:03:43 +00002444 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002445 else if ( error == BDF_Err_Ok )
2446 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002447
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002448 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002449
2450 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002451 if ( p )
2452 {
David Turner68df4f72005-03-15 18:18:57 +00002453 _bdf_list_done( &p->list );
2454
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002455 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002456
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002457 FT_FREE( p );
2458 }
2459
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002460 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002461
2462 Fail:
2463 bdf_free_font( p->font );
2464
2465 memory = extmemory;
2466
2467 FT_FREE( p->font );
2468
2469 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002470 }
David Turner993a8d02002-05-18 12:03:43 +00002471
2472
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002473 FT_LOCAL_DEF( void )
2474 bdf_free_font( bdf_font_t* font )
2475 {
2476 bdf_property_t* prop;
2477 unsigned long i;
2478 bdf_glyph_t* glyphs;
2479 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002480
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002481
2482 if ( font == 0 )
2483 return;
David Turner993a8d02002-05-18 12:03:43 +00002484
2485 memory = font->memory;
2486
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002487 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002488
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002489 /* Free up the internal hash table of property names. */
2490 if ( font->internal )
2491 {
2492 hash_free( (hashtable *)font->internal, memory );
2493 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002494 }
2495
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002496 /* Free up the comment info. */
2497 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002498
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002499 /* Free up the properties. */
2500 for ( i = 0; i < font->props_size; i++ )
2501 {
2502 if ( font->props[i].format == BDF_ATOM )
2503 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002504 }
2505
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002506 FT_FREE( font->props );
2507
2508 /* Free up the character info. */
2509 for ( i = 0, glyphs = font->glyphs;
2510 i < font->glyphs_used; i++, glyphs++ )
2511 {
2512 FT_FREE( glyphs->name );
2513 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002514 }
2515
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002516 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2517 i++, glyphs++ )
2518 {
2519 FT_FREE( glyphs->name );
2520 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002521 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002522
2523 FT_FREE( font->glyphs );
2524 FT_FREE( font->unencoded );
2525
2526 /* Free up the overflow storage if it was used. */
2527 for ( i = 0, glyphs = font->overflow.glyphs;
2528 i < font->overflow.glyphs_used; i++, glyphs++ )
2529 {
2530 FT_FREE( glyphs->name );
2531 FT_FREE( glyphs->bitmap );
2532 }
2533
2534 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002535
2536 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002537 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002538
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002539 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002540 for ( prop = font->user_props, i = 0;
2541 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002542 {
2543 FT_FREE( prop->name );
2544 if ( prop->format == BDF_ATOM )
2545 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002546 }
David Turner993a8d02002-05-18 12:03:43 +00002547
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002548 FT_FREE( font->user_props );
2549
2550 /* FREE( font ); */ /* XXX Fixme */
2551 }
David Turner993a8d02002-05-18 12:03:43 +00002552
2553
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002554 FT_LOCAL_DEF( bdf_property_t * )
2555 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002556 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002557 {
2558 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002559
David Turner993a8d02002-05-18 12:03:43 +00002560
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002561 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002562 return 0;
2563
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002564 hn = hash_lookup( name, (hashtable *)font->internal );
2565
suzuki toshiya704f4d72009-09-13 00:50:14 +09002566 return hn ? ( font->props + hn->data ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002567 }
2568
2569
2570/* END */