blob: 7b40f42ff77c882db48c85b02266655a3fc5bf9a [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 Lemberg4a150132015-11-25 07:53:49 +01001793
1794 /* Reset the initial glyph info. */
1795 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001796 }
1797 else
Werner Lemberg94cacac2015-11-15 04:45:42 +01001798 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001799 /* Free up the glyph name if the unencoded shouldn't be */
1800 /* kept. */
1801 FT_FREE( p->glyph_name );
Werner Lemberg94cacac2015-11-15 04:45:42 +01001802 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001803
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001804 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001805 }
1806
1807 /* Clear the flags that might be added when width and height are */
1808 /* checked for consistency. */
1809 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1810
1811 p->flags |= _BDF_ENCODING;
1812
1813 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001814 }
1815
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001816 /* Point at the glyph being constructed. */
1817 if ( p->glyph_enc == -1 )
1818 glyph = font->unencoded + ( font->unencoded_used - 1 );
1819 else
1820 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001821
Werner Lemberg96ddc672011-06-29 09:15:54 +02001822 /* Check whether a bitmap is being constructed. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001823 if ( p->flags & _BDF_BITMAP )
1824 {
1825 /* If there are more rows than are specified in the glyph metrics, */
1826 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001827 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001828 {
1829 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1830 {
1831 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1832 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001833 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001834 }
1835
1836 goto Exit;
1837 }
1838
1839 /* Only collect the number of nibbles indicated by the glyph */
1840 /* metrics. If there are more columns, they are simply ignored. */
1841 nibbles = glyph->bpr << 1;
1842 bp = glyph->bitmap + p->row * glyph->bpr;
1843
David Turnerb698eed2006-02-23 14:50:13 +00001844 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001845 {
1846 c = line[i];
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001847 if ( !sbitset( hdigits, c ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001848 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001849 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001850 if ( i + 1 < nibbles && ( i & 1 ) )
1851 *++bp = 0;
1852 }
1853
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001854 /* If any line has not enough columns, */
1855 /* indicate they have been padded with zero bits. */
1856 if ( i < nibbles &&
1857 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1858 {
1859 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
1860 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1861 font->modified = 1;
1862 }
1863
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001864 /* Remove possible garbage at the right. */
1865 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001866 if ( glyph->bbx.width )
1867 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001868
1869 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001870 if ( i == nibbles &&
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001871 sbitset( hdigits, line[nibbles] ) &&
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001872 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001873 {
1874 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1875 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1876 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001877 }
1878
1879 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001880 goto Exit;
1881 }
David Turner993a8d02002-05-18 12:03:43 +00001882
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001883 /* Expect the SWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001884 if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001885 {
1886 if ( !( p->flags & _BDF_ENCODING ) )
Werner Lemberg4086fb72012-03-01 08:55:40 +01001887 goto Missing_Encoding;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001888
David Turner68df4f72005-03-15 18:18:57 +00001889 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001890 if ( error )
1891 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001892
David Turnerb1b47622002-05-21 21:17:43 +00001893 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001894 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001895
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001896 goto Exit;
1897 }
David Turner993a8d02002-05-18 12:03:43 +00001898
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001899 /* Expect the DWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001900 if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001901 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001902 if ( !( p->flags & _BDF_ENCODING ) )
1903 goto Missing_Encoding;
1904
David Turner68df4f72005-03-15 18:18:57 +00001905 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001906 if ( error )
1907 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001908
David Turnerb1b47622002-05-21 21:17:43 +00001909 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001910
1911 if ( !( p->flags & _BDF_SWIDTH ) )
1912 {
1913 /* Missing SWIDTH field. Emit an auto correction message and set */
1914 /* the scalable width from the device width. */
1915 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1916
Werner Lemberg02d4d592002-05-28 22:38:05 +00001917 glyph->swidth = (unsigned short)FT_MulDiv(
1918 glyph->dwidth, 72000L,
1919 (FT_Long)( font->point_size *
1920 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001921 }
1922
1923 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001924 goto Exit;
1925 }
David Turner993a8d02002-05-18 12:03:43 +00001926
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001927 /* Expect the BBX field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001928 if ( _bdf_strncmp( line, "BBX", 3 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001929 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001930 if ( !( p->flags & _BDF_ENCODING ) )
1931 goto Missing_Encoding;
1932
David Turner68df4f72005-03-15 18:18:57 +00001933 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001934 if ( error )
1935 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001936
Werner Lembergb13945a2015-02-22 09:15:47 +01001937 glyph->bbx.width = _bdf_atous( p->list.field[1], 0, 10 );
1938 glyph->bbx.height = _bdf_atous( p->list.field[2], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001939 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1940 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1941
1942 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001943 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1944 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001945
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001946 /* Determine the overall font bounding box as the characters are */
1947 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001948 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1949 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001950
David Turnerb1b47622002-05-21 21:17:43 +00001951 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001952
Werner Lembergdfa46192004-03-05 09:26:24 +00001953 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1954 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1955 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001956
1957 if ( !( p->flags & _BDF_DWIDTH ) )
1958 {
1959 /* Missing DWIDTH field. Emit an auto correction message and set */
1960 /* the device width to the glyph width. */
1961 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1962 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001963 }
1964
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001965 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1966 /* value if necessary. */
1967 if ( p->opts->correct_metrics != 0 )
1968 {
1969 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001970 unsigned short sw = (unsigned short)FT_MulDiv(
1971 glyph->dwidth, 72000L,
1972 (FT_Long)( font->point_size *
1973 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001974
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001975
1976 if ( sw != glyph->swidth )
1977 {
1978 glyph->swidth = sw;
1979
1980 if ( p->glyph_enc == -1 )
1981 _bdf_set_glyph_modified( font->umod,
1982 font->unencoded_used - 1 );
1983 else
1984 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1985
1986 p->flags |= _BDF_SWIDTH_ADJ;
1987 font->modified = 1;
1988 }
David Turner993a8d02002-05-18 12:03:43 +00001989 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001990
David Turner993a8d02002-05-18 12:03:43 +00001991 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001992 goto Exit;
1993 }
David Turner993a8d02002-05-18 12:03:43 +00001994
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001995 /* And finally, gather up the bitmap. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001996 if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001997 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001998 unsigned long bitmap_size;
1999
2000
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002001 if ( !( p->flags & _BDF_BBX ) )
2002 {
2003 /* Missing BBX field. */
2004 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002005 error = FT_THROW( Missing_Bbx_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002006 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002007 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002008
2009 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002010 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00002011
2012 bitmap_size = glyph->bpr * glyph->bbx.height;
Werner Lembergc4cad302012-03-08 20:11:37 +01002013 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
Werner Lemberg26170df2006-03-26 07:19:07 +00002014 {
2015 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002016 error = FT_THROW( Bbx_Too_Big );
Werner Lemberg26170df2006-03-26 07:19:07 +00002017 goto Exit;
2018 }
2019 else
2020 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002021
2022 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
2023 goto Exit;
2024
2025 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00002026 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002027
2028 goto Exit;
2029 }
2030
Werner Lemberge01406b2011-11-25 09:44:28 +01002031 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002032 error = FT_THROW( Invalid_File_Format );
Werner Lemberg4086fb72012-03-01 08:55:40 +01002033 goto Exit;
2034
2035 Missing_Encoding:
2036 /* Missing ENCODING field. */
2037 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002038 error = FT_THROW( Missing_Encoding_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002039
2040 Exit:
Werner Lembergf4c94d42010-06-19 16:08:31 +02002041 if ( error && ( p->flags & _BDF_GLYPH ) )
2042 FT_FREE( p->glyph_name );
2043
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002044 return error;
David Turner993a8d02002-05-18 12:03:43 +00002045 }
2046
David Turner993a8d02002-05-18 12:03:43 +00002047
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002048 /* Load the font properties. */
2049 static FT_Error
2050 _bdf_parse_properties( char* line,
2051 unsigned long linelen,
2052 unsigned long lineno,
2053 void* call_data,
2054 void* client_data )
2055 {
2056 unsigned long vlen;
2057 _bdf_line_func_t* next;
2058 _bdf_parse_t* p;
2059 char* name;
2060 char* value;
2061 char nbuf[128];
Werner Lemberge3c93012013-03-14 11:21:17 +01002062 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00002063
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002064 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00002065
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002066
2067 next = (_bdf_line_func_t *)call_data;
2068 p = (_bdf_parse_t *) client_data;
2069
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002070 /* Check for the end of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002071 if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002072 {
2073 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
2074 /* encountered yet, then make sure they are added as properties and */
2075 /* make sure they are set from the font bounding box info. */
2076 /* */
2077 /* This is *always* done regardless of the options, because X11 */
2078 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00002079 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002080 {
2081 p->font->font_ascent = p->font->bbx.ascent;
2082 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002083 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2084 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002085 if ( error )
2086 goto Exit;
2087
2088 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2089 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002090 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002091
Werner Lemberg428c2e42003-04-25 05:35:04 +00002092 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002093 {
2094 p->font->font_descent = p->font->bbx.descent;
2095 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002096 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2097 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002098 if ( error )
2099 goto Exit;
2100
2101 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2102 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002103 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002104
David Turner993a8d02002-05-18 12:03:43 +00002105 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002106 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00002107
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002108 goto Exit;
2109 }
David Turner993a8d02002-05-18 12:03:43 +00002110
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002111 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002112 if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002113 goto Exit;
2114
2115 /* Handle COMMENT fields and properties in a special way to preserve */
2116 /* the spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002117 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002118 {
David Turner993a8d02002-05-18 12:03:43 +00002119 name = value = line;
2120 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002121 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00002122 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01002123 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002124 if ( error )
2125 goto Exit;
2126 }
2127 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
2128 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002129 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002130 if ( error )
2131 goto Exit;
2132 }
2133 else
2134 {
David Turner68df4f72005-03-15 18:18:57 +00002135 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002136 if ( error )
2137 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002138 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002139
David Turner68df4f72005-03-15 18:18:57 +00002140 _bdf_list_shift( &p->list, 1 );
2141 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002142
Werner Lemberge01406b2011-11-25 09:44:28 +01002143 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002144 if ( error )
2145 goto Exit;
2146 }
2147
2148 Exit:
2149 return error;
David Turner993a8d02002-05-18 12:03:43 +00002150 }
2151
David Turner993a8d02002-05-18 12:03:43 +00002152
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002153 /* Load the font header. */
2154 static FT_Error
2155 _bdf_parse_start( char* line,
2156 unsigned long linelen,
2157 unsigned long lineno,
2158 void* call_data,
2159 void* client_data )
2160 {
2161 unsigned long slen;
2162 _bdf_line_func_t* next;
2163 _bdf_parse_t* p;
2164 bdf_font_t* font;
2165 char *s;
David Turner993a8d02002-05-18 12:03:43 +00002166
David Turnerd490e372002-05-28 23:40:37 +00002167 FT_Memory memory = NULL;
Werner Lemberge3c93012013-03-14 11:21:17 +01002168 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002169
2170 FT_UNUSED( lineno ); /* only used in debug mode */
2171
2172
2173 next = (_bdf_line_func_t *)call_data;
2174 p = (_bdf_parse_t *) client_data;
2175
2176 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00002177 memory = p->font->memory;
2178
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002179 /* Check for a comment. This is done to handle those fonts that have */
2180 /* comments before the STARTFONT line for some reason. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002181 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002182 {
2183 if ( p->opts->keep_comments != 0 && p->font != 0 )
2184 {
2185 linelen -= 7;
2186
2187 s = line + 7;
2188 if ( *s != 0 )
2189 {
2190 s++;
2191 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002192 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002193
2194 error = _bdf_add_comment( p->font, s, linelen );
2195 if ( error )
2196 goto Exit;
2197 /* here font is not defined! */
2198 }
2199
2200 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002201 }
2202
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002203 if ( !( p->flags & _BDF_START ) )
2204 {
2205 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002206
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002207 if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002208 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01002209 /* we don't emit an error message since this code gets */
2210 /* explicitly caught one level higher */
Werner Lemberg059bc332013-03-14 10:27:35 +01002211 error = FT_THROW( Missing_Startfont_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002212 goto Exit;
2213 }
David Turner993a8d02002-05-18 12:03:43 +00002214
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002215 p->flags = _BDF_START;
2216 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002217
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002218 if ( FT_NEW( font ) )
2219 goto Exit;
2220 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002221
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002222 font->memory = p->memory;
2223 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002224
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002225 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09002226 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002227 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002228
David Turner993a8d02002-05-18 12:03:43 +00002229
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002230 error = hash_init( &(font->proptbl), memory );
2231 if ( error )
2232 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002233 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002234 i < _num_bdf_properties; i++, prop++ )
2235 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09002236 error = hash_insert( prop->name, i,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002237 &(font->proptbl), memory );
2238 if ( error )
2239 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002240 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002241 }
2242
2243 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2244 goto Exit;
2245 error = hash_init( (hashtable *)p->font->internal,memory );
2246 if ( error )
2247 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002248 p->font->spacing = p->opts->font_spacing;
2249 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002250
2251 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002252 }
2253
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002254 /* Check for the start of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002255 if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002256 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002257 if ( !( p->flags & _BDF_FONT_BBX ) )
Werner Lembergfb690292010-06-23 10:00:52 +02002258 {
2259 /* Missing the FONTBOUNDINGBOX field. */
2260 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002261 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergfb690292010-06-23 10:00:52 +02002262 goto Exit;
2263 }
2264
David Turner68df4f72005-03-15 18:18:57 +00002265 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002266 if ( error )
2267 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00002268 /* at this point, `p->font' can't be NULL */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002269 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2270
2271 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
Werner Lemberg9b6b5752012-12-15 01:34:41 +01002272 {
2273 p->font->props_size = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002274 goto Exit;
Werner Lemberg9b6b5752012-12-15 01:34:41 +01002275 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002276
2277 p->flags |= _BDF_PROPS;
2278 *next = _bdf_parse_properties;
2279
2280 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002281 }
2282
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002283 /* Check for the FONTBOUNDINGBOX field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002284 if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002285 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002286 if ( !( p->flags & _BDF_SIZE ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002287 {
2288 /* Missing the SIZE field. */
2289 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002290 error = FT_THROW( Missing_Size_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002291 goto Exit;
2292 }
2293
David Turner68df4f72005-03-15 18:18:57 +00002294 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002295 if ( error )
2296 goto Exit;
2297
Werner Lembergb13945a2015-02-22 09:15:47 +01002298 p->font->bbx.width = _bdf_atous( p->list.field[1], 0, 10 );
2299 p->font->bbx.height = _bdf_atous( p->list.field[2], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002300
2301 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2302 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2303
David Turnerd490e372002-05-28 23:40:37 +00002304 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002305 p->font->bbx.y_offset );
2306
2307 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002308
2309 p->flags |= _BDF_FONT_BBX;
2310
2311 goto Exit;
2312 }
2313
2314 /* The next thing to check for is the FONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002315 if ( _bdf_strncmp( line, "FONT", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002316 {
David Turner68df4f72005-03-15 18:18:57 +00002317 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002318 if ( error )
2319 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002320 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002321
David Turner68df4f72005-03-15 18:18:57 +00002322 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002323
2324 if ( !s )
2325 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002326 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002327 error = FT_THROW( Invalid_File_Format );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002328 goto Exit;
2329 }
2330
Werner Lembergfb690292010-06-23 10:00:52 +02002331 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2332 FT_FREE( p->font->name );
2333
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002334 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2335 goto Exit;
2336 FT_MEM_COPY( p->font->name, s, slen + 1 );
2337
2338 /* If the font name is an XLFD name, set the spacing to the one in */
2339 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002340 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002341 if ( error )
2342 goto Exit;
2343
2344 p->flags |= _BDF_FONT_NAME;
2345
2346 goto Exit;
2347 }
2348
2349 /* Check for the SIZE field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002350 if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002351 {
2352 if ( !( p->flags & _BDF_FONT_NAME ) )
2353 {
2354 /* Missing the FONT field. */
2355 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002356 error = FT_THROW( Missing_Font_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002357 goto Exit;
2358 }
2359
David Turner68df4f72005-03-15 18:18:57 +00002360 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002361 if ( error )
2362 goto Exit;
2363
2364 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2365 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2366 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2367
2368 /* Check for the bits per pixel field. */
2369 if ( p->list.used == 5 )
2370 {
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002371 unsigned short bpp;
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002372
2373
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002374 bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002375
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002376 /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
2377 if ( bpp > 4 )
2378 p->font->bpp = 8;
2379 else if ( bpp > 2 )
2380 p->font->bpp = 4;
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002381 else if ( bpp > 1 )
2382 p->font->bpp = 2;
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002383 else
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002384 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002385
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002386 if ( p->font->bpp != bpp )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002387 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002388 }
2389 else
2390 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002391
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002392 p->flags |= _BDF_SIZE;
2393
2394 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002395 }
2396
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002397 /* Check for the CHARS field -- font properties are optional */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002398 if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002399 {
2400 char nbuf[128];
2401
2402
2403 if ( !( p->flags & _BDF_FONT_BBX ) )
2404 {
2405 /* Missing the FONTBOUNDINGBOX field. */
2406 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002407 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002408 goto Exit;
2409 }
2410
2411 /* Add the two standard X11 properties which are required */
2412 /* for compiling fonts. */
2413 p->font->font_ascent = p->font->bbx.ascent;
2414 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002415 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2416 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002417 if ( error )
2418 goto Exit;
2419 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2420
2421 p->font->font_descent = p->font->bbx.descent;
2422 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002423 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2424 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002425 if ( error )
2426 goto Exit;
2427 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2428
2429 p->font->modified = 1;
2430
2431 *next = _bdf_parse_glyphs;
2432
2433 /* A special return value. */
2434 error = -1;
2435 goto Exit;
2436 }
2437
Werner Lemberge01406b2011-11-25 09:44:28 +01002438 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002439 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002440
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002441 Exit:
2442 return error;
2443 }
David Turner993a8d02002-05-18 12:03:43 +00002444
2445
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002446 /*************************************************************************/
2447 /* */
2448 /* API. */
2449 /* */
2450 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002451
David Turner993a8d02002-05-18 12:03:43 +00002452
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002453 FT_LOCAL_DEF( FT_Error )
2454 bdf_load_font( FT_Stream stream,
2455 FT_Memory extmemory,
2456 bdf_options_t* opts,
2457 bdf_font_t* *font )
2458 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002459 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002460 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002461
Sean McBride7be2a942014-02-08 13:55:38 +01002462 FT_Memory memory = extmemory; /* needed for FT_NEW */
2463 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002464
2465
David Turner68df4f72005-03-15 18:18:57 +00002466 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002467 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002468
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002469 memory = NULL;
2470 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2471 p->minlb = 32767;
Werner Lemberge1ca18d2015-10-17 11:51:27 +02002472 p->size = stream->size;
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002473 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002474
David Turner68df4f72005-03-15 18:18:57 +00002475 _bdf_list_init( &p->list, extmemory );
2476
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002477 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002478 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002479 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002480 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002481
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002482 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002483 {
2484 /* If the font is not proportional, set the font's monowidth */
2485 /* field to the width of the font bounding box. */
David Turner993a8d02002-05-18 12:03:43 +00002486
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002487 if ( p->font->spacing != BDF_PROPORTIONAL )
2488 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002489
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002490 /* If the number of glyphs loaded is not that of the original count, */
2491 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002492 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002493 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002494 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2495 p->font->glyphs_used + p->font->unencoded_used ));
2496 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002497 }
2498
2499 /* Once the font has been loaded, adjust the overall font metrics if */
2500 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002501 if ( p->opts->correct_metrics != 0 &&
2502 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002503 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002504 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002505 {
2506 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002507 p->font->bbx.width, p->maxrb - p->minlb ));
2508 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2509 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002510 }
2511
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002512 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002513 {
2514 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002515 p->font->bbx.x_offset, p->minlb ));
2516 p->font->bbx.x_offset = p->minlb;
2517 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002518 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002519
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002520 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002521 {
2522 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002523 p->font->bbx.ascent, p->maxas ));
2524 p->font->bbx.ascent = p->maxas;
2525 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002526 }
2527
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002528 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002529 {
2530 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002531 p->font->bbx.descent, p->maxds ));
2532 p->font->bbx.descent = p->maxds;
2533 p->font->bbx.y_offset = (short)( -p->maxds );
2534 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002535 }
2536
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002537 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002538 {
2539 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002540 p->font->bbx.height, p->maxas + p->maxds ));
2541 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002542 }
2543
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002544 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002545 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2546 }
David Turner993a8d02002-05-18 12:03:43 +00002547 }
2548
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002549 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002550 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002551 /* The ENDFONT field was never reached or did not exist. */
2552 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002553 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002554 /* Error happened while parsing header. */
2555 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002556 error = FT_THROW( Corrupted_Font_Header );
Bungeman65d89802015-10-15 23:50:16 +02002557 goto Fail;
Werner Lemberge01406b2011-11-25 09:44:28 +01002558 }
2559 else
2560 {
2561 /* Error happened when parsing glyphs. */
2562 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002563 error = FT_THROW( Corrupted_Font_Glyphs );
Bungeman65d89802015-10-15 23:50:16 +02002564 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002565 }
David Turner993a8d02002-05-18 12:03:43 +00002566 }
2567
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002568 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002569 {
2570 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002571 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002572
Werner Lemberg370aea82010-06-08 08:37:11 +02002573 if ( p->font->comments_len > 0 )
2574 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002575 if ( FT_RENEW_ARRAY( p->font->comments,
2576 p->font->comments_len,
2577 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002578 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002579
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002580 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002581 }
David Turner993a8d02002-05-18 12:03:43 +00002582 }
Werner Lemberge3c93012013-03-14 11:21:17 +01002583 else if ( error == FT_Err_Ok )
Werner Lemberg059bc332013-03-14 10:27:35 +01002584 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002585
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002586 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002587
2588 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002589 if ( p )
2590 {
David Turner68df4f72005-03-15 18:18:57 +00002591 _bdf_list_done( &p->list );
2592
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002593 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002594
Werner Lemberg4a150132015-11-25 07:53:49 +01002595 FT_FREE( p->glyph_name );
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002596 FT_FREE( p );
2597 }
2598
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002599 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002600
2601 Fail:
2602 bdf_free_font( p->font );
2603
2604 memory = extmemory;
2605
2606 FT_FREE( p->font );
2607
2608 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002609 }
David Turner993a8d02002-05-18 12:03:43 +00002610
2611
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002612 FT_LOCAL_DEF( void )
2613 bdf_free_font( bdf_font_t* font )
2614 {
2615 bdf_property_t* prop;
2616 unsigned long i;
2617 bdf_glyph_t* glyphs;
2618 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002619
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002620
2621 if ( font == 0 )
2622 return;
David Turner993a8d02002-05-18 12:03:43 +00002623
2624 memory = font->memory;
2625
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002626 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002627
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002628 /* Free up the internal hash table of property names. */
2629 if ( font->internal )
2630 {
2631 hash_free( (hashtable *)font->internal, memory );
2632 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002633 }
2634
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002635 /* Free up the comment info. */
2636 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002637
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002638 /* Free up the properties. */
2639 for ( i = 0; i < font->props_size; i++ )
2640 {
2641 if ( font->props[i].format == BDF_ATOM )
2642 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002643 }
2644
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002645 FT_FREE( font->props );
2646
2647 /* Free up the character info. */
2648 for ( i = 0, glyphs = font->glyphs;
2649 i < font->glyphs_used; i++, glyphs++ )
2650 {
2651 FT_FREE( glyphs->name );
2652 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002653 }
2654
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002655 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2656 i++, glyphs++ )
2657 {
2658 FT_FREE( glyphs->name );
2659 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002660 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002661
2662 FT_FREE( font->glyphs );
2663 FT_FREE( font->unencoded );
2664
2665 /* Free up the overflow storage if it was used. */
2666 for ( i = 0, glyphs = font->overflow.glyphs;
2667 i < font->overflow.glyphs_used; i++, glyphs++ )
2668 {
2669 FT_FREE( glyphs->name );
2670 FT_FREE( glyphs->bitmap );
2671 }
2672
2673 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002674
2675 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002676 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002677
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002678 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002679 for ( prop = font->user_props, i = 0;
2680 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002681 {
2682 FT_FREE( prop->name );
2683 if ( prop->format == BDF_ATOM )
2684 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002685 }
David Turner993a8d02002-05-18 12:03:43 +00002686
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002687 FT_FREE( font->user_props );
2688
2689 /* FREE( font ); */ /* XXX Fixme */
2690 }
David Turner993a8d02002-05-18 12:03:43 +00002691
2692
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002693 FT_LOCAL_DEF( bdf_property_t * )
2694 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002695 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002696 {
2697 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002698
David Turner993a8d02002-05-18 12:03:43 +00002699
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002700 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002701 return 0;
2702
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002703 hn = hash_lookup( name, (hashtable *)font->internal );
2704
suzuki toshiya704f4d72009-09-13 00:50:14 +09002705 return hn ? ( font->props + hn->data ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002706 }
2707
2708
2709/* END */