blob: abcfdee7be6d39075de57651f47118e14a2df0a5 [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 )
246 res = ( res << 5 ) - res + *kp++;
247
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 Lemberg7cf4d372002-05-21 14:13:01 +0000267 hashnode* obp = ht->table, *bp, *nbp;
David Turner993a8d02002-05-18 12:03:43 +0000268 int i, sz = ht->size;
Werner Lemberge3c93012013-03-14 11:21:17 +0100269 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 Lemberg059bc332013-03-14 10:27:35 +0100297 int sz = INITIAL_HT_SIZE;
Werner Lemberge3c93012013-03-14 11:21:17 +0100298 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 Lemberg7cf4d372002-05-21 14:13:01 +0000319 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 {
573 int mult, final_empty;
574 char *sp, *ep, *end;
575 char seps[32];
Werner Lemberge3c93012013-03-14 11:21:17 +0100576 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000577
578
579 /* Initialize the list. */
580 list->used = 0;
Werner Lembergd9c16592012-03-01 15:15:00 +0100581 if ( list->size )
582 {
583 list->field[0] = (char*)empty;
584 list->field[1] = (char*)empty;
585 list->field[2] = (char*)empty;
586 list->field[3] = (char*)empty;
Werner Lemberg649c6732012-03-16 21:12:41 +0100587 list->field[4] = (char*)empty;
Werner Lembergd9c16592012-03-01 15:15:00 +0100588 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000589
590 /* If the line is empty, then simply return. */
591 if ( linelen == 0 || line[0] == 0 )
592 goto Exit;
593
594 /* In the original code, if the `separators' parameter is NULL or */
595 /* empty, the list is split into individual bytes. We don't need */
596 /* this, so an error is signaled. */
597 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000598 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100599 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000600 goto Exit;
601 }
602
603 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000604 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000605
606 /* If the very last character of the separator string is a plus, then */
607 /* set the `mult' flag to indicate that multiple separators should be */
608 /* collapsed into one. */
609 for ( mult = 0, sp = separators; sp && *sp; sp++ )
610 {
611 if ( *sp == '+' && *( sp + 1 ) == 0 )
612 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000613 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000614 setsbit( seps, *sp );
615 }
616
617 /* Break the line up into fields. */
618 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
619 sp < end && *sp; )
620 {
621 /* Collect everything that is not a separator. */
622 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
623 ;
624
625 /* Resize the list if necessary. */
626 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000627 {
Werner Lembergebf55852005-03-16 01:49:54 +0000628 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000629 if ( error )
630 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000631 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000632
633 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000634 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000635
636 sp = ep;
637
638 if ( mult )
639 {
640 /* If multiple separators should be collapsed, do it now by */
641 /* setting all the separator characters to 0. */
642 for ( ; *ep && sbitset( seps, *ep ); ep++ )
643 *ep = 0;
644 }
645 else if ( *ep != 0 )
646 /* Don't collapse multiple separators by making them 0, so just */
647 /* make the one encountered 0. */
648 *ep++ = 0;
649
650 final_empty = ( ep > sp && *ep == 0 );
651 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000652 }
653
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000654 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000655 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000656 {
Werner Lembergebf55852005-03-16 01:49:54 +0000657 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000658 if ( error )
659 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000660 }
661
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000662 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000663 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000664
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000665 list->field[list->used] = 0;
666
667 Exit:
668 return error;
David Turner993a8d02002-05-18 12:03:43 +0000669 }
670
David Turner993a8d02002-05-18 12:03:43 +0000671
David Turner68df4f72005-03-15 18:18:57 +0000672#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000673
Werner Lembergebf55852005-03-16 01:49:54 +0000674
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000675 static FT_Error
676 _bdf_readstream( FT_Stream stream,
677 _bdf_line_func_t callback,
678 void* client_data,
679 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000680 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000681 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000682 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900683 int refill, hold, to_skip;
684 ptrdiff_t bytes, start, end, cursor, avail;
Werner Lemberg059bc332013-03-14 10:27:35 +0100685 char* buf = 0;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000686 FT_Memory memory = stream->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100687 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000688
David Turner993a8d02002-05-18 12:03:43 +0000689
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000690 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000691 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100692 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000693 goto Exit;
694 }
David Turner993a8d02002-05-18 12:03:43 +0000695
Werner Lembergebf55852005-03-16 01:49:54 +0000696 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000697 buf_size = 1024;
698
699 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000700 goto Exit;
701
Werner Lembergebf55852005-03-16 01:49:54 +0000702 cb = callback;
703 lineno = 1;
704 buf[0] = 0;
705 start = 0;
Werner Lembergebf55852005-03-16 01:49:54 +0000706 avail = 0;
707 cursor = 0;
708 refill = 1;
709 to_skip = NO_SKIP;
710 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000711
David Turner68df4f72005-03-15 18:18:57 +0000712 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000713 {
David Turner68df4f72005-03-15 18:18:57 +0000714 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000715 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +0200716 bytes = (ptrdiff_t)FT_Stream_TryRead(
717 stream, (FT_Byte*)buf + cursor,
718 (FT_ULong)( buf_size - cursor ) );
David Turner68df4f72005-03-15 18:18:57 +0000719 avail = cursor + bytes;
720 cursor = 0;
721 refill = 0;
722 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000723
David Turner68df4f72005-03-15 18:18:57 +0000724 end = start;
725
Werner Lembergebf55852005-03-16 01:49:54 +0000726 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000727 if ( start < avail && buf[start] == to_skip )
728 {
729 start += 1;
730 to_skip = NO_SKIP;
731 continue;
732 }
733
734 /* try to find the end of the line */
735 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
736 end++;
737
Werner Lembergebf55852005-03-16 01:49:54 +0000738 /* if we hit the end of the buffer, try shifting its content */
739 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000740 if ( end >= avail )
741 {
742 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
743 break; /* ignore it then exit */
744
745 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000746 {
Werner Lembergebf55852005-03-16 01:49:54 +0000747 /* this line is definitely too long; try resizing the input */
748 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000749 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000750
Werner Lembergebf55852005-03-16 01:49:54 +0000751
752 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000753 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100754 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +0100755 error = FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +0000756 goto Exit;
757 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000758
Werner Lembergebf55852005-03-16 01:49:54 +0000759 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000760 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
761 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000762
David Turner68df4f72005-03-15 18:18:57 +0000763 cursor = buf_size;
764 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000765 }
766 else
767 {
David Turner68df4f72005-03-15 18:18:57 +0000768 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000769
Werner Lemberg04e547b2013-04-03 07:37:56 +0200770 FT_MEM_MOVE( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000771
David Turner68df4f72005-03-15 18:18:57 +0000772 cursor = bytes;
773 avail -= bytes;
774 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000775 }
David Turner68df4f72005-03-15 18:18:57 +0000776 refill = 1;
777 continue;
David Turner993a8d02002-05-18 12:03:43 +0000778 }
David Turner68df4f72005-03-15 18:18:57 +0000779
780 /* Temporarily NUL-terminate the line. */
781 hold = buf[end];
782 buf[end] = 0;
783
Werner Lemberg0098d552014-12-07 11:03:57 +0100784 /* XXX: Use encoding independent value for 0x1A */
785 if ( buf[start] != '#' && buf[start] != 0x1A && end > start )
David Turner68df4f72005-03-15 18:18:57 +0000786 {
Werner Lemberga9f6f852012-12-17 09:08:09 +0100787 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergebf55852005-03-16 01:49:54 +0000788 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200789 /* Redo if we have encountered CHARS without properties. */
790 if ( error == -1 )
Werner Lemberga9f6f852012-12-17 09:08:09 +0100791 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200792 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000793 if ( error )
794 break;
795 }
796
797 lineno += 1;
798 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000799 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000800
801 if ( hold == '\n' )
802 to_skip = '\r';
803 else if ( hold == '\r' )
804 to_skip = '\n';
805 else
806 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000807 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000808
David Turner68df4f72005-03-15 18:18:57 +0000809 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000810
811 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000812 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000813 return error;
David Turner993a8d02002-05-18 12:03:43 +0000814 }
David Turner993a8d02002-05-18 12:03:43 +0000815
816
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000817 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000818
David Turnerb1b47622002-05-21 21:17:43 +0000819 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000820 {
David Turner993a8d02002-05-18 12:03:43 +0000821 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
822 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, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
Werner Lemberg0098d552014-12-07 11:03:57 +0100826 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000827 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
828 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg0098d552014-12-07 11:03:57 +0100829 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000830 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
831 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000832 };
David Turner993a8d02002-05-18 12:03:43 +0000833
David Turnerb1b47622002-05-21 21:17:43 +0000834 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000835 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100836 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000837 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
838 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
839 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000840 };
David Turner993a8d02002-05-18 12:03:43 +0000841
David Turnerb1b47622002-05-21 21:17:43 +0000842 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000843 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100844 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
David Turner993a8d02002-05-18 12:03:43 +0000845 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
846 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
847 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000848 };
David Turner993a8d02002-05-18 12:03:43 +0000849
David Turnerb1b47622002-05-21 21:17:43 +0000850 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000851 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100852 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
853 0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000854 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
855 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000856 };
David Turner993a8d02002-05-18 12:03:43 +0000857
David Turner993a8d02002-05-18 12:03:43 +0000858
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000859 /* Routine to convert an ASCII string into an unsigned long integer. */
860 static unsigned long
861 _bdf_atoul( char* s,
862 char** end,
863 int base )
David Turner993a8d02002-05-18 12:03:43 +0000864 {
David Turnerb1b47622002-05-21 21:17:43 +0000865 unsigned long v;
866 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000867
868
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000869 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000870 return 0;
871
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000872 /* Make sure the radix is something recognizable. Default to 10. */
873 switch ( base )
874 {
875 case 8:
876 dmap = odigits;
877 break;
878 case 16:
879 dmap = hdigits;
880 break;
881 default:
882 base = 10;
883 dmap = ddigits;
884 break;
David Turner993a8d02002-05-18 12:03:43 +0000885 }
886
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000887 /* Check for the special hex prefix. */
888 if ( *s == '0' &&
889 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
890 {
891 base = 16;
892 dmap = hdigits;
893 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000894 }
895
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +0100896 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000897 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000898
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000899 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000900 *end = s;
901
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000902 return v;
903 }
David Turner993a8d02002-05-18 12:03:43 +0000904
David Turner993a8d02002-05-18 12:03:43 +0000905
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000906 /* Routine to convert an ASCII string into an signed long integer. */
907 static long
908 _bdf_atol( char* s,
909 char** end,
910 int base )
911 {
David Turnerb1b47622002-05-21 21:17:43 +0000912 long v, neg;
913 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000914
915
916 if ( s == 0 || *s == 0 )
917 return 0;
918
919 /* Make sure the radix is something recognizable. Default to 10. */
920 switch ( base )
921 {
922 case 8:
923 dmap = odigits;
924 break;
925 case 16:
926 dmap = hdigits;
927 break;
928 default:
929 base = 10;
930 dmap = ddigits;
931 break;
932 }
933
934 /* Check for a minus sign. */
935 neg = 0;
936 if ( *s == '-' )
937 {
938 s++;
939 neg = 1;
940 }
941
942 /* Check for the special hex prefix. */
943 if ( *s == '0' &&
944 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
945 {
946 base = 16;
947 dmap = hdigits;
948 s += 2;
949 }
950
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +0100951 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000952 v = v * base + a2i[(int)*s];
953
954 if ( end != 0 )
955 *end = s;
956
957 return ( !neg ) ? v : -v;
958 }
959
960
961 /* Routine to convert an ASCII string into an signed short integer. */
962 static short
963 _bdf_atos( char* s,
964 char** end,
965 int base )
966 {
David Turnerb1b47622002-05-21 21:17:43 +0000967 short v, neg;
968 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000969
970
971 if ( s == 0 || *s == 0 )
972 return 0;
973
974 /* Make sure the radix is something recognizable. Default to 10. */
975 switch ( base )
976 {
977 case 8:
978 dmap = odigits;
979 break;
980 case 16:
981 dmap = hdigits;
982 break;
983 default:
984 base = 10;
985 dmap = ddigits;
986 break;
987 }
988
989 /* Check for a minus. */
990 neg = 0;
991 if ( *s == '-' )
992 {
993 s++;
994 neg = 1;
995 }
996
997 /* Check for the special hex prefix. */
998 if ( *s == '0' &&
999 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
1000 {
1001 base = 16;
1002 dmap = hdigits;
1003 s += 2;
1004 }
1005
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001006 for ( v = 0; sbitset( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +00001007 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001008
1009 if ( end != 0 )
1010 *end = s;
1011
Werner Lemberg233302a2002-05-22 05:41:06 +00001012 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001013 }
1014
1015
1016 /* Routine to compare two glyphs by encoding so they can be sorted. */
1017 static int
1018 by_encoding( const void* a,
1019 const void* b )
1020 {
1021 bdf_glyph_t *c1, *c2;
1022
1023
1024 c1 = (bdf_glyph_t *)a;
1025 c2 = (bdf_glyph_t *)b;
1026
1027 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001028 return -1;
David Turner68df4f72005-03-15 18:18:57 +00001029
1030 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +00001031 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001032
David Turner993a8d02002-05-18 12:03:43 +00001033 return 0;
David Turner993a8d02002-05-18 12:03:43 +00001034 }
1035
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001036
1037 static FT_Error
1038 bdf_create_property( char* name,
1039 int format,
1040 bdf_font_t* font )
1041 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001042 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001043 bdf_property_t* p;
1044 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001045 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001046
1047
Werner Lemberg96ddc672011-06-29 09:15:54 +02001048 /* First check whether the property has */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001049 /* already been added or not. If it has, then */
1050 /* simply ignore it. */
1051 if ( hash_lookup( name, &(font->proptbl) ) )
1052 goto Exit;
1053
David Turner68df4f72005-03-15 18:18:57 +00001054 if ( FT_RENEW_ARRAY( font->user_props,
1055 font->nuser_props,
1056 font->nuser_props + 1 ) )
1057 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001058
1059 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +00001060 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001061
suzuki toshiya704f4d72009-09-13 00:50:14 +09001062 n = ft_strlen( name ) + 1;
1063 if ( n > FT_ULONG_MAX )
Werner Lemberg059bc332013-03-14 10:27:35 +01001064 return FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +00001065
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001066 if ( FT_NEW_ARRAY( p->name, n ) )
1067 goto Exit;
1068
1069 FT_MEM_COPY( (char *)p->name, name, n );
1070
1071 p->format = format;
1072 p->builtin = 0;
1073
1074 n = _num_bdf_properties + font->nuser_props;
1075
suzuki toshiya704f4d72009-09-13 00:50:14 +09001076 error = hash_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001077 if ( error )
1078 goto Exit;
1079
1080 font->nuser_props++;
1081
1082 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001083 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001084 }
David Turner993a8d02002-05-18 12:03:43 +00001085
1086
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001087 FT_LOCAL_DEF( bdf_property_t * )
1088 bdf_get_property( char* name,
1089 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001090 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001091 hashnode hn;
1092 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001093
1094
1095 if ( name == 0 || *name == 0 )
1096 return 0;
1097
1098 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1099 return 0;
1100
suzuki toshiya704f4d72009-09-13 00:50:14 +09001101 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001102 if ( propid >= _num_bdf_properties )
1103 return font->user_props + ( propid - _num_bdf_properties );
1104
Werner Lemberg233302a2002-05-22 05:41:06 +00001105 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001106 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001107
1108
1109 /*************************************************************************/
1110 /* */
1111 /* BDF font file parsing flags and functions. */
1112 /* */
1113 /*************************************************************************/
1114
1115
1116 /* Parse flags. */
1117
1118#define _BDF_START 0x0001
1119#define _BDF_FONT_NAME 0x0002
1120#define _BDF_SIZE 0x0004
1121#define _BDF_FONT_BBX 0x0008
1122#define _BDF_PROPS 0x0010
1123#define _BDF_GLYPHS 0x0020
1124#define _BDF_GLYPH 0x0040
1125#define _BDF_ENCODING 0x0080
1126#define _BDF_SWIDTH 0x0100
1127#define _BDF_DWIDTH 0x0200
1128#define _BDF_BBX 0x0400
1129#define _BDF_BITMAP 0x0800
1130
1131#define _BDF_SWIDTH_ADJ 0x1000
1132
1133#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1134 _BDF_ENCODING | \
1135 _BDF_SWIDTH | \
1136 _BDF_DWIDTH | \
1137 _BDF_BBX | \
1138 _BDF_BITMAP )
1139
Werner Lembergf1c2b912006-01-13 14:53:28 +00001140#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1141#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001142
1143
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001144 static FT_Error
1145 _bdf_add_comment( bdf_font_t* font,
1146 char* comment,
1147 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001148 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001149 char* cp;
1150 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001151 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001152
1153
David Turner68df4f72005-03-15 18:18:57 +00001154 if ( FT_RENEW_ARRAY( font->comments,
1155 font->comments_len,
1156 font->comments_len + len + 1 ) )
1157 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001158
1159 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001160
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001161 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001162 cp[len] = '\n';
1163
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001164 font->comments_len += len + 1;
1165
1166 Exit:
1167 return error;
David Turner993a8d02002-05-18 12:03:43 +00001168 }
1169
David Turner993a8d02002-05-18 12:03:43 +00001170
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001171 /* Set the spacing from the font name if it exists, or set it to the */
1172 /* default specified in the options. */
1173 static FT_Error
1174 _bdf_set_default_spacing( bdf_font_t* font,
Werner Lemberge01406b2011-11-25 09:44:28 +01001175 bdf_options_t* opts,
1176 unsigned long lineno )
David Turner993a8d02002-05-18 12:03:43 +00001177 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001178 size_t len;
1179 char name[256];
1180 _bdf_list_t list;
1181 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001182 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001183
Dave Arnoldc3782492013-06-05 19:57:55 +02001184 FT_UNUSED( lineno ); /* only used in debug mode */
1185
David Turner993a8d02002-05-18 12:03:43 +00001186
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001187 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1188 {
Werner Lemberg059bc332013-03-14 10:27:35 +01001189 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001190 goto Exit;
1191 }
David Turner993a8d02002-05-18 12:03:43 +00001192
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001193 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001194
David Turner68df4f72005-03-15 18:18:57 +00001195 _bdf_list_init( &list, memory );
1196
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001197 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001198
suzuki toshiya704f4d72009-09-13 00:50:14 +09001199 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +00001200 /* Limit ourselves to 256 characters in the font name. */
1201 if ( len >= 256 )
1202 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001203 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001204 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001205 goto Exit;
1206 }
1207
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001208 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001209
Werner Lembergbadf3172013-06-06 09:16:38 +02001210 error = _bdf_list_split( &list, (char *)"-", name, (unsigned long)len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001211 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001212 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001213
1214 if ( list.used == 15 )
1215 {
1216 switch ( list.field[11][0] )
1217 {
1218 case 'C':
1219 case 'c':
1220 font->spacing = BDF_CHARCELL;
1221 break;
1222 case 'M':
1223 case 'm':
1224 font->spacing = BDF_MONOWIDTH;
1225 break;
1226 case 'P':
1227 case 'p':
1228 font->spacing = BDF_PROPORTIONAL;
1229 break;
David Turner993a8d02002-05-18 12:03:43 +00001230 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001231 }
1232
David Turner68df4f72005-03-15 18:18:57 +00001233 Fail:
1234 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001235
1236 Exit:
1237 return error;
David Turner993a8d02002-05-18 12:03:43 +00001238 }
David Turner993a8d02002-05-18 12:03:43 +00001239
1240
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001241 /* Determine whether the property is an atom or not. If it is, then */
1242 /* clean it up so the double quotes are removed if they exist. */
1243 static int
1244 _bdf_is_atom( char* line,
1245 unsigned long linelen,
1246 char** name,
1247 char** value,
1248 bdf_font_t* font )
1249 {
1250 int hold;
1251 char *sp, *ep;
1252 bdf_property_t* p;
1253
David Turner993a8d02002-05-18 12:03:43 +00001254
1255 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001256
1257 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001258 ep++;
1259
1260 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001261 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001262 {
1263 hold = *ep;
1264 *ep = 0;
1265 }
1266
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001267 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001268
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001269 /* Restore the character that was saved before any return can happen. */
1270 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001271 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001272
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001273 /* If the property exists and is not an atom, just return here. */
1274 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001275 return 0;
1276
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001277 /* The property is an atom. Trim all leading and trailing whitespace */
1278 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001279 sp = ep;
1280 ep = line + linelen;
1281
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001282 /* Trim the leading whitespace if it exists. */
Werner Lemberg320d4972012-02-24 18:06:46 +01001283 if ( *sp )
1284 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001285 while ( *sp &&
1286 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001287 sp++;
1288
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001289 /* Trim the leading double quote if it exists. */
1290 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001291 sp++;
1292 *value = sp;
1293
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001294 /* Trim the trailing whitespace if it exists. */
1295 while ( ep > sp &&
1296 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001297 *--ep = 0;
1298
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001299 /* Trim the trailing double quote if it exists. */
1300 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001301 *--ep = 0;
1302
1303 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001304 }
David Turner993a8d02002-05-18 12:03:43 +00001305
1306
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001307 static FT_Error
Werner Lemberge01406b2011-11-25 09:44:28 +01001308 _bdf_add_property( bdf_font_t* font,
1309 char* name,
1310 char* value,
1311 unsigned long lineno )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001312 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001313 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001314 hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001315 bdf_property_t *prop, *fp;
1316 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001317 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001318
Dave Arnoldc3782492013-06-05 19:57:55 +02001319 FT_UNUSED( lineno ); /* only used in debug mode */
1320
David Turner993a8d02002-05-18 12:03:43 +00001321
Werner Lemberg96ddc672011-06-29 09:15:54 +02001322 /* First, check whether the property already exists in the font. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001323 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001324 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001325 /* The property already exists in the font, so simply replace */
1326 /* the value of the property with the current value. */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001327 fp = font->props + hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001328
David Turnerb1b47622002-05-21 21:17:43 +00001329 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001330 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001331 case BDF_ATOM:
1332 /* Delete the current atom if it exists. */
1333 FT_FREE( fp->value.atom );
1334
David Turnerc0f9c4a2007-02-12 14:55:03 +00001335 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001336 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001337 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001338 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001339 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001340 break;
1341
1342 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001343 fp->value.l = _bdf_atol( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001344 break;
1345
1346 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001347 fp->value.ul = _bdf_atoul( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001348 break;
David Turnerd490e372002-05-28 23:40:37 +00001349
David Turnerb1b47622002-05-21 21:17:43 +00001350 default:
1351 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001352 }
David Turnerd490e372002-05-28 23:40:37 +00001353
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001354 goto Exit;
1355 }
1356
1357 /* See whether this property type exists yet or not. */
1358 /* If not, create it. */
1359 hn = hash_lookup( name, &(font->proptbl) );
1360 if ( hn == 0 )
1361 {
1362 error = bdf_create_property( name, BDF_ATOM, font );
1363 if ( error )
1364 goto Exit;
1365 hn = hash_lookup( name, &(font->proptbl) );
1366 }
1367
1368 /* Allocate another property if this is overflow. */
1369 if ( font->props_used == font->props_size )
1370 {
1371 if ( font->props_size == 0 )
1372 {
1373 if ( FT_NEW_ARRAY( font->props, 1 ) )
1374 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001375 }
1376 else
1377 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001378 if ( FT_RENEW_ARRAY( font->props,
1379 font->props_size,
1380 font->props_size + 1 ) )
1381 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001382 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001383
David Turner993a8d02002-05-18 12:03:43 +00001384 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001385 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001386 font->props_size++;
1387 }
1388
suzuki toshiya704f4d72009-09-13 00:50:14 +09001389 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001390 if ( propid >= _num_bdf_properties )
1391 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001392 else
David Turnerb1b47622002-05-21 21:17:43 +00001393 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001394
1395 fp = font->props + font->props_used;
1396
1397 fp->name = prop->name;
1398 fp->format = prop->format;
1399 fp->builtin = prop->builtin;
1400
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001401 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001402 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001403 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001404 fp->value.atom = 0;
1405 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001406 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001407 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001408 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001409 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001410 break;
David Turner993a8d02002-05-18 12:03:43 +00001411
1412 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001413 fp->value.l = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001414 break;
1415
1416 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001417 fp->value.ul = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001418 break;
David Turner993a8d02002-05-18 12:03:43 +00001419 }
1420
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001421 /* If the property happens to be a comment, then it doesn't need */
1422 /* to be added to the internal hash table. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001423 if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 )
Werner Lemberg370aea82010-06-08 08:37:11 +02001424 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001425 /* Add the property to the font property table. */
1426 error = hash_insert( fp->name,
suzuki toshiya704f4d72009-09-13 00:50:14 +09001427 font->props_used,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001428 (hashtable *)font->internal,
1429 memory );
1430 if ( error )
1431 goto Exit;
1432 }
David Turner993a8d02002-05-18 12:03:43 +00001433
1434 font->props_used++;
1435
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001436 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1437 /* property needs to be located if it exists in the property list, the */
1438 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1439 /* present, and the SPACING property should override the default */
1440 /* spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001441 if ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001442 font->default_char = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001443 else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001444 font->font_ascent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001445 else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001446 font->font_descent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001447 else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001448 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001449 if ( !fp->value.atom )
1450 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001451 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001452 error = FT_THROW( Invalid_File_Format );
Werner Lembergb66efef2009-03-12 08:07:49 +00001453 goto Exit;
1454 }
1455
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001456 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001457 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001458 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001459 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001460 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001461 font->spacing = BDF_CHARCELL;
1462 }
1463
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001464 Exit:
1465 return error;
David Turner993a8d02002-05-18 12:03:43 +00001466 }
1467
David Turner993a8d02002-05-18 12:03:43 +00001468
David Turnerb1b47622002-05-21 21:17:43 +00001469 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001470 {
1471 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1472 };
1473
1474
1475 /* Actually parse the glyph info and bitmaps. */
1476 static FT_Error
1477 _bdf_parse_glyphs( char* line,
1478 unsigned long linelen,
1479 unsigned long lineno,
1480 void* call_data,
1481 void* client_data )
1482 {
1483 int c, mask_index;
1484 char* s;
1485 unsigned char* bp;
1486 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001487
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001488 _bdf_parse_t* p;
1489 bdf_glyph_t* glyph;
1490 bdf_font_t* font;
1491
1492 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001493 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001494
Werner Lemberg319c00d2003-04-23 19:48:24 +00001495 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001496 FT_UNUSED( lineno ); /* only used in debug mode */
1497
1498
Werner Lemberg319c00d2003-04-23 19:48:24 +00001499 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001500
1501 font = p->font;
1502 memory = font->memory;
1503
1504 /* Check for a comment. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001505 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001506 {
1507 linelen -= 7;
1508
1509 s = line + 7;
1510 if ( *s != 0 )
1511 {
1512 s++;
1513 linelen--;
1514 }
1515 error = _bdf_add_comment( p->font, s, linelen );
1516 goto Exit;
1517 }
1518
1519 /* The very first thing expected is the number of glyphs. */
1520 if ( !( p->flags & _BDF_GLYPHS ) )
1521 {
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001522 if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001523 {
1524 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001525 error = FT_THROW( Missing_Chars_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001526 goto Exit;
1527 }
1528
David Turner68df4f72005-03-15 18:18:57 +00001529 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001530 if ( error )
1531 goto Exit;
1532 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1533
1534 /* Make sure the number of glyphs is non-zero. */
1535 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001536 font->glyphs_size = 64;
1537
Werner Lemberga08b2172007-03-28 07:17:17 +00001538 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1539 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001540 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001541 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001542 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001543 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001544 goto Exit;
1545 }
1546
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001547 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1548 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001549
David Turner993a8d02002-05-18 12:03:43 +00001550 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001551
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001552 goto Exit;
1553 }
1554
1555 /* Check for the ENDFONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001556 if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001557 {
Werner Lembergaf834612014-11-22 13:29:10 +01001558 if ( p->flags & _BDF_GLYPH_BITS )
1559 {
1560 /* Missing ENDCHAR field. */
1561 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1562 error = FT_THROW( Corrupted_Font_Glyphs );
1563 goto Exit;
1564 }
1565
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001566 /* Sort the glyphs by encoding. */
1567 ft_qsort( (char *)font->glyphs,
1568 font->glyphs_used,
1569 sizeof ( bdf_glyph_t ),
1570 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001571
1572 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001573
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001574 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001575 }
1576
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001577 /* Check for the ENDCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001578 if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001579 {
1580 p->glyph_enc = 0;
1581 p->flags &= ~_BDF_GLYPH_BITS;
1582
1583 goto Exit;
1584 }
1585
Werner Lemberg96ddc672011-06-29 09:15:54 +02001586 /* Check whether a glyph is being scanned but should be */
1587 /* ignored because it is an unencoded glyph. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001588 if ( ( p->flags & _BDF_GLYPH ) &&
1589 p->glyph_enc == -1 &&
1590 p->opts->keep_unencoded == 0 )
1591 goto Exit;
1592
1593 /* Check for the STARTCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001594 if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001595 {
1596 /* Set the character name in the parse info first until the */
1597 /* encoding can be checked for an unencoded character. */
1598 FT_FREE( p->glyph_name );
1599
David Turner68df4f72005-03-15 18:18:57 +00001600 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001601 if ( error )
1602 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001603
David Turner68df4f72005-03-15 18:18:57 +00001604 _bdf_list_shift( &p->list, 1 );
1605
1606 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001607
Werner Lembergba03af62007-05-30 13:57:02 +00001608 if ( !s )
1609 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001610 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001611 error = FT_THROW( Invalid_File_Format );
Werner Lembergba03af62007-05-30 13:57:02 +00001612 goto Exit;
1613 }
1614
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001615 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1616 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001617
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001618 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1619
1620 p->flags |= _BDF_GLYPH;
1621
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001622 FT_TRACE4(( DBGMSG1, lineno, s ));
1623
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001624 goto Exit;
1625 }
1626
1627 /* Check for the ENCODING field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001628 if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001629 {
1630 if ( !( p->flags & _BDF_GLYPH ) )
1631 {
1632 /* Missing STARTCHAR field. */
1633 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001634 error = FT_THROW( Missing_Startchar_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001635 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001636 }
1637
David Turner68df4f72005-03-15 18:18:57 +00001638 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001639 if ( error )
1640 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001641
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001642 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001643
Werner Lemberg28dd2c42012-02-26 06:18:58 +01001644 /* Normalize negative encoding values. The specification only */
1645 /* allows -1, but we can be more generous here. */
1646 if ( p->glyph_enc < -1 )
1647 p->glyph_enc = -1;
1648
Werner Lemberg03242f52012-02-26 06:52:56 +01001649 /* Check for alternative encoding format. */
1650 if ( p->glyph_enc == -1 && p->list.used > 2 )
1651 p->glyph_enc = _bdf_atol( p->list.field[2], 0, 10 );
1652
Werner Lemberg7f2e4f42012-12-15 09:39:41 +01001653 if ( p->glyph_enc < -1 )
1654 p->glyph_enc = -1;
1655
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001656 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1657
Werner Lemberged54e432011-11-27 16:39:53 +01001658 /* Check that the encoding is in the Unicode range because */
1659 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lemberg07bdb6e2012-12-15 02:02:23 +01001660 if ( p->glyph_enc > 0 &&
1661 (size_t)p->glyph_enc >= sizeof ( p->have ) /
1662 sizeof ( unsigned long ) * 32 )
David Turner481838e2006-02-23 12:40:14 +00001663 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001664 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001665 error = FT_THROW( Invalid_File_Format );
David Turner481838e2006-02-23 12:40:14 +00001666 goto Exit;
1667 }
1668
Werner Lemberg96ddc672011-06-29 09:15:54 +02001669 /* Check whether this encoding has already been encountered. */
1670 /* If it has then change it to unencoded so it gets added if */
1671 /* indicated. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001672 if ( p->glyph_enc >= 0 )
1673 {
1674 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1675 {
1676 /* Emit a message saying a glyph has been moved to the */
1677 /* unencoded area. */
1678 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1679 p->glyph_enc, p->glyph_name ));
1680 p->glyph_enc = -1;
1681 font->modified = 1;
1682 }
1683 else
1684 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1685 }
1686
1687 if ( p->glyph_enc >= 0 )
1688 {
1689 /* Make sure there are enough glyphs allocated in case the */
1690 /* number of characters happen to be wrong. */
1691 if ( font->glyphs_used == font->glyphs_size )
1692 {
1693 if ( FT_RENEW_ARRAY( font->glyphs,
1694 font->glyphs_size,
1695 font->glyphs_size + 64 ) )
1696 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001697
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001698 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001699 }
1700
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001701 glyph = font->glyphs + font->glyphs_used++;
1702 glyph->name = p->glyph_name;
1703 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001704
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001705 /* Reset the initial glyph info. */
1706 p->glyph_name = 0;
1707 }
1708 else
1709 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001710 /* Unencoded glyph. Check whether it should */
1711 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001712 if ( p->opts->keep_unencoded != 0 )
1713 {
1714 /* Allocate the next unencoded glyph. */
1715 if ( font->unencoded_used == font->unencoded_size )
1716 {
David Turner68df4f72005-03-15 18:18:57 +00001717 if ( FT_RENEW_ARRAY( font->unencoded ,
1718 font->unencoded_size,
1719 font->unencoded_size + 4 ) )
1720 goto Exit;
1721
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001722 font->unencoded_size += 4;
1723 }
1724
1725 glyph = font->unencoded + font->unencoded_used;
1726 glyph->name = p->glyph_name;
1727 glyph->encoding = font->unencoded_used++;
1728 }
1729 else
1730 /* Free up the glyph name if the unencoded shouldn't be */
1731 /* kept. */
1732 FT_FREE( p->glyph_name );
1733
1734 p->glyph_name = 0;
1735 }
1736
1737 /* Clear the flags that might be added when width and height are */
1738 /* checked for consistency. */
1739 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1740
1741 p->flags |= _BDF_ENCODING;
1742
1743 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001744 }
1745
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001746 /* Point at the glyph being constructed. */
1747 if ( p->glyph_enc == -1 )
1748 glyph = font->unencoded + ( font->unencoded_used - 1 );
1749 else
1750 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001751
Werner Lemberg96ddc672011-06-29 09:15:54 +02001752 /* Check whether a bitmap is being constructed. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001753 if ( p->flags & _BDF_BITMAP )
1754 {
1755 /* If there are more rows than are specified in the glyph metrics, */
1756 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001757 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001758 {
1759 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1760 {
1761 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1762 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001763 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001764 }
1765
1766 goto Exit;
1767 }
1768
1769 /* Only collect the number of nibbles indicated by the glyph */
1770 /* metrics. If there are more columns, they are simply ignored. */
1771 nibbles = glyph->bpr << 1;
1772 bp = glyph->bitmap + p->row * glyph->bpr;
1773
David Turnerb698eed2006-02-23 14:50:13 +00001774 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001775 {
1776 c = line[i];
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001777 if ( !sbitset( hdigits, c ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001778 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001779 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001780 if ( i + 1 < nibbles && ( i & 1 ) )
1781 *++bp = 0;
1782 }
1783
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001784 /* If any line has not enough columns, */
1785 /* indicate they have been padded with zero bits. */
1786 if ( i < nibbles &&
1787 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1788 {
1789 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
1790 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1791 font->modified = 1;
1792 }
1793
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001794 /* Remove possible garbage at the right. */
1795 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001796 if ( glyph->bbx.width )
1797 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001798
1799 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001800 if ( i == nibbles &&
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001801 sbitset( hdigits, line[nibbles] ) &&
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001802 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001803 {
1804 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1805 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1806 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001807 }
1808
1809 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001810 goto Exit;
1811 }
David Turner993a8d02002-05-18 12:03:43 +00001812
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001813 /* Expect the SWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001814 if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001815 {
1816 if ( !( p->flags & _BDF_ENCODING ) )
Werner Lemberg4086fb72012-03-01 08:55:40 +01001817 goto Missing_Encoding;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001818
David Turner68df4f72005-03-15 18:18:57 +00001819 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001820 if ( error )
1821 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001822
David Turnerb1b47622002-05-21 21:17:43 +00001823 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001824 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001825
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001826 goto Exit;
1827 }
David Turner993a8d02002-05-18 12:03:43 +00001828
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001829 /* Expect the DWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001830 if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001831 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001832 if ( !( p->flags & _BDF_ENCODING ) )
1833 goto Missing_Encoding;
1834
David Turner68df4f72005-03-15 18:18:57 +00001835 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001836 if ( error )
1837 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001838
David Turnerb1b47622002-05-21 21:17:43 +00001839 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001840
1841 if ( !( p->flags & _BDF_SWIDTH ) )
1842 {
1843 /* Missing SWIDTH field. Emit an auto correction message and set */
1844 /* the scalable width from the device width. */
1845 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1846
Werner Lemberg02d4d592002-05-28 22:38:05 +00001847 glyph->swidth = (unsigned short)FT_MulDiv(
1848 glyph->dwidth, 72000L,
1849 (FT_Long)( font->point_size *
1850 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001851 }
1852
1853 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001854 goto Exit;
1855 }
David Turner993a8d02002-05-18 12:03:43 +00001856
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001857 /* Expect the BBX field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001858 if ( _bdf_strncmp( line, "BBX", 3 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001859 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001860 if ( !( p->flags & _BDF_ENCODING ) )
1861 goto Missing_Encoding;
1862
David Turner68df4f72005-03-15 18:18:57 +00001863 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001864 if ( error )
1865 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001866
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001867 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1868 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1869 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1870 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1871
1872 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001873 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1874 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001875
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001876 /* Determine the overall font bounding box as the characters are */
1877 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001878 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1879 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001880
David Turnerb1b47622002-05-21 21:17:43 +00001881 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001882
Werner Lembergdfa46192004-03-05 09:26:24 +00001883 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1884 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1885 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001886
1887 if ( !( p->flags & _BDF_DWIDTH ) )
1888 {
1889 /* Missing DWIDTH field. Emit an auto correction message and set */
1890 /* the device width to the glyph width. */
1891 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1892 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001893 }
1894
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001895 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1896 /* value if necessary. */
1897 if ( p->opts->correct_metrics != 0 )
1898 {
1899 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001900 unsigned short sw = (unsigned short)FT_MulDiv(
1901 glyph->dwidth, 72000L,
1902 (FT_Long)( font->point_size *
1903 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001904
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001905
1906 if ( sw != glyph->swidth )
1907 {
1908 glyph->swidth = sw;
1909
1910 if ( p->glyph_enc == -1 )
1911 _bdf_set_glyph_modified( font->umod,
1912 font->unencoded_used - 1 );
1913 else
1914 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1915
1916 p->flags |= _BDF_SWIDTH_ADJ;
1917 font->modified = 1;
1918 }
David Turner993a8d02002-05-18 12:03:43 +00001919 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001920
David Turner993a8d02002-05-18 12:03:43 +00001921 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001922 goto Exit;
1923 }
David Turner993a8d02002-05-18 12:03:43 +00001924
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001925 /* And finally, gather up the bitmap. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001926 if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001927 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001928 unsigned long bitmap_size;
1929
1930
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001931 if ( !( p->flags & _BDF_BBX ) )
1932 {
1933 /* Missing BBX field. */
1934 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001935 error = FT_THROW( Missing_Bbx_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001936 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001937 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001938
1939 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001940 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001941
1942 bitmap_size = glyph->bpr * glyph->bbx.height;
Werner Lembergc4cad302012-03-08 20:11:37 +01001943 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
Werner Lemberg26170df2006-03-26 07:19:07 +00001944 {
1945 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001946 error = FT_THROW( Bbx_Too_Big );
Werner Lemberg26170df2006-03-26 07:19:07 +00001947 goto Exit;
1948 }
1949 else
1950 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001951
1952 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1953 goto Exit;
1954
1955 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001956 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001957
1958 goto Exit;
1959 }
1960
Werner Lemberge01406b2011-11-25 09:44:28 +01001961 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001962 error = FT_THROW( Invalid_File_Format );
Werner Lemberg4086fb72012-03-01 08:55:40 +01001963 goto Exit;
1964
1965 Missing_Encoding:
1966 /* Missing ENCODING field. */
1967 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001968 error = FT_THROW( Missing_Encoding_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001969
1970 Exit:
Werner Lembergf4c94d42010-06-19 16:08:31 +02001971 if ( error && ( p->flags & _BDF_GLYPH ) )
1972 FT_FREE( p->glyph_name );
1973
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001974 return error;
David Turner993a8d02002-05-18 12:03:43 +00001975 }
1976
David Turner993a8d02002-05-18 12:03:43 +00001977
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001978 /* Load the font properties. */
1979 static FT_Error
1980 _bdf_parse_properties( char* line,
1981 unsigned long linelen,
1982 unsigned long lineno,
1983 void* call_data,
1984 void* client_data )
1985 {
1986 unsigned long vlen;
1987 _bdf_line_func_t* next;
1988 _bdf_parse_t* p;
1989 char* name;
1990 char* value;
1991 char nbuf[128];
Werner Lemberge3c93012013-03-14 11:21:17 +01001992 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001993
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001994 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001995
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001996
1997 next = (_bdf_line_func_t *)call_data;
1998 p = (_bdf_parse_t *) client_data;
1999
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002000 /* Check for the end of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002001 if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002002 {
2003 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
2004 /* encountered yet, then make sure they are added as properties and */
2005 /* make sure they are set from the font bounding box info. */
2006 /* */
2007 /* This is *always* done regardless of the options, because X11 */
2008 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00002009 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002010 {
2011 p->font->font_ascent = p->font->bbx.ascent;
2012 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002013 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2014 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002015 if ( error )
2016 goto Exit;
2017
2018 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2019 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002020 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002021
Werner Lemberg428c2e42003-04-25 05:35:04 +00002022 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002023 {
2024 p->font->font_descent = p->font->bbx.descent;
2025 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002026 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2027 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002028 if ( error )
2029 goto Exit;
2030
2031 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2032 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002033 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002034
David Turner993a8d02002-05-18 12:03:43 +00002035 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002036 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00002037
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002038 goto Exit;
2039 }
David Turner993a8d02002-05-18 12:03:43 +00002040
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002041 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002042 if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002043 goto Exit;
2044
2045 /* Handle COMMENT fields and properties in a special way to preserve */
2046 /* the spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002047 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002048 {
David Turner993a8d02002-05-18 12:03:43 +00002049 name = value = line;
2050 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002051 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00002052 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01002053 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002054 if ( error )
2055 goto Exit;
2056 }
2057 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
2058 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002059 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002060 if ( error )
2061 goto Exit;
2062 }
2063 else
2064 {
David Turner68df4f72005-03-15 18:18:57 +00002065 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002066 if ( error )
2067 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002068 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002069
David Turner68df4f72005-03-15 18:18:57 +00002070 _bdf_list_shift( &p->list, 1 );
2071 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002072
Werner Lemberge01406b2011-11-25 09:44:28 +01002073 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002074 if ( error )
2075 goto Exit;
2076 }
2077
2078 Exit:
2079 return error;
David Turner993a8d02002-05-18 12:03:43 +00002080 }
2081
David Turner993a8d02002-05-18 12:03:43 +00002082
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002083 /* Load the font header. */
2084 static FT_Error
2085 _bdf_parse_start( char* line,
2086 unsigned long linelen,
2087 unsigned long lineno,
2088 void* call_data,
2089 void* client_data )
2090 {
2091 unsigned long slen;
2092 _bdf_line_func_t* next;
2093 _bdf_parse_t* p;
2094 bdf_font_t* font;
2095 char *s;
David Turner993a8d02002-05-18 12:03:43 +00002096
David Turnerd490e372002-05-28 23:40:37 +00002097 FT_Memory memory = NULL;
Werner Lemberge3c93012013-03-14 11:21:17 +01002098 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002099
2100 FT_UNUSED( lineno ); /* only used in debug mode */
2101
2102
2103 next = (_bdf_line_func_t *)call_data;
2104 p = (_bdf_parse_t *) client_data;
2105
2106 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00002107 memory = p->font->memory;
2108
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002109 /* Check for a comment. This is done to handle those fonts that have */
2110 /* comments before the STARTFONT line for some reason. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002111 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002112 {
2113 if ( p->opts->keep_comments != 0 && p->font != 0 )
2114 {
2115 linelen -= 7;
2116
2117 s = line + 7;
2118 if ( *s != 0 )
2119 {
2120 s++;
2121 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002122 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002123
2124 error = _bdf_add_comment( p->font, s, linelen );
2125 if ( error )
2126 goto Exit;
2127 /* here font is not defined! */
2128 }
2129
2130 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002131 }
2132
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002133 if ( !( p->flags & _BDF_START ) )
2134 {
2135 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002136
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002137 if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002138 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01002139 /* we don't emit an error message since this code gets */
2140 /* explicitly caught one level higher */
Werner Lemberg059bc332013-03-14 10:27:35 +01002141 error = FT_THROW( Missing_Startfont_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002142 goto Exit;
2143 }
David Turner993a8d02002-05-18 12:03:43 +00002144
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002145 p->flags = _BDF_START;
2146 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002147
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002148 if ( FT_NEW( font ) )
2149 goto Exit;
2150 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002151
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002152 font->memory = p->memory;
2153 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002154
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002155 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09002156 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002157 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002158
David Turner993a8d02002-05-18 12:03:43 +00002159
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002160 error = hash_init( &(font->proptbl), memory );
2161 if ( error )
2162 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002163 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002164 i < _num_bdf_properties; i++, prop++ )
2165 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09002166 error = hash_insert( prop->name, i,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002167 &(font->proptbl), memory );
2168 if ( error )
2169 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002170 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002171 }
2172
2173 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2174 goto Exit;
2175 error = hash_init( (hashtable *)p->font->internal,memory );
2176 if ( error )
2177 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002178 p->font->spacing = p->opts->font_spacing;
2179 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002180
2181 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002182 }
2183
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002184 /* Check for the start of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002185 if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002186 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002187 if ( !( p->flags & _BDF_FONT_BBX ) )
Werner Lembergfb690292010-06-23 10:00:52 +02002188 {
2189 /* Missing the FONTBOUNDINGBOX field. */
2190 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002191 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergfb690292010-06-23 10:00:52 +02002192 goto Exit;
2193 }
2194
David Turner68df4f72005-03-15 18:18:57 +00002195 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002196 if ( error )
2197 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00002198 /* at this point, `p->font' can't be NULL */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002199 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2200
2201 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
Werner Lemberg9b6b5752012-12-15 01:34:41 +01002202 {
2203 p->font->props_size = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002204 goto Exit;
Werner Lemberg9b6b5752012-12-15 01:34:41 +01002205 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002206
2207 p->flags |= _BDF_PROPS;
2208 *next = _bdf_parse_properties;
2209
2210 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002211 }
2212
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002213 /* Check for the FONTBOUNDINGBOX field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002214 if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002215 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002216 if ( !( p->flags & _BDF_SIZE ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002217 {
2218 /* Missing the SIZE field. */
2219 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002220 error = FT_THROW( Missing_Size_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002221 goto Exit;
2222 }
2223
David Turner68df4f72005-03-15 18:18:57 +00002224 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002225 if ( error )
2226 goto Exit;
2227
2228 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2229 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2230
2231 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2232 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2233
David Turnerd490e372002-05-28 23:40:37 +00002234 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002235 p->font->bbx.y_offset );
2236
2237 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002238
2239 p->flags |= _BDF_FONT_BBX;
2240
2241 goto Exit;
2242 }
2243
2244 /* The next thing to check for is the FONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002245 if ( _bdf_strncmp( line, "FONT", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002246 {
David Turner68df4f72005-03-15 18:18:57 +00002247 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002248 if ( error )
2249 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002250 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002251
David Turner68df4f72005-03-15 18:18:57 +00002252 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002253
2254 if ( !s )
2255 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002256 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002257 error = FT_THROW( Invalid_File_Format );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002258 goto Exit;
2259 }
2260
Werner Lembergfb690292010-06-23 10:00:52 +02002261 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2262 FT_FREE( p->font->name );
2263
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002264 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2265 goto Exit;
2266 FT_MEM_COPY( p->font->name, s, slen + 1 );
2267
2268 /* If the font name is an XLFD name, set the spacing to the one in */
2269 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002270 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002271 if ( error )
2272 goto Exit;
2273
2274 p->flags |= _BDF_FONT_NAME;
2275
2276 goto Exit;
2277 }
2278
2279 /* Check for the SIZE field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002280 if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002281 {
2282 if ( !( p->flags & _BDF_FONT_NAME ) )
2283 {
2284 /* Missing the FONT field. */
2285 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002286 error = FT_THROW( Missing_Font_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002287 goto Exit;
2288 }
2289
David Turner68df4f72005-03-15 18:18:57 +00002290 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002291 if ( error )
2292 goto Exit;
2293
2294 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2295 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2296 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2297
2298 /* Check for the bits per pixel field. */
2299 if ( p->list.used == 5 )
2300 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002301 unsigned short bitcount, i, shift;
2302
2303
2304 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2305
2306 /* Only values 1, 2, 4, 8 are allowed. */
2307 shift = p->font->bpp;
2308 bitcount = 0;
2309 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002310 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002311 if ( shift & 1 )
2312 bitcount = i;
2313 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002314 }
David Turner993a8d02002-05-18 12:03:43 +00002315
Werner Lembergbd8e3242002-06-12 08:43:58 +00002316 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002317
2318 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002319 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002320 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002321 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002322 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002323 }
2324 }
2325 else
2326 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002327
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002328 p->flags |= _BDF_SIZE;
2329
2330 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002331 }
2332
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002333 /* Check for the CHARS field -- font properties are optional */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002334 if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002335 {
2336 char nbuf[128];
2337
2338
2339 if ( !( p->flags & _BDF_FONT_BBX ) )
2340 {
2341 /* Missing the FONTBOUNDINGBOX field. */
2342 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002343 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002344 goto Exit;
2345 }
2346
2347 /* Add the two standard X11 properties which are required */
2348 /* for compiling fonts. */
2349 p->font->font_ascent = p->font->bbx.ascent;
2350 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002351 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2352 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002353 if ( error )
2354 goto Exit;
2355 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2356
2357 p->font->font_descent = p->font->bbx.descent;
2358 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002359 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2360 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002361 if ( error )
2362 goto Exit;
2363 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2364
2365 p->font->modified = 1;
2366
2367 *next = _bdf_parse_glyphs;
2368
2369 /* A special return value. */
2370 error = -1;
2371 goto Exit;
2372 }
2373
Werner Lemberge01406b2011-11-25 09:44:28 +01002374 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002375 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002376
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002377 Exit:
2378 return error;
2379 }
David Turner993a8d02002-05-18 12:03:43 +00002380
2381
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002382 /*************************************************************************/
2383 /* */
2384 /* API. */
2385 /* */
2386 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002387
David Turner993a8d02002-05-18 12:03:43 +00002388
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002389 FT_LOCAL_DEF( FT_Error )
2390 bdf_load_font( FT_Stream stream,
2391 FT_Memory extmemory,
2392 bdf_options_t* opts,
2393 bdf_font_t* *font )
2394 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002395 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002396 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002397
Sean McBride7be2a942014-02-08 13:55:38 +01002398 FT_Memory memory = extmemory; /* needed for FT_NEW */
2399 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002400
2401
David Turner68df4f72005-03-15 18:18:57 +00002402 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002403 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002404
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002405 memory = NULL;
2406 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2407 p->minlb = 32767;
2408 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002409
David Turner68df4f72005-03-15 18:18:57 +00002410 _bdf_list_init( &p->list, extmemory );
2411
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002412 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002413 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002414 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002415 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002416
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002417 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002418 {
2419 /* If the font is not proportional, set the font's monowidth */
2420 /* field to the width of the font bounding box. */
David Turner993a8d02002-05-18 12:03:43 +00002421
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002422 if ( p->font->spacing != BDF_PROPORTIONAL )
2423 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002424
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002425 /* If the number of glyphs loaded is not that of the original count, */
2426 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002427 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002428 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002429 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2430 p->font->glyphs_used + p->font->unencoded_used ));
2431 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002432 }
2433
2434 /* Once the font has been loaded, adjust the overall font metrics if */
2435 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002436 if ( p->opts->correct_metrics != 0 &&
2437 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002438 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002439 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002440 {
2441 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002442 p->font->bbx.width, p->maxrb - p->minlb ));
2443 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2444 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002445 }
2446
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002447 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002448 {
2449 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002450 p->font->bbx.x_offset, p->minlb ));
2451 p->font->bbx.x_offset = p->minlb;
2452 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002453 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002454
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002455 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002456 {
2457 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002458 p->font->bbx.ascent, p->maxas ));
2459 p->font->bbx.ascent = p->maxas;
2460 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002461 }
2462
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002463 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002464 {
2465 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002466 p->font->bbx.descent, p->maxds ));
2467 p->font->bbx.descent = p->maxds;
2468 p->font->bbx.y_offset = (short)( -p->maxds );
2469 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002470 }
2471
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002472 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002473 {
2474 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002475 p->font->bbx.height, p->maxas + p->maxds ));
2476 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002477 }
2478
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002479 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002480 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2481 }
David Turner993a8d02002-05-18 12:03:43 +00002482 }
2483
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002484 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002485 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002486 /* The ENDFONT field was never reached or did not exist. */
2487 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002488 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002489 /* Error happened while parsing header. */
2490 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002491 error = FT_THROW( Corrupted_Font_Header );
Werner Lemberge01406b2011-11-25 09:44:28 +01002492 goto Exit;
2493 }
2494 else
2495 {
2496 /* Error happened when parsing glyphs. */
2497 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002498 error = FT_THROW( Corrupted_Font_Glyphs );
Werner Lemberge01406b2011-11-25 09:44:28 +01002499 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002500 }
David Turner993a8d02002-05-18 12:03:43 +00002501 }
2502
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002503 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002504 {
2505 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002506 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002507
Werner Lemberg370aea82010-06-08 08:37:11 +02002508 if ( p->font->comments_len > 0 )
2509 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002510 if ( FT_RENEW_ARRAY( p->font->comments,
2511 p->font->comments_len,
2512 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002513 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002514
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002515 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002516 }
David Turner993a8d02002-05-18 12:03:43 +00002517 }
Werner Lemberge3c93012013-03-14 11:21:17 +01002518 else if ( error == FT_Err_Ok )
Werner Lemberg059bc332013-03-14 10:27:35 +01002519 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002520
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002521 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002522
2523 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002524 if ( p )
2525 {
David Turner68df4f72005-03-15 18:18:57 +00002526 _bdf_list_done( &p->list );
2527
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002528 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002529
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002530 FT_FREE( p );
2531 }
2532
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002533 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002534
2535 Fail:
2536 bdf_free_font( p->font );
2537
2538 memory = extmemory;
2539
2540 FT_FREE( p->font );
2541
2542 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002543 }
David Turner993a8d02002-05-18 12:03:43 +00002544
2545
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002546 FT_LOCAL_DEF( void )
2547 bdf_free_font( bdf_font_t* font )
2548 {
2549 bdf_property_t* prop;
2550 unsigned long i;
2551 bdf_glyph_t* glyphs;
2552 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002553
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002554
2555 if ( font == 0 )
2556 return;
David Turner993a8d02002-05-18 12:03:43 +00002557
2558 memory = font->memory;
2559
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002560 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002561
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002562 /* Free up the internal hash table of property names. */
2563 if ( font->internal )
2564 {
2565 hash_free( (hashtable *)font->internal, memory );
2566 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002567 }
2568
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002569 /* Free up the comment info. */
2570 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002571
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002572 /* Free up the properties. */
2573 for ( i = 0; i < font->props_size; i++ )
2574 {
2575 if ( font->props[i].format == BDF_ATOM )
2576 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002577 }
2578
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002579 FT_FREE( font->props );
2580
2581 /* Free up the character info. */
2582 for ( i = 0, glyphs = font->glyphs;
2583 i < font->glyphs_used; i++, glyphs++ )
2584 {
2585 FT_FREE( glyphs->name );
2586 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002587 }
2588
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002589 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2590 i++, glyphs++ )
2591 {
2592 FT_FREE( glyphs->name );
2593 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002594 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002595
2596 FT_FREE( font->glyphs );
2597 FT_FREE( font->unencoded );
2598
2599 /* Free up the overflow storage if it was used. */
2600 for ( i = 0, glyphs = font->overflow.glyphs;
2601 i < font->overflow.glyphs_used; i++, glyphs++ )
2602 {
2603 FT_FREE( glyphs->name );
2604 FT_FREE( glyphs->bitmap );
2605 }
2606
2607 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002608
2609 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002610 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002611
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002612 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002613 for ( prop = font->user_props, i = 0;
2614 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002615 {
2616 FT_FREE( prop->name );
2617 if ( prop->format == BDF_ATOM )
2618 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002619 }
David Turner993a8d02002-05-18 12:03:43 +00002620
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002621 FT_FREE( font->user_props );
2622
2623 /* FREE( font ); */ /* XXX Fixme */
2624 }
David Turner993a8d02002-05-18 12:03:43 +00002625
2626
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002627 FT_LOCAL_DEF( bdf_property_t * )
2628 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002629 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002630 {
2631 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002632
David Turner993a8d02002-05-18 12:03:43 +00002633
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002634 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002635 return 0;
2636
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002637 hn = hash_lookup( name, (hashtable *)font->internal );
2638
suzuki toshiya704f4d72009-09-13 00:50:14 +09002639 return hn ? ( font->props + hn->data ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002640 }
2641
2642
2643/* END */