blob: d4c22e2a47d51ea137e3d4b38b81253ffc49fc2a [file] [log] [blame]
David Turner993a8d02002-05-18 12:03:43 +00001/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
Sean McBride7be2a942014-02-08 13:55:38 +01003 * Copyright 2001-2014
Werner Lemberg442bfb82007-02-12 21:44:10 +00004 * Francesco Zappa Nardelli
David Turner993a8d02002-05-18 12:03:43 +00005 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
Werner Lemberg7cf4d372002-05-21 14:13:01 +000025 /*************************************************************************/
26 /* */
27 /* This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 */
28 /* */
29 /* taken from Mark Leisher's xmbdfed package */
30 /* */
31 /*************************************************************************/
32
David Turner993a8d02002-05-18 12:03:43 +000033
34#include <ft2build.h>
35
Werner Lemberg02d4d592002-05-28 22:38:05 +000036#include FT_FREETYPE_H
David Turner993a8d02002-05-18 12:03:43 +000037#include FT_INTERNAL_DEBUG_H
38#include FT_INTERNAL_STREAM_H
39#include FT_INTERNAL_OBJECTS_H
40
41#include "bdf.h"
David Turner993a8d02002-05-18 12:03:43 +000042#include "bdferror.h"
43
David Turner993a8d02002-05-18 12:03:43 +000044
Werner Lemberg7cf4d372002-05-21 14:13:01 +000045 /*************************************************************************/
46 /* */
47 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
48 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
49 /* messages during execution. */
50 /* */
51#undef FT_COMPONENT
52#define FT_COMPONENT trace_bdflib
David Turner993a8d02002-05-18 12:03:43 +000053
David Turner993a8d02002-05-18 12:03:43 +000054
Werner Lemberg7cf4d372002-05-21 14:13:01 +000055 /*************************************************************************/
56 /* */
57 /* Default BDF font options. */
58 /* */
59 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000060
David Turner993a8d02002-05-18 12:03:43 +000061
David Turnerb1b47622002-05-21 21:17:43 +000062 static const bdf_options_t _bdf_opts =
Werner Lemberg7cf4d372002-05-21 14:13:01 +000063 {
David Turner993a8d02002-05-18 12:03:43 +000064 1, /* Correct metrics. */
65 1, /* Preserve unencoded glyphs. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000066 0, /* Preserve comments. */
67 BDF_PROPORTIONAL /* Default spacing. */
68 };
David Turner993a8d02002-05-18 12:03:43 +000069
David Turner993a8d02002-05-18 12:03:43 +000070
Werner Lemberg7cf4d372002-05-21 14:13:01 +000071 /*************************************************************************/
72 /* */
73 /* Builtin BDF font properties. */
74 /* */
75 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000076
Werner Lemberg7cf4d372002-05-21 14:13:01 +000077 /* List of most properties that might appear in a font. Doesn't include */
78 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
David Turner993a8d02002-05-18 12:03:43 +000079
David Turnerb1b47622002-05-21 21:17:43 +000080 static const bdf_property_t _bdf_properties[] =
David Turner993a8d02002-05-18 12:03:43 +000081 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +000082 { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
83 { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
84 { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
85 { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
86 { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
87 { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
88 { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
89 { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
90 { (char *)"COMMENT", BDF_ATOM, 1, { 0 } },
91 { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } },
92 { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
93 { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } },
94 { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
95 { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } },
96 { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } },
97 { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } },
98 { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
99 { (char *)"FONT", BDF_ATOM, 1, { 0 } },
100 { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
101 { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
102 { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
103 { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } },
104 { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } },
105 { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
106 { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } },
107 { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } },
108 { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } },
109 { (char *)"NOTICE", BDF_ATOM, 1, { 0 } },
110 { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
111 { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } },
112 { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
113 { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
114 { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
115 { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
116 { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
117 { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
118 { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
119 { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
120 { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
121 { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
122 { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
123 { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
124 { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
125 { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
126 { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
127 { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
128 { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
129 { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
130 { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
131 { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
132 { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
133 { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
134 { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
135 { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
136 { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
137 { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
138 { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
139 { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
140 { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
141 { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
142 { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
143 { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } },
144 { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
145 { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
146 { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
147 { (char *)"SLANT", BDF_ATOM, 1, { 0 } },
148 { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
149 { (char *)"SPACING", BDF_ATOM, 1, { 0 } },
150 { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
151 { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
152 { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
153 { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
154 { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
155 { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
156 { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
157 { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
158 { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
159 { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
160 { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } },
161 { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
162 { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } },
163 { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
164 { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
165 };
David Turner993a8d02002-05-18 12:03:43 +0000166
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000167 static const unsigned long
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000168 _num_bdf_properties = sizeof ( _bdf_properties ) /
169 sizeof ( _bdf_properties[0] );
David Turner993a8d02002-05-18 12:03:43 +0000170
171
Werner Lemberg2c4832d2014-11-07 07:42:33 +0100172 /* An auxiliary macro to parse properties, to be used in conditionals. */
173 /* It behaves like `strncmp' but also tests the following character */
174 /* whether it is a whitespace or NULL. */
175 /* `property' is a constant string of length `n' to compare with. */
176#define _bdf_strncmp( name, property, n ) \
177 ( ft_strncmp( name, property, n ) || \
178 !( name[n] == ' ' || \
179 name[n] == '\0' || \
180 name[n] == '\n' || \
181 name[n] == '\r' || \
182 name[n] == '\t' ) )
183
Werner Lemberge01406b2011-11-25 09:44:28 +0100184 /* Auto correction messages. */
185#define ACMSG1 "FONT_ASCENT property missing. " \
186 "Added `FONT_ASCENT %hd'.\n"
187#define ACMSG2 "FONT_DESCENT property missing. " \
188 "Added `FONT_DESCENT %hd'.\n"
189#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
190#define ACMSG4 "Font left bearing != actual left bearing. " \
191 "Old: %hd New: %hd.\n"
192#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
193#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
194#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
195#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
196#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
197#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
198#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
199#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
200#define ACMSG13 "Glyph %ld extra rows removed.\n"
201#define ACMSG14 "Glyph %ld extra columns removed.\n"
202#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
Werner Lemberg0b1c0c62012-02-25 10:23:04 +0100203#define ACMSG16 "Glyph %ld missing columns padded with zero bits.\n"
Werner Lemberge1ca18d2015-10-17 11:51:27 +0200204#define ACMSG17 "Adjusting number of glyphs to %ld.\n"
Werner Lemberge01406b2011-11-25 09:44:28 +0100205
206 /* Error messages. */
207#define ERRMSG1 "[line %ld] Missing `%s' line.\n"
208#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
209#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
210#define ERRMSG4 "[line %ld] BBX too big.\n"
211#define ERRMSG5 "[line %ld] `%s' value too big.\n"
212#define ERRMSG6 "[line %ld] Input line too long.\n"
213#define ERRMSG7 "[line %ld] Font name too long.\n"
214#define ERRMSG8 "[line %ld] Invalid `%s' value.\n"
215#define ERRMSG9 "[line %ld] Invalid keyword.\n"
216
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +0100217 /* Debug messages. */
218#define DBGMSG1 " [%6ld] %s" /* no \n */
219#define DBGMSG2 " (0x%lX)\n"
220
Werner Lemberge01406b2011-11-25 09:44:28 +0100221
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000222 /*************************************************************************/
223 /* */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000224 /* Utility types and functions. */
225 /* */
226 /*************************************************************************/
227
228
229 /* Function type for parsing lines of a BDF font. */
230
231 typedef FT_Error
232 (*_bdf_line_func_t)( char* line,
233 unsigned long linelen,
234 unsigned long lineno,
235 void* call_data,
236 void* client_data );
237
238
239 /* List structure for splitting lines into fields. */
240
241 typedef struct _bdf_list_t_
242 {
243 char** field;
244 unsigned long size;
245 unsigned long used;
David Turner68df4f72005-03-15 18:18:57 +0000246 FT_Memory memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000247
248 } _bdf_list_t;
249
250
251 /* Structure used while loading BDF fonts. */
252
253 typedef struct _bdf_parse_t_
254 {
255 unsigned long flags;
256 unsigned long cnt;
257 unsigned long row;
258
259 short minlb;
260 short maxlb;
261 short maxrb;
262 short maxas;
263 short maxds;
264
265 short rbearing;
266
267 char* glyph_name;
268 long glyph_enc;
269
270 bdf_font_t* font;
271 bdf_options_t* opts;
272
Werner Lemberged54e432011-11-27 16:39:53 +0100273 unsigned long have[34816]; /* must be in sync with `nmod' and `umod' */
274 /* arrays from `bdf_font_t' structure */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000275 _bdf_list_t list;
276
277 FT_Memory memory;
Werner Lemberge1ca18d2015-10-17 11:51:27 +0200278 unsigned long size; /* the stream size */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000279
280 } _bdf_parse_t;
281
282
Werner Lemberga08b2172007-03-28 07:17:17 +0000283#define setsbit( m, cc ) \
284 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
285#define sbitset( m, cc ) \
286 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000287
288
David Turner68df4f72005-03-15 18:18:57 +0000289 static void
290 _bdf_list_init( _bdf_list_t* list,
291 FT_Memory memory )
292 {
Werner Lembergebf55852005-03-16 01:49:54 +0000293 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000294 list->memory = memory;
295 }
296
Werner Lembergebf55852005-03-16 01:49:54 +0000297
David Turner68df4f72005-03-15 18:18:57 +0000298 static void
299 _bdf_list_done( _bdf_list_t* list )
300 {
301 FT_Memory memory = list->memory;
302
Werner Lembergebf55852005-03-16 01:49:54 +0000303
David Turner68df4f72005-03-15 18:18:57 +0000304 if ( memory )
305 {
306 FT_FREE( list->field );
Werner Lembergebf55852005-03-16 01:49:54 +0000307 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000308 }
309 }
310
311
312 static FT_Error
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900313 _bdf_list_ensure( _bdf_list_t* list,
314 unsigned long num_items ) /* same as _bdf_list_t.used */
David Turner68df4f72005-03-15 18:18:57 +0000315 {
Werner Lemberge3c93012013-03-14 11:21:17 +0100316 FT_Error error = FT_Err_Ok;
Werner Lembergebf55852005-03-16 01:49:54 +0000317
David Turner68df4f72005-03-15 18:18:57 +0000318
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900319 if ( num_items > list->size )
David Turner68df4f72005-03-15 18:18:57 +0000320 {
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900321 unsigned long oldsize = list->size; /* same as _bdf_list_t.size */
Werner Lembergcee5d592012-03-01 09:26:03 +0100322 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 5;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900323 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
324 FT_Memory memory = list->memory;
David Turner68df4f72005-03-15 18:18:57 +0000325
Werner Lembergebf55852005-03-16 01:49:54 +0000326
David Turner68df4f72005-03-15 18:18:57 +0000327 if ( oldsize == bigsize )
328 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100329 error = FT_THROW( Out_Of_Memory );
David Turner68df4f72005-03-15 18:18:57 +0000330 goto Exit;
331 }
332 else if ( newsize < oldsize || newsize > bigsize )
333 newsize = bigsize;
334
335 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
336 goto Exit;
337
338 list->size = newsize;
339 }
Werner Lembergebf55852005-03-16 01:49:54 +0000340
David Turner68df4f72005-03-15 18:18:57 +0000341 Exit:
342 return error;
343 }
344
345
346 static void
347 _bdf_list_shift( _bdf_list_t* list,
348 unsigned long n )
349 {
350 unsigned long i, u;
351
352
353 if ( list == 0 || list->used == 0 || n == 0 )
354 return;
355
356 if ( n >= list->used )
357 {
358 list->used = 0;
359 return;
360 }
361
362 for ( u = n, i = 0; u < list->used; i++, u++ )
363 list->field[i] = list->field[u];
364 list->used -= n;
365 }
366
367
Werner Lembergf4c94d42010-06-19 16:08:31 +0200368 /* An empty string for empty fields. */
369
370 static const char empty[1] = { 0 }; /* XXX eliminate this */
371
372
David Turner68df4f72005-03-15 18:18:57 +0000373 static char *
374 _bdf_list_join( _bdf_list_t* list,
375 int c,
376 unsigned long *alen )
377 {
378 unsigned long i, j;
Werner Lembergdc624ca2013-06-04 10:30:48 +0200379 char* dp;
David Turner68df4f72005-03-15 18:18:57 +0000380
381
382 *alen = 0;
383
384 if ( list == 0 || list->used == 0 )
385 return 0;
386
387 dp = list->field[0];
388 for ( i = j = 0; i < list->used; i++ )
389 {
Werner Lembergdc624ca2013-06-04 10:30:48 +0200390 char* fp = list->field[i];
391
392
David Turner68df4f72005-03-15 18:18:57 +0000393 while ( *fp )
394 dp[j++] = *fp++;
395
396 if ( i + 1 < list->used )
397 dp[j++] = (char)c;
398 }
Werner Lembergf4c94d42010-06-19 16:08:31 +0200399 if ( dp != empty )
400 dp[j] = 0;
David Turner68df4f72005-03-15 18:18:57 +0000401
402 *alen = j;
403 return dp;
404 }
405
406
Werner Lemberg03242f52012-02-26 06:52:56 +0100407 /* The code below ensures that we have at least 4 + 1 `field' */
408 /* elements in `list' (which are possibly NULL) so that we */
409 /* don't have to check the number of fields in most cases. */
410
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000411 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000412 _bdf_list_split( _bdf_list_t* list,
413 char* separators,
414 char* line,
415 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000416 {
Werner Lemberg3c374c82015-02-22 09:16:53 +0100417 unsigned long final_empty;
418 int mult;
419 char *sp, *ep, *end;
420 char seps[32];
421 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000422
423
424 /* Initialize the list. */
425 list->used = 0;
Werner Lembergd9c16592012-03-01 15:15:00 +0100426 if ( list->size )
427 {
428 list->field[0] = (char*)empty;
429 list->field[1] = (char*)empty;
430 list->field[2] = (char*)empty;
431 list->field[3] = (char*)empty;
Werner Lemberg649c6732012-03-16 21:12:41 +0100432 list->field[4] = (char*)empty;
Werner Lembergd9c16592012-03-01 15:15:00 +0100433 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000434
435 /* If the line is empty, then simply return. */
436 if ( linelen == 0 || line[0] == 0 )
437 goto Exit;
438
439 /* In the original code, if the `separators' parameter is NULL or */
440 /* empty, the list is split into individual bytes. We don't need */
441 /* this, so an error is signaled. */
442 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000443 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100444 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000445 goto Exit;
446 }
447
448 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000449 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000450
451 /* If the very last character of the separator string is a plus, then */
452 /* set the `mult' flag to indicate that multiple separators should be */
453 /* collapsed into one. */
454 for ( mult = 0, sp = separators; sp && *sp; sp++ )
455 {
456 if ( *sp == '+' && *( sp + 1 ) == 0 )
457 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000458 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000459 setsbit( seps, *sp );
460 }
461
462 /* Break the line up into fields. */
463 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
464 sp < end && *sp; )
465 {
466 /* Collect everything that is not a separator. */
467 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
468 ;
469
470 /* Resize the list if necessary. */
471 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000472 {
Werner Lembergebf55852005-03-16 01:49:54 +0000473 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000474 if ( error )
475 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000476 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000477
478 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000479 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000480
481 sp = ep;
482
483 if ( mult )
484 {
485 /* If multiple separators should be collapsed, do it now by */
486 /* setting all the separator characters to 0. */
487 for ( ; *ep && sbitset( seps, *ep ); ep++ )
488 *ep = 0;
489 }
490 else if ( *ep != 0 )
491 /* Don't collapse multiple separators by making them 0, so just */
492 /* make the one encountered 0. */
493 *ep++ = 0;
494
495 final_empty = ( ep > sp && *ep == 0 );
496 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000497 }
498
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000499 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000500 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000501 {
Werner Lembergebf55852005-03-16 01:49:54 +0000502 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000503 if ( error )
504 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000505 }
506
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000507 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000508 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000509
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000510 list->field[list->used] = 0;
511
512 Exit:
513 return error;
David Turner993a8d02002-05-18 12:03:43 +0000514 }
515
David Turner993a8d02002-05-18 12:03:43 +0000516
David Turner68df4f72005-03-15 18:18:57 +0000517#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000518
Werner Lembergebf55852005-03-16 01:49:54 +0000519
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000520 static FT_Error
521 _bdf_readstream( FT_Stream stream,
522 _bdf_line_func_t callback,
523 void* client_data,
524 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000525 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000526 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000527 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900528 int refill, hold, to_skip;
529 ptrdiff_t bytes, start, end, cursor, avail;
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -0400530 char* buf = NULL;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000531 FT_Memory memory = stream->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100532 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000533
David Turner993a8d02002-05-18 12:03:43 +0000534
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000535 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000536 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100537 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000538 goto Exit;
539 }
David Turner993a8d02002-05-18 12:03:43 +0000540
Werner Lembergebf55852005-03-16 01:49:54 +0000541 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000542 buf_size = 1024;
543
544 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000545 goto Exit;
546
Werner Lembergebf55852005-03-16 01:49:54 +0000547 cb = callback;
548 lineno = 1;
549 buf[0] = 0;
550 start = 0;
Werner Lembergebf55852005-03-16 01:49:54 +0000551 avail = 0;
552 cursor = 0;
553 refill = 1;
554 to_skip = NO_SKIP;
555 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000556
David Turner68df4f72005-03-15 18:18:57 +0000557 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000558 {
David Turner68df4f72005-03-15 18:18:57 +0000559 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000560 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +0200561 bytes = (ptrdiff_t)FT_Stream_TryRead(
562 stream, (FT_Byte*)buf + cursor,
Werner Lemberg3c374c82015-02-22 09:16:53 +0100563 buf_size - (unsigned long)cursor );
David Turner68df4f72005-03-15 18:18:57 +0000564 avail = cursor + bytes;
565 cursor = 0;
566 refill = 0;
567 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000568
David Turner68df4f72005-03-15 18:18:57 +0000569 end = start;
570
Werner Lembergebf55852005-03-16 01:49:54 +0000571 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000572 if ( start < avail && buf[start] == to_skip )
573 {
574 start += 1;
575 to_skip = NO_SKIP;
576 continue;
577 }
578
579 /* try to find the end of the line */
580 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
581 end++;
582
Werner Lembergebf55852005-03-16 01:49:54 +0000583 /* if we hit the end of the buffer, try shifting its content */
584 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000585 if ( end >= avail )
586 {
587 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
588 break; /* ignore it then exit */
589
590 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000591 {
Werner Lembergebf55852005-03-16 01:49:54 +0000592 /* this line is definitely too long; try resizing the input */
593 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000594 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000595
Werner Lembergebf55852005-03-16 01:49:54 +0000596
597 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000598 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100599 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +0100600 error = FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +0000601 goto Exit;
602 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000603
Werner Lembergebf55852005-03-16 01:49:54 +0000604 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000605 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
606 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000607
Werner Lemberg3c374c82015-02-22 09:16:53 +0100608 cursor = (ptrdiff_t)buf_size;
David Turner68df4f72005-03-15 18:18:57 +0000609 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000610 }
611 else
612 {
David Turner68df4f72005-03-15 18:18:57 +0000613 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000614
Werner Lemberg04e547b2013-04-03 07:37:56 +0200615 FT_MEM_MOVE( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000616
David Turner68df4f72005-03-15 18:18:57 +0000617 cursor = bytes;
618 avail -= bytes;
619 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000620 }
David Turner68df4f72005-03-15 18:18:57 +0000621 refill = 1;
622 continue;
David Turner993a8d02002-05-18 12:03:43 +0000623 }
David Turner68df4f72005-03-15 18:18:57 +0000624
625 /* Temporarily NUL-terminate the line. */
626 hold = buf[end];
627 buf[end] = 0;
628
Werner Lemberg0098d552014-12-07 11:03:57 +0100629 /* XXX: Use encoding independent value for 0x1A */
630 if ( buf[start] != '#' && buf[start] != 0x1A && end > start )
David Turner68df4f72005-03-15 18:18:57 +0000631 {
Werner Lemberga9f6f852012-12-17 09:08:09 +0100632 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergebf55852005-03-16 01:49:54 +0000633 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200634 /* Redo if we have encountered CHARS without properties. */
635 if ( error == -1 )
Werner Lemberga9f6f852012-12-17 09:08:09 +0100636 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200637 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000638 if ( error )
639 break;
640 }
641
642 lineno += 1;
643 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000644 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000645
646 if ( hold == '\n' )
647 to_skip = '\r';
648 else if ( hold == '\r' )
649 to_skip = '\n';
650 else
651 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000652 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000653
David Turner68df4f72005-03-15 18:18:57 +0000654 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000655
656 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000657 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000658 return error;
David Turner993a8d02002-05-18 12:03:43 +0000659 }
David Turner993a8d02002-05-18 12:03:43 +0000660
661
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000662 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000663
David Turnerb1b47622002-05-21 21:17:43 +0000664 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000665 {
David Turner993a8d02002-05-18 12:03:43 +0000666 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
667 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
668 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
669 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
Werner Lemberg0098d552014-12-07 11:03:57 +0100671 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000672 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
673 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg0098d552014-12-07 11:03:57 +0100674 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000675 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
676 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000677 };
David Turner993a8d02002-05-18 12:03:43 +0000678
David Turnerb1b47622002-05-21 21:17:43 +0000679 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000680 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
David Turner993a8d02002-05-18 12:03:43 +0000682 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
683 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
684 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000685 };
David Turner993a8d02002-05-18 12:03:43 +0000686
David Turnerb1b47622002-05-21 21:17:43 +0000687 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000688 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100689 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
690 0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000691 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
692 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000693 };
David Turner993a8d02002-05-18 12:03:43 +0000694
David Turner993a8d02002-05-18 12:03:43 +0000695
Ben Wagnera512b0f2015-12-14 09:19:52 +0100696 /* Routine to convert a decimal ASCII string to an unsigned long integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000697 static unsigned long
Ben Wagnera512b0f2015-12-14 09:19:52 +0100698 _bdf_atoul( char* s )
David Turner993a8d02002-05-18 12:03:43 +0000699 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100700 unsigned long v;
David Turner993a8d02002-05-18 12:03:43 +0000701
702
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000703 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000704 return 0;
705
Ben Wagnera512b0f2015-12-14 09:19:52 +0100706 for ( v = 0; sbitset( ddigits, *s ); s++ )
707 v = v * 10 + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000708
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000709 return v;
710 }
David Turner993a8d02002-05-18 12:03:43 +0000711
David Turner993a8d02002-05-18 12:03:43 +0000712
Ben Wagnera512b0f2015-12-14 09:19:52 +0100713 /* Routine to convert a decimal ASCII string to a signed long integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000714 static long
Ben Wagnera512b0f2015-12-14 09:19:52 +0100715 _bdf_atol( char* s )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000716 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100717 long v, neg;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000718
719
720 if ( s == 0 || *s == 0 )
721 return 0;
722
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000723 /* Check for a minus sign. */
724 neg = 0;
725 if ( *s == '-' )
726 {
727 s++;
728 neg = 1;
729 }
730
Ben Wagnera512b0f2015-12-14 09:19:52 +0100731 for ( v = 0; sbitset( ddigits, *s ); s++ )
732 v = v * 10 + a2i[(int)*s];
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000733
734 return ( !neg ) ? v : -v;
735 }
736
737
Ben Wagnera512b0f2015-12-14 09:19:52 +0100738 /* Routine to convert a decimal ASCII string to an unsigned short integer. */
Werner Lembergb13945a2015-02-22 09:15:47 +0100739 static unsigned short
Ben Wagnera512b0f2015-12-14 09:19:52 +0100740 _bdf_atous( char* s )
Werner Lembergb13945a2015-02-22 09:15:47 +0100741 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100742 unsigned short v;
Werner Lembergb13945a2015-02-22 09:15:47 +0100743
744
745 if ( s == 0 || *s == 0 )
746 return 0;
747
Ben Wagnera512b0f2015-12-14 09:19:52 +0100748 for ( v = 0; sbitset( ddigits, *s ); s++ )
749 v = (unsigned short)( v * 10 + a2i[(int)*s] );
Werner Lembergb13945a2015-02-22 09:15:47 +0100750
751 return v;
752 }
753
754
Ben Wagnera512b0f2015-12-14 09:19:52 +0100755 /* Routine to convert a decimal ASCII string to a signed short integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000756 static short
Ben Wagnera512b0f2015-12-14 09:19:52 +0100757 _bdf_atos( char* s )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000758 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100759 short v, neg;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000760
761
762 if ( s == 0 || *s == 0 )
763 return 0;
764
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000765 /* Check for a minus. */
766 neg = 0;
767 if ( *s == '-' )
768 {
769 s++;
770 neg = 1;
771 }
772
Ben Wagnera512b0f2015-12-14 09:19:52 +0100773 for ( v = 0; sbitset( ddigits, *s ); s++ )
774 v = (short)( v * 10 + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000775
Werner Lemberg233302a2002-05-22 05:41:06 +0000776 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000777 }
778
779
780 /* Routine to compare two glyphs by encoding so they can be sorted. */
781 static int
782 by_encoding( const void* a,
783 const void* b )
784 {
785 bdf_glyph_t *c1, *c2;
786
787
788 c1 = (bdf_glyph_t *)a;
789 c2 = (bdf_glyph_t *)b;
790
791 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000792 return -1;
David Turner68df4f72005-03-15 18:18:57 +0000793
794 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000795 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000796
David Turner993a8d02002-05-18 12:03:43 +0000797 return 0;
David Turner993a8d02002-05-18 12:03:43 +0000798 }
799
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000800
801 static FT_Error
802 bdf_create_property( char* name,
803 int format,
804 bdf_font_t* font )
805 {
suzuki toshiya704f4d72009-09-13 00:50:14 +0900806 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000807 bdf_property_t* p;
808 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100809 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000810
811
Werner Lemberg96ddc672011-06-29 09:15:54 +0200812 /* First check whether the property has */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000813 /* already been added or not. If it has, then */
814 /* simply ignore it. */
Werner Lemberg31343562015-12-19 17:02:13 +0100815 if ( ft_hash_lookup( name, &(font->proptbl) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000816 goto Exit;
817
David Turner68df4f72005-03-15 18:18:57 +0000818 if ( FT_RENEW_ARRAY( font->user_props,
819 font->nuser_props,
820 font->nuser_props + 1 ) )
821 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000822
823 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +0000824 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000825
suzuki toshiya704f4d72009-09-13 00:50:14 +0900826 n = ft_strlen( name ) + 1;
827 if ( n > FT_ULONG_MAX )
Werner Lemberg059bc332013-03-14 10:27:35 +0100828 return FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +0000829
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000830 if ( FT_NEW_ARRAY( p->name, n ) )
831 goto Exit;
832
833 FT_MEM_COPY( (char *)p->name, name, n );
834
835 p->format = format;
836 p->builtin = 0;
837
838 n = _num_bdf_properties + font->nuser_props;
839
Werner Lemberg31343562015-12-19 17:02:13 +0100840 error = ft_hash_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000841 if ( error )
842 goto Exit;
843
844 font->nuser_props++;
845
846 Exit:
David Turner993a8d02002-05-18 12:03:43 +0000847 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000848 }
David Turner993a8d02002-05-18 12:03:43 +0000849
850
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000851 FT_LOCAL_DEF( bdf_property_t * )
852 bdf_get_property( char* name,
853 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +0000854 {
Werner Lemberg31343562015-12-19 17:02:13 +0100855 FT_Hashnode hn;
856 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000857
858
859 if ( name == 0 || *name == 0 )
860 return 0;
861
Werner Lemberg31343562015-12-19 17:02:13 +0100862 if ( ( hn = ft_hash_lookup( name, &(font->proptbl) ) ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000863 return 0;
864
suzuki toshiya704f4d72009-09-13 00:50:14 +0900865 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000866 if ( propid >= _num_bdf_properties )
867 return font->user_props + ( propid - _num_bdf_properties );
868
Werner Lemberg233302a2002-05-22 05:41:06 +0000869 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +0000870 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000871
872
873 /*************************************************************************/
874 /* */
875 /* BDF font file parsing flags and functions. */
876 /* */
877 /*************************************************************************/
878
879
880 /* Parse flags. */
881
Werner Lemberg3c374c82015-02-22 09:16:53 +0100882#define _BDF_START 0x0001U
883#define _BDF_FONT_NAME 0x0002U
884#define _BDF_SIZE 0x0004U
885#define _BDF_FONT_BBX 0x0008U
886#define _BDF_PROPS 0x0010U
887#define _BDF_GLYPHS 0x0020U
888#define _BDF_GLYPH 0x0040U
889#define _BDF_ENCODING 0x0080U
890#define _BDF_SWIDTH 0x0100U
891#define _BDF_DWIDTH 0x0200U
892#define _BDF_BBX 0x0400U
893#define _BDF_BITMAP 0x0800U
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000894
Werner Lemberg3c374c82015-02-22 09:16:53 +0100895#define _BDF_SWIDTH_ADJ 0x1000U
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000896
897#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
898 _BDF_ENCODING | \
899 _BDF_SWIDTH | \
900 _BDF_DWIDTH | \
901 _BDF_BBX | \
902 _BDF_BITMAP )
903
Werner Lembergf1c2b912006-01-13 14:53:28 +0000904#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
905#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000906
907
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000908 static FT_Error
909 _bdf_add_comment( bdf_font_t* font,
910 char* comment,
911 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +0000912 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000913 char* cp;
914 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100915 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000916
917
David Turner68df4f72005-03-15 18:18:57 +0000918 if ( FT_RENEW_ARRAY( font->comments,
919 font->comments_len,
920 font->comments_len + len + 1 ) )
921 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000922
923 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +0000924
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000925 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +0000926 cp[len] = '\n';
927
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000928 font->comments_len += len + 1;
929
930 Exit:
931 return error;
David Turner993a8d02002-05-18 12:03:43 +0000932 }
933
David Turner993a8d02002-05-18 12:03:43 +0000934
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000935 /* Set the spacing from the font name if it exists, or set it to the */
936 /* default specified in the options. */
937 static FT_Error
938 _bdf_set_default_spacing( bdf_font_t* font,
Werner Lemberge01406b2011-11-25 09:44:28 +0100939 bdf_options_t* opts,
940 unsigned long lineno )
David Turner993a8d02002-05-18 12:03:43 +0000941 {
suzuki toshiya704f4d72009-09-13 00:50:14 +0900942 size_t len;
943 char name[256];
944 _bdf_list_t list;
945 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100946 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000947
Dave Arnoldc3782492013-06-05 19:57:55 +0200948 FT_UNUSED( lineno ); /* only used in debug mode */
949
David Turner993a8d02002-05-18 12:03:43 +0000950
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000951 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
952 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100953 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000954 goto Exit;
955 }
David Turner993a8d02002-05-18 12:03:43 +0000956
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000957 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +0000958
David Turner68df4f72005-03-15 18:18:57 +0000959 _bdf_list_init( &list, memory );
960
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000961 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +0000962
suzuki toshiya704f4d72009-09-13 00:50:14 +0900963 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +0000964 /* Limit ourselves to 256 characters in the font name. */
965 if ( len >= 256 )
966 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100967 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +0100968 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +0000969 goto Exit;
970 }
971
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000972 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +0000973
Werner Lembergbadf3172013-06-06 09:16:38 +0200974 error = _bdf_list_split( &list, (char *)"-", name, (unsigned long)len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000975 if ( error )
David Turner68df4f72005-03-15 18:18:57 +0000976 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000977
978 if ( list.used == 15 )
979 {
980 switch ( list.field[11][0] )
981 {
982 case 'C':
983 case 'c':
984 font->spacing = BDF_CHARCELL;
985 break;
986 case 'M':
987 case 'm':
988 font->spacing = BDF_MONOWIDTH;
989 break;
990 case 'P':
991 case 'p':
992 font->spacing = BDF_PROPORTIONAL;
993 break;
David Turner993a8d02002-05-18 12:03:43 +0000994 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000995 }
996
David Turner68df4f72005-03-15 18:18:57 +0000997 Fail:
998 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000999
1000 Exit:
1001 return error;
David Turner993a8d02002-05-18 12:03:43 +00001002 }
David Turner993a8d02002-05-18 12:03:43 +00001003
1004
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001005 /* Determine whether the property is an atom or not. If it is, then */
1006 /* clean it up so the double quotes are removed if they exist. */
1007 static int
1008 _bdf_is_atom( char* line,
1009 unsigned long linelen,
1010 char** name,
1011 char** value,
1012 bdf_font_t* font )
1013 {
1014 int hold;
1015 char *sp, *ep;
1016 bdf_property_t* p;
1017
David Turner993a8d02002-05-18 12:03:43 +00001018
1019 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001020
1021 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001022 ep++;
1023
1024 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001025 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001026 {
1027 hold = *ep;
1028 *ep = 0;
1029 }
1030
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001031 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001032
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001033 /* Restore the character that was saved before any return can happen. */
1034 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001035 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001036
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001037 /* If the property exists and is not an atom, just return here. */
1038 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001039 return 0;
1040
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001041 /* The property is an atom. Trim all leading and trailing whitespace */
1042 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001043 sp = ep;
1044 ep = line + linelen;
1045
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001046 /* Trim the leading whitespace if it exists. */
Werner Lemberg320d4972012-02-24 18:06:46 +01001047 if ( *sp )
1048 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001049 while ( *sp &&
1050 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001051 sp++;
1052
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001053 /* Trim the leading double quote if it exists. */
1054 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001055 sp++;
1056 *value = sp;
1057
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001058 /* Trim the trailing whitespace if it exists. */
1059 while ( ep > sp &&
1060 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001061 *--ep = 0;
1062
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001063 /* Trim the trailing double quote if it exists. */
1064 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001065 *--ep = 0;
1066
1067 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001068 }
David Turner993a8d02002-05-18 12:03:43 +00001069
1070
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001071 static FT_Error
Werner Lemberge01406b2011-11-25 09:44:28 +01001072 _bdf_add_property( bdf_font_t* font,
1073 char* name,
1074 char* value,
1075 unsigned long lineno )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001076 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001077 size_t propid;
Werner Lemberg31343562015-12-19 17:02:13 +01001078 FT_Hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001079 bdf_property_t *prop, *fp;
1080 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001081 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001082
Dave Arnoldc3782492013-06-05 19:57:55 +02001083 FT_UNUSED( lineno ); /* only used in debug mode */
1084
David Turner993a8d02002-05-18 12:03:43 +00001085
Werner Lemberg96ddc672011-06-29 09:15:54 +02001086 /* First, check whether the property already exists in the font. */
Werner Lemberg31343562015-12-19 17:02:13 +01001087 if ( ( hn = ft_hash_lookup( name, (FT_Hash)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001088 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001089 /* The property already exists in the font, so simply replace */
1090 /* the value of the property with the current value. */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001091 fp = font->props + hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001092
David Turnerb1b47622002-05-21 21:17:43 +00001093 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001094 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001095 case BDF_ATOM:
1096 /* Delete the current atom if it exists. */
1097 FT_FREE( fp->value.atom );
1098
David Turnerc0f9c4a2007-02-12 14:55:03 +00001099 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001100 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001101 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001102 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001103 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001104 break;
1105
1106 case BDF_INTEGER:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001107 fp->value.l = _bdf_atol( value );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001108 break;
1109
1110 case BDF_CARDINAL:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001111 fp->value.ul = _bdf_atoul( value );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001112 break;
David Turnerd490e372002-05-28 23:40:37 +00001113
David Turnerb1b47622002-05-21 21:17:43 +00001114 default:
1115 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001116 }
David Turnerd490e372002-05-28 23:40:37 +00001117
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001118 goto Exit;
1119 }
1120
1121 /* See whether this property type exists yet or not. */
1122 /* If not, create it. */
Werner Lemberg31343562015-12-19 17:02:13 +01001123 hn = ft_hash_lookup( name, &(font->proptbl) );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001124 if ( hn == 0 )
1125 {
1126 error = bdf_create_property( name, BDF_ATOM, font );
1127 if ( error )
1128 goto Exit;
Werner Lemberg31343562015-12-19 17:02:13 +01001129 hn = ft_hash_lookup( name, &(font->proptbl) );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001130 }
1131
1132 /* Allocate another property if this is overflow. */
1133 if ( font->props_used == font->props_size )
1134 {
1135 if ( font->props_size == 0 )
1136 {
1137 if ( FT_NEW_ARRAY( font->props, 1 ) )
1138 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001139 }
1140 else
1141 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001142 if ( FT_RENEW_ARRAY( font->props,
1143 font->props_size,
1144 font->props_size + 1 ) )
1145 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001146 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001147
David Turner993a8d02002-05-18 12:03:43 +00001148 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001149 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001150 font->props_size++;
1151 }
1152
suzuki toshiya704f4d72009-09-13 00:50:14 +09001153 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001154 if ( propid >= _num_bdf_properties )
1155 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001156 else
David Turnerb1b47622002-05-21 21:17:43 +00001157 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001158
1159 fp = font->props + font->props_used;
1160
1161 fp->name = prop->name;
1162 fp->format = prop->format;
1163 fp->builtin = prop->builtin;
1164
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001165 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001166 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001167 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001168 fp->value.atom = 0;
1169 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001170 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001171 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001172 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001173 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001174 break;
David Turner993a8d02002-05-18 12:03:43 +00001175
1176 case BDF_INTEGER:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001177 fp->value.l = _bdf_atol( value );
David Turner993a8d02002-05-18 12:03:43 +00001178 break;
1179
1180 case BDF_CARDINAL:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001181 fp->value.ul = _bdf_atoul( value );
David Turner993a8d02002-05-18 12:03:43 +00001182 break;
David Turner993a8d02002-05-18 12:03:43 +00001183 }
1184
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001185 /* If the property happens to be a comment, then it doesn't need */
1186 /* to be added to the internal hash table. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001187 if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 )
Werner Lemberg370aea82010-06-08 08:37:11 +02001188 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001189 /* Add the property to the font property table. */
Werner Lemberg31343562015-12-19 17:02:13 +01001190 error = ft_hash_insert( fp->name,
1191 font->props_used,
1192 (FT_Hash)font->internal,
1193 memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001194 if ( error )
1195 goto Exit;
1196 }
David Turner993a8d02002-05-18 12:03:43 +00001197
1198 font->props_used++;
1199
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001200 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1201 /* property needs to be located if it exists in the property list, the */
1202 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1203 /* present, and the SPACING property should override the default */
1204 /* spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001205 if ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001206 font->default_char = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001207 else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001208 font->font_ascent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001209 else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001210 font->font_descent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001211 else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001212 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001213 if ( !fp->value.atom )
1214 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001215 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001216 error = FT_THROW( Invalid_File_Format );
Werner Lembergb66efef2009-03-12 08:07:49 +00001217 goto Exit;
1218 }
1219
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001220 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001221 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001222 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001223 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001224 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001225 font->spacing = BDF_CHARCELL;
1226 }
1227
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001228 Exit:
1229 return error;
David Turner993a8d02002-05-18 12:03:43 +00001230 }
1231
David Turner993a8d02002-05-18 12:03:43 +00001232
David Turnerb1b47622002-05-21 21:17:43 +00001233 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001234 {
1235 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1236 };
1237
1238
1239 /* Actually parse the glyph info and bitmaps. */
1240 static FT_Error
1241 _bdf_parse_glyphs( char* line,
1242 unsigned long linelen,
1243 unsigned long lineno,
1244 void* call_data,
1245 void* client_data )
1246 {
1247 int c, mask_index;
1248 char* s;
1249 unsigned char* bp;
1250 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001251
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001252 _bdf_parse_t* p;
1253 bdf_glyph_t* glyph;
1254 bdf_font_t* font;
1255
1256 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001257 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001258
Werner Lemberg319c00d2003-04-23 19:48:24 +00001259 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001260 FT_UNUSED( lineno ); /* only used in debug mode */
1261
1262
Werner Lemberg319c00d2003-04-23 19:48:24 +00001263 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001264
1265 font = p->font;
1266 memory = font->memory;
1267
1268 /* Check for a comment. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001269 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001270 {
1271 linelen -= 7;
1272
1273 s = line + 7;
1274 if ( *s != 0 )
1275 {
1276 s++;
1277 linelen--;
1278 }
1279 error = _bdf_add_comment( p->font, s, linelen );
1280 goto Exit;
1281 }
1282
1283 /* The very first thing expected is the number of glyphs. */
1284 if ( !( p->flags & _BDF_GLYPHS ) )
1285 {
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001286 if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001287 {
1288 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001289 error = FT_THROW( Missing_Chars_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001290 goto Exit;
1291 }
1292
David Turner68df4f72005-03-15 18:18:57 +00001293 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001294 if ( error )
1295 goto Exit;
Ben Wagnera512b0f2015-12-14 09:19:52 +01001296 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001297
Werner Lemberge1ca18d2015-10-17 11:51:27 +02001298 /* We need at least 20 bytes per glyph. */
1299 if ( p->cnt > p->size / 20 )
1300 {
Werner Lemberg797ca5a2015-10-17 11:57:16 +02001301 p->cnt = font->glyphs_size = p->size / 20;
Werner Lemberge1ca18d2015-10-17 11:51:27 +02001302 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG17, p->cnt ));
1303 }
1304
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001305 /* Make sure the number of glyphs is non-zero. */
1306 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001307 font->glyphs_size = 64;
1308
Werner Lemberga08b2172007-03-28 07:17:17 +00001309 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1310 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001311 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001312 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001313 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001314 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001315 goto Exit;
1316 }
1317
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001318 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1319 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001320
David Turner993a8d02002-05-18 12:03:43 +00001321 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001322
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001323 goto Exit;
1324 }
1325
1326 /* Check for the ENDFONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001327 if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001328 {
Werner Lembergaf834612014-11-22 13:29:10 +01001329 if ( p->flags & _BDF_GLYPH_BITS )
1330 {
1331 /* Missing ENDCHAR field. */
1332 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1333 error = FT_THROW( Corrupted_Font_Glyphs );
1334 goto Exit;
1335 }
1336
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001337 /* Sort the glyphs by encoding. */
1338 ft_qsort( (char *)font->glyphs,
1339 font->glyphs_used,
1340 sizeof ( bdf_glyph_t ),
1341 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001342
1343 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001344
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001345 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001346 }
1347
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001348 /* Check for the ENDCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001349 if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001350 {
1351 p->glyph_enc = 0;
1352 p->flags &= ~_BDF_GLYPH_BITS;
1353
1354 goto Exit;
1355 }
1356
Werner Lemberg96ddc672011-06-29 09:15:54 +02001357 /* Check whether a glyph is being scanned but should be */
1358 /* ignored because it is an unencoded glyph. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001359 if ( ( p->flags & _BDF_GLYPH ) &&
1360 p->glyph_enc == -1 &&
1361 p->opts->keep_unencoded == 0 )
1362 goto Exit;
1363
1364 /* Check for the STARTCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001365 if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001366 {
Werner Lembergb1857472015-10-17 14:21:41 +02001367 if ( p->flags & _BDF_GLYPH_BITS )
1368 {
1369 /* Missing ENDCHAR field. */
1370 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1371 error = FT_THROW( Missing_Startchar_Field );
1372 goto Exit;
1373 }
1374
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001375 /* Set the character name in the parse info first until the */
1376 /* encoding can be checked for an unencoded character. */
1377 FT_FREE( p->glyph_name );
1378
David Turner68df4f72005-03-15 18:18:57 +00001379 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001380 if ( error )
1381 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001382
David Turner68df4f72005-03-15 18:18:57 +00001383 _bdf_list_shift( &p->list, 1 );
1384
1385 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001386
Werner Lembergba03af62007-05-30 13:57:02 +00001387 if ( !s )
1388 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001389 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001390 error = FT_THROW( Invalid_File_Format );
Werner Lembergba03af62007-05-30 13:57:02 +00001391 goto Exit;
1392 }
1393
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001394 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1395 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001396
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001397 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1398
1399 p->flags |= _BDF_GLYPH;
1400
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001401 FT_TRACE4(( DBGMSG1, lineno, s ));
1402
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001403 goto Exit;
1404 }
1405
1406 /* Check for the ENCODING field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001407 if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001408 {
1409 if ( !( p->flags & _BDF_GLYPH ) )
1410 {
1411 /* Missing STARTCHAR field. */
1412 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001413 error = FT_THROW( Missing_Startchar_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001414 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001415 }
1416
David Turner68df4f72005-03-15 18:18:57 +00001417 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001418 if ( error )
1419 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001420
Ben Wagnera512b0f2015-12-14 09:19:52 +01001421 p->glyph_enc = _bdf_atol( p->list.field[1] );
David Turner993a8d02002-05-18 12:03:43 +00001422
Werner Lemberg28dd2c42012-02-26 06:18:58 +01001423 /* Normalize negative encoding values. The specification only */
1424 /* allows -1, but we can be more generous here. */
1425 if ( p->glyph_enc < -1 )
1426 p->glyph_enc = -1;
1427
Werner Lemberg03242f52012-02-26 06:52:56 +01001428 /* Check for alternative encoding format. */
1429 if ( p->glyph_enc == -1 && p->list.used > 2 )
Ben Wagnera512b0f2015-12-14 09:19:52 +01001430 p->glyph_enc = _bdf_atol( p->list.field[2] );
Werner Lemberg03242f52012-02-26 06:52:56 +01001431
Werner Lemberg7f2e4f42012-12-15 09:39:41 +01001432 if ( p->glyph_enc < -1 )
1433 p->glyph_enc = -1;
1434
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001435 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1436
Werner Lemberged54e432011-11-27 16:39:53 +01001437 /* Check that the encoding is in the Unicode range because */
1438 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lemberg07bdb6e2012-12-15 02:02:23 +01001439 if ( p->glyph_enc > 0 &&
1440 (size_t)p->glyph_enc >= sizeof ( p->have ) /
1441 sizeof ( unsigned long ) * 32 )
David Turner481838e2006-02-23 12:40:14 +00001442 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001443 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001444 error = FT_THROW( Invalid_File_Format );
David Turner481838e2006-02-23 12:40:14 +00001445 goto Exit;
1446 }
1447
Werner Lemberg96ddc672011-06-29 09:15:54 +02001448 /* Check whether this encoding has already been encountered. */
1449 /* If it has then change it to unencoded so it gets added if */
1450 /* indicated. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001451 if ( p->glyph_enc >= 0 )
1452 {
1453 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1454 {
1455 /* Emit a message saying a glyph has been moved to the */
1456 /* unencoded area. */
1457 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1458 p->glyph_enc, p->glyph_name ));
1459 p->glyph_enc = -1;
1460 font->modified = 1;
1461 }
1462 else
1463 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1464 }
1465
1466 if ( p->glyph_enc >= 0 )
1467 {
1468 /* Make sure there are enough glyphs allocated in case the */
1469 /* number of characters happen to be wrong. */
1470 if ( font->glyphs_used == font->glyphs_size )
1471 {
1472 if ( FT_RENEW_ARRAY( font->glyphs,
1473 font->glyphs_size,
1474 font->glyphs_size + 64 ) )
1475 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001476
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001477 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001478 }
1479
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001480 glyph = font->glyphs + font->glyphs_used++;
1481 glyph->name = p->glyph_name;
1482 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001483
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001484 /* Reset the initial glyph info. */
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001485 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001486 }
1487 else
1488 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001489 /* Unencoded glyph. Check whether it should */
1490 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001491 if ( p->opts->keep_unencoded != 0 )
1492 {
1493 /* Allocate the next unencoded glyph. */
1494 if ( font->unencoded_used == font->unencoded_size )
1495 {
David Turner68df4f72005-03-15 18:18:57 +00001496 if ( FT_RENEW_ARRAY( font->unencoded ,
1497 font->unencoded_size,
1498 font->unencoded_size + 4 ) )
1499 goto Exit;
1500
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001501 font->unencoded_size += 4;
1502 }
1503
1504 glyph = font->unencoded + font->unencoded_used;
1505 glyph->name = p->glyph_name;
Werner Lemberg3c374c82015-02-22 09:16:53 +01001506 glyph->encoding = (long)font->unencoded_used++;
Werner Lemberg4a150132015-11-25 07:53:49 +01001507
1508 /* Reset the initial glyph info. */
1509 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001510 }
1511 else
Werner Lemberg94cacac2015-11-15 04:45:42 +01001512 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001513 /* Free up the glyph name if the unencoded shouldn't be */
1514 /* kept. */
1515 FT_FREE( p->glyph_name );
Werner Lemberg94cacac2015-11-15 04:45:42 +01001516 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001517
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001518 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001519 }
1520
1521 /* Clear the flags that might be added when width and height are */
1522 /* checked for consistency. */
1523 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1524
1525 p->flags |= _BDF_ENCODING;
1526
1527 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001528 }
1529
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001530 /* Point at the glyph being constructed. */
1531 if ( p->glyph_enc == -1 )
1532 glyph = font->unencoded + ( font->unencoded_used - 1 );
1533 else
1534 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001535
Werner Lemberg96ddc672011-06-29 09:15:54 +02001536 /* Check whether a bitmap is being constructed. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001537 if ( p->flags & _BDF_BITMAP )
1538 {
1539 /* If there are more rows than are specified in the glyph metrics, */
1540 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001541 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001542 {
1543 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1544 {
1545 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1546 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001547 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001548 }
1549
1550 goto Exit;
1551 }
1552
1553 /* Only collect the number of nibbles indicated by the glyph */
1554 /* metrics. If there are more columns, they are simply ignored. */
1555 nibbles = glyph->bpr << 1;
1556 bp = glyph->bitmap + p->row * glyph->bpr;
1557
David Turnerb698eed2006-02-23 14:50:13 +00001558 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001559 {
1560 c = line[i];
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001561 if ( !sbitset( hdigits, c ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001562 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001563 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001564 if ( i + 1 < nibbles && ( i & 1 ) )
1565 *++bp = 0;
1566 }
1567
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001568 /* If any line has not enough columns, */
1569 /* indicate they have been padded with zero bits. */
1570 if ( i < nibbles &&
1571 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1572 {
1573 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
1574 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1575 font->modified = 1;
1576 }
1577
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001578 /* Remove possible garbage at the right. */
1579 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001580 if ( glyph->bbx.width )
1581 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001582
1583 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001584 if ( i == nibbles &&
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001585 sbitset( hdigits, line[nibbles] ) &&
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001586 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001587 {
1588 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1589 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1590 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001591 }
1592
1593 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001594 goto Exit;
1595 }
David Turner993a8d02002-05-18 12:03:43 +00001596
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001597 /* Expect the SWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001598 if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001599 {
1600 if ( !( p->flags & _BDF_ENCODING ) )
Werner Lemberg4086fb72012-03-01 08:55:40 +01001601 goto Missing_Encoding;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001602
David Turner68df4f72005-03-15 18:18:57 +00001603 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001604 if ( error )
1605 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001606
Ben Wagnera512b0f2015-12-14 09:19:52 +01001607 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1] );
David Turner993a8d02002-05-18 12:03:43 +00001608 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001609
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001610 goto Exit;
1611 }
David Turner993a8d02002-05-18 12:03:43 +00001612
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001613 /* Expect the DWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001614 if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001615 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001616 if ( !( p->flags & _BDF_ENCODING ) )
1617 goto Missing_Encoding;
1618
David Turner68df4f72005-03-15 18:18:57 +00001619 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001620 if ( error )
1621 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001622
Ben Wagnera512b0f2015-12-14 09:19:52 +01001623 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001624
1625 if ( !( p->flags & _BDF_SWIDTH ) )
1626 {
1627 /* Missing SWIDTH field. Emit an auto correction message and set */
1628 /* the scalable width from the device width. */
1629 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1630
Werner Lemberg02d4d592002-05-28 22:38:05 +00001631 glyph->swidth = (unsigned short)FT_MulDiv(
1632 glyph->dwidth, 72000L,
1633 (FT_Long)( font->point_size *
1634 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001635 }
1636
1637 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001638 goto Exit;
1639 }
David Turner993a8d02002-05-18 12:03:43 +00001640
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001641 /* Expect the BBX field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001642 if ( _bdf_strncmp( line, "BBX", 3 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001643 {
Werner Lemberg4086fb72012-03-01 08:55:40 +01001644 if ( !( p->flags & _BDF_ENCODING ) )
1645 goto Missing_Encoding;
1646
David Turner68df4f72005-03-15 18:18:57 +00001647 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001648 if ( error )
1649 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001650
Ben Wagnera512b0f2015-12-14 09:19:52 +01001651 glyph->bbx.width = _bdf_atous( p->list.field[1] );
1652 glyph->bbx.height = _bdf_atous( p->list.field[2] );
1653 glyph->bbx.x_offset = _bdf_atos( p->list.field[3] );
1654 glyph->bbx.y_offset = _bdf_atos( p->list.field[4] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001655
1656 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001657 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1658 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001659
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001660 /* Determine the overall font bounding box as the characters are */
1661 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001662 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1663 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001664
David Turnerb1b47622002-05-21 21:17:43 +00001665 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001666
Werner Lembergdfa46192004-03-05 09:26:24 +00001667 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1668 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1669 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001670
1671 if ( !( p->flags & _BDF_DWIDTH ) )
1672 {
1673 /* Missing DWIDTH field. Emit an auto correction message and set */
1674 /* the device width to the glyph width. */
1675 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1676 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001677 }
1678
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001679 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1680 /* value if necessary. */
1681 if ( p->opts->correct_metrics != 0 )
1682 {
1683 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001684 unsigned short sw = (unsigned short)FT_MulDiv(
1685 glyph->dwidth, 72000L,
1686 (FT_Long)( font->point_size *
1687 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001688
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001689
1690 if ( sw != glyph->swidth )
1691 {
1692 glyph->swidth = sw;
1693
1694 if ( p->glyph_enc == -1 )
1695 _bdf_set_glyph_modified( font->umod,
1696 font->unencoded_used - 1 );
1697 else
1698 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1699
1700 p->flags |= _BDF_SWIDTH_ADJ;
1701 font->modified = 1;
1702 }
David Turner993a8d02002-05-18 12:03:43 +00001703 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001704
David Turner993a8d02002-05-18 12:03:43 +00001705 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001706 goto Exit;
1707 }
David Turner993a8d02002-05-18 12:03:43 +00001708
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001709 /* And finally, gather up the bitmap. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001710 if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001711 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001712 unsigned long bitmap_size;
1713
1714
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001715 if ( !( p->flags & _BDF_BBX ) )
1716 {
1717 /* Missing BBX field. */
1718 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001719 error = FT_THROW( Missing_Bbx_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001720 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001721 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001722
1723 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001724 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001725
1726 bitmap_size = glyph->bpr * glyph->bbx.height;
Werner Lembergc4cad302012-03-08 20:11:37 +01001727 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
Werner Lemberg26170df2006-03-26 07:19:07 +00001728 {
1729 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001730 error = FT_THROW( Bbx_Too_Big );
Werner Lemberg26170df2006-03-26 07:19:07 +00001731 goto Exit;
1732 }
1733 else
1734 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001735
1736 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1737 goto Exit;
1738
1739 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001740 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001741
1742 goto Exit;
1743 }
1744
Werner Lemberge01406b2011-11-25 09:44:28 +01001745 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001746 error = FT_THROW( Invalid_File_Format );
Werner Lemberg4086fb72012-03-01 08:55:40 +01001747 goto Exit;
1748
1749 Missing_Encoding:
1750 /* Missing ENCODING field. */
1751 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001752 error = FT_THROW( Missing_Encoding_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001753
1754 Exit:
Werner Lembergf4c94d42010-06-19 16:08:31 +02001755 if ( error && ( p->flags & _BDF_GLYPH ) )
1756 FT_FREE( p->glyph_name );
1757
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001758 return error;
David Turner993a8d02002-05-18 12:03:43 +00001759 }
1760
David Turner993a8d02002-05-18 12:03:43 +00001761
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001762 /* Load the font properties. */
1763 static FT_Error
1764 _bdf_parse_properties( char* line,
1765 unsigned long linelen,
1766 unsigned long lineno,
1767 void* call_data,
1768 void* client_data )
1769 {
1770 unsigned long vlen;
1771 _bdf_line_func_t* next;
1772 _bdf_parse_t* p;
1773 char* name;
1774 char* value;
1775 char nbuf[128];
Werner Lemberge3c93012013-03-14 11:21:17 +01001776 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001777
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001778 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001779
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001780
1781 next = (_bdf_line_func_t *)call_data;
1782 p = (_bdf_parse_t *) client_data;
1783
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001784 /* Check for the end of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001785 if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001786 {
1787 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1788 /* encountered yet, then make sure they are added as properties and */
1789 /* make sure they are set from the font bounding box info. */
1790 /* */
1791 /* This is *always* done regardless of the options, because X11 */
1792 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001793 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001794 {
1795 p->font->font_ascent = p->font->bbx.ascent;
1796 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001797 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
1798 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001799 if ( error )
1800 goto Exit;
1801
1802 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1803 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001804 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001805
Werner Lemberg428c2e42003-04-25 05:35:04 +00001806 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001807 {
1808 p->font->font_descent = p->font->bbx.descent;
1809 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001810 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
1811 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001812 if ( error )
1813 goto Exit;
1814
1815 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1816 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001817 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001818
David Turner993a8d02002-05-18 12:03:43 +00001819 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001820 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001821
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001822 goto Exit;
1823 }
David Turner993a8d02002-05-18 12:03:43 +00001824
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001825 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001826 if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001827 goto Exit;
1828
1829 /* Handle COMMENT fields and properties in a special way to preserve */
1830 /* the spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001831 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001832 {
David Turner993a8d02002-05-18 12:03:43 +00001833 name = value = line;
1834 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001835 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001836 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01001837 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001838 if ( error )
1839 goto Exit;
1840 }
1841 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1842 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001843 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001844 if ( error )
1845 goto Exit;
1846 }
1847 else
1848 {
David Turner68df4f72005-03-15 18:18:57 +00001849 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001850 if ( error )
1851 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001852 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001853
David Turner68df4f72005-03-15 18:18:57 +00001854 _bdf_list_shift( &p->list, 1 );
1855 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001856
Werner Lemberge01406b2011-11-25 09:44:28 +01001857 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001858 if ( error )
1859 goto Exit;
1860 }
1861
1862 Exit:
1863 return error;
David Turner993a8d02002-05-18 12:03:43 +00001864 }
1865
David Turner993a8d02002-05-18 12:03:43 +00001866
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001867 /* Load the font header. */
1868 static FT_Error
1869 _bdf_parse_start( char* line,
1870 unsigned long linelen,
1871 unsigned long lineno,
1872 void* call_data,
1873 void* client_data )
1874 {
1875 unsigned long slen;
1876 _bdf_line_func_t* next;
1877 _bdf_parse_t* p;
1878 bdf_font_t* font;
1879 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001880
David Turnerd490e372002-05-28 23:40:37 +00001881 FT_Memory memory = NULL;
Werner Lemberge3c93012013-03-14 11:21:17 +01001882 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001883
1884 FT_UNUSED( lineno ); /* only used in debug mode */
1885
1886
1887 next = (_bdf_line_func_t *)call_data;
1888 p = (_bdf_parse_t *) client_data;
1889
1890 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00001891 memory = p->font->memory;
1892
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001893 /* Check for a comment. This is done to handle those fonts that have */
1894 /* comments before the STARTFONT line for some reason. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001895 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001896 {
1897 if ( p->opts->keep_comments != 0 && p->font != 0 )
1898 {
1899 linelen -= 7;
1900
1901 s = line + 7;
1902 if ( *s != 0 )
1903 {
1904 s++;
1905 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00001906 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001907
1908 error = _bdf_add_comment( p->font, s, linelen );
1909 if ( error )
1910 goto Exit;
1911 /* here font is not defined! */
1912 }
1913
1914 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001915 }
1916
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001917 if ( !( p->flags & _BDF_START ) )
1918 {
1919 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00001920
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001921 if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001922 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01001923 /* we don't emit an error message since this code gets */
1924 /* explicitly caught one level higher */
Werner Lemberg059bc332013-03-14 10:27:35 +01001925 error = FT_THROW( Missing_Startfont_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001926 goto Exit;
1927 }
David Turner993a8d02002-05-18 12:03:43 +00001928
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001929 p->flags = _BDF_START;
1930 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00001931
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001932 if ( FT_NEW( font ) )
1933 goto Exit;
1934 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00001935
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001936 font->memory = p->memory;
1937 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00001938
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001939 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001940 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001941 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00001942
David Turner993a8d02002-05-18 12:03:43 +00001943
Werner Lemberg31343562015-12-19 17:02:13 +01001944 error = ft_hash_init( &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001945 if ( error )
1946 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00001947 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001948 i < _num_bdf_properties; i++, prop++ )
1949 {
Werner Lemberg31343562015-12-19 17:02:13 +01001950 error = ft_hash_insert( prop->name, i,
1951 &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001952 if ( error )
1953 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001954 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001955 }
1956
Werner Lemberg31343562015-12-19 17:02:13 +01001957 if ( FT_ALLOC( p->font->internal, sizeof ( FT_HashRec ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001958 goto Exit;
Werner Lemberg31343562015-12-19 17:02:13 +01001959 error = ft_hash_init( (FT_Hash)p->font->internal, memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001960 if ( error )
1961 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00001962 p->font->spacing = p->opts->font_spacing;
1963 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001964
1965 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001966 }
1967
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001968 /* Check for the start of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001969 if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001970 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02001971 if ( !( p->flags & _BDF_FONT_BBX ) )
Werner Lembergfb690292010-06-23 10:00:52 +02001972 {
1973 /* Missing the FONTBOUNDINGBOX field. */
1974 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001975 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergfb690292010-06-23 10:00:52 +02001976 goto Exit;
1977 }
1978
David Turner68df4f72005-03-15 18:18:57 +00001979 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001980 if ( error )
1981 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00001982 /* at this point, `p->font' can't be NULL */
Ben Wagnera512b0f2015-12-14 09:19:52 +01001983 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001984
1985 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
Werner Lemberg9b6b5752012-12-15 01:34:41 +01001986 {
1987 p->font->props_size = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001988 goto Exit;
Werner Lemberg9b6b5752012-12-15 01:34:41 +01001989 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001990
1991 p->flags |= _BDF_PROPS;
1992 *next = _bdf_parse_properties;
1993
1994 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001995 }
1996
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001997 /* Check for the FONTBOUNDINGBOX field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001998 if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001999 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002000 if ( !( p->flags & _BDF_SIZE ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002001 {
2002 /* Missing the SIZE field. */
2003 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002004 error = FT_THROW( Missing_Size_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002005 goto Exit;
2006 }
2007
David Turner68df4f72005-03-15 18:18:57 +00002008 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002009 if ( error )
2010 goto Exit;
2011
Ben Wagnera512b0f2015-12-14 09:19:52 +01002012 p->font->bbx.width = _bdf_atous( p->list.field[1] );
2013 p->font->bbx.height = _bdf_atous( p->list.field[2] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002014
Ben Wagnera512b0f2015-12-14 09:19:52 +01002015 p->font->bbx.x_offset = _bdf_atos( p->list.field[3] );
2016 p->font->bbx.y_offset = _bdf_atos( p->list.field[4] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002017
David Turnerd490e372002-05-28 23:40:37 +00002018 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002019 p->font->bbx.y_offset );
2020
2021 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002022
2023 p->flags |= _BDF_FONT_BBX;
2024
2025 goto Exit;
2026 }
2027
2028 /* The next thing to check for is the FONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002029 if ( _bdf_strncmp( line, "FONT", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002030 {
David Turner68df4f72005-03-15 18:18:57 +00002031 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002032 if ( error )
2033 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002034 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002035
David Turner68df4f72005-03-15 18:18:57 +00002036 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002037
2038 if ( !s )
2039 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002040 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002041 error = FT_THROW( Invalid_File_Format );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002042 goto Exit;
2043 }
2044
Werner Lembergfb690292010-06-23 10:00:52 +02002045 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2046 FT_FREE( p->font->name );
2047
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002048 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2049 goto Exit;
2050 FT_MEM_COPY( p->font->name, s, slen + 1 );
2051
2052 /* If the font name is an XLFD name, set the spacing to the one in */
2053 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002054 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002055 if ( error )
2056 goto Exit;
2057
2058 p->flags |= _BDF_FONT_NAME;
2059
2060 goto Exit;
2061 }
2062
2063 /* Check for the SIZE field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002064 if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002065 {
2066 if ( !( p->flags & _BDF_FONT_NAME ) )
2067 {
2068 /* Missing the FONT field. */
2069 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002070 error = FT_THROW( Missing_Font_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002071 goto Exit;
2072 }
2073
David Turner68df4f72005-03-15 18:18:57 +00002074 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002075 if ( error )
2076 goto Exit;
2077
Ben Wagnera512b0f2015-12-14 09:19:52 +01002078 p->font->point_size = _bdf_atoul( p->list.field[1] );
2079 p->font->resolution_x = _bdf_atoul( p->list.field[2] );
2080 p->font->resolution_y = _bdf_atoul( p->list.field[3] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002081
2082 /* Check for the bits per pixel field. */
2083 if ( p->list.used == 5 )
2084 {
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002085 unsigned short bpp;
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002086
2087
Ben Wagnera512b0f2015-12-14 09:19:52 +01002088 bpp = (unsigned short)_bdf_atos( p->list.field[4] );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002089
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002090 /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
2091 if ( bpp > 4 )
2092 p->font->bpp = 8;
2093 else if ( bpp > 2 )
2094 p->font->bpp = 4;
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002095 else if ( bpp > 1 )
2096 p->font->bpp = 2;
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002097 else
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002098 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002099
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002100 if ( p->font->bpp != bpp )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002101 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002102 }
2103 else
2104 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002105
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002106 p->flags |= _BDF_SIZE;
2107
2108 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002109 }
2110
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002111 /* Check for the CHARS field -- font properties are optional */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002112 if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002113 {
2114 char nbuf[128];
2115
2116
2117 if ( !( p->flags & _BDF_FONT_BBX ) )
2118 {
2119 /* Missing the FONTBOUNDINGBOX field. */
2120 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002121 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002122 goto Exit;
2123 }
2124
2125 /* Add the two standard X11 properties which are required */
2126 /* for compiling fonts. */
2127 p->font->font_ascent = p->font->bbx.ascent;
2128 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002129 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2130 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002131 if ( error )
2132 goto Exit;
2133 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2134
2135 p->font->font_descent = p->font->bbx.descent;
2136 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002137 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2138 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002139 if ( error )
2140 goto Exit;
2141 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2142
2143 p->font->modified = 1;
2144
2145 *next = _bdf_parse_glyphs;
2146
2147 /* A special return value. */
2148 error = -1;
2149 goto Exit;
2150 }
2151
Werner Lemberge01406b2011-11-25 09:44:28 +01002152 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002153 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002154
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002155 Exit:
2156 return error;
2157 }
David Turner993a8d02002-05-18 12:03:43 +00002158
2159
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002160 /*************************************************************************/
2161 /* */
2162 /* API. */
2163 /* */
2164 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002165
David Turner993a8d02002-05-18 12:03:43 +00002166
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002167 FT_LOCAL_DEF( FT_Error )
2168 bdf_load_font( FT_Stream stream,
2169 FT_Memory extmemory,
2170 bdf_options_t* opts,
2171 bdf_font_t* *font )
2172 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002173 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002174 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002175
Sean McBride7be2a942014-02-08 13:55:38 +01002176 FT_Memory memory = extmemory; /* needed for FT_NEW */
2177 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002178
2179
David Turner68df4f72005-03-15 18:18:57 +00002180 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002181 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002182
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002183 memory = NULL;
2184 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2185 p->minlb = 32767;
Werner Lemberge1ca18d2015-10-17 11:51:27 +02002186 p->size = stream->size;
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002187 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002188
David Turner68df4f72005-03-15 18:18:57 +00002189 _bdf_list_init( &p->list, extmemory );
2190
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002191 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002192 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002193 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002194 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002195
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002196 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002197 {
2198 /* If the font is not proportional, set the font's monowidth */
2199 /* field to the width of the font bounding box. */
David Turner993a8d02002-05-18 12:03:43 +00002200
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002201 if ( p->font->spacing != BDF_PROPORTIONAL )
2202 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002203
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002204 /* If the number of glyphs loaded is not that of the original count, */
2205 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002206 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002207 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002208 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2209 p->font->glyphs_used + p->font->unencoded_used ));
2210 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002211 }
2212
2213 /* Once the font has been loaded, adjust the overall font metrics if */
2214 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002215 if ( p->opts->correct_metrics != 0 &&
2216 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002217 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002218 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002219 {
2220 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002221 p->font->bbx.width, p->maxrb - p->minlb ));
2222 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2223 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002224 }
2225
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002226 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002227 {
2228 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002229 p->font->bbx.x_offset, p->minlb ));
2230 p->font->bbx.x_offset = p->minlb;
2231 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002232 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002233
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002234 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002235 {
2236 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002237 p->font->bbx.ascent, p->maxas ));
2238 p->font->bbx.ascent = p->maxas;
2239 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002240 }
2241
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002242 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002243 {
2244 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002245 p->font->bbx.descent, p->maxds ));
2246 p->font->bbx.descent = p->maxds;
2247 p->font->bbx.y_offset = (short)( -p->maxds );
2248 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002249 }
2250
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002251 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002252 {
2253 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002254 p->font->bbx.height, p->maxas + p->maxds ));
2255 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002256 }
2257
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002258 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002259 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2260 }
David Turner993a8d02002-05-18 12:03:43 +00002261 }
2262
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002263 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002264 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002265 /* The ENDFONT field was never reached or did not exist. */
2266 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002267 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002268 /* Error happened while parsing header. */
2269 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002270 error = FT_THROW( Corrupted_Font_Header );
Bungeman65d89802015-10-15 23:50:16 +02002271 goto Fail;
Werner Lemberge01406b2011-11-25 09:44:28 +01002272 }
2273 else
2274 {
2275 /* Error happened when parsing glyphs. */
2276 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002277 error = FT_THROW( Corrupted_Font_Glyphs );
Bungeman65d89802015-10-15 23:50:16 +02002278 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002279 }
David Turner993a8d02002-05-18 12:03:43 +00002280 }
2281
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002282 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002283 {
2284 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002285 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002286
Werner Lemberg370aea82010-06-08 08:37:11 +02002287 if ( p->font->comments_len > 0 )
2288 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002289 if ( FT_RENEW_ARRAY( p->font->comments,
2290 p->font->comments_len,
2291 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002292 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002293
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002294 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002295 }
David Turner993a8d02002-05-18 12:03:43 +00002296 }
Werner Lemberge3c93012013-03-14 11:21:17 +01002297 else if ( error == FT_Err_Ok )
Werner Lemberg059bc332013-03-14 10:27:35 +01002298 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002299
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002300 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002301
2302 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002303 if ( p )
2304 {
David Turner68df4f72005-03-15 18:18:57 +00002305 _bdf_list_done( &p->list );
2306
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002307 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002308
Werner Lemberg4a150132015-11-25 07:53:49 +01002309 FT_FREE( p->glyph_name );
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002310 FT_FREE( p );
2311 }
2312
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002313 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002314
2315 Fail:
2316 bdf_free_font( p->font );
2317
2318 memory = extmemory;
2319
2320 FT_FREE( p->font );
2321
2322 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002323 }
David Turner993a8d02002-05-18 12:03:43 +00002324
2325
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002326 FT_LOCAL_DEF( void )
2327 bdf_free_font( bdf_font_t* font )
2328 {
2329 bdf_property_t* prop;
2330 unsigned long i;
2331 bdf_glyph_t* glyphs;
2332 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002333
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002334
2335 if ( font == 0 )
2336 return;
David Turner993a8d02002-05-18 12:03:43 +00002337
2338 memory = font->memory;
2339
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002340 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002341
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002342 /* Free up the internal hash table of property names. */
2343 if ( font->internal )
2344 {
Werner Lemberg31343562015-12-19 17:02:13 +01002345 ft_hash_free( (FT_Hash)font->internal, memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002346 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002347 }
2348
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002349 /* Free up the comment info. */
2350 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002351
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002352 /* Free up the properties. */
2353 for ( i = 0; i < font->props_size; i++ )
2354 {
2355 if ( font->props[i].format == BDF_ATOM )
2356 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002357 }
2358
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002359 FT_FREE( font->props );
2360
2361 /* Free up the character info. */
2362 for ( i = 0, glyphs = font->glyphs;
2363 i < font->glyphs_used; i++, glyphs++ )
2364 {
2365 FT_FREE( glyphs->name );
2366 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002367 }
2368
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002369 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2370 i++, glyphs++ )
2371 {
2372 FT_FREE( glyphs->name );
2373 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002374 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002375
2376 FT_FREE( font->glyphs );
2377 FT_FREE( font->unencoded );
2378
2379 /* Free up the overflow storage if it was used. */
2380 for ( i = 0, glyphs = font->overflow.glyphs;
2381 i < font->overflow.glyphs_used; i++, glyphs++ )
2382 {
2383 FT_FREE( glyphs->name );
2384 FT_FREE( glyphs->bitmap );
2385 }
2386
2387 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002388
2389 /* bdf_cleanup */
Werner Lemberg31343562015-12-19 17:02:13 +01002390 ft_hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002391
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002392 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002393 for ( prop = font->user_props, i = 0;
2394 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002395 {
2396 FT_FREE( prop->name );
2397 if ( prop->format == BDF_ATOM )
2398 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002399 }
David Turner993a8d02002-05-18 12:03:43 +00002400
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002401 FT_FREE( font->user_props );
2402
2403 /* FREE( font ); */ /* XXX Fixme */
2404 }
David Turner993a8d02002-05-18 12:03:43 +00002405
2406
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002407 FT_LOCAL_DEF( bdf_property_t * )
2408 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002409 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002410 {
Werner Lemberg31343562015-12-19 17:02:13 +01002411 FT_Hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002412
David Turner993a8d02002-05-18 12:03:43 +00002413
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002414 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002415 return 0;
2416
Werner Lemberg31343562015-12-19 17:02:13 +01002417 hn = ft_hash_lookup( name, (FT_Hash)font->internal );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002418
suzuki toshiya704f4d72009-09-13 00:50:14 +09002419 return hn ? ( font->props + hn->data ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002420 }
2421
2422
2423/* END */