blob: 8655d0ed398f790a7e6b1a04e48d36face1f9e82 [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 Lemberge01406b2011-11-25 09:44:28 +0100204
205 /* Error messages. */
206#define ERRMSG1 "[line %ld] Missing `%s' line.\n"
207#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
208#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
209#define ERRMSG4 "[line %ld] BBX too big.\n"
210#define ERRMSG5 "[line %ld] `%s' value too big.\n"
211#define ERRMSG6 "[line %ld] Input line too long.\n"
212#define ERRMSG7 "[line %ld] Font name too long.\n"
213#define ERRMSG8 "[line %ld] Invalid `%s' value.\n"
214#define ERRMSG9 "[line %ld] Invalid keyword.\n"
215
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +0100216 /* Debug messages. */
217#define DBGMSG1 " [%6ld] %s" /* no \n */
218#define DBGMSG2 " (0x%lX)\n"
219
Werner Lemberge01406b2011-11-25 09:44:28 +0100220
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000221 /*************************************************************************/
222 /* */
223 /* Hash table utilities for the properties. */
224 /* */
225 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +0000226
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000227 /* XXX: Replace this with FreeType's hash functions */
David Turner993a8d02002-05-18 12:03:43 +0000228
David Turner993a8d02002-05-18 12:03:43 +0000229
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000230#define INITIAL_HT_SIZE 241
231
232 typedef void
233 (*hash_free_func)( hashnode node );
234
235 static hashnode*
Werner Lemberg428c2e42003-04-25 05:35:04 +0000236 hash_bucket( const char* key,
237 hashtable* ht )
David Turner993a8d02002-05-18 12:03:43 +0000238 {
Werner Lemberg428c2e42003-04-25 05:35:04 +0000239 const char* kp = key;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000240 unsigned long res = 0;
241 hashnode* bp = ht->table, *ndp;
242
243
244 /* Mocklisp hash function. */
245 while ( *kp )
Werner Lemberg3c374c82015-02-22 09:16:53 +0100246 res = ( res << 5 ) - res + (unsigned long)*kp++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000247
248 ndp = bp + ( res % ht->size );
249 while ( *ndp )
David Turner993a8d02002-05-18 12:03:43 +0000250 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000251 kp = (*ndp)->key;
252 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
253 break;
254 ndp--;
255 if ( ndp < bp )
256 ndp = bp + ( ht->size - 1 );
David Turner993a8d02002-05-18 12:03:43 +0000257 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000258
259 return ndp;
David Turner993a8d02002-05-18 12:03:43 +0000260 }
David Turner993a8d02002-05-18 12:03:43 +0000261
262
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000263 static FT_Error
264 hash_rehash( hashtable* ht,
265 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000266 {
Werner Lemberg3c374c82015-02-22 09:16:53 +0100267 hashnode* obp = ht->table, *bp, *nbp;
268 unsigned int i, sz = ht->size;
269 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000270
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000271
272 ht->size <<= 1;
273 ht->limit = ht->size / 3;
274
275 if ( FT_NEW_ARRAY( ht->table, ht->size ) )
276 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000277
278 for ( i = 0, bp = obp; i < sz; i++, bp++ )
David Turner993a8d02002-05-18 12:03:43 +0000279 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000280 if ( *bp )
281 {
282 nbp = hash_bucket( (*bp)->key, ht );
283 *nbp = *bp;
284 }
David Turner993a8d02002-05-18 12:03:43 +0000285 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000286 FT_FREE( obp );
287
288 Exit:
289 return error;
David Turner993a8d02002-05-18 12:03:43 +0000290 }
David Turner993a8d02002-05-18 12:03:43 +0000291
292
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000293 static FT_Error
294 hash_init( hashtable* ht,
295 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000296 {
Werner Lemberg3c374c82015-02-22 09:16:53 +0100297 unsigned int sz = INITIAL_HT_SIZE;
298 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000299
David Turner993a8d02002-05-18 12:03:43 +0000300
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000301 ht->size = sz;
302 ht->limit = sz / 3;
303 ht->used = 0;
David Turner993a8d02002-05-18 12:03:43 +0000304
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000305 if ( FT_NEW_ARRAY( ht->table, sz ) )
306 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000307
308 Exit:
309 return error;
David Turner993a8d02002-05-18 12:03:43 +0000310 }
David Turner993a8d02002-05-18 12:03:43 +0000311
312
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000313 static void
314 hash_free( hashtable* ht,
315 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000316 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000317 if ( ht != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000318 {
Werner Lemberg3c374c82015-02-22 09:16:53 +0100319 unsigned int i, sz = ht->size;
320 hashnode* bp = ht->table;
David Turner993a8d02002-05-18 12:03:43 +0000321
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000322
323 for ( i = 0; i < sz; i++, bp++ )
324 FT_FREE( *bp );
325
326 FT_FREE( ht->table );
327 }
David Turner993a8d02002-05-18 12:03:43 +0000328 }
329
David Turner993a8d02002-05-18 12:03:43 +0000330
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000331 static FT_Error
332 hash_insert( char* key,
suzuki toshiya704f4d72009-09-13 00:50:14 +0900333 size_t data,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000334 hashtable* ht,
335 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000336 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100337 hashnode nn;
338 hashnode* bp = hash_bucket( key, ht );
Werner Lemberge3c93012013-03-14 11:21:17 +0100339 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000340
341
342 nn = *bp;
343 if ( !nn )
344 {
345 if ( FT_NEW( nn ) )
346 goto Exit;
347 *bp = nn;
348
349 nn->key = key;
350 nn->data = data;
351
352 if ( ht->used >= ht->limit )
353 {
354 error = hash_rehash( ht, memory );
355 if ( error )
356 goto Exit;
357 }
358 ht->used++;
359 }
David Turner993a8d02002-05-18 12:03:43 +0000360 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000361 nn->data = data;
362
363 Exit:
364 return error;
David Turner993a8d02002-05-18 12:03:43 +0000365 }
366
David Turner993a8d02002-05-18 12:03:43 +0000367
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000368 static hashnode
Werner Lemberg428c2e42003-04-25 05:35:04 +0000369 hash_lookup( const char* key,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000370 hashtable* ht )
371 {
372 hashnode *np = hash_bucket( key, ht );
373
374
375 return *np;
376 }
377
378
379 /*************************************************************************/
380 /* */
381 /* Utility types and functions. */
382 /* */
383 /*************************************************************************/
384
385
386 /* Function type for parsing lines of a BDF font. */
387
388 typedef FT_Error
389 (*_bdf_line_func_t)( char* line,
390 unsigned long linelen,
391 unsigned long lineno,
392 void* call_data,
393 void* client_data );
394
395
396 /* List structure for splitting lines into fields. */
397
398 typedef struct _bdf_list_t_
399 {
400 char** field;
401 unsigned long size;
402 unsigned long used;
David Turner68df4f72005-03-15 18:18:57 +0000403 FT_Memory memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000404
405 } _bdf_list_t;
406
407
408 /* Structure used while loading BDF fonts. */
409
410 typedef struct _bdf_parse_t_
411 {
412 unsigned long flags;
413 unsigned long cnt;
414 unsigned long row;
415
416 short minlb;
417 short maxlb;
418 short maxrb;
419 short maxas;
420 short maxds;
421
422 short rbearing;
423
424 char* glyph_name;
425 long glyph_enc;
426
427 bdf_font_t* font;
428 bdf_options_t* opts;
429
Werner Lemberged54e432011-11-27 16:39:53 +0100430 unsigned long have[34816]; /* must be in sync with `nmod' and `umod' */
431 /* arrays from `bdf_font_t' structure */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000432 _bdf_list_t list;
433
434 FT_Memory memory;
435
436 } _bdf_parse_t;
437
438
Werner Lemberga08b2172007-03-28 07:17:17 +0000439#define setsbit( m, cc ) \
440 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
441#define sbitset( m, cc ) \
442 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000443
444
David Turner68df4f72005-03-15 18:18:57 +0000445 static void
446 _bdf_list_init( _bdf_list_t* list,
447 FT_Memory memory )
448 {
Werner Lembergebf55852005-03-16 01:49:54 +0000449 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000450 list->memory = memory;
451 }
452
Werner Lembergebf55852005-03-16 01:49:54 +0000453
David Turner68df4f72005-03-15 18:18:57 +0000454 static void
455 _bdf_list_done( _bdf_list_t* list )
456 {
457 FT_Memory memory = list->memory;
458
Werner Lembergebf55852005-03-16 01:49:54 +0000459
David Turner68df4f72005-03-15 18:18:57 +0000460 if ( memory )
461 {
462 FT_FREE( list->field );
Werner Lembergebf55852005-03-16 01:49:54 +0000463 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000464 }
465 }
466
467
468 static FT_Error
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900469 _bdf_list_ensure( _bdf_list_t* list,
470 unsigned long num_items ) /* same as _bdf_list_t.used */
David Turner68df4f72005-03-15 18:18:57 +0000471 {
Werner Lemberge3c93012013-03-14 11:21:17 +0100472 FT_Error error = FT_Err_Ok;
Werner Lembergebf55852005-03-16 01:49:54 +0000473
David Turner68df4f72005-03-15 18:18:57 +0000474
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900475 if ( num_items > list->size )
David Turner68df4f72005-03-15 18:18:57 +0000476 {
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900477 unsigned long oldsize = list->size; /* same as _bdf_list_t.size */
Werner Lembergcee5d592012-03-01 09:26:03 +0100478 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 5;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900479 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
480 FT_Memory memory = list->memory;
David Turner68df4f72005-03-15 18:18:57 +0000481
Werner Lembergebf55852005-03-16 01:49:54 +0000482
David Turner68df4f72005-03-15 18:18:57 +0000483 if ( oldsize == bigsize )
484 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100485 error = FT_THROW( Out_Of_Memory );
David Turner68df4f72005-03-15 18:18:57 +0000486 goto Exit;
487 }
488 else if ( newsize < oldsize || newsize > bigsize )
489 newsize = bigsize;
490
491 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
492 goto Exit;
493
494 list->size = newsize;
495 }
Werner Lembergebf55852005-03-16 01:49:54 +0000496
David Turner68df4f72005-03-15 18:18:57 +0000497 Exit:
498 return error;
499 }
500
501
502 static void
503 _bdf_list_shift( _bdf_list_t* list,
504 unsigned long n )
505 {
506 unsigned long i, u;
507
508
509 if ( list == 0 || list->used == 0 || n == 0 )
510 return;
511
512 if ( n >= list->used )
513 {
514 list->used = 0;
515 return;
516 }
517
518 for ( u = n, i = 0; u < list->used; i++, u++ )
519 list->field[i] = list->field[u];
520 list->used -= n;
521 }
522
523
Werner Lembergf4c94d42010-06-19 16:08:31 +0200524 /* An empty string for empty fields. */
525
526 static const char empty[1] = { 0 }; /* XXX eliminate this */
527
528
David Turner68df4f72005-03-15 18:18:57 +0000529 static char *
530 _bdf_list_join( _bdf_list_t* list,
531 int c,
532 unsigned long *alen )
533 {
534 unsigned long i, j;
Werner Lembergdc624ca2013-06-04 10:30:48 +0200535 char* dp;
David Turner68df4f72005-03-15 18:18:57 +0000536
537
538 *alen = 0;
539
540 if ( list == 0 || list->used == 0 )
541 return 0;
542
543 dp = list->field[0];
544 for ( i = j = 0; i < list->used; i++ )
545 {
Werner Lembergdc624ca2013-06-04 10:30:48 +0200546 char* fp = list->field[i];
547
548
David Turner68df4f72005-03-15 18:18:57 +0000549 while ( *fp )
550 dp[j++] = *fp++;
551
552 if ( i + 1 < list->used )
553 dp[j++] = (char)c;
554 }
Werner Lembergf4c94d42010-06-19 16:08:31 +0200555 if ( dp != empty )
556 dp[j] = 0;
David Turner68df4f72005-03-15 18:18:57 +0000557
558 *alen = j;
559 return dp;
560 }
561
562
Werner Lemberg03242f52012-02-26 06:52:56 +0100563 /* The code below ensures that we have at least 4 + 1 `field' */
564 /* elements in `list' (which are possibly NULL) so that we */
565 /* don't have to check the number of fields in most cases. */
566
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000567 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000568 _bdf_list_split( _bdf_list_t* list,
569 char* separators,
570 char* line,
571 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000572 {
Werner Lemberg3c374c82015-02-22 09:16:53 +0100573 unsigned long final_empty;
574 int mult;
575 char *sp, *ep, *end;
576 char seps[32];
577 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000578
579
580 /* Initialize the list. */
581 list->used = 0;
Werner Lembergd9c16592012-03-01 15:15:00 +0100582 if ( list->size )
583 {
584 list->field[0] = (char*)empty;
585 list->field[1] = (char*)empty;
586 list->field[2] = (char*)empty;
587 list->field[3] = (char*)empty;
Werner Lemberg649c6732012-03-16 21:12:41 +0100588 list->field[4] = (char*)empty;
Werner Lembergd9c16592012-03-01 15:15:00 +0100589 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000590
591 /* If the line is empty, then simply return. */
592 if ( linelen == 0 || line[0] == 0 )
593 goto Exit;
594
595 /* In the original code, if the `separators' parameter is NULL or */
596 /* empty, the list is split into individual bytes. We don't need */
597 /* this, so an error is signaled. */
598 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000599 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100600 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000601 goto Exit;
602 }
603
604 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000605 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000606
607 /* If the very last character of the separator string is a plus, then */
608 /* set the `mult' flag to indicate that multiple separators should be */
609 /* collapsed into one. */
610 for ( mult = 0, sp = separators; sp && *sp; sp++ )
611 {
612 if ( *sp == '+' && *( sp + 1 ) == 0 )
613 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000614 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000615 setsbit( seps, *sp );
616 }
617
618 /* Break the line up into fields. */
619 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
620 sp < end && *sp; )
621 {
622 /* Collect everything that is not a separator. */
623 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
624 ;
625
626 /* Resize the list if necessary. */
627 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000628 {
Werner Lembergebf55852005-03-16 01:49:54 +0000629 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000630 if ( error )
631 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000632 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000633
634 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000635 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000636
637 sp = ep;
638
639 if ( mult )
640 {
641 /* If multiple separators should be collapsed, do it now by */
642 /* setting all the separator characters to 0. */
643 for ( ; *ep && sbitset( seps, *ep ); ep++ )
644 *ep = 0;
645 }
646 else if ( *ep != 0 )
647 /* Don't collapse multiple separators by making them 0, so just */
648 /* make the one encountered 0. */
649 *ep++ = 0;
650
651 final_empty = ( ep > sp && *ep == 0 );
652 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000653 }
654
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000655 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000656 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000657 {
Werner Lembergebf55852005-03-16 01:49:54 +0000658 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000659 if ( error )
660 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000661 }
662
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000663 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000664 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000665
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000666 list->field[list->used] = 0;
667
668 Exit:
669 return error;
David Turner993a8d02002-05-18 12:03:43 +0000670 }
671
David Turner993a8d02002-05-18 12:03:43 +0000672
David Turner68df4f72005-03-15 18:18:57 +0000673#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000674
Werner Lembergebf55852005-03-16 01:49:54 +0000675
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000676 static FT_Error
677 _bdf_readstream( FT_Stream stream,
678 _bdf_line_func_t callback,
679 void* client_data,
680 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000681 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000682 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000683 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900684 int refill, hold, to_skip;
685 ptrdiff_t bytes, start, end, cursor, avail;
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -0400686 char* buf = NULL;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000687 FT_Memory memory = stream->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100688 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000689
David Turner993a8d02002-05-18 12:03:43 +0000690
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000691 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000692 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100693 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000694 goto Exit;
695 }
David Turner993a8d02002-05-18 12:03:43 +0000696
Werner Lembergebf55852005-03-16 01:49:54 +0000697 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000698 buf_size = 1024;
699
700 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000701 goto Exit;
702
Werner Lembergebf55852005-03-16 01:49:54 +0000703 cb = callback;
704 lineno = 1;
705 buf[0] = 0;
706 start = 0;
Werner Lembergebf55852005-03-16 01:49:54 +0000707 avail = 0;
708 cursor = 0;
709 refill = 1;
710 to_skip = NO_SKIP;
711 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000712
David Turner68df4f72005-03-15 18:18:57 +0000713 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000714 {
David Turner68df4f72005-03-15 18:18:57 +0000715 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000716 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +0200717 bytes = (ptrdiff_t)FT_Stream_TryRead(
718 stream, (FT_Byte*)buf + cursor,
Werner Lemberg3c374c82015-02-22 09:16:53 +0100719 buf_size - (unsigned long)cursor );
David Turner68df4f72005-03-15 18:18:57 +0000720 avail = cursor + bytes;
721 cursor = 0;
722 refill = 0;
723 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000724
David Turner68df4f72005-03-15 18:18:57 +0000725 end = start;
726
Werner Lembergebf55852005-03-16 01:49:54 +0000727 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000728 if ( start < avail && buf[start] == to_skip )
729 {
730 start += 1;
731 to_skip = NO_SKIP;
732 continue;
733 }
734
735 /* try to find the end of the line */
736 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
737 end++;
738
Werner Lembergebf55852005-03-16 01:49:54 +0000739 /* if we hit the end of the buffer, try shifting its content */
740 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000741 if ( end >= avail )
742 {
743 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
744 break; /* ignore it then exit */
745
746 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000747 {
Werner Lembergebf55852005-03-16 01:49:54 +0000748 /* this line is definitely too long; try resizing the input */
749 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000750 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000751
Werner Lembergebf55852005-03-16 01:49:54 +0000752
753 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000754 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100755 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +0100756 error = FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +0000757 goto Exit;
758 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000759
Werner Lembergebf55852005-03-16 01:49:54 +0000760 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000761 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
762 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000763
Werner Lemberg3c374c82015-02-22 09:16:53 +0100764 cursor = (ptrdiff_t)buf_size;
David Turner68df4f72005-03-15 18:18:57 +0000765 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000766 }
767 else
768 {
David Turner68df4f72005-03-15 18:18:57 +0000769 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000770
Werner Lemberg04e547b2013-04-03 07:37:56 +0200771 FT_MEM_MOVE( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000772
David Turner68df4f72005-03-15 18:18:57 +0000773 cursor = bytes;
774 avail -= bytes;
775 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000776 }
David Turner68df4f72005-03-15 18:18:57 +0000777 refill = 1;
778 continue;
David Turner993a8d02002-05-18 12:03:43 +0000779 }
David Turner68df4f72005-03-15 18:18:57 +0000780
781 /* Temporarily NUL-terminate the line. */
782 hold = buf[end];
783 buf[end] = 0;
784
Werner Lemberg0098d552014-12-07 11:03:57 +0100785 /* XXX: Use encoding independent value for 0x1A */
786 if ( buf[start] != '#' && buf[start] != 0x1A && end > start )
David Turner68df4f72005-03-15 18:18:57 +0000787 {
Werner Lemberga9f6f852012-12-17 09:08:09 +0100788 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergebf55852005-03-16 01:49:54 +0000789 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200790 /* Redo if we have encountered CHARS without properties. */
791 if ( error == -1 )
Werner Lemberga9f6f852012-12-17 09:08:09 +0100792 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200793 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000794 if ( error )
795 break;
796 }
797
798 lineno += 1;
799 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000800 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000801
802 if ( hold == '\n' )
803 to_skip = '\r';
804 else if ( hold == '\r' )
805 to_skip = '\n';
806 else
807 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000808 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000809
David Turner68df4f72005-03-15 18:18:57 +0000810 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000811
812 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000813 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000814 return error;
David Turner993a8d02002-05-18 12:03:43 +0000815 }
David Turner993a8d02002-05-18 12:03:43 +0000816
817
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000818 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000819
David Turnerb1b47622002-05-21 21:17:43 +0000820 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000821 {
David Turner993a8d02002-05-18 12:03:43 +0000822 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
823 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
824 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, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
Werner Lemberg0098d552014-12-07 11:03:57 +0100827 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000828 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
829 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg0098d552014-12-07 11:03:57 +0100830 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000831 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
832 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000833 };
David Turner993a8d02002-05-18 12:03:43 +0000834
David Turnerb1b47622002-05-21 21:17:43 +0000835 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000836 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100837 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000838 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
839 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
840 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000841 };
David Turner993a8d02002-05-18 12:03:43 +0000842
David Turnerb1b47622002-05-21 21:17:43 +0000843 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000844 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100845 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
David Turner993a8d02002-05-18 12:03:43 +0000846 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
847 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
848 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000849 };
David Turner993a8d02002-05-18 12:03:43 +0000850
David Turnerb1b47622002-05-21 21:17:43 +0000851 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000852 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100853 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
854 0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000855 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
856 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000857 };
David Turner993a8d02002-05-18 12:03:43 +0000858
David Turner993a8d02002-05-18 12:03:43 +0000859
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000860 /* Routine to convert an ASCII string into an unsigned long integer. */
861 static unsigned long
Werner Lemberg3c374c82015-02-22 09:16:53 +0100862 _bdf_atoul( char* s,
863 char** end,
864 unsigned int base )
David Turner993a8d02002-05-18 12:03:43 +0000865 {
David Turnerb1b47622002-05-21 21:17:43 +0000866 unsigned long v;
867 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000868
869
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000870 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000871 return 0;
872
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000873 /* Make sure the radix is something recognizable. Default to 10. */
874 switch ( base )
875 {
876 case 8:
877 dmap = odigits;
878 break;
879 case 16:
880 dmap = hdigits;
881 break;
882 default:
883 base = 10;
884 dmap = ddigits;
885 break;
David Turner993a8d02002-05-18 12:03:43 +0000886 }
887
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000888 /* Check for the special hex prefix. */
889 if ( *s == '0' &&
890 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
891 {
892 base = 16;
893 dmap = hdigits;
894 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000895 }
896
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +0100897 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000898 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000899
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000900 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000901 *end = s;
902
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000903 return v;
904 }
David Turner993a8d02002-05-18 12:03:43 +0000905
David Turner993a8d02002-05-18 12:03:43 +0000906
Werner Lemberg3c374c82015-02-22 09:16:53 +0100907 /* Routine to convert an ASCII string into a signed long integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000908 static long
909 _bdf_atol( char* s,
910 char** end,
911 int base )
912 {
David Turnerb1b47622002-05-21 21:17:43 +0000913 long v, neg;
914 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000915
916
917 if ( s == 0 || *s == 0 )
918 return 0;
919
920 /* Make sure the radix is something recognizable. Default to 10. */
921 switch ( base )
922 {
923 case 8:
924 dmap = odigits;
925 break;
926 case 16:
927 dmap = hdigits;
928 break;
929 default:
930 base = 10;
931 dmap = ddigits;
932 break;
933 }
934
935 /* Check for a minus sign. */
936 neg = 0;
937 if ( *s == '-' )
938 {
939 s++;
940 neg = 1;
941 }
942
943 /* Check for the special hex prefix. */
944 if ( *s == '0' &&
945 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
946 {
947 base = 16;
948 dmap = hdigits;
949 s += 2;
950 }
951
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +0100952 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000953 v = v * base + a2i[(int)*s];
954
955 if ( end != 0 )
956 *end = s;
957
958 return ( !neg ) ? v : -v;
959 }
960
961
Werner Lembergb13945a2015-02-22 09:15:47 +0100962 /* Routine to convert an ASCII string into an unsigned short integer. */
963 static unsigned short
964 _bdf_atous( char* s,
965 char** end,
966 unsigned int base )
967 {
968 unsigned short v;
969 const unsigned char* dmap;
970
971
972 if ( s == 0 || *s == 0 )
973 return 0;
974
975 /* Make sure the radix is something recognizable. Default to 10. */
976 switch ( base )
977 {
978 case 8:
979 dmap = odigits;
980 break;
981 case 16:
982 dmap = hdigits;
983 break;
984 default:
985 base = 10;
986 dmap = ddigits;
987 break;
988 }
989
990 /* Check for the special hex prefix. */
991 if ( *s == '0' &&
992 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
993 {
994 base = 16;
995 dmap = hdigits;
996 s += 2;
997 }
998
999 for ( v = 0; sbitset( dmap, *s ); s++ )
1000 v = (unsigned short)( v * base + a2i[(int)*s] );
1001
1002 if ( end != 0 )
1003 *end = s;
1004
1005 return v;
1006 }
1007
1008
1009 /* Routine to convert an ASCII string into a signed short integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001010 static short
1011 _bdf_atos( char* s,
1012 char** end,
1013 int base )
1014 {
David Turnerb1b47622002-05-21 21:17:43 +00001015 short v, neg;
1016 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001017
1018
1019 if ( s == 0 || *s == 0 )
1020 return 0;
1021
1022 /* Make sure the radix is something recognizable. Default to 10. */
1023 switch ( base )
1024 {
1025 case 8:
1026 dmap = odigits;
1027 break;
1028 case 16:
1029 dmap = hdigits;
1030 break;
1031 default:
1032 base = 10;
1033 dmap = ddigits;
1034 break;
1035 }
1036
1037 /* Check for a minus. */
1038 neg = 0;
1039 if ( *s == '-' )
1040 {
1041 s++;
1042 neg = 1;
1043 }
1044
1045 /* Check for the special hex prefix. */
1046 if ( *s == '0' &&
1047 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
1048 {
1049 base = 16;
1050 dmap = hdigits;
1051 s += 2;
1052 }
1053
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001054 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +00001055 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001056
1057 if ( end != 0 )
1058 *end = s;
1059
Werner Lemberg233302a2002-05-22 05:41:06 +00001060 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001061 }
1062
1063
1064 /* Routine to compare two glyphs by encoding so they can be sorted. */
1065 static int
1066 by_encoding( const void* a,
1067 const void* b )
1068 {
1069 bdf_glyph_t *c1, *c2;
1070
1071
1072 c1 = (bdf_glyph_t *)a;
1073 c2 = (bdf_glyph_t *)b;
1074
1075 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001076 return -1;
David Turner68df4f72005-03-15 18:18:57 +00001077
1078 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001079 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001080
David Turner993a8d02002-05-18 12:03:43 +00001081 return 0;
David Turner993a8d02002-05-18 12:03:43 +00001082 }
1083
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001084
1085 static FT_Error
1086 bdf_create_property( char* name,
1087 int format,
1088 bdf_font_t* font )
1089 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001090 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001091 bdf_property_t* p;
1092 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001093 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001094
1095
Werner Lemberg96ddc672011-06-29 09:15:54 +02001096 /* First check whether the property has */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001097 /* already been added or not. If it has, then */
1098 /* simply ignore it. */
1099 if ( hash_lookup( name, &(font->proptbl) ) )
1100 goto Exit;
1101
David Turner68df4f72005-03-15 18:18:57 +00001102 if ( FT_RENEW_ARRAY( font->user_props,
1103 font->nuser_props,
1104 font->nuser_props + 1 ) )
1105 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001106
1107 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +00001108 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001109
suzuki toshiya704f4d72009-09-13 00:50:14 +09001110 n = ft_strlen( name ) + 1;
1111 if ( n > FT_ULONG_MAX )
Werner Lemberg059bc332013-03-14 10:27:35 +01001112 return FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +00001113
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001114 if ( FT_NEW_ARRAY( p->name, n ) )
1115 goto Exit;
1116
1117 FT_MEM_COPY( (char *)p->name, name, n );
1118
1119 p->format = format;
1120 p->builtin = 0;
1121
1122 n = _num_bdf_properties + font->nuser_props;
1123
suzuki toshiya704f4d72009-09-13 00:50:14 +09001124 error = hash_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001125 if ( error )
1126 goto Exit;
1127
1128 font->nuser_props++;
1129
1130 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001131 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001132 }
David Turner993a8d02002-05-18 12:03:43 +00001133
1134
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001135 FT_LOCAL_DEF( bdf_property_t * )
1136 bdf_get_property( char* name,
1137 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001138 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001139 hashnode hn;
1140 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001141
1142
1143 if ( name == 0 || *name == 0 )
1144 return 0;
1145
1146 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1147 return 0;
1148
suzuki toshiya704f4d72009-09-13 00:50:14 +09001149 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001150 if ( propid >= _num_bdf_properties )
1151 return font->user_props + ( propid - _num_bdf_properties );
1152
Werner Lemberg233302a2002-05-22 05:41:06 +00001153 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001154 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001155
1156
1157 /*************************************************************************/
1158 /* */
1159 /* BDF font file parsing flags and functions. */
1160 /* */
1161 /*************************************************************************/
1162
1163
1164 /* Parse flags. */
1165
Werner Lemberg3c374c82015-02-22 09:16:53 +01001166#define _BDF_START 0x0001U
1167#define _BDF_FONT_NAME 0x0002U
1168#define _BDF_SIZE 0x0004U
1169#define _BDF_FONT_BBX 0x0008U
1170#define _BDF_PROPS 0x0010U
1171#define _BDF_GLYPHS 0x0020U
1172#define _BDF_GLYPH 0x0040U
1173#define _BDF_ENCODING 0x0080U
1174#define _BDF_SWIDTH 0x0100U
1175#define _BDF_DWIDTH 0x0200U
1176#define _BDF_BBX 0x0400U
1177#define _BDF_BITMAP 0x0800U
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001178
Werner Lemberg3c374c82015-02-22 09:16:53 +01001179#define _BDF_SWIDTH_ADJ 0x1000U
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001180
1181#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1182 _BDF_ENCODING | \
1183 _BDF_SWIDTH | \
1184 _BDF_DWIDTH | \
1185 _BDF_BBX | \
1186 _BDF_BITMAP )
1187
Werner Lembergf1c2b912006-01-13 14:53:28 +00001188#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1189#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001190
1191
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001192 static FT_Error
1193 _bdf_add_comment( bdf_font_t* font,
1194 char* comment,
1195 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001196 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001197 char* cp;
1198 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001199 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001200
1201
David Turner68df4f72005-03-15 18:18:57 +00001202 if ( FT_RENEW_ARRAY( font->comments,
1203 font->comments_len,
1204 font->comments_len + len + 1 ) )
1205 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001206
1207 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001208
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001209 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001210 cp[len] = '\n';
1211
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001212 font->comments_len += len + 1;
1213
1214 Exit:
1215 return error;
David Turner993a8d02002-05-18 12:03:43 +00001216 }
1217
David Turner993a8d02002-05-18 12:03:43 +00001218
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001219 /* Set the spacing from the font name if it exists, or set it to the */
1220 /* default specified in the options. */
1221 static FT_Error
1222 _bdf_set_default_spacing( bdf_font_t* font,
Werner Lemberge01406b2011-11-25 09:44:28 +01001223 bdf_options_t* opts,
1224 unsigned long lineno )
David Turner993a8d02002-05-18 12:03:43 +00001225 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001226 size_t len;
1227 char name[256];
1228 _bdf_list_t list;
1229 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001230 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001231
Dave Arnoldc3782492013-06-05 19:57:55 +02001232 FT_UNUSED( lineno ); /* only used in debug mode */
1233
David Turner993a8d02002-05-18 12:03:43 +00001234
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001235 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1236 {
Werner Lemberg059bc332013-03-14 10:27:35 +01001237 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001238 goto Exit;
1239 }
David Turner993a8d02002-05-18 12:03:43 +00001240
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001241 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001242
David Turner68df4f72005-03-15 18:18:57 +00001243 _bdf_list_init( &list, memory );
1244
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001245 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001246
suzuki toshiya704f4d72009-09-13 00:50:14 +09001247 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +00001248 /* Limit ourselves to 256 characters in the font name. */
1249 if ( len >= 256 )
1250 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001251 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001252 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001253 goto Exit;
1254 }
1255
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001256 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001257
Werner Lembergbadf3172013-06-06 09:16:38 +02001258 error = _bdf_list_split( &list, (char *)"-", name, (unsigned long)len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001259 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001260 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001261
1262 if ( list.used == 15 )
1263 {
1264 switch ( list.field[11][0] )
1265 {
1266 case 'C':
1267 case 'c':
1268 font->spacing = BDF_CHARCELL;
1269 break;
1270 case 'M':
1271 case 'm':
1272 font->spacing = BDF_MONOWIDTH;
1273 break;
1274 case 'P':
1275 case 'p':
1276 font->spacing = BDF_PROPORTIONAL;
1277 break;
David Turner993a8d02002-05-18 12:03:43 +00001278 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001279 }
1280
David Turner68df4f72005-03-15 18:18:57 +00001281 Fail:
1282 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001283
1284 Exit:
1285 return error;
David Turner993a8d02002-05-18 12:03:43 +00001286 }
David Turner993a8d02002-05-18 12:03:43 +00001287
1288
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001289 /* Determine whether the property is an atom or not. If it is, then */
1290 /* clean it up so the double quotes are removed if they exist. */
1291 static int
1292 _bdf_is_atom( char* line,
1293 unsigned long linelen,
1294 char** name,
1295 char** value,
1296 bdf_font_t* font )
1297 {
1298 int hold;
1299 char *sp, *ep;
1300 bdf_property_t* p;
1301
David Turner993a8d02002-05-18 12:03:43 +00001302
1303 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001304
1305 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001306 ep++;
1307
1308 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001309 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001310 {
1311 hold = *ep;
1312 *ep = 0;
1313 }
1314
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001315 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001316
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001317 /* Restore the character that was saved before any return can happen. */
1318 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001319 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001320
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001321 /* If the property exists and is not an atom, just return here. */
1322 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001323 return 0;
1324
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001325 /* The property is an atom. Trim all leading and trailing whitespace */
1326 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001327 sp = ep;
1328 ep = line + linelen;
1329
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001330 /* Trim the leading whitespace if it exists. */
Werner Lemberg320d4972012-02-24 18:06:46 +01001331 if ( *sp )
1332 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001333 while ( *sp &&
1334 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001335 sp++;
1336
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001337 /* Trim the leading double quote if it exists. */
1338 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001339 sp++;
1340 *value = sp;
1341
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001342 /* Trim the trailing whitespace if it exists. */
1343 while ( ep > sp &&
1344 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001345 *--ep = 0;
1346
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001347 /* Trim the trailing double quote if it exists. */
1348 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001349 *--ep = 0;
1350
1351 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001352 }
David Turner993a8d02002-05-18 12:03:43 +00001353
1354
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001355 static FT_Error
Werner Lemberge01406b2011-11-25 09:44:28 +01001356 _bdf_add_property( bdf_font_t* font,
1357 char* name,
1358 char* value,
1359 unsigned long lineno )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001360 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001361 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001362 hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001363 bdf_property_t *prop, *fp;
1364 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001365 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001366
Dave Arnoldc3782492013-06-05 19:57:55 +02001367 FT_UNUSED( lineno ); /* only used in debug mode */
1368
David Turner993a8d02002-05-18 12:03:43 +00001369
Werner Lemberg96ddc672011-06-29 09:15:54 +02001370 /* First, check whether the property already exists in the font. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001371 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001372 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001373 /* The property already exists in the font, so simply replace */
1374 /* the value of the property with the current value. */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001375 fp = font->props + hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001376
David Turnerb1b47622002-05-21 21:17:43 +00001377 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001378 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001379 case BDF_ATOM:
1380 /* Delete the current atom if it exists. */
1381 FT_FREE( fp->value.atom );
1382
David Turnerc0f9c4a2007-02-12 14:55:03 +00001383 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001384 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001385 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001386 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001387 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001388 break;
1389
1390 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001391 fp->value.l = _bdf_atol( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001392 break;
1393
1394 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001395 fp->value.ul = _bdf_atoul( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001396 break;
David Turnerd490e372002-05-28 23:40:37 +00001397
David Turnerb1b47622002-05-21 21:17:43 +00001398 default:
1399 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001400 }
David Turnerd490e372002-05-28 23:40:37 +00001401
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001402 goto Exit;
1403 }
1404
1405 /* See whether this property type exists yet or not. */
1406 /* If not, create it. */
1407 hn = hash_lookup( name, &(font->proptbl) );
1408 if ( hn == 0 )
1409 {
1410 error = bdf_create_property( name, BDF_ATOM, font );
1411 if ( error )
1412 goto Exit;
1413 hn = hash_lookup( name, &(font->proptbl) );
1414 }
1415
1416 /* Allocate another property if this is overflow. */
1417 if ( font->props_used == font->props_size )
1418 {
1419 if ( font->props_size == 0 )
1420 {
1421 if ( FT_NEW_ARRAY( font->props, 1 ) )
1422 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001423 }
1424 else
1425 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001426 if ( FT_RENEW_ARRAY( font->props,
1427 font->props_size,
1428 font->props_size + 1 ) )
1429 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001430 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001431
David Turner993a8d02002-05-18 12:03:43 +00001432 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001433 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001434 font->props_size++;
1435 }
1436
suzuki toshiya704f4d72009-09-13 00:50:14 +09001437 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001438 if ( propid >= _num_bdf_properties )
1439 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001440 else
David Turnerb1b47622002-05-21 21:17:43 +00001441 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001442
1443 fp = font->props + font->props_used;
1444
1445 fp->name = prop->name;
1446 fp->format = prop->format;
1447 fp->builtin = prop->builtin;
1448
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001449 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001450 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001451 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001452 fp->value.atom = 0;
1453 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001454 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001455 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001456 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001457 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001458 break;
David Turner993a8d02002-05-18 12:03:43 +00001459
1460 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001461 fp->value.l = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001462 break;
1463
1464 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001465 fp->value.ul = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001466 break;
David Turner993a8d02002-05-18 12:03:43 +00001467 }
1468
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001469 /* If the property happens to be a comment, then it doesn't need */
1470 /* to be added to the internal hash table. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001471 if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 )
Werner Lemberg370aea82010-06-08 08:37:11 +02001472 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001473 /* Add the property to the font property table. */
1474 error = hash_insert( fp->name,
suzuki toshiya704f4d72009-09-13 00:50:14 +09001475 font->props_used,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001476 (hashtable *)font->internal,
1477 memory );
1478 if ( error )
1479 goto Exit;
1480 }
David Turner993a8d02002-05-18 12:03:43 +00001481
1482 font->props_used++;
1483
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001484 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1485 /* property needs to be located if it exists in the property list, the */
1486 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1487 /* present, and the SPACING property should override the default */
1488 /* spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001489 if ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001490 font->default_char = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001491 else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001492 font->font_ascent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001493 else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001494 font->font_descent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001495 else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001496 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001497 if ( !fp->value.atom )
1498 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001499 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001500 error = FT_THROW( Invalid_File_Format );
Werner Lembergb66efef2009-03-12 08:07:49 +00001501 goto Exit;
1502 }
1503
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001504 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001505 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001506 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001507 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001508 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001509 font->spacing = BDF_CHARCELL;
1510 }
1511
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001512 Exit:
1513 return error;
David Turner993a8d02002-05-18 12:03:43 +00001514 }
1515
David Turner993a8d02002-05-18 12:03:43 +00001516
David Turnerb1b47622002-05-21 21:17:43 +00001517 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001518 {
1519 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1520 };
1521
1522
1523 /* Actually parse the glyph info and bitmaps. */
1524 static FT_Error
1525 _bdf_parse_glyphs( char* line,
1526 unsigned long linelen,
1527 unsigned long lineno,
1528 void* call_data,
1529 void* client_data )
1530 {
1531 int c, mask_index;
1532 char* s;
1533 unsigned char* bp;
1534 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001535
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001536 _bdf_parse_t* p;
1537 bdf_glyph_t* glyph;
1538 bdf_font_t* font;
1539
1540 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001541 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001542
Werner Lemberg319c00d2003-04-23 19:48:24 +00001543 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001544 FT_UNUSED( lineno ); /* only used in debug mode */
1545
1546
Werner Lemberg319c00d2003-04-23 19:48:24 +00001547 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001548
1549 font = p->font;
1550 memory = font->memory;
1551
1552 /* Check for a comment. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001553 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001554 {
1555 linelen -= 7;
1556
1557 s = line + 7;
1558 if ( *s != 0 )
1559 {
1560 s++;
1561 linelen--;
1562 }
1563 error = _bdf_add_comment( p->font, s, linelen );
1564 goto Exit;
1565 }
1566
1567 /* The very first thing expected is the number of glyphs. */
1568 if ( !( p->flags & _BDF_GLYPHS ) )
1569 {
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001570 if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001571 {
1572 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001573 error = FT_THROW( Missing_Chars_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001574 goto Exit;
1575 }
1576
David Turner68df4f72005-03-15 18:18:57 +00001577 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001578 if ( error )
1579 goto Exit;
1580 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1581
1582 /* Make sure the number of glyphs is non-zero. */
1583 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001584 font->glyphs_size = 64;
1585
Werner Lemberga08b2172007-03-28 07:17:17 +00001586 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1587 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001588 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001589 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001590 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001591 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001592 goto Exit;
1593 }
1594
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001595 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1596 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001597
David Turner993a8d02002-05-18 12:03:43 +00001598 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001599
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001600 goto Exit;
1601 }
1602
1603 /* Check for the ENDFONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001604 if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001605 {
Werner Lembergaf834612014-11-22 13:29:10 +01001606 if ( p->flags & _BDF_GLYPH_BITS )
1607 {
1608 /* Missing ENDCHAR field. */
1609 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1610 error = FT_THROW( Corrupted_Font_Glyphs );
1611 goto Exit;
1612 }
1613
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001614 /* Sort the glyphs by encoding. */
1615 ft_qsort( (char *)font->glyphs,
1616 font->glyphs_used,
1617 sizeof ( bdf_glyph_t ),
1618 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001619
1620 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001621
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001622 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001623 }
1624
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001625 /* Check for the ENDCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001626 if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001627 {
1628 p->glyph_enc = 0;
1629 p->flags &= ~_BDF_GLYPH_BITS;
1630
1631 goto Exit;
1632 }
1633
Werner Lemberg96ddc672011-06-29 09:15:54 +02001634 /* Check whether a glyph is being scanned but should be */
1635 /* ignored because it is an unencoded glyph. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001636 if ( ( p->flags & _BDF_GLYPH ) &&
1637 p->glyph_enc == -1 &&
1638 p->opts->keep_unencoded == 0 )
1639 goto Exit;
1640
1641 /* Check for the STARTCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001642 if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001643 {
1644 /* Set the character name in the parse info first until the */
1645 /* encoding can be checked for an unencoded character. */
1646 FT_FREE( p->glyph_name );
1647
David Turner68df4f72005-03-15 18:18:57 +00001648 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001649 if ( error )
1650 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001651
David Turner68df4f72005-03-15 18:18:57 +00001652 _bdf_list_shift( &p->list, 1 );
1653
1654 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001655
Werner Lembergba03af62007-05-30 13:57:02 +00001656 if ( !s )
1657 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001658 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001659 error = FT_THROW( Invalid_File_Format );
Werner Lembergba03af62007-05-30 13:57:02 +00001660 goto Exit;
1661 }
1662
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001663 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1664 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001665
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001666 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1667
1668 p->flags |= _BDF_GLYPH;
1669
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001670 FT_TRACE4(( DBGMSG1, lineno, s ));
1671
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001672 goto Exit;
1673 }
1674
1675 /* Check for the ENCODING field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001676 if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001677 {
1678 if ( !( p->flags & _BDF_GLYPH ) )
1679 {
1680 /* Missing STARTCHAR field. */
1681 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001682 error = FT_THROW( Missing_Startchar_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001683 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001684 }
1685
David Turner68df4f72005-03-15 18:18:57 +00001686 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001687 if ( error )
1688 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001689
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001690 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001691
Werner Lemberg28dd2c42012-02-26 06:18:58 +01001692 /* Normalize negative encoding values. The specification only */
1693 /* allows -1, but we can be more generous here. */
1694 if ( p->glyph_enc < -1 )
1695 p->glyph_enc = -1;
1696
Werner Lemberg03242f52012-02-26 06:52:56 +01001697 /* Check for alternative encoding format. */
1698 if ( p->glyph_enc == -1 && p->list.used > 2 )
1699 p->glyph_enc = _bdf_atol( p->list.field[2], 0, 10 );
1700
Werner Lemberg7f2e4f42012-12-15 09:39:41 +01001701 if ( p->glyph_enc < -1 )
1702 p->glyph_enc = -1;
1703
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001704 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1705
Werner Lemberged54e432011-11-27 16:39:53 +01001706 /* Check that the encoding is in the Unicode range because */
1707 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lemberg07bdb6e2012-12-15 02:02:23 +01001708 if ( p->glyph_enc > 0 &&
1709 (size_t)p->glyph_enc >= sizeof ( p->have ) /
1710 sizeof ( unsigned long ) * 32 )
David Turner481838e2006-02-23 12:40:14 +00001711 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001712 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001713 error = FT_THROW( Invalid_File_Format );
David Turner481838e2006-02-23 12:40:14 +00001714 goto Exit;
1715 }
1716
Werner Lemberg96ddc672011-06-29 09:15:54 +02001717 /* Check whether this encoding has already been encountered. */
1718 /* If it has then change it to unencoded so it gets added if */
1719 /* indicated. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001720 if ( p->glyph_enc >= 0 )
1721 {
1722 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1723 {
1724 /* Emit a message saying a glyph has been moved to the */
1725 /* unencoded area. */
1726 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1727 p->glyph_enc, p->glyph_name ));
1728 p->glyph_enc = -1;
1729 font->modified = 1;
1730 }
1731 else
1732 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1733 }
1734
1735 if ( p->glyph_enc >= 0 )
1736 {
1737 /* Make sure there are enough glyphs allocated in case the */
1738 /* number of characters happen to be wrong. */
1739 if ( font->glyphs_used == font->glyphs_size )
1740 {
1741 if ( FT_RENEW_ARRAY( font->glyphs,
1742 font->glyphs_size,
1743 font->glyphs_size + 64 ) )
1744 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001745
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001746 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001747 }
1748
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001749 glyph = font->glyphs + font->glyphs_used++;
1750 glyph->name = p->glyph_name;
1751 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001752
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001753 /* Reset the initial glyph info. */
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001754 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001755 }
1756 else
1757 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001758 /* Unencoded glyph. Check whether it should */
1759 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001760 if ( p->opts->keep_unencoded != 0 )
1761 {
1762 /* Allocate the next unencoded glyph. */
1763 if ( font->unencoded_used == font->unencoded_size )
1764 {
David Turner68df4f72005-03-15 18:18:57 +00001765 if ( FT_RENEW_ARRAY( font->unencoded ,
1766 font->unencoded_size,
1767 font->unencoded_size + 4 ) )
1768 goto Exit;
1769
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001770 font->unencoded_size += 4;
1771 }
1772
1773 glyph = font->unencoded + font->unencoded_used;
1774 glyph->name = p->glyph_name;
Werner Lemberg3c374c82015-02-22 09:16:53 +01001775 glyph->encoding = (long)font->unencoded_used++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001776 }
1777 else
1778 /* Free up the glyph name if the unencoded shouldn't be */
1779 /* kept. */
1780 FT_FREE( p->glyph_name );
1781
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001782 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001783 }
1784
1785 /* Clear the flags that might be added when width and height are */
1786 /* checked for consistency. */
1787 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1788
1789 p->flags |= _BDF_ENCODING;
1790
1791 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001792 }
1793
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001794 /* Point at the glyph being constructed. */
1795 if ( p->glyph_enc == -1 )
1796 glyph = font->unencoded + ( font->unencoded_used - 1 );
1797 else
1798 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001799
Werner Lemberg96ddc672011-06-29 09:15:54 +02001800 /* Check whether a bitmap is being constructed. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001801 if ( p->flags & _BDF_BITMAP )
1802 {
1803 /* If there are more rows than are specified in the glyph metrics, */
1804 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001805 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001806 {
1807 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1808 {
1809 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1810 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001811 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001812 }
1813
1814 goto Exit;
1815 }
1816
1817 /* Only collect the number of nibbles indicated by the glyph */
1818 /* metrics. If there are more columns, they are simply ignored. */
1819 nibbles = glyph->bpr << 1;
1820 bp = glyph->bitmap + p->row * glyph->bpr;
1821
David Turnerb698eed2006-02-23 14:50:13 +00001822 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001823 {
1824 c = line[i];
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001825 if ( !sbitset( hdigits, c ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001826 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001827 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001828 if ( i + 1 < nibbles && ( i & 1 ) )
1829 *++bp = 0;
1830 }
1831
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001832 /* If any line has not enough columns, */
1833 /* indicate they have been padded with zero bits. */
1834 if ( i < nibbles &&
1835 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1836 {
1837 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
1838 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1839 font->modified = 1;
1840 }
1841
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001842 /* Remove possible garbage at the right. */
1843 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001844 if ( glyph->bbx.width )
1845 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001846
1847 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001848 if ( i == nibbles &&
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001849 sbitset( hdigits, line[nibbles] ) &&
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001850 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001851 {
1852 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1853 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1854 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001855 }
1856
1857 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001858 goto Exit;
1859 }
David Turner993a8d02002-05-18 12:03:43 +00001860
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001861 /* Expect the SWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001862 if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001863 {
1864 if ( !( p->flags & _BDF_ENCODING ) )
Werner Lemberg4086fb72012-03-01 08:55:40 +01001865 goto Missing_Encoding;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001866
David Turner68df4f72005-03-15 18:18:57 +00001867 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001868 if ( error )
1869 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001870
David Turnerb1b47622002-05-21 21:17:43 +00001871 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001872 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001873
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001874 goto Exit;
1875 }
David Turner993a8d02002-05-18 12:03:43 +00001876
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001877 /* Expect the DWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001878 if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001879 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001880 if ( !( p->flags & _BDF_ENCODING ) )
1881 goto Missing_Encoding;
1882
David Turner68df4f72005-03-15 18:18:57 +00001883 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001884 if ( error )
1885 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001886
David Turnerb1b47622002-05-21 21:17:43 +00001887 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001888
1889 if ( !( p->flags & _BDF_SWIDTH ) )
1890 {
1891 /* Missing SWIDTH field. Emit an auto correction message and set */
1892 /* the scalable width from the device width. */
1893 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1894
Werner Lemberg02d4d592002-05-28 22:38:05 +00001895 glyph->swidth = (unsigned short)FT_MulDiv(
1896 glyph->dwidth, 72000L,
1897 (FT_Long)( font->point_size *
1898 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001899 }
1900
1901 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001902 goto Exit;
1903 }
David Turner993a8d02002-05-18 12:03:43 +00001904
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001905 /* Expect the BBX field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001906 if ( _bdf_strncmp( line, "BBX", 3 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001907 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001908 if ( !( p->flags & _BDF_ENCODING ) )
1909 goto Missing_Encoding;
1910
David Turner68df4f72005-03-15 18:18:57 +00001911 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001912 if ( error )
1913 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001914
Werner Lembergb13945a2015-02-22 09:15:47 +01001915 glyph->bbx.width = _bdf_atous( p->list.field[1], 0, 10 );
1916 glyph->bbx.height = _bdf_atous( p->list.field[2], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001917 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1918 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1919
1920 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001921 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1922 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001923
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001924 /* Determine the overall font bounding box as the characters are */
1925 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001926 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1927 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001928
David Turnerb1b47622002-05-21 21:17:43 +00001929 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001930
Werner Lembergdfa46192004-03-05 09:26:24 +00001931 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1932 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1933 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001934
1935 if ( !( p->flags & _BDF_DWIDTH ) )
1936 {
1937 /* Missing DWIDTH field. Emit an auto correction message and set */
1938 /* the device width to the glyph width. */
1939 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1940 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001941 }
1942
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001943 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1944 /* value if necessary. */
1945 if ( p->opts->correct_metrics != 0 )
1946 {
1947 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001948 unsigned short sw = (unsigned short)FT_MulDiv(
1949 glyph->dwidth, 72000L,
1950 (FT_Long)( font->point_size *
1951 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001952
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001953
1954 if ( sw != glyph->swidth )
1955 {
1956 glyph->swidth = sw;
1957
1958 if ( p->glyph_enc == -1 )
1959 _bdf_set_glyph_modified( font->umod,
1960 font->unencoded_used - 1 );
1961 else
1962 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1963
1964 p->flags |= _BDF_SWIDTH_ADJ;
1965 font->modified = 1;
1966 }
David Turner993a8d02002-05-18 12:03:43 +00001967 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001968
David Turner993a8d02002-05-18 12:03:43 +00001969 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001970 goto Exit;
1971 }
David Turner993a8d02002-05-18 12:03:43 +00001972
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001973 /* And finally, gather up the bitmap. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001974 if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001975 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001976 unsigned long bitmap_size;
1977
1978
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001979 if ( !( p->flags & _BDF_BBX ) )
1980 {
1981 /* Missing BBX field. */
1982 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001983 error = FT_THROW( Missing_Bbx_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001984 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001985 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001986
1987 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001988 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001989
1990 bitmap_size = glyph->bpr * glyph->bbx.height;
Werner Lembergc4cad302012-03-08 20:11:37 +01001991 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
Werner Lemberg26170df2006-03-26 07:19:07 +00001992 {
1993 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001994 error = FT_THROW( Bbx_Too_Big );
Werner Lemberg26170df2006-03-26 07:19:07 +00001995 goto Exit;
1996 }
1997 else
1998 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001999
2000 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
2001 goto Exit;
2002
2003 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00002004 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002005
2006 goto Exit;
2007 }
2008
Werner Lemberge01406b2011-11-25 09:44:28 +01002009 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002010 error = FT_THROW( Invalid_File_Format );
Werner Lemberg4086fb72012-03-01 08:55:40 +01002011 goto Exit;
2012
2013 Missing_Encoding:
2014 /* Missing ENCODING field. */
2015 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002016 error = FT_THROW( Missing_Encoding_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002017
2018 Exit:
Werner Lembergf4c94d42010-06-19 16:08:31 +02002019 if ( error && ( p->flags & _BDF_GLYPH ) )
2020 FT_FREE( p->glyph_name );
2021
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002022 return error;
David Turner993a8d02002-05-18 12:03:43 +00002023 }
2024
David Turner993a8d02002-05-18 12:03:43 +00002025
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002026 /* Load the font properties. */
2027 static FT_Error
2028 _bdf_parse_properties( char* line,
2029 unsigned long linelen,
2030 unsigned long lineno,
2031 void* call_data,
2032 void* client_data )
2033 {
2034 unsigned long vlen;
2035 _bdf_line_func_t* next;
2036 _bdf_parse_t* p;
2037 char* name;
2038 char* value;
2039 char nbuf[128];
Werner Lemberge3c93012013-03-14 11:21:17 +01002040 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00002041
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002042 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00002043
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002044
2045 next = (_bdf_line_func_t *)call_data;
2046 p = (_bdf_parse_t *) client_data;
2047
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002048 /* Check for the end of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002049 if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002050 {
2051 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
2052 /* encountered yet, then make sure they are added as properties and */
2053 /* make sure they are set from the font bounding box info. */
2054 /* */
2055 /* This is *always* done regardless of the options, because X11 */
2056 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00002057 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002058 {
2059 p->font->font_ascent = p->font->bbx.ascent;
2060 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002061 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2062 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002063 if ( error )
2064 goto Exit;
2065
2066 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2067 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002068 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002069
Werner Lemberg428c2e42003-04-25 05:35:04 +00002070 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002071 {
2072 p->font->font_descent = p->font->bbx.descent;
2073 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002074 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2075 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002076 if ( error )
2077 goto Exit;
2078
2079 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2080 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002081 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002082
David Turner993a8d02002-05-18 12:03:43 +00002083 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002084 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00002085
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002086 goto Exit;
2087 }
David Turner993a8d02002-05-18 12:03:43 +00002088
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002089 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002090 if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002091 goto Exit;
2092
2093 /* Handle COMMENT fields and properties in a special way to preserve */
2094 /* the spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002095 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002096 {
David Turner993a8d02002-05-18 12:03:43 +00002097 name = value = line;
2098 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002099 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00002100 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01002101 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002102 if ( error )
2103 goto Exit;
2104 }
2105 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
2106 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002107 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002108 if ( error )
2109 goto Exit;
2110 }
2111 else
2112 {
David Turner68df4f72005-03-15 18:18:57 +00002113 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002114 if ( error )
2115 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002116 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002117
David Turner68df4f72005-03-15 18:18:57 +00002118 _bdf_list_shift( &p->list, 1 );
2119 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002120
Werner Lemberge01406b2011-11-25 09:44:28 +01002121 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002122 if ( error )
2123 goto Exit;
2124 }
2125
2126 Exit:
2127 return error;
David Turner993a8d02002-05-18 12:03:43 +00002128 }
2129
David Turner993a8d02002-05-18 12:03:43 +00002130
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002131 /* Load the font header. */
2132 static FT_Error
2133 _bdf_parse_start( char* line,
2134 unsigned long linelen,
2135 unsigned long lineno,
2136 void* call_data,
2137 void* client_data )
2138 {
2139 unsigned long slen;
2140 _bdf_line_func_t* next;
2141 _bdf_parse_t* p;
2142 bdf_font_t* font;
2143 char *s;
David Turner993a8d02002-05-18 12:03:43 +00002144
David Turnerd490e372002-05-28 23:40:37 +00002145 FT_Memory memory = NULL;
Werner Lemberge3c93012013-03-14 11:21:17 +01002146 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002147
2148 FT_UNUSED( lineno ); /* only used in debug mode */
2149
2150
2151 next = (_bdf_line_func_t *)call_data;
2152 p = (_bdf_parse_t *) client_data;
2153
2154 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00002155 memory = p->font->memory;
2156
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002157 /* Check for a comment. This is done to handle those fonts that have */
2158 /* comments before the STARTFONT line for some reason. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002159 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002160 {
2161 if ( p->opts->keep_comments != 0 && p->font != 0 )
2162 {
2163 linelen -= 7;
2164
2165 s = line + 7;
2166 if ( *s != 0 )
2167 {
2168 s++;
2169 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002170 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002171
2172 error = _bdf_add_comment( p->font, s, linelen );
2173 if ( error )
2174 goto Exit;
2175 /* here font is not defined! */
2176 }
2177
2178 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002179 }
2180
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002181 if ( !( p->flags & _BDF_START ) )
2182 {
2183 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002184
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002185 if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002186 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01002187 /* we don't emit an error message since this code gets */
2188 /* explicitly caught one level higher */
Werner Lemberg059bc332013-03-14 10:27:35 +01002189 error = FT_THROW( Missing_Startfont_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002190 goto Exit;
2191 }
David Turner993a8d02002-05-18 12:03:43 +00002192
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002193 p->flags = _BDF_START;
2194 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002195
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002196 if ( FT_NEW( font ) )
2197 goto Exit;
2198 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002199
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002200 font->memory = p->memory;
2201 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002202
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002203 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09002204 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002205 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002206
David Turner993a8d02002-05-18 12:03:43 +00002207
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002208 error = hash_init( &(font->proptbl), memory );
2209 if ( error )
2210 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002211 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002212 i < _num_bdf_properties; i++, prop++ )
2213 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09002214 error = hash_insert( prop->name, i,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002215 &(font->proptbl), memory );
2216 if ( error )
2217 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002218 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002219 }
2220
2221 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2222 goto Exit;
2223 error = hash_init( (hashtable *)p->font->internal,memory );
2224 if ( error )
2225 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002226 p->font->spacing = p->opts->font_spacing;
2227 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002228
2229 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002230 }
2231
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002232 /* Check for the start of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002233 if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002234 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002235 if ( !( p->flags & _BDF_FONT_BBX ) )
Werner Lembergfb690292010-06-23 10:00:52 +02002236 {
2237 /* Missing the FONTBOUNDINGBOX field. */
2238 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002239 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergfb690292010-06-23 10:00:52 +02002240 goto Exit;
2241 }
2242
David Turner68df4f72005-03-15 18:18:57 +00002243 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002244 if ( error )
2245 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00002246 /* at this point, `p->font' can't be NULL */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002247 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2248
2249 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
Werner Lemberg9b6b5752012-12-15 01:34:41 +01002250 {
2251 p->font->props_size = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002252 goto Exit;
Werner Lemberg9b6b5752012-12-15 01:34:41 +01002253 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002254
2255 p->flags |= _BDF_PROPS;
2256 *next = _bdf_parse_properties;
2257
2258 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002259 }
2260
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002261 /* Check for the FONTBOUNDINGBOX field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002262 if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002263 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002264 if ( !( p->flags & _BDF_SIZE ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002265 {
2266 /* Missing the SIZE field. */
2267 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002268 error = FT_THROW( Missing_Size_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002269 goto Exit;
2270 }
2271
David Turner68df4f72005-03-15 18:18:57 +00002272 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002273 if ( error )
2274 goto Exit;
2275
Werner Lembergb13945a2015-02-22 09:15:47 +01002276 p->font->bbx.width = _bdf_atous( p->list.field[1], 0, 10 );
2277 p->font->bbx.height = _bdf_atous( p->list.field[2], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002278
2279 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2280 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2281
David Turnerd490e372002-05-28 23:40:37 +00002282 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002283 p->font->bbx.y_offset );
2284
2285 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002286
2287 p->flags |= _BDF_FONT_BBX;
2288
2289 goto Exit;
2290 }
2291
2292 /* The next thing to check for is the FONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002293 if ( _bdf_strncmp( line, "FONT", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002294 {
David Turner68df4f72005-03-15 18:18:57 +00002295 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002296 if ( error )
2297 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002298 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002299
David Turner68df4f72005-03-15 18:18:57 +00002300 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002301
2302 if ( !s )
2303 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002304 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002305 error = FT_THROW( Invalid_File_Format );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002306 goto Exit;
2307 }
2308
Werner Lembergfb690292010-06-23 10:00:52 +02002309 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2310 FT_FREE( p->font->name );
2311
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002312 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2313 goto Exit;
2314 FT_MEM_COPY( p->font->name, s, slen + 1 );
2315
2316 /* If the font name is an XLFD name, set the spacing to the one in */
2317 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002318 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002319 if ( error )
2320 goto Exit;
2321
2322 p->flags |= _BDF_FONT_NAME;
2323
2324 goto Exit;
2325 }
2326
2327 /* Check for the SIZE field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002328 if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002329 {
2330 if ( !( p->flags & _BDF_FONT_NAME ) )
2331 {
2332 /* Missing the FONT field. */
2333 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002334 error = FT_THROW( Missing_Font_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002335 goto Exit;
2336 }
2337
David Turner68df4f72005-03-15 18:18:57 +00002338 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002339 if ( error )
2340 goto Exit;
2341
2342 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2343 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2344 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2345
2346 /* Check for the bits per pixel field. */
2347 if ( p->list.used == 5 )
2348 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002349 unsigned short bitcount, i, shift;
2350
2351
2352 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2353
2354 /* Only values 1, 2, 4, 8 are allowed. */
2355 shift = p->font->bpp;
2356 bitcount = 0;
2357 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002358 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002359 if ( shift & 1 )
2360 bitcount = i;
2361 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002362 }
David Turner993a8d02002-05-18 12:03:43 +00002363
Werner Lemberg3c374c82015-02-22 09:16:53 +01002364 shift = (unsigned short)( ( bitcount > 3 ) ? 8
2365 : ( 1U << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002366
2367 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002368 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002369 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002370 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002371 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002372 }
2373 }
2374 else
2375 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002376
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002377 p->flags |= _BDF_SIZE;
2378
2379 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002380 }
2381
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002382 /* Check for the CHARS field -- font properties are optional */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002383 if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002384 {
2385 char nbuf[128];
2386
2387
2388 if ( !( p->flags & _BDF_FONT_BBX ) )
2389 {
2390 /* Missing the FONTBOUNDINGBOX field. */
2391 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002392 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002393 goto Exit;
2394 }
2395
2396 /* Add the two standard X11 properties which are required */
2397 /* for compiling fonts. */
2398 p->font->font_ascent = p->font->bbx.ascent;
2399 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002400 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2401 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002402 if ( error )
2403 goto Exit;
2404 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2405
2406 p->font->font_descent = p->font->bbx.descent;
2407 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002408 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2409 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002410 if ( error )
2411 goto Exit;
2412 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2413
2414 p->font->modified = 1;
2415
2416 *next = _bdf_parse_glyphs;
2417
2418 /* A special return value. */
2419 error = -1;
2420 goto Exit;
2421 }
2422
Werner Lemberge01406b2011-11-25 09:44:28 +01002423 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002424 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002425
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002426 Exit:
2427 return error;
2428 }
David Turner993a8d02002-05-18 12:03:43 +00002429
2430
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002431 /*************************************************************************/
2432 /* */
2433 /* API. */
2434 /* */
2435 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002436
David Turner993a8d02002-05-18 12:03:43 +00002437
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002438 FT_LOCAL_DEF( FT_Error )
2439 bdf_load_font( FT_Stream stream,
2440 FT_Memory extmemory,
2441 bdf_options_t* opts,
2442 bdf_font_t* *font )
2443 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002444 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002445 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002446
Sean McBride7be2a942014-02-08 13:55:38 +01002447 FT_Memory memory = extmemory; /* needed for FT_NEW */
2448 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002449
2450
David Turner68df4f72005-03-15 18:18:57 +00002451 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002452 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002453
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002454 memory = NULL;
2455 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2456 p->minlb = 32767;
2457 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002458
David Turner68df4f72005-03-15 18:18:57 +00002459 _bdf_list_init( &p->list, extmemory );
2460
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002461 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002462 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002463 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002464 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002465
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002466 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002467 {
2468 /* If the font is not proportional, set the font's monowidth */
2469 /* field to the width of the font bounding box. */
David Turner993a8d02002-05-18 12:03:43 +00002470
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002471 if ( p->font->spacing != BDF_PROPORTIONAL )
2472 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002473
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002474 /* If the number of glyphs loaded is not that of the original count, */
2475 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002476 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002477 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002478 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2479 p->font->glyphs_used + p->font->unencoded_used ));
2480 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002481 }
2482
2483 /* Once the font has been loaded, adjust the overall font metrics if */
2484 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002485 if ( p->opts->correct_metrics != 0 &&
2486 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002487 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002488 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002489 {
2490 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002491 p->font->bbx.width, p->maxrb - p->minlb ));
2492 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2493 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002494 }
2495
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002496 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002497 {
2498 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002499 p->font->bbx.x_offset, p->minlb ));
2500 p->font->bbx.x_offset = p->minlb;
2501 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002502 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002503
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002504 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002505 {
2506 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002507 p->font->bbx.ascent, p->maxas ));
2508 p->font->bbx.ascent = p->maxas;
2509 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002510 }
2511
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002512 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002513 {
2514 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002515 p->font->bbx.descent, p->maxds ));
2516 p->font->bbx.descent = p->maxds;
2517 p->font->bbx.y_offset = (short)( -p->maxds );
2518 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002519 }
2520
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002521 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002522 {
2523 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002524 p->font->bbx.height, p->maxas + p->maxds ));
2525 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002526 }
2527
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002528 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002529 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2530 }
David Turner993a8d02002-05-18 12:03:43 +00002531 }
2532
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002533 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002534 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002535 /* The ENDFONT field was never reached or did not exist. */
2536 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002537 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002538 /* Error happened while parsing header. */
2539 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002540 error = FT_THROW( Corrupted_Font_Header );
Werner Lemberge01406b2011-11-25 09:44:28 +01002541 goto Exit;
2542 }
2543 else
2544 {
2545 /* Error happened when parsing glyphs. */
2546 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002547 error = FT_THROW( Corrupted_Font_Glyphs );
Werner Lemberge01406b2011-11-25 09:44:28 +01002548 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002549 }
David Turner993a8d02002-05-18 12:03:43 +00002550 }
2551
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002552 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002553 {
2554 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002555 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002556
Werner Lemberg370aea82010-06-08 08:37:11 +02002557 if ( p->font->comments_len > 0 )
2558 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002559 if ( FT_RENEW_ARRAY( p->font->comments,
2560 p->font->comments_len,
2561 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002562 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002563
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002564 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002565 }
David Turner993a8d02002-05-18 12:03:43 +00002566 }
Werner Lemberge3c93012013-03-14 11:21:17 +01002567 else if ( error == FT_Err_Ok )
Werner Lemberg059bc332013-03-14 10:27:35 +01002568 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002569
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002570 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002571
2572 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002573 if ( p )
2574 {
David Turner68df4f72005-03-15 18:18:57 +00002575 _bdf_list_done( &p->list );
2576
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002577 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002578
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002579 FT_FREE( p );
2580 }
2581
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002582 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002583
2584 Fail:
2585 bdf_free_font( p->font );
2586
2587 memory = extmemory;
2588
2589 FT_FREE( p->font );
2590
2591 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002592 }
David Turner993a8d02002-05-18 12:03:43 +00002593
2594
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002595 FT_LOCAL_DEF( void )
2596 bdf_free_font( bdf_font_t* font )
2597 {
2598 bdf_property_t* prop;
2599 unsigned long i;
2600 bdf_glyph_t* glyphs;
2601 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002602
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002603
2604 if ( font == 0 )
2605 return;
David Turner993a8d02002-05-18 12:03:43 +00002606
2607 memory = font->memory;
2608
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002609 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002610
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002611 /* Free up the internal hash table of property names. */
2612 if ( font->internal )
2613 {
2614 hash_free( (hashtable *)font->internal, memory );
2615 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002616 }
2617
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002618 /* Free up the comment info. */
2619 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002620
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002621 /* Free up the properties. */
2622 for ( i = 0; i < font->props_size; i++ )
2623 {
2624 if ( font->props[i].format == BDF_ATOM )
2625 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002626 }
2627
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002628 FT_FREE( font->props );
2629
2630 /* Free up the character info. */
2631 for ( i = 0, glyphs = font->glyphs;
2632 i < font->glyphs_used; i++, glyphs++ )
2633 {
2634 FT_FREE( glyphs->name );
2635 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002636 }
2637
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002638 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2639 i++, glyphs++ )
2640 {
2641 FT_FREE( glyphs->name );
2642 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002643 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002644
2645 FT_FREE( font->glyphs );
2646 FT_FREE( font->unencoded );
2647
2648 /* Free up the overflow storage if it was used. */
2649 for ( i = 0, glyphs = font->overflow.glyphs;
2650 i < font->overflow.glyphs_used; i++, glyphs++ )
2651 {
2652 FT_FREE( glyphs->name );
2653 FT_FREE( glyphs->bitmap );
2654 }
2655
2656 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002657
2658 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002659 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002660
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002661 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002662 for ( prop = font->user_props, i = 0;
2663 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002664 {
2665 FT_FREE( prop->name );
2666 if ( prop->format == BDF_ATOM )
2667 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002668 }
David Turner993a8d02002-05-18 12:03:43 +00002669
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002670 FT_FREE( font->user_props );
2671
2672 /* FREE( font ); */ /* XXX Fixme */
2673 }
David Turner993a8d02002-05-18 12:03:43 +00002674
2675
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002676 FT_LOCAL_DEF( bdf_property_t * )
2677 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002678 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002679 {
2680 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002681
David Turner993a8d02002-05-18 12:03:43 +00002682
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002683 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002684 return 0;
2685
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002686 hn = hash_lookup( name, (hashtable *)font->internal );
2687
suzuki toshiya704f4d72009-09-13 00:50:14 +09002688 return hn ? ( font->props + hn->data ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002689 }
2690
2691
2692/* END */