blob: d1d1704f6a5ea9699d168234881b64614d1bbbff [file] [log] [blame]
David Turner993a8d02002-05-18 12:03:43 +00001/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
Sean McBride7be2a942014-02-08 13:55:38 +01003 * Copyright 2001-2014
Werner Lemberg442bfb82007-02-12 21:44:10 +00004 * Francesco Zappa Nardelli
David Turner993a8d02002-05-18 12:03:43 +00005 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
Werner Lemberg7cf4d372002-05-21 14:13:01 +000025 /*************************************************************************/
26 /* */
27 /* This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 */
28 /* */
29 /* taken from Mark Leisher's xmbdfed package */
30 /* */
31 /*************************************************************************/
32
David Turner993a8d02002-05-18 12:03:43 +000033
34#include <ft2build.h>
35
Werner Lemberg02d4d592002-05-28 22:38:05 +000036#include FT_FREETYPE_H
David Turner993a8d02002-05-18 12:03:43 +000037#include FT_INTERNAL_DEBUG_H
38#include FT_INTERNAL_STREAM_H
39#include FT_INTERNAL_OBJECTS_H
40
41#include "bdf.h"
David Turner993a8d02002-05-18 12:03:43 +000042#include "bdferror.h"
43
David Turner993a8d02002-05-18 12:03:43 +000044
Werner Lemberg7cf4d372002-05-21 14:13:01 +000045 /*************************************************************************/
46 /* */
47 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
48 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
49 /* messages during execution. */
50 /* */
51#undef FT_COMPONENT
52#define FT_COMPONENT trace_bdflib
David Turner993a8d02002-05-18 12:03:43 +000053
David Turner993a8d02002-05-18 12:03:43 +000054
Werner Lemberg7cf4d372002-05-21 14:13:01 +000055 /*************************************************************************/
56 /* */
57 /* Default BDF font options. */
58 /* */
59 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000060
David Turner993a8d02002-05-18 12:03:43 +000061
David Turnerb1b47622002-05-21 21:17:43 +000062 static const bdf_options_t _bdf_opts =
Werner Lemberg7cf4d372002-05-21 14:13:01 +000063 {
David Turner993a8d02002-05-18 12:03:43 +000064 1, /* Correct metrics. */
65 1, /* Preserve unencoded glyphs. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000066 0, /* Preserve comments. */
67 BDF_PROPORTIONAL /* Default spacing. */
68 };
David Turner993a8d02002-05-18 12:03:43 +000069
David Turner993a8d02002-05-18 12:03:43 +000070
Werner Lemberg7cf4d372002-05-21 14:13:01 +000071 /*************************************************************************/
72 /* */
73 /* Builtin BDF font properties. */
74 /* */
75 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000076
Werner Lemberg7cf4d372002-05-21 14:13:01 +000077 /* List of most properties that might appear in a font. Doesn't include */
78 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
David Turner993a8d02002-05-18 12:03:43 +000079
David Turnerb1b47622002-05-21 21:17:43 +000080 static const bdf_property_t _bdf_properties[] =
David Turner993a8d02002-05-18 12:03:43 +000081 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +000082 { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
83 { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
84 { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
85 { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
86 { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
87 { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
88 { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
89 { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
90 { (char *)"COMMENT", BDF_ATOM, 1, { 0 } },
91 { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } },
92 { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
93 { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } },
94 { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
95 { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } },
96 { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } },
97 { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } },
98 { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
99 { (char *)"FONT", BDF_ATOM, 1, { 0 } },
100 { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
101 { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
102 { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
103 { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } },
104 { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } },
105 { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
106 { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } },
107 { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } },
108 { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } },
109 { (char *)"NOTICE", BDF_ATOM, 1, { 0 } },
110 { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
111 { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } },
112 { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
113 { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
114 { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
115 { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
116 { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
117 { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
118 { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
119 { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
120 { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
121 { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
122 { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
123 { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
124 { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
125 { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
126 { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
127 { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
128 { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
129 { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
130 { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
131 { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
132 { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
133 { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
134 { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
135 { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
136 { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
137 { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
138 { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
139 { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
140 { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
141 { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
142 { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
143 { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } },
144 { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
145 { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
146 { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
147 { (char *)"SLANT", BDF_ATOM, 1, { 0 } },
148 { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
149 { (char *)"SPACING", BDF_ATOM, 1, { 0 } },
150 { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
151 { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
152 { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
153 { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
154 { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
155 { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
156 { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
157 { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
158 { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
159 { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
160 { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } },
161 { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
162 { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } },
163 { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
164 { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
165 };
David Turner993a8d02002-05-18 12:03:43 +0000166
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000167 static const unsigned long
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000168 _num_bdf_properties = sizeof ( _bdf_properties ) /
169 sizeof ( _bdf_properties[0] );
David Turner993a8d02002-05-18 12:03:43 +0000170
171
Werner Lemberg2c4832d2014-11-07 07:42:33 +0100172 /* An auxiliary macro to parse properties, to be used in conditionals. */
173 /* It behaves like `strncmp' but also tests the following character */
174 /* whether it is a whitespace or NULL. */
175 /* `property' is a constant string of length `n' to compare with. */
176#define _bdf_strncmp( name, property, n ) \
177 ( ft_strncmp( name, property, n ) || \
178 !( name[n] == ' ' || \
179 name[n] == '\0' || \
180 name[n] == '\n' || \
181 name[n] == '\r' || \
182 name[n] == '\t' ) )
183
Werner Lemberge01406b2011-11-25 09:44:28 +0100184 /* Auto correction messages. */
185#define ACMSG1 "FONT_ASCENT property missing. " \
186 "Added `FONT_ASCENT %hd'.\n"
187#define ACMSG2 "FONT_DESCENT property missing. " \
188 "Added `FONT_DESCENT %hd'.\n"
189#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
190#define ACMSG4 "Font left bearing != actual left bearing. " \
191 "Old: %hd New: %hd.\n"
192#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
193#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
194#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
195#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
196#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
197#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
198#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
199#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
200#define ACMSG13 "Glyph %ld extra rows removed.\n"
201#define ACMSG14 "Glyph %ld extra columns removed.\n"
202#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
Werner Lemberg0b1c0c62012-02-25 10:23:04 +0100203#define ACMSG16 "Glyph %ld missing columns padded with zero bits.\n"
Werner Lemberge1ca18d2015-10-17 11:51:27 +0200204#define ACMSG17 "Adjusting number of glyphs to %ld.\n"
Werner Lemberge01406b2011-11-25 09:44:28 +0100205
206 /* Error messages. */
207#define ERRMSG1 "[line %ld] Missing `%s' line.\n"
208#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
209#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
210#define ERRMSG4 "[line %ld] BBX too big.\n"
211#define ERRMSG5 "[line %ld] `%s' value too big.\n"
212#define ERRMSG6 "[line %ld] Input line too long.\n"
213#define ERRMSG7 "[line %ld] Font name too long.\n"
214#define ERRMSG8 "[line %ld] Invalid `%s' value.\n"
215#define ERRMSG9 "[line %ld] Invalid keyword.\n"
216
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +0100217 /* Debug messages. */
218#define DBGMSG1 " [%6ld] %s" /* no \n */
219#define DBGMSG2 " (0x%lX)\n"
220
Werner Lemberge01406b2011-11-25 09:44:28 +0100221
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000222 /*************************************************************************/
223 /* */
224 /* Hash table utilities for the properties. */
225 /* */
226 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +0000227
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000228 /* XXX: Replace this with FreeType's hash functions */
David Turner993a8d02002-05-18 12:03:43 +0000229
David Turner993a8d02002-05-18 12:03:43 +0000230
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000231#define INITIAL_HT_SIZE 241
232
233 typedef void
234 (*hash_free_func)( hashnode node );
235
236 static hashnode*
Werner Lemberg428c2e42003-04-25 05:35:04 +0000237 hash_bucket( const char* key,
238 hashtable* ht )
David Turner993a8d02002-05-18 12:03:43 +0000239 {
Werner Lemberg428c2e42003-04-25 05:35:04 +0000240 const char* kp = key;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000241 unsigned long res = 0;
242 hashnode* bp = ht->table, *ndp;
243
244
245 /* Mocklisp hash function. */
246 while ( *kp )
Werner Lemberg3c374c82015-02-22 09:16:53 +0100247 res = ( res << 5 ) - res + (unsigned long)*kp++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000248
249 ndp = bp + ( res % ht->size );
250 while ( *ndp )
David Turner993a8d02002-05-18 12:03:43 +0000251 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000252 kp = (*ndp)->key;
253 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
254 break;
255 ndp--;
256 if ( ndp < bp )
257 ndp = bp + ( ht->size - 1 );
David Turner993a8d02002-05-18 12:03:43 +0000258 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000259
260 return ndp;
David Turner993a8d02002-05-18 12:03:43 +0000261 }
David Turner993a8d02002-05-18 12:03:43 +0000262
263
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000264 static FT_Error
265 hash_rehash( hashtable* ht,
266 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000267 {
Werner Lemberg3c374c82015-02-22 09:16:53 +0100268 hashnode* obp = ht->table, *bp, *nbp;
269 unsigned int i, sz = ht->size;
270 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000271
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000272
273 ht->size <<= 1;
274 ht->limit = ht->size / 3;
275
276 if ( FT_NEW_ARRAY( ht->table, ht->size ) )
277 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000278
279 for ( i = 0, bp = obp; i < sz; i++, bp++ )
David Turner993a8d02002-05-18 12:03:43 +0000280 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000281 if ( *bp )
282 {
283 nbp = hash_bucket( (*bp)->key, ht );
284 *nbp = *bp;
285 }
David Turner993a8d02002-05-18 12:03:43 +0000286 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000287 FT_FREE( obp );
288
289 Exit:
290 return error;
David Turner993a8d02002-05-18 12:03:43 +0000291 }
David Turner993a8d02002-05-18 12:03:43 +0000292
293
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000294 static FT_Error
295 hash_init( hashtable* ht,
296 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000297 {
Werner Lemberg3c374c82015-02-22 09:16:53 +0100298 unsigned int sz = INITIAL_HT_SIZE;
299 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000300
David Turner993a8d02002-05-18 12:03:43 +0000301
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000302 ht->size = sz;
303 ht->limit = sz / 3;
304 ht->used = 0;
David Turner993a8d02002-05-18 12:03:43 +0000305
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000306 if ( FT_NEW_ARRAY( ht->table, sz ) )
307 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000308
309 Exit:
310 return error;
David Turner993a8d02002-05-18 12:03:43 +0000311 }
David Turner993a8d02002-05-18 12:03:43 +0000312
313
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000314 static void
315 hash_free( hashtable* ht,
316 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000317 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000318 if ( ht != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000319 {
Werner Lemberg3c374c82015-02-22 09:16:53 +0100320 unsigned int i, sz = ht->size;
321 hashnode* bp = ht->table;
David Turner993a8d02002-05-18 12:03:43 +0000322
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000323
324 for ( i = 0; i < sz; i++, bp++ )
325 FT_FREE( *bp );
326
327 FT_FREE( ht->table );
328 }
David Turner993a8d02002-05-18 12:03:43 +0000329 }
330
David Turner993a8d02002-05-18 12:03:43 +0000331
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000332 static FT_Error
333 hash_insert( char* key,
suzuki toshiya704f4d72009-09-13 00:50:14 +0900334 size_t data,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000335 hashtable* ht,
336 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000337 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100338 hashnode nn;
339 hashnode* bp = hash_bucket( key, ht );
Werner Lemberge3c93012013-03-14 11:21:17 +0100340 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000341
342
343 nn = *bp;
344 if ( !nn )
345 {
346 if ( FT_NEW( nn ) )
347 goto Exit;
348 *bp = nn;
349
350 nn->key = key;
351 nn->data = data;
352
353 if ( ht->used >= ht->limit )
354 {
355 error = hash_rehash( ht, memory );
356 if ( error )
357 goto Exit;
358 }
359 ht->used++;
360 }
David Turner993a8d02002-05-18 12:03:43 +0000361 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000362 nn->data = data;
363
364 Exit:
365 return error;
David Turner993a8d02002-05-18 12:03:43 +0000366 }
367
David Turner993a8d02002-05-18 12:03:43 +0000368
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000369 static hashnode
Werner Lemberg428c2e42003-04-25 05:35:04 +0000370 hash_lookup( const char* key,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000371 hashtable* ht )
372 {
373 hashnode *np = hash_bucket( key, ht );
374
375
376 return *np;
377 }
378
379
380 /*************************************************************************/
381 /* */
382 /* Utility types and functions. */
383 /* */
384 /*************************************************************************/
385
386
387 /* Function type for parsing lines of a BDF font. */
388
389 typedef FT_Error
390 (*_bdf_line_func_t)( char* line,
391 unsigned long linelen,
392 unsigned long lineno,
393 void* call_data,
394 void* client_data );
395
396
397 /* List structure for splitting lines into fields. */
398
399 typedef struct _bdf_list_t_
400 {
401 char** field;
402 unsigned long size;
403 unsigned long used;
David Turner68df4f72005-03-15 18:18:57 +0000404 FT_Memory memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000405
406 } _bdf_list_t;
407
408
409 /* Structure used while loading BDF fonts. */
410
411 typedef struct _bdf_parse_t_
412 {
413 unsigned long flags;
414 unsigned long cnt;
415 unsigned long row;
416
417 short minlb;
418 short maxlb;
419 short maxrb;
420 short maxas;
421 short maxds;
422
423 short rbearing;
424
425 char* glyph_name;
426 long glyph_enc;
427
428 bdf_font_t* font;
429 bdf_options_t* opts;
430
Werner Lemberged54e432011-11-27 16:39:53 +0100431 unsigned long have[34816]; /* must be in sync with `nmod' and `umod' */
432 /* arrays from `bdf_font_t' structure */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000433 _bdf_list_t list;
434
435 FT_Memory memory;
Werner Lemberge1ca18d2015-10-17 11:51:27 +0200436 unsigned long size; /* the stream size */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000437
438 } _bdf_parse_t;
439
440
Werner Lemberga08b2172007-03-28 07:17:17 +0000441#define setsbit( m, cc ) \
442 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
443#define sbitset( m, cc ) \
444 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000445
446
David Turner68df4f72005-03-15 18:18:57 +0000447 static void
448 _bdf_list_init( _bdf_list_t* list,
449 FT_Memory memory )
450 {
Werner Lembergebf55852005-03-16 01:49:54 +0000451 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000452 list->memory = memory;
453 }
454
Werner Lembergebf55852005-03-16 01:49:54 +0000455
David Turner68df4f72005-03-15 18:18:57 +0000456 static void
457 _bdf_list_done( _bdf_list_t* list )
458 {
459 FT_Memory memory = list->memory;
460
Werner Lembergebf55852005-03-16 01:49:54 +0000461
David Turner68df4f72005-03-15 18:18:57 +0000462 if ( memory )
463 {
464 FT_FREE( list->field );
Werner Lembergebf55852005-03-16 01:49:54 +0000465 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000466 }
467 }
468
469
470 static FT_Error
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900471 _bdf_list_ensure( _bdf_list_t* list,
472 unsigned long num_items ) /* same as _bdf_list_t.used */
David Turner68df4f72005-03-15 18:18:57 +0000473 {
Werner Lemberge3c93012013-03-14 11:21:17 +0100474 FT_Error error = FT_Err_Ok;
Werner Lembergebf55852005-03-16 01:49:54 +0000475
David Turner68df4f72005-03-15 18:18:57 +0000476
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900477 if ( num_items > list->size )
David Turner68df4f72005-03-15 18:18:57 +0000478 {
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900479 unsigned long oldsize = list->size; /* same as _bdf_list_t.size */
Werner Lembergcee5d592012-03-01 09:26:03 +0100480 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 5;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900481 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
482 FT_Memory memory = list->memory;
David Turner68df4f72005-03-15 18:18:57 +0000483
Werner Lembergebf55852005-03-16 01:49:54 +0000484
David Turner68df4f72005-03-15 18:18:57 +0000485 if ( oldsize == bigsize )
486 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100487 error = FT_THROW( Out_Of_Memory );
David Turner68df4f72005-03-15 18:18:57 +0000488 goto Exit;
489 }
490 else if ( newsize < oldsize || newsize > bigsize )
491 newsize = bigsize;
492
493 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
494 goto Exit;
495
496 list->size = newsize;
497 }
Werner Lembergebf55852005-03-16 01:49:54 +0000498
David Turner68df4f72005-03-15 18:18:57 +0000499 Exit:
500 return error;
501 }
502
503
504 static void
505 _bdf_list_shift( _bdf_list_t* list,
506 unsigned long n )
507 {
508 unsigned long i, u;
509
510
511 if ( list == 0 || list->used == 0 || n == 0 )
512 return;
513
514 if ( n >= list->used )
515 {
516 list->used = 0;
517 return;
518 }
519
520 for ( u = n, i = 0; u < list->used; i++, u++ )
521 list->field[i] = list->field[u];
522 list->used -= n;
523 }
524
525
Werner Lembergf4c94d42010-06-19 16:08:31 +0200526 /* An empty string for empty fields. */
527
528 static const char empty[1] = { 0 }; /* XXX eliminate this */
529
530
David Turner68df4f72005-03-15 18:18:57 +0000531 static char *
532 _bdf_list_join( _bdf_list_t* list,
533 int c,
534 unsigned long *alen )
535 {
536 unsigned long i, j;
Werner Lembergdc624ca2013-06-04 10:30:48 +0200537 char* dp;
David Turner68df4f72005-03-15 18:18:57 +0000538
539
540 *alen = 0;
541
542 if ( list == 0 || list->used == 0 )
543 return 0;
544
545 dp = list->field[0];
546 for ( i = j = 0; i < list->used; i++ )
547 {
Werner Lembergdc624ca2013-06-04 10:30:48 +0200548 char* fp = list->field[i];
549
550
David Turner68df4f72005-03-15 18:18:57 +0000551 while ( *fp )
552 dp[j++] = *fp++;
553
554 if ( i + 1 < list->used )
555 dp[j++] = (char)c;
556 }
Werner Lembergf4c94d42010-06-19 16:08:31 +0200557 if ( dp != empty )
558 dp[j] = 0;
David Turner68df4f72005-03-15 18:18:57 +0000559
560 *alen = j;
561 return dp;
562 }
563
564
Werner Lemberg03242f52012-02-26 06:52:56 +0100565 /* The code below ensures that we have at least 4 + 1 `field' */
566 /* elements in `list' (which are possibly NULL) so that we */
567 /* don't have to check the number of fields in most cases. */
568
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000569 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000570 _bdf_list_split( _bdf_list_t* list,
571 char* separators,
572 char* line,
573 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000574 {
Werner Lemberg3c374c82015-02-22 09:16:53 +0100575 unsigned long final_empty;
576 int mult;
577 char *sp, *ep, *end;
578 char seps[32];
579 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000580
581
582 /* Initialize the list. */
583 list->used = 0;
Werner Lembergd9c16592012-03-01 15:15:00 +0100584 if ( list->size )
585 {
586 list->field[0] = (char*)empty;
587 list->field[1] = (char*)empty;
588 list->field[2] = (char*)empty;
589 list->field[3] = (char*)empty;
Werner Lemberg649c6732012-03-16 21:12:41 +0100590 list->field[4] = (char*)empty;
Werner Lembergd9c16592012-03-01 15:15:00 +0100591 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000592
593 /* If the line is empty, then simply return. */
594 if ( linelen == 0 || line[0] == 0 )
595 goto Exit;
596
597 /* In the original code, if the `separators' parameter is NULL or */
598 /* empty, the list is split into individual bytes. We don't need */
599 /* this, so an error is signaled. */
600 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000601 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100602 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000603 goto Exit;
604 }
605
606 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000607 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000608
609 /* If the very last character of the separator string is a plus, then */
610 /* set the `mult' flag to indicate that multiple separators should be */
611 /* collapsed into one. */
612 for ( mult = 0, sp = separators; sp && *sp; sp++ )
613 {
614 if ( *sp == '+' && *( sp + 1 ) == 0 )
615 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000616 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000617 setsbit( seps, *sp );
618 }
619
620 /* Break the line up into fields. */
621 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
622 sp < end && *sp; )
623 {
624 /* Collect everything that is not a separator. */
625 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
626 ;
627
628 /* Resize the list if necessary. */
629 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000630 {
Werner Lembergebf55852005-03-16 01:49:54 +0000631 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000632 if ( error )
633 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000634 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000635
636 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000637 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000638
639 sp = ep;
640
641 if ( mult )
642 {
643 /* If multiple separators should be collapsed, do it now by */
644 /* setting all the separator characters to 0. */
645 for ( ; *ep && sbitset( seps, *ep ); ep++ )
646 *ep = 0;
647 }
648 else if ( *ep != 0 )
649 /* Don't collapse multiple separators by making them 0, so just */
650 /* make the one encountered 0. */
651 *ep++ = 0;
652
653 final_empty = ( ep > sp && *ep == 0 );
654 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000655 }
656
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000657 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000658 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000659 {
Werner Lembergebf55852005-03-16 01:49:54 +0000660 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000661 if ( error )
662 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000663 }
664
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000665 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000666 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000667
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000668 list->field[list->used] = 0;
669
670 Exit:
671 return error;
David Turner993a8d02002-05-18 12:03:43 +0000672 }
673
David Turner993a8d02002-05-18 12:03:43 +0000674
David Turner68df4f72005-03-15 18:18:57 +0000675#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000676
Werner Lembergebf55852005-03-16 01:49:54 +0000677
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000678 static FT_Error
679 _bdf_readstream( FT_Stream stream,
680 _bdf_line_func_t callback,
681 void* client_data,
682 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000683 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000684 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000685 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900686 int refill, hold, to_skip;
687 ptrdiff_t bytes, start, end, cursor, avail;
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -0400688 char* buf = NULL;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000689 FT_Memory memory = stream->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100690 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000691
David Turner993a8d02002-05-18 12:03:43 +0000692
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000693 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000694 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100695 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000696 goto Exit;
697 }
David Turner993a8d02002-05-18 12:03:43 +0000698
Werner Lembergebf55852005-03-16 01:49:54 +0000699 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000700 buf_size = 1024;
701
702 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000703 goto Exit;
704
Werner Lembergebf55852005-03-16 01:49:54 +0000705 cb = callback;
706 lineno = 1;
707 buf[0] = 0;
708 start = 0;
Werner Lembergebf55852005-03-16 01:49:54 +0000709 avail = 0;
710 cursor = 0;
711 refill = 1;
712 to_skip = NO_SKIP;
713 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000714
David Turner68df4f72005-03-15 18:18:57 +0000715 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000716 {
David Turner68df4f72005-03-15 18:18:57 +0000717 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000718 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +0200719 bytes = (ptrdiff_t)FT_Stream_TryRead(
720 stream, (FT_Byte*)buf + cursor,
Werner Lemberg3c374c82015-02-22 09:16:53 +0100721 buf_size - (unsigned long)cursor );
David Turner68df4f72005-03-15 18:18:57 +0000722 avail = cursor + bytes;
723 cursor = 0;
724 refill = 0;
725 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000726
David Turner68df4f72005-03-15 18:18:57 +0000727 end = start;
728
Werner Lembergebf55852005-03-16 01:49:54 +0000729 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000730 if ( start < avail && buf[start] == to_skip )
731 {
732 start += 1;
733 to_skip = NO_SKIP;
734 continue;
735 }
736
737 /* try to find the end of the line */
738 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
739 end++;
740
Werner Lembergebf55852005-03-16 01:49:54 +0000741 /* if we hit the end of the buffer, try shifting its content */
742 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000743 if ( end >= avail )
744 {
745 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
746 break; /* ignore it then exit */
747
748 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000749 {
Werner Lembergebf55852005-03-16 01:49:54 +0000750 /* this line is definitely too long; try resizing the input */
751 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000752 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000753
Werner Lembergebf55852005-03-16 01:49:54 +0000754
755 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000756 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100757 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +0100758 error = FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +0000759 goto Exit;
760 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000761
Werner Lembergebf55852005-03-16 01:49:54 +0000762 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000763 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
764 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000765
Werner Lemberg3c374c82015-02-22 09:16:53 +0100766 cursor = (ptrdiff_t)buf_size;
David Turner68df4f72005-03-15 18:18:57 +0000767 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000768 }
769 else
770 {
David Turner68df4f72005-03-15 18:18:57 +0000771 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000772
Werner Lemberg04e547b2013-04-03 07:37:56 +0200773 FT_MEM_MOVE( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000774
David Turner68df4f72005-03-15 18:18:57 +0000775 cursor = bytes;
776 avail -= bytes;
777 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000778 }
David Turner68df4f72005-03-15 18:18:57 +0000779 refill = 1;
780 continue;
David Turner993a8d02002-05-18 12:03:43 +0000781 }
David Turner68df4f72005-03-15 18:18:57 +0000782
783 /* Temporarily NUL-terminate the line. */
784 hold = buf[end];
785 buf[end] = 0;
786
Werner Lemberg0098d552014-12-07 11:03:57 +0100787 /* XXX: Use encoding independent value for 0x1A */
788 if ( buf[start] != '#' && buf[start] != 0x1A && end > start )
David Turner68df4f72005-03-15 18:18:57 +0000789 {
Werner Lemberga9f6f852012-12-17 09:08:09 +0100790 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergebf55852005-03-16 01:49:54 +0000791 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200792 /* Redo if we have encountered CHARS without properties. */
793 if ( error == -1 )
Werner Lemberga9f6f852012-12-17 09:08:09 +0100794 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200795 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000796 if ( error )
797 break;
798 }
799
800 lineno += 1;
801 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000802 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000803
804 if ( hold == '\n' )
805 to_skip = '\r';
806 else if ( hold == '\r' )
807 to_skip = '\n';
808 else
809 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000810 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000811
David Turner68df4f72005-03-15 18:18:57 +0000812 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000813
814 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000815 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000816 return error;
David Turner993a8d02002-05-18 12:03:43 +0000817 }
David Turner993a8d02002-05-18 12:03:43 +0000818
819
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000820 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000821
David Turnerb1b47622002-05-21 21:17:43 +0000822 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000823 {
David Turner993a8d02002-05-18 12:03:43 +0000824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
825 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
826 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
827 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
828 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
Werner Lemberg0098d552014-12-07 11:03:57 +0100829 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000830 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
831 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg0098d552014-12-07 11:03:57 +0100832 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000833 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
834 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000835 };
David Turner993a8d02002-05-18 12:03:43 +0000836
David Turnerb1b47622002-05-21 21:17:43 +0000837 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000838 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100839 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000840 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
841 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
842 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000843 };
David Turner993a8d02002-05-18 12:03:43 +0000844
David Turnerb1b47622002-05-21 21:17:43 +0000845 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000846 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100847 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
David Turner993a8d02002-05-18 12:03:43 +0000848 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
849 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
850 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000851 };
David Turner993a8d02002-05-18 12:03:43 +0000852
David Turnerb1b47622002-05-21 21:17:43 +0000853 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000854 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100855 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
856 0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000857 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
858 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000859 };
David Turner993a8d02002-05-18 12:03:43 +0000860
David Turner993a8d02002-05-18 12:03:43 +0000861
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000862 /* Routine to convert an ASCII string into an unsigned long integer. */
863 static unsigned long
Werner Lemberg3c374c82015-02-22 09:16:53 +0100864 _bdf_atoul( char* s,
865 char** end,
866 unsigned int base )
David Turner993a8d02002-05-18 12:03:43 +0000867 {
David Turnerb1b47622002-05-21 21:17:43 +0000868 unsigned long v;
869 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000870
871
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000872 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000873 return 0;
874
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000875 /* Make sure the radix is something recognizable. Default to 10. */
876 switch ( base )
877 {
878 case 8:
879 dmap = odigits;
880 break;
881 case 16:
882 dmap = hdigits;
883 break;
884 default:
885 base = 10;
886 dmap = ddigits;
887 break;
David Turner993a8d02002-05-18 12:03:43 +0000888 }
889
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000890 /* Check for the special hex prefix. */
891 if ( *s == '0' &&
892 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
893 {
894 base = 16;
895 dmap = hdigits;
896 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000897 }
898
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +0100899 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000900 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000901
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000902 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000903 *end = s;
904
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000905 return v;
906 }
David Turner993a8d02002-05-18 12:03:43 +0000907
David Turner993a8d02002-05-18 12:03:43 +0000908
Werner Lemberg3c374c82015-02-22 09:16:53 +0100909 /* Routine to convert an ASCII string into a signed long integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000910 static long
911 _bdf_atol( char* s,
912 char** end,
913 int base )
914 {
David Turnerb1b47622002-05-21 21:17:43 +0000915 long v, neg;
916 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000917
918
919 if ( s == 0 || *s == 0 )
920 return 0;
921
922 /* Make sure the radix is something recognizable. Default to 10. */
923 switch ( base )
924 {
925 case 8:
926 dmap = odigits;
927 break;
928 case 16:
929 dmap = hdigits;
930 break;
931 default:
932 base = 10;
933 dmap = ddigits;
934 break;
935 }
936
937 /* Check for a minus sign. */
938 neg = 0;
939 if ( *s == '-' )
940 {
941 s++;
942 neg = 1;
943 }
944
945 /* Check for the special hex prefix. */
946 if ( *s == '0' &&
947 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
948 {
949 base = 16;
950 dmap = hdigits;
951 s += 2;
952 }
953
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +0100954 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000955 v = v * base + a2i[(int)*s];
956
957 if ( end != 0 )
958 *end = s;
959
960 return ( !neg ) ? v : -v;
961 }
962
963
Werner Lembergb13945a2015-02-22 09:15:47 +0100964 /* Routine to convert an ASCII string into an unsigned short integer. */
965 static unsigned short
966 _bdf_atous( char* s,
967 char** end,
968 unsigned int base )
969 {
970 unsigned short v;
971 const unsigned char* dmap;
972
973
974 if ( s == 0 || *s == 0 )
975 return 0;
976
977 /* Make sure the radix is something recognizable. Default to 10. */
978 switch ( base )
979 {
980 case 8:
981 dmap = odigits;
982 break;
983 case 16:
984 dmap = hdigits;
985 break;
986 default:
987 base = 10;
988 dmap = ddigits;
989 break;
990 }
991
992 /* Check for the special hex prefix. */
993 if ( *s == '0' &&
994 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
995 {
996 base = 16;
997 dmap = hdigits;
998 s += 2;
999 }
1000
1001 for ( v = 0; sbitset( dmap, *s ); s++ )
1002 v = (unsigned short)( v * base + a2i[(int)*s] );
1003
1004 if ( end != 0 )
1005 *end = s;
1006
1007 return v;
1008 }
1009
1010
1011 /* Routine to convert an ASCII string into a signed short integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001012 static short
1013 _bdf_atos( char* s,
1014 char** end,
1015 int base )
1016 {
David Turnerb1b47622002-05-21 21:17:43 +00001017 short v, neg;
1018 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001019
1020
1021 if ( s == 0 || *s == 0 )
1022 return 0;
1023
1024 /* Make sure the radix is something recognizable. Default to 10. */
1025 switch ( base )
1026 {
1027 case 8:
1028 dmap = odigits;
1029 break;
1030 case 16:
1031 dmap = hdigits;
1032 break;
1033 default:
1034 base = 10;
1035 dmap = ddigits;
1036 break;
1037 }
1038
1039 /* Check for a minus. */
1040 neg = 0;
1041 if ( *s == '-' )
1042 {
1043 s++;
1044 neg = 1;
1045 }
1046
1047 /* Check for the special hex prefix. */
1048 if ( *s == '0' &&
1049 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
1050 {
1051 base = 16;
1052 dmap = hdigits;
1053 s += 2;
1054 }
1055
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001056 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +00001057 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001058
1059 if ( end != 0 )
1060 *end = s;
1061
Werner Lemberg233302a2002-05-22 05:41:06 +00001062 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001063 }
1064
1065
1066 /* Routine to compare two glyphs by encoding so they can be sorted. */
1067 static int
1068 by_encoding( const void* a,
1069 const void* b )
1070 {
1071 bdf_glyph_t *c1, *c2;
1072
1073
1074 c1 = (bdf_glyph_t *)a;
1075 c2 = (bdf_glyph_t *)b;
1076
1077 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001078 return -1;
David Turner68df4f72005-03-15 18:18:57 +00001079
1080 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001081 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001082
David Turner993a8d02002-05-18 12:03:43 +00001083 return 0;
David Turner993a8d02002-05-18 12:03:43 +00001084 }
1085
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001086
1087 static FT_Error
1088 bdf_create_property( char* name,
1089 int format,
1090 bdf_font_t* font )
1091 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001092 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001093 bdf_property_t* p;
1094 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001095 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001096
1097
Werner Lemberg96ddc672011-06-29 09:15:54 +02001098 /* First check whether the property has */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001099 /* already been added or not. If it has, then */
1100 /* simply ignore it. */
1101 if ( hash_lookup( name, &(font->proptbl) ) )
1102 goto Exit;
1103
David Turner68df4f72005-03-15 18:18:57 +00001104 if ( FT_RENEW_ARRAY( font->user_props,
1105 font->nuser_props,
1106 font->nuser_props + 1 ) )
1107 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001108
1109 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +00001110 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001111
suzuki toshiya704f4d72009-09-13 00:50:14 +09001112 n = ft_strlen( name ) + 1;
1113 if ( n > FT_ULONG_MAX )
Werner Lemberg059bc332013-03-14 10:27:35 +01001114 return FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +00001115
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001116 if ( FT_NEW_ARRAY( p->name, n ) )
1117 goto Exit;
1118
1119 FT_MEM_COPY( (char *)p->name, name, n );
1120
1121 p->format = format;
1122 p->builtin = 0;
1123
1124 n = _num_bdf_properties + font->nuser_props;
1125
suzuki toshiya704f4d72009-09-13 00:50:14 +09001126 error = hash_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001127 if ( error )
1128 goto Exit;
1129
1130 font->nuser_props++;
1131
1132 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001133 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001134 }
David Turner993a8d02002-05-18 12:03:43 +00001135
1136
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001137 FT_LOCAL_DEF( bdf_property_t * )
1138 bdf_get_property( char* name,
1139 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001140 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001141 hashnode hn;
1142 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001143
1144
1145 if ( name == 0 || *name == 0 )
1146 return 0;
1147
1148 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1149 return 0;
1150
suzuki toshiya704f4d72009-09-13 00:50:14 +09001151 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001152 if ( propid >= _num_bdf_properties )
1153 return font->user_props + ( propid - _num_bdf_properties );
1154
Werner Lemberg233302a2002-05-22 05:41:06 +00001155 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001156 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001157
1158
1159 /*************************************************************************/
1160 /* */
1161 /* BDF font file parsing flags and functions. */
1162 /* */
1163 /*************************************************************************/
1164
1165
1166 /* Parse flags. */
1167
Werner Lemberg3c374c82015-02-22 09:16:53 +01001168#define _BDF_START 0x0001U
1169#define _BDF_FONT_NAME 0x0002U
1170#define _BDF_SIZE 0x0004U
1171#define _BDF_FONT_BBX 0x0008U
1172#define _BDF_PROPS 0x0010U
1173#define _BDF_GLYPHS 0x0020U
1174#define _BDF_GLYPH 0x0040U
1175#define _BDF_ENCODING 0x0080U
1176#define _BDF_SWIDTH 0x0100U
1177#define _BDF_DWIDTH 0x0200U
1178#define _BDF_BBX 0x0400U
1179#define _BDF_BITMAP 0x0800U
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001180
Werner Lemberg3c374c82015-02-22 09:16:53 +01001181#define _BDF_SWIDTH_ADJ 0x1000U
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001182
1183#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1184 _BDF_ENCODING | \
1185 _BDF_SWIDTH | \
1186 _BDF_DWIDTH | \
1187 _BDF_BBX | \
1188 _BDF_BITMAP )
1189
Werner Lembergf1c2b912006-01-13 14:53:28 +00001190#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1191#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001192
1193
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001194 static FT_Error
1195 _bdf_add_comment( bdf_font_t* font,
1196 char* comment,
1197 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001198 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001199 char* cp;
1200 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001201 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001202
1203
David Turner68df4f72005-03-15 18:18:57 +00001204 if ( FT_RENEW_ARRAY( font->comments,
1205 font->comments_len,
1206 font->comments_len + len + 1 ) )
1207 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001208
1209 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001210
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001211 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001212 cp[len] = '\n';
1213
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001214 font->comments_len += len + 1;
1215
1216 Exit:
1217 return error;
David Turner993a8d02002-05-18 12:03:43 +00001218 }
1219
David Turner993a8d02002-05-18 12:03:43 +00001220
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001221 /* Set the spacing from the font name if it exists, or set it to the */
1222 /* default specified in the options. */
1223 static FT_Error
1224 _bdf_set_default_spacing( bdf_font_t* font,
Werner Lemberge01406b2011-11-25 09:44:28 +01001225 bdf_options_t* opts,
1226 unsigned long lineno )
David Turner993a8d02002-05-18 12:03:43 +00001227 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001228 size_t len;
1229 char name[256];
1230 _bdf_list_t list;
1231 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001232 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001233
Dave Arnoldc3782492013-06-05 19:57:55 +02001234 FT_UNUSED( lineno ); /* only used in debug mode */
1235
David Turner993a8d02002-05-18 12:03:43 +00001236
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001237 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1238 {
Werner Lemberg059bc332013-03-14 10:27:35 +01001239 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001240 goto Exit;
1241 }
David Turner993a8d02002-05-18 12:03:43 +00001242
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001243 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001244
David Turner68df4f72005-03-15 18:18:57 +00001245 _bdf_list_init( &list, memory );
1246
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001247 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001248
suzuki toshiya704f4d72009-09-13 00:50:14 +09001249 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +00001250 /* Limit ourselves to 256 characters in the font name. */
1251 if ( len >= 256 )
1252 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001253 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001254 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001255 goto Exit;
1256 }
1257
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001258 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001259
Werner Lembergbadf3172013-06-06 09:16:38 +02001260 error = _bdf_list_split( &list, (char *)"-", name, (unsigned long)len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001261 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001262 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001263
1264 if ( list.used == 15 )
1265 {
1266 switch ( list.field[11][0] )
1267 {
1268 case 'C':
1269 case 'c':
1270 font->spacing = BDF_CHARCELL;
1271 break;
1272 case 'M':
1273 case 'm':
1274 font->spacing = BDF_MONOWIDTH;
1275 break;
1276 case 'P':
1277 case 'p':
1278 font->spacing = BDF_PROPORTIONAL;
1279 break;
David Turner993a8d02002-05-18 12:03:43 +00001280 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001281 }
1282
David Turner68df4f72005-03-15 18:18:57 +00001283 Fail:
1284 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001285
1286 Exit:
1287 return error;
David Turner993a8d02002-05-18 12:03:43 +00001288 }
David Turner993a8d02002-05-18 12:03:43 +00001289
1290
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001291 /* Determine whether the property is an atom or not. If it is, then */
1292 /* clean it up so the double quotes are removed if they exist. */
1293 static int
1294 _bdf_is_atom( char* line,
1295 unsigned long linelen,
1296 char** name,
1297 char** value,
1298 bdf_font_t* font )
1299 {
1300 int hold;
1301 char *sp, *ep;
1302 bdf_property_t* p;
1303
David Turner993a8d02002-05-18 12:03:43 +00001304
1305 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001306
1307 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001308 ep++;
1309
1310 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001311 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001312 {
1313 hold = *ep;
1314 *ep = 0;
1315 }
1316
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001317 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001318
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001319 /* Restore the character that was saved before any return can happen. */
1320 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001321 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001322
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001323 /* If the property exists and is not an atom, just return here. */
1324 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001325 return 0;
1326
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001327 /* The property is an atom. Trim all leading and trailing whitespace */
1328 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001329 sp = ep;
1330 ep = line + linelen;
1331
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001332 /* Trim the leading whitespace if it exists. */
Werner Lemberg320d4972012-02-24 18:06:46 +01001333 if ( *sp )
1334 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001335 while ( *sp &&
1336 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001337 sp++;
1338
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001339 /* Trim the leading double quote if it exists. */
1340 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001341 sp++;
1342 *value = sp;
1343
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001344 /* Trim the trailing whitespace if it exists. */
1345 while ( ep > sp &&
1346 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001347 *--ep = 0;
1348
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001349 /* Trim the trailing double quote if it exists. */
1350 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001351 *--ep = 0;
1352
1353 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001354 }
David Turner993a8d02002-05-18 12:03:43 +00001355
1356
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001357 static FT_Error
Werner Lemberge01406b2011-11-25 09:44:28 +01001358 _bdf_add_property( bdf_font_t* font,
1359 char* name,
1360 char* value,
1361 unsigned long lineno )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001362 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001363 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001364 hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001365 bdf_property_t *prop, *fp;
1366 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001367 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001368
Dave Arnoldc3782492013-06-05 19:57:55 +02001369 FT_UNUSED( lineno ); /* only used in debug mode */
1370
David Turner993a8d02002-05-18 12:03:43 +00001371
Werner Lemberg96ddc672011-06-29 09:15:54 +02001372 /* First, check whether the property already exists in the font. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001373 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001374 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001375 /* The property already exists in the font, so simply replace */
1376 /* the value of the property with the current value. */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001377 fp = font->props + hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001378
David Turnerb1b47622002-05-21 21:17:43 +00001379 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001380 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001381 case BDF_ATOM:
1382 /* Delete the current atom if it exists. */
1383 FT_FREE( fp->value.atom );
1384
David Turnerc0f9c4a2007-02-12 14:55:03 +00001385 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001386 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001387 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001388 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001389 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001390 break;
1391
1392 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001393 fp->value.l = _bdf_atol( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001394 break;
1395
1396 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001397 fp->value.ul = _bdf_atoul( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001398 break;
David Turnerd490e372002-05-28 23:40:37 +00001399
David Turnerb1b47622002-05-21 21:17:43 +00001400 default:
1401 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001402 }
David Turnerd490e372002-05-28 23:40:37 +00001403
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001404 goto Exit;
1405 }
1406
1407 /* See whether this property type exists yet or not. */
1408 /* If not, create it. */
1409 hn = hash_lookup( name, &(font->proptbl) );
1410 if ( hn == 0 )
1411 {
1412 error = bdf_create_property( name, BDF_ATOM, font );
1413 if ( error )
1414 goto Exit;
1415 hn = hash_lookup( name, &(font->proptbl) );
1416 }
1417
1418 /* Allocate another property if this is overflow. */
1419 if ( font->props_used == font->props_size )
1420 {
1421 if ( font->props_size == 0 )
1422 {
1423 if ( FT_NEW_ARRAY( font->props, 1 ) )
1424 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001425 }
1426 else
1427 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001428 if ( FT_RENEW_ARRAY( font->props,
1429 font->props_size,
1430 font->props_size + 1 ) )
1431 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001432 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001433
David Turner993a8d02002-05-18 12:03:43 +00001434 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001435 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001436 font->props_size++;
1437 }
1438
suzuki toshiya704f4d72009-09-13 00:50:14 +09001439 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001440 if ( propid >= _num_bdf_properties )
1441 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001442 else
David Turnerb1b47622002-05-21 21:17:43 +00001443 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001444
1445 fp = font->props + font->props_used;
1446
1447 fp->name = prop->name;
1448 fp->format = prop->format;
1449 fp->builtin = prop->builtin;
1450
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001451 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001452 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001453 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001454 fp->value.atom = 0;
1455 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001456 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001457 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001458 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001459 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001460 break;
David Turner993a8d02002-05-18 12:03:43 +00001461
1462 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001463 fp->value.l = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001464 break;
1465
1466 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001467 fp->value.ul = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001468 break;
David Turner993a8d02002-05-18 12:03:43 +00001469 }
1470
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001471 /* If the property happens to be a comment, then it doesn't need */
1472 /* to be added to the internal hash table. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001473 if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 )
Werner Lemberg370aea82010-06-08 08:37:11 +02001474 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001475 /* Add the property to the font property table. */
1476 error = hash_insert( fp->name,
suzuki toshiya704f4d72009-09-13 00:50:14 +09001477 font->props_used,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001478 (hashtable *)font->internal,
1479 memory );
1480 if ( error )
1481 goto Exit;
1482 }
David Turner993a8d02002-05-18 12:03:43 +00001483
1484 font->props_used++;
1485
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001486 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1487 /* property needs to be located if it exists in the property list, the */
1488 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1489 /* present, and the SPACING property should override the default */
1490 /* spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001491 if ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001492 font->default_char = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001493 else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001494 font->font_ascent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001495 else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001496 font->font_descent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001497 else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001498 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001499 if ( !fp->value.atom )
1500 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001501 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001502 error = FT_THROW( Invalid_File_Format );
Werner Lembergb66efef2009-03-12 08:07:49 +00001503 goto Exit;
1504 }
1505
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001506 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001507 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001508 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001509 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001510 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001511 font->spacing = BDF_CHARCELL;
1512 }
1513
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001514 Exit:
1515 return error;
David Turner993a8d02002-05-18 12:03:43 +00001516 }
1517
David Turner993a8d02002-05-18 12:03:43 +00001518
David Turnerb1b47622002-05-21 21:17:43 +00001519 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001520 {
1521 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1522 };
1523
1524
1525 /* Actually parse the glyph info and bitmaps. */
1526 static FT_Error
1527 _bdf_parse_glyphs( char* line,
1528 unsigned long linelen,
1529 unsigned long lineno,
1530 void* call_data,
1531 void* client_data )
1532 {
1533 int c, mask_index;
1534 char* s;
1535 unsigned char* bp;
1536 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001537
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001538 _bdf_parse_t* p;
1539 bdf_glyph_t* glyph;
1540 bdf_font_t* font;
1541
1542 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001543 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001544
Werner Lemberg319c00d2003-04-23 19:48:24 +00001545 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001546 FT_UNUSED( lineno ); /* only used in debug mode */
1547
1548
Werner Lemberg319c00d2003-04-23 19:48:24 +00001549 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001550
1551 font = p->font;
1552 memory = font->memory;
1553
1554 /* Check for a comment. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001555 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001556 {
1557 linelen -= 7;
1558
1559 s = line + 7;
1560 if ( *s != 0 )
1561 {
1562 s++;
1563 linelen--;
1564 }
1565 error = _bdf_add_comment( p->font, s, linelen );
1566 goto Exit;
1567 }
1568
1569 /* The very first thing expected is the number of glyphs. */
1570 if ( !( p->flags & _BDF_GLYPHS ) )
1571 {
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001572 if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001573 {
1574 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001575 error = FT_THROW( Missing_Chars_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001576 goto Exit;
1577 }
1578
David Turner68df4f72005-03-15 18:18:57 +00001579 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001580 if ( error )
1581 goto Exit;
1582 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1583
Werner Lemberge1ca18d2015-10-17 11:51:27 +02001584 /* We need at least 20 bytes per glyph. */
1585 if ( p->cnt > p->size / 20 )
1586 {
Werner Lemberg797ca5a2015-10-17 11:57:16 +02001587 p->cnt = font->glyphs_size = p->size / 20;
Werner Lemberge1ca18d2015-10-17 11:51:27 +02001588 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG17, p->cnt ));
1589 }
1590
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001591 /* Make sure the number of glyphs is non-zero. */
1592 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001593 font->glyphs_size = 64;
1594
Werner Lemberga08b2172007-03-28 07:17:17 +00001595 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1596 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001597 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001598 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001599 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001600 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001601 goto Exit;
1602 }
1603
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001604 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1605 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001606
David Turner993a8d02002-05-18 12:03:43 +00001607 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001608
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001609 goto Exit;
1610 }
1611
1612 /* Check for the ENDFONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001613 if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001614 {
Werner Lembergaf834612014-11-22 13:29:10 +01001615 if ( p->flags & _BDF_GLYPH_BITS )
1616 {
1617 /* Missing ENDCHAR field. */
1618 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1619 error = FT_THROW( Corrupted_Font_Glyphs );
1620 goto Exit;
1621 }
1622
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001623 /* Sort the glyphs by encoding. */
1624 ft_qsort( (char *)font->glyphs,
1625 font->glyphs_used,
1626 sizeof ( bdf_glyph_t ),
1627 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001628
1629 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001630
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001631 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001632 }
1633
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001634 /* Check for the ENDCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001635 if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001636 {
1637 p->glyph_enc = 0;
1638 p->flags &= ~_BDF_GLYPH_BITS;
1639
1640 goto Exit;
1641 }
1642
Werner Lemberg96ddc672011-06-29 09:15:54 +02001643 /* Check whether a glyph is being scanned but should be */
1644 /* ignored because it is an unencoded glyph. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001645 if ( ( p->flags & _BDF_GLYPH ) &&
1646 p->glyph_enc == -1 &&
1647 p->opts->keep_unencoded == 0 )
1648 goto Exit;
1649
1650 /* Check for the STARTCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001651 if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001652 {
Werner Lembergb1857472015-10-17 14:21:41 +02001653 if ( p->flags & _BDF_GLYPH_BITS )
1654 {
1655 /* Missing ENDCHAR field. */
1656 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1657 error = FT_THROW( Missing_Startchar_Field );
1658 goto Exit;
1659 }
1660
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001661 /* Set the character name in the parse info first until the */
1662 /* encoding can be checked for an unencoded character. */
1663 FT_FREE( p->glyph_name );
1664
David Turner68df4f72005-03-15 18:18:57 +00001665 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001666 if ( error )
1667 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001668
David Turner68df4f72005-03-15 18:18:57 +00001669 _bdf_list_shift( &p->list, 1 );
1670
1671 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001672
Werner Lembergba03af62007-05-30 13:57:02 +00001673 if ( !s )
1674 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001675 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001676 error = FT_THROW( Invalid_File_Format );
Werner Lembergba03af62007-05-30 13:57:02 +00001677 goto Exit;
1678 }
1679
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001680 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1681 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001682
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001683 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1684
1685 p->flags |= _BDF_GLYPH;
1686
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001687 FT_TRACE4(( DBGMSG1, lineno, s ));
1688
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001689 goto Exit;
1690 }
1691
1692 /* Check for the ENCODING field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001693 if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001694 {
1695 if ( !( p->flags & _BDF_GLYPH ) )
1696 {
1697 /* Missing STARTCHAR field. */
1698 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001699 error = FT_THROW( Missing_Startchar_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001700 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001701 }
1702
David Turner68df4f72005-03-15 18:18:57 +00001703 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001704 if ( error )
1705 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001706
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001707 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001708
Werner Lemberg28dd2c42012-02-26 06:18:58 +01001709 /* Normalize negative encoding values. The specification only */
1710 /* allows -1, but we can be more generous here. */
1711 if ( p->glyph_enc < -1 )
1712 p->glyph_enc = -1;
1713
Werner Lemberg03242f52012-02-26 06:52:56 +01001714 /* Check for alternative encoding format. */
1715 if ( p->glyph_enc == -1 && p->list.used > 2 )
1716 p->glyph_enc = _bdf_atol( p->list.field[2], 0, 10 );
1717
Werner Lemberg7f2e4f42012-12-15 09:39:41 +01001718 if ( p->glyph_enc < -1 )
1719 p->glyph_enc = -1;
1720
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001721 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1722
Werner Lemberged54e432011-11-27 16:39:53 +01001723 /* Check that the encoding is in the Unicode range because */
1724 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lemberg07bdb6e2012-12-15 02:02:23 +01001725 if ( p->glyph_enc > 0 &&
1726 (size_t)p->glyph_enc >= sizeof ( p->have ) /
1727 sizeof ( unsigned long ) * 32 )
David Turner481838e2006-02-23 12:40:14 +00001728 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001729 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001730 error = FT_THROW( Invalid_File_Format );
David Turner481838e2006-02-23 12:40:14 +00001731 goto Exit;
1732 }
1733
Werner Lemberg96ddc672011-06-29 09:15:54 +02001734 /* Check whether this encoding has already been encountered. */
1735 /* If it has then change it to unencoded so it gets added if */
1736 /* indicated. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001737 if ( p->glyph_enc >= 0 )
1738 {
1739 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1740 {
1741 /* Emit a message saying a glyph has been moved to the */
1742 /* unencoded area. */
1743 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1744 p->glyph_enc, p->glyph_name ));
1745 p->glyph_enc = -1;
1746 font->modified = 1;
1747 }
1748 else
1749 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1750 }
1751
1752 if ( p->glyph_enc >= 0 )
1753 {
1754 /* Make sure there are enough glyphs allocated in case the */
1755 /* number of characters happen to be wrong. */
1756 if ( font->glyphs_used == font->glyphs_size )
1757 {
1758 if ( FT_RENEW_ARRAY( font->glyphs,
1759 font->glyphs_size,
1760 font->glyphs_size + 64 ) )
1761 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001762
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001763 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001764 }
1765
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001766 glyph = font->glyphs + font->glyphs_used++;
1767 glyph->name = p->glyph_name;
1768 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001769
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001770 /* Reset the initial glyph info. */
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001771 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001772 }
1773 else
1774 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001775 /* Unencoded glyph. Check whether it should */
1776 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001777 if ( p->opts->keep_unencoded != 0 )
1778 {
1779 /* Allocate the next unencoded glyph. */
1780 if ( font->unencoded_used == font->unencoded_size )
1781 {
David Turner68df4f72005-03-15 18:18:57 +00001782 if ( FT_RENEW_ARRAY( font->unencoded ,
1783 font->unencoded_size,
1784 font->unencoded_size + 4 ) )
1785 goto Exit;
1786
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001787 font->unencoded_size += 4;
1788 }
1789
1790 glyph = font->unencoded + font->unencoded_used;
1791 glyph->name = p->glyph_name;
Werner Lemberg3c374c82015-02-22 09:16:53 +01001792 glyph->encoding = (long)font->unencoded_used++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001793 }
1794 else
Werner Lemberg94cacac2015-11-15 04:45:42 +01001795 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001796 /* Free up the glyph name if the unencoded shouldn't be */
1797 /* kept. */
1798 FT_FREE( p->glyph_name );
Werner Lemberg94cacac2015-11-15 04:45:42 +01001799 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001800
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001801 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001802 }
1803
1804 /* Clear the flags that might be added when width and height are */
1805 /* checked for consistency. */
1806 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1807
1808 p->flags |= _BDF_ENCODING;
1809
1810 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001811 }
1812
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001813 /* Point at the glyph being constructed. */
1814 if ( p->glyph_enc == -1 )
1815 glyph = font->unencoded + ( font->unencoded_used - 1 );
1816 else
1817 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001818
Werner Lemberg96ddc672011-06-29 09:15:54 +02001819 /* Check whether a bitmap is being constructed. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001820 if ( p->flags & _BDF_BITMAP )
1821 {
1822 /* If there are more rows than are specified in the glyph metrics, */
1823 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001824 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001825 {
1826 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1827 {
1828 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1829 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001830 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001831 }
1832
1833 goto Exit;
1834 }
1835
1836 /* Only collect the number of nibbles indicated by the glyph */
1837 /* metrics. If there are more columns, they are simply ignored. */
1838 nibbles = glyph->bpr << 1;
1839 bp = glyph->bitmap + p->row * glyph->bpr;
1840
David Turnerb698eed2006-02-23 14:50:13 +00001841 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001842 {
1843 c = line[i];
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001844 if ( !sbitset( hdigits, c ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001845 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001846 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001847 if ( i + 1 < nibbles && ( i & 1 ) )
1848 *++bp = 0;
1849 }
1850
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001851 /* If any line has not enough columns, */
1852 /* indicate they have been padded with zero bits. */
1853 if ( i < nibbles &&
1854 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1855 {
1856 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
1857 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1858 font->modified = 1;
1859 }
1860
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001861 /* Remove possible garbage at the right. */
1862 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001863 if ( glyph->bbx.width )
1864 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001865
1866 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001867 if ( i == nibbles &&
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001868 sbitset( hdigits, line[nibbles] ) &&
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001869 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001870 {
1871 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1872 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1873 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001874 }
1875
1876 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001877 goto Exit;
1878 }
David Turner993a8d02002-05-18 12:03:43 +00001879
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001880 /* Expect the SWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001881 if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001882 {
1883 if ( !( p->flags & _BDF_ENCODING ) )
Werner Lemberg4086fb72012-03-01 08:55:40 +01001884 goto Missing_Encoding;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001885
David Turner68df4f72005-03-15 18:18:57 +00001886 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001887 if ( error )
1888 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001889
David Turnerb1b47622002-05-21 21:17:43 +00001890 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001891 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001892
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001893 goto Exit;
1894 }
David Turner993a8d02002-05-18 12:03:43 +00001895
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001896 /* Expect the DWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001897 if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001898 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001899 if ( !( p->flags & _BDF_ENCODING ) )
1900 goto Missing_Encoding;
1901
David Turner68df4f72005-03-15 18:18:57 +00001902 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001903 if ( error )
1904 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001905
David Turnerb1b47622002-05-21 21:17:43 +00001906 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001907
1908 if ( !( p->flags & _BDF_SWIDTH ) )
1909 {
1910 /* Missing SWIDTH field. Emit an auto correction message and set */
1911 /* the scalable width from the device width. */
1912 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1913
Werner Lemberg02d4d592002-05-28 22:38:05 +00001914 glyph->swidth = (unsigned short)FT_MulDiv(
1915 glyph->dwidth, 72000L,
1916 (FT_Long)( font->point_size *
1917 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001918 }
1919
1920 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001921 goto Exit;
1922 }
David Turner993a8d02002-05-18 12:03:43 +00001923
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001924 /* Expect the BBX field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001925 if ( _bdf_strncmp( line, "BBX", 3 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001926 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001927 if ( !( p->flags & _BDF_ENCODING ) )
1928 goto Missing_Encoding;
1929
David Turner68df4f72005-03-15 18:18:57 +00001930 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001931 if ( error )
1932 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001933
Werner Lembergb13945a2015-02-22 09:15:47 +01001934 glyph->bbx.width = _bdf_atous( p->list.field[1], 0, 10 );
1935 glyph->bbx.height = _bdf_atous( p->list.field[2], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001936 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1937 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1938
1939 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001940 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1941 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001942
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001943 /* Determine the overall font bounding box as the characters are */
1944 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001945 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1946 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001947
David Turnerb1b47622002-05-21 21:17:43 +00001948 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001949
Werner Lembergdfa46192004-03-05 09:26:24 +00001950 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1951 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1952 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001953
1954 if ( !( p->flags & _BDF_DWIDTH ) )
1955 {
1956 /* Missing DWIDTH field. Emit an auto correction message and set */
1957 /* the device width to the glyph width. */
1958 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1959 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001960 }
1961
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001962 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1963 /* value if necessary. */
1964 if ( p->opts->correct_metrics != 0 )
1965 {
1966 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001967 unsigned short sw = (unsigned short)FT_MulDiv(
1968 glyph->dwidth, 72000L,
1969 (FT_Long)( font->point_size *
1970 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001971
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001972
1973 if ( sw != glyph->swidth )
1974 {
1975 glyph->swidth = sw;
1976
1977 if ( p->glyph_enc == -1 )
1978 _bdf_set_glyph_modified( font->umod,
1979 font->unencoded_used - 1 );
1980 else
1981 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1982
1983 p->flags |= _BDF_SWIDTH_ADJ;
1984 font->modified = 1;
1985 }
David Turner993a8d02002-05-18 12:03:43 +00001986 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001987
David Turner993a8d02002-05-18 12:03:43 +00001988 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001989 goto Exit;
1990 }
David Turner993a8d02002-05-18 12:03:43 +00001991
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001992 /* And finally, gather up the bitmap. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001993 if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001994 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001995 unsigned long bitmap_size;
1996
1997
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001998 if ( !( p->flags & _BDF_BBX ) )
1999 {
2000 /* Missing BBX field. */
2001 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002002 error = FT_THROW( Missing_Bbx_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002003 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002004 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002005
2006 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002007 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00002008
2009 bitmap_size = glyph->bpr * glyph->bbx.height;
Werner Lembergc4cad302012-03-08 20:11:37 +01002010 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
Werner Lemberg26170df2006-03-26 07:19:07 +00002011 {
2012 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002013 error = FT_THROW( Bbx_Too_Big );
Werner Lemberg26170df2006-03-26 07:19:07 +00002014 goto Exit;
2015 }
2016 else
2017 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002018
2019 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
2020 goto Exit;
2021
2022 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00002023 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002024
2025 goto Exit;
2026 }
2027
Werner Lemberge01406b2011-11-25 09:44:28 +01002028 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002029 error = FT_THROW( Invalid_File_Format );
Werner Lemberg4086fb72012-03-01 08:55:40 +01002030 goto Exit;
2031
2032 Missing_Encoding:
2033 /* Missing ENCODING field. */
2034 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002035 error = FT_THROW( Missing_Encoding_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002036
2037 Exit:
Werner Lembergf4c94d42010-06-19 16:08:31 +02002038 if ( error && ( p->flags & _BDF_GLYPH ) )
2039 FT_FREE( p->glyph_name );
2040
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002041 return error;
David Turner993a8d02002-05-18 12:03:43 +00002042 }
2043
David Turner993a8d02002-05-18 12:03:43 +00002044
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002045 /* Load the font properties. */
2046 static FT_Error
2047 _bdf_parse_properties( char* line,
2048 unsigned long linelen,
2049 unsigned long lineno,
2050 void* call_data,
2051 void* client_data )
2052 {
2053 unsigned long vlen;
2054 _bdf_line_func_t* next;
2055 _bdf_parse_t* p;
2056 char* name;
2057 char* value;
2058 char nbuf[128];
Werner Lemberge3c93012013-03-14 11:21:17 +01002059 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00002060
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002061 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00002062
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002063
2064 next = (_bdf_line_func_t *)call_data;
2065 p = (_bdf_parse_t *) client_data;
2066
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002067 /* Check for the end of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002068 if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002069 {
2070 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
2071 /* encountered yet, then make sure they are added as properties and */
2072 /* make sure they are set from the font bounding box info. */
2073 /* */
2074 /* This is *always* done regardless of the options, because X11 */
2075 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00002076 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002077 {
2078 p->font->font_ascent = p->font->bbx.ascent;
2079 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002080 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2081 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002082 if ( error )
2083 goto Exit;
2084
2085 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2086 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002087 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002088
Werner Lemberg428c2e42003-04-25 05:35:04 +00002089 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002090 {
2091 p->font->font_descent = p->font->bbx.descent;
2092 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002093 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2094 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002095 if ( error )
2096 goto Exit;
2097
2098 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2099 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002100 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002101
David Turner993a8d02002-05-18 12:03:43 +00002102 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002103 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00002104
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002105 goto Exit;
2106 }
David Turner993a8d02002-05-18 12:03:43 +00002107
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002108 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002109 if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002110 goto Exit;
2111
2112 /* Handle COMMENT fields and properties in a special way to preserve */
2113 /* the spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002114 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002115 {
David Turner993a8d02002-05-18 12:03:43 +00002116 name = value = line;
2117 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002118 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00002119 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01002120 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002121 if ( error )
2122 goto Exit;
2123 }
2124 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
2125 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002126 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002127 if ( error )
2128 goto Exit;
2129 }
2130 else
2131 {
David Turner68df4f72005-03-15 18:18:57 +00002132 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002133 if ( error )
2134 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002135 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002136
David Turner68df4f72005-03-15 18:18:57 +00002137 _bdf_list_shift( &p->list, 1 );
2138 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002139
Werner Lemberge01406b2011-11-25 09:44:28 +01002140 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002141 if ( error )
2142 goto Exit;
2143 }
2144
2145 Exit:
2146 return error;
David Turner993a8d02002-05-18 12:03:43 +00002147 }
2148
David Turner993a8d02002-05-18 12:03:43 +00002149
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002150 /* Load the font header. */
2151 static FT_Error
2152 _bdf_parse_start( char* line,
2153 unsigned long linelen,
2154 unsigned long lineno,
2155 void* call_data,
2156 void* client_data )
2157 {
2158 unsigned long slen;
2159 _bdf_line_func_t* next;
2160 _bdf_parse_t* p;
2161 bdf_font_t* font;
2162 char *s;
David Turner993a8d02002-05-18 12:03:43 +00002163
David Turnerd490e372002-05-28 23:40:37 +00002164 FT_Memory memory = NULL;
Werner Lemberge3c93012013-03-14 11:21:17 +01002165 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002166
2167 FT_UNUSED( lineno ); /* only used in debug mode */
2168
2169
2170 next = (_bdf_line_func_t *)call_data;
2171 p = (_bdf_parse_t *) client_data;
2172
2173 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00002174 memory = p->font->memory;
2175
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002176 /* Check for a comment. This is done to handle those fonts that have */
2177 /* comments before the STARTFONT line for some reason. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002178 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002179 {
2180 if ( p->opts->keep_comments != 0 && p->font != 0 )
2181 {
2182 linelen -= 7;
2183
2184 s = line + 7;
2185 if ( *s != 0 )
2186 {
2187 s++;
2188 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002189 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002190
2191 error = _bdf_add_comment( p->font, s, linelen );
2192 if ( error )
2193 goto Exit;
2194 /* here font is not defined! */
2195 }
2196
2197 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002198 }
2199
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002200 if ( !( p->flags & _BDF_START ) )
2201 {
2202 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002203
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002204 if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002205 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01002206 /* we don't emit an error message since this code gets */
2207 /* explicitly caught one level higher */
Werner Lemberg059bc332013-03-14 10:27:35 +01002208 error = FT_THROW( Missing_Startfont_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002209 goto Exit;
2210 }
David Turner993a8d02002-05-18 12:03:43 +00002211
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002212 p->flags = _BDF_START;
2213 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002214
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002215 if ( FT_NEW( font ) )
2216 goto Exit;
2217 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002218
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002219 font->memory = p->memory;
2220 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002221
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002222 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09002223 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002224 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002225
David Turner993a8d02002-05-18 12:03:43 +00002226
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002227 error = hash_init( &(font->proptbl), memory );
2228 if ( error )
2229 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002230 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002231 i < _num_bdf_properties; i++, prop++ )
2232 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09002233 error = hash_insert( prop->name, i,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002234 &(font->proptbl), memory );
2235 if ( error )
2236 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002237 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002238 }
2239
2240 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2241 goto Exit;
2242 error = hash_init( (hashtable *)p->font->internal,memory );
2243 if ( error )
2244 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002245 p->font->spacing = p->opts->font_spacing;
2246 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002247
2248 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002249 }
2250
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002251 /* Check for the start of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002252 if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002253 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002254 if ( !( p->flags & _BDF_FONT_BBX ) )
Werner Lembergfb690292010-06-23 10:00:52 +02002255 {
2256 /* Missing the FONTBOUNDINGBOX field. */
2257 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002258 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergfb690292010-06-23 10:00:52 +02002259 goto Exit;
2260 }
2261
David Turner68df4f72005-03-15 18:18:57 +00002262 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002263 if ( error )
2264 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00002265 /* at this point, `p->font' can't be NULL */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002266 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2267
2268 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
Werner Lemberg9b6b5752012-12-15 01:34:41 +01002269 {
2270 p->font->props_size = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002271 goto Exit;
Werner Lemberg9b6b5752012-12-15 01:34:41 +01002272 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002273
2274 p->flags |= _BDF_PROPS;
2275 *next = _bdf_parse_properties;
2276
2277 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002278 }
2279
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002280 /* Check for the FONTBOUNDINGBOX field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002281 if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002282 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002283 if ( !( p->flags & _BDF_SIZE ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002284 {
2285 /* Missing the SIZE field. */
2286 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002287 error = FT_THROW( Missing_Size_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002288 goto Exit;
2289 }
2290
David Turner68df4f72005-03-15 18:18:57 +00002291 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002292 if ( error )
2293 goto Exit;
2294
Werner Lembergb13945a2015-02-22 09:15:47 +01002295 p->font->bbx.width = _bdf_atous( p->list.field[1], 0, 10 );
2296 p->font->bbx.height = _bdf_atous( p->list.field[2], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002297
2298 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2299 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2300
David Turnerd490e372002-05-28 23:40:37 +00002301 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002302 p->font->bbx.y_offset );
2303
2304 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002305
2306 p->flags |= _BDF_FONT_BBX;
2307
2308 goto Exit;
2309 }
2310
2311 /* The next thing to check for is the FONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002312 if ( _bdf_strncmp( line, "FONT", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002313 {
David Turner68df4f72005-03-15 18:18:57 +00002314 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002315 if ( error )
2316 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002317 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002318
David Turner68df4f72005-03-15 18:18:57 +00002319 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002320
2321 if ( !s )
2322 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002323 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002324 error = FT_THROW( Invalid_File_Format );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002325 goto Exit;
2326 }
2327
Werner Lembergfb690292010-06-23 10:00:52 +02002328 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2329 FT_FREE( p->font->name );
2330
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002331 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2332 goto Exit;
2333 FT_MEM_COPY( p->font->name, s, slen + 1 );
2334
2335 /* If the font name is an XLFD name, set the spacing to the one in */
2336 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002337 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002338 if ( error )
2339 goto Exit;
2340
2341 p->flags |= _BDF_FONT_NAME;
2342
2343 goto Exit;
2344 }
2345
2346 /* Check for the SIZE field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002347 if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002348 {
2349 if ( !( p->flags & _BDF_FONT_NAME ) )
2350 {
2351 /* Missing the FONT field. */
2352 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002353 error = FT_THROW( Missing_Font_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002354 goto Exit;
2355 }
2356
David Turner68df4f72005-03-15 18:18:57 +00002357 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002358 if ( error )
2359 goto Exit;
2360
2361 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2362 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2363 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2364
2365 /* Check for the bits per pixel field. */
2366 if ( p->list.used == 5 )
2367 {
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002368 unsigned short bpp;
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002369
2370
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002371 bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002372
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002373 /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
2374 if ( bpp > 4 )
2375 p->font->bpp = 8;
2376 else if ( bpp > 2 )
2377 p->font->bpp = 4;
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002378 else if ( bpp > 1 )
2379 p->font->bpp = 2;
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002380 else
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002381 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002382
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002383 if ( p->font->bpp != bpp )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002384 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002385 }
2386 else
2387 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002388
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002389 p->flags |= _BDF_SIZE;
2390
2391 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002392 }
2393
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002394 /* Check for the CHARS field -- font properties are optional */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002395 if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002396 {
2397 char nbuf[128];
2398
2399
2400 if ( !( p->flags & _BDF_FONT_BBX ) )
2401 {
2402 /* Missing the FONTBOUNDINGBOX field. */
2403 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002404 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002405 goto Exit;
2406 }
2407
2408 /* Add the two standard X11 properties which are required */
2409 /* for compiling fonts. */
2410 p->font->font_ascent = p->font->bbx.ascent;
2411 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002412 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2413 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002414 if ( error )
2415 goto Exit;
2416 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2417
2418 p->font->font_descent = p->font->bbx.descent;
2419 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002420 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2421 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002422 if ( error )
2423 goto Exit;
2424 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2425
2426 p->font->modified = 1;
2427
2428 *next = _bdf_parse_glyphs;
2429
2430 /* A special return value. */
2431 error = -1;
2432 goto Exit;
2433 }
2434
Werner Lemberge01406b2011-11-25 09:44:28 +01002435 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002436 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002437
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002438 Exit:
2439 return error;
2440 }
David Turner993a8d02002-05-18 12:03:43 +00002441
2442
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002443 /*************************************************************************/
2444 /* */
2445 /* API. */
2446 /* */
2447 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002448
David Turner993a8d02002-05-18 12:03:43 +00002449
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002450 FT_LOCAL_DEF( FT_Error )
2451 bdf_load_font( FT_Stream stream,
2452 FT_Memory extmemory,
2453 bdf_options_t* opts,
2454 bdf_font_t* *font )
2455 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002456 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002457 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002458
Sean McBride7be2a942014-02-08 13:55:38 +01002459 FT_Memory memory = extmemory; /* needed for FT_NEW */
2460 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002461
2462
David Turner68df4f72005-03-15 18:18:57 +00002463 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002464 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002465
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002466 memory = NULL;
2467 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2468 p->minlb = 32767;
Werner Lemberge1ca18d2015-10-17 11:51:27 +02002469 p->size = stream->size;
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002470 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002471
David Turner68df4f72005-03-15 18:18:57 +00002472 _bdf_list_init( &p->list, extmemory );
2473
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002474 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002475 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002476 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002477 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002478
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002479 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002480 {
2481 /* If the font is not proportional, set the font's monowidth */
2482 /* field to the width of the font bounding box. */
David Turner993a8d02002-05-18 12:03:43 +00002483
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002484 if ( p->font->spacing != BDF_PROPORTIONAL )
2485 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002486
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002487 /* If the number of glyphs loaded is not that of the original count, */
2488 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002489 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002490 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002491 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2492 p->font->glyphs_used + p->font->unencoded_used ));
2493 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002494 }
2495
2496 /* Once the font has been loaded, adjust the overall font metrics if */
2497 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002498 if ( p->opts->correct_metrics != 0 &&
2499 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002500 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002501 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002502 {
2503 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002504 p->font->bbx.width, p->maxrb - p->minlb ));
2505 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2506 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002507 }
2508
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002509 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002510 {
2511 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002512 p->font->bbx.x_offset, p->minlb ));
2513 p->font->bbx.x_offset = p->minlb;
2514 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002515 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002516
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002517 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002518 {
2519 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002520 p->font->bbx.ascent, p->maxas ));
2521 p->font->bbx.ascent = p->maxas;
2522 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002523 }
2524
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002525 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002526 {
2527 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002528 p->font->bbx.descent, p->maxds ));
2529 p->font->bbx.descent = p->maxds;
2530 p->font->bbx.y_offset = (short)( -p->maxds );
2531 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002532 }
2533
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002534 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002535 {
2536 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002537 p->font->bbx.height, p->maxas + p->maxds ));
2538 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002539 }
2540
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002541 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002542 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2543 }
David Turner993a8d02002-05-18 12:03:43 +00002544 }
2545
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002546 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002547 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002548 /* The ENDFONT field was never reached or did not exist. */
2549 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002550 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002551 /* Error happened while parsing header. */
2552 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002553 error = FT_THROW( Corrupted_Font_Header );
Bungeman65d89802015-10-15 23:50:16 +02002554 goto Fail;
Werner Lemberge01406b2011-11-25 09:44:28 +01002555 }
2556 else
2557 {
2558 /* Error happened when parsing glyphs. */
2559 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002560 error = FT_THROW( Corrupted_Font_Glyphs );
Bungeman65d89802015-10-15 23:50:16 +02002561 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002562 }
David Turner993a8d02002-05-18 12:03:43 +00002563 }
2564
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002565 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002566 {
2567 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002568 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002569
Werner Lemberg370aea82010-06-08 08:37:11 +02002570 if ( p->font->comments_len > 0 )
2571 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002572 if ( FT_RENEW_ARRAY( p->font->comments,
2573 p->font->comments_len,
2574 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002575 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002576
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002577 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002578 }
David Turner993a8d02002-05-18 12:03:43 +00002579 }
Werner Lemberge3c93012013-03-14 11:21:17 +01002580 else if ( error == FT_Err_Ok )
Werner Lemberg059bc332013-03-14 10:27:35 +01002581 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002582
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002583 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002584
2585 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002586 if ( p )
2587 {
David Turner68df4f72005-03-15 18:18:57 +00002588 _bdf_list_done( &p->list );
2589
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002590 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002591
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002592 FT_FREE( p );
2593 }
2594
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002595 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002596
2597 Fail:
2598 bdf_free_font( p->font );
2599
2600 memory = extmemory;
2601
2602 FT_FREE( p->font );
Werner Lemberg94cacac2015-11-15 04:45:42 +01002603 FT_FREE( p->glyph_name );
Werner Lembergb10e45a2006-06-08 07:32:56 +00002604
2605 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002606 }
David Turner993a8d02002-05-18 12:03:43 +00002607
2608
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002609 FT_LOCAL_DEF( void )
2610 bdf_free_font( bdf_font_t* font )
2611 {
2612 bdf_property_t* prop;
2613 unsigned long i;
2614 bdf_glyph_t* glyphs;
2615 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002616
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002617
2618 if ( font == 0 )
2619 return;
David Turner993a8d02002-05-18 12:03:43 +00002620
2621 memory = font->memory;
2622
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002623 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002624
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002625 /* Free up the internal hash table of property names. */
2626 if ( font->internal )
2627 {
2628 hash_free( (hashtable *)font->internal, memory );
2629 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002630 }
2631
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002632 /* Free up the comment info. */
2633 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002634
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002635 /* Free up the properties. */
2636 for ( i = 0; i < font->props_size; i++ )
2637 {
2638 if ( font->props[i].format == BDF_ATOM )
2639 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002640 }
2641
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002642 FT_FREE( font->props );
2643
2644 /* Free up the character info. */
2645 for ( i = 0, glyphs = font->glyphs;
2646 i < font->glyphs_used; i++, glyphs++ )
2647 {
2648 FT_FREE( glyphs->name );
2649 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002650 }
2651
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002652 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2653 i++, glyphs++ )
2654 {
2655 FT_FREE( glyphs->name );
2656 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002657 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002658
2659 FT_FREE( font->glyphs );
2660 FT_FREE( font->unencoded );
2661
2662 /* Free up the overflow storage if it was used. */
2663 for ( i = 0, glyphs = font->overflow.glyphs;
2664 i < font->overflow.glyphs_used; i++, glyphs++ )
2665 {
2666 FT_FREE( glyphs->name );
2667 FT_FREE( glyphs->bitmap );
2668 }
2669
2670 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002671
2672 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002673 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002674
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002675 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002676 for ( prop = font->user_props, i = 0;
2677 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002678 {
2679 FT_FREE( prop->name );
2680 if ( prop->format == BDF_ATOM )
2681 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002682 }
David Turner993a8d02002-05-18 12:03:43 +00002683
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002684 FT_FREE( font->user_props );
2685
2686 /* FREE( font ); */ /* XXX Fixme */
2687 }
David Turner993a8d02002-05-18 12:03:43 +00002688
2689
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002690 FT_LOCAL_DEF( bdf_property_t * )
2691 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002692 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002693 {
2694 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002695
David Turner993a8d02002-05-18 12:03:43 +00002696
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002697 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002698 return 0;
2699
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002700 hn = hash_lookup( name, (hashtable *)font->internal );
2701
suzuki toshiya704f4d72009-09-13 00:50:14 +09002702 return hn ? ( font->props + hn->data ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002703 }
2704
2705
2706/* END */