blob: 7fd95a7385810fa865bb0ce8b6c00df1b9d7e043 [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 Lemberg609546c2015-12-20 07:17:29 +0100815 if ( ft_hash_str_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 Lemberg609546c2015-12-20 07:17:29 +0100840 error = ft_hash_str_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 Lemberg76e79ec2015-12-20 09:03:15 +0100851 FT_LOCAL_DEF( bdf_property_t* )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000852 bdf_get_property( char* name,
853 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +0000854 {
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100855 size_t* propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000856
857
858 if ( name == 0 || *name == 0 )
859 return 0;
860
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100861 if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000862 return 0;
863
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100864 if ( *propid >= _num_bdf_properties )
865 return font->user_props + ( *propid - _num_bdf_properties );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000866
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100867 return (bdf_property_t*)_bdf_properties + *propid;
David Turner993a8d02002-05-18 12:03:43 +0000868 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000869
870
871 /*************************************************************************/
872 /* */
873 /* BDF font file parsing flags and functions. */
874 /* */
875 /*************************************************************************/
876
877
878 /* Parse flags. */
879
Werner Lemberg758587d2016-01-12 22:20:06 +0100880#define BDF_START_ 0x0001U
881#define BDF_FONT_NAME_ 0x0002U
882#define BDF_SIZE_ 0x0004U
883#define BDF_FONT_BBX_ 0x0008U
884#define BDF_PROPS_ 0x0010U
885#define BDF_GLYPHS_ 0x0020U
886#define BDF_GLYPH_ 0x0040U
887#define BDF_ENCODING_ 0x0080U
888#define BDF_SWIDTH_ 0x0100U
889#define BDF_DWIDTH_ 0x0200U
890#define BDF_BBX_ 0x0400U
891#define BDF_BITMAP_ 0x0800U
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000892
Werner Lemberg758587d2016-01-12 22:20:06 +0100893#define BDF_SWIDTH_ADJ_ 0x1000U
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000894
Werner Lemberg758587d2016-01-12 22:20:06 +0100895#define BDF_GLYPH_BITS_ ( BDF_GLYPH_ | \
896 BDF_ENCODING_ | \
897 BDF_SWIDTH_ | \
898 BDF_DWIDTH_ | \
899 BDF_BBX_ | \
900 BDF_BITMAP_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000901
Werner Lemberg758587d2016-01-12 22:20:06 +0100902#define BDF_GLYPH_WIDTH_CHECK_ 0x40000000UL
903#define BDF_GLYPH_HEIGHT_CHECK_ 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000904
905
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000906 static FT_Error
907 _bdf_add_comment( bdf_font_t* font,
908 char* comment,
909 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +0000910 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000911 char* cp;
912 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100913 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000914
915
David Turner68df4f72005-03-15 18:18:57 +0000916 if ( FT_RENEW_ARRAY( font->comments,
917 font->comments_len,
918 font->comments_len + len + 1 ) )
919 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000920
921 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +0000922
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000923 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +0000924 cp[len] = '\n';
925
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000926 font->comments_len += len + 1;
927
928 Exit:
929 return error;
David Turner993a8d02002-05-18 12:03:43 +0000930 }
931
David Turner993a8d02002-05-18 12:03:43 +0000932
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000933 /* Set the spacing from the font name if it exists, or set it to the */
934 /* default specified in the options. */
935 static FT_Error
936 _bdf_set_default_spacing( bdf_font_t* font,
Werner Lemberge01406b2011-11-25 09:44:28 +0100937 bdf_options_t* opts,
938 unsigned long lineno )
David Turner993a8d02002-05-18 12:03:43 +0000939 {
suzuki toshiya704f4d72009-09-13 00:50:14 +0900940 size_t len;
941 char name[256];
942 _bdf_list_t list;
943 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100944 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000945
Dave Arnoldc3782492013-06-05 19:57:55 +0200946 FT_UNUSED( lineno ); /* only used in debug mode */
947
David Turner993a8d02002-05-18 12:03:43 +0000948
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000949 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
950 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100951 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000952 goto Exit;
953 }
David Turner993a8d02002-05-18 12:03:43 +0000954
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000955 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +0000956
David Turner68df4f72005-03-15 18:18:57 +0000957 _bdf_list_init( &list, memory );
958
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000959 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +0000960
suzuki toshiya704f4d72009-09-13 00:50:14 +0900961 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +0000962 /* Limit ourselves to 256 characters in the font name. */
963 if ( len >= 256 )
964 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100965 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +0100966 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +0000967 goto Exit;
968 }
969
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000970 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +0000971
Werner Lembergbadf3172013-06-06 09:16:38 +0200972 error = _bdf_list_split( &list, (char *)"-", name, (unsigned long)len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000973 if ( error )
David Turner68df4f72005-03-15 18:18:57 +0000974 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000975
976 if ( list.used == 15 )
977 {
978 switch ( list.field[11][0] )
979 {
980 case 'C':
981 case 'c':
982 font->spacing = BDF_CHARCELL;
983 break;
984 case 'M':
985 case 'm':
986 font->spacing = BDF_MONOWIDTH;
987 break;
988 case 'P':
989 case 'p':
990 font->spacing = BDF_PROPORTIONAL;
991 break;
David Turner993a8d02002-05-18 12:03:43 +0000992 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000993 }
994
David Turner68df4f72005-03-15 18:18:57 +0000995 Fail:
996 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000997
998 Exit:
999 return error;
David Turner993a8d02002-05-18 12:03:43 +00001000 }
David Turner993a8d02002-05-18 12:03:43 +00001001
1002
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001003 /* Determine whether the property is an atom or not. If it is, then */
1004 /* clean it up so the double quotes are removed if they exist. */
1005 static int
1006 _bdf_is_atom( char* line,
1007 unsigned long linelen,
1008 char** name,
1009 char** value,
1010 bdf_font_t* font )
1011 {
1012 int hold;
1013 char *sp, *ep;
1014 bdf_property_t* p;
1015
David Turner993a8d02002-05-18 12:03:43 +00001016
1017 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001018
1019 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001020 ep++;
1021
1022 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001023 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001024 {
1025 hold = *ep;
1026 *ep = 0;
1027 }
1028
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001029 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001030
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001031 /* Restore the character that was saved before any return can happen. */
1032 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001033 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001034
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001035 /* If the property exists and is not an atom, just return here. */
1036 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001037 return 0;
1038
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001039 /* The property is an atom. Trim all leading and trailing whitespace */
1040 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001041 sp = ep;
1042 ep = line + linelen;
1043
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001044 /* Trim the leading whitespace if it exists. */
Werner Lemberg320d4972012-02-24 18:06:46 +01001045 if ( *sp )
1046 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001047 while ( *sp &&
1048 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001049 sp++;
1050
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001051 /* Trim the leading double quote if it exists. */
1052 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001053 sp++;
1054 *value = sp;
1055
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001056 /* Trim the trailing whitespace if it exists. */
1057 while ( ep > sp &&
1058 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001059 *--ep = 0;
1060
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001061 /* Trim the trailing double quote if it exists. */
1062 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001063 *--ep = 0;
1064
1065 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001066 }
David Turner993a8d02002-05-18 12:03:43 +00001067
1068
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001069 static FT_Error
Werner Lemberge01406b2011-11-25 09:44:28 +01001070 _bdf_add_property( bdf_font_t* font,
1071 char* name,
1072 char* value,
1073 unsigned long lineno )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001074 {
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001075 size_t* propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001076 bdf_property_t *prop, *fp;
1077 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001078 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001079
Dave Arnoldc3782492013-06-05 19:57:55 +02001080 FT_UNUSED( lineno ); /* only used in debug mode */
1081
David Turner993a8d02002-05-18 12:03:43 +00001082
Werner Lemberg96ddc672011-06-29 09:15:54 +02001083 /* First, check whether the property already exists in the font. */
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001084 if ( ( propid = ft_hash_str_lookup( name,
1085 (FT_Hash)font->internal ) ) != NULL )
David Turner993a8d02002-05-18 12:03:43 +00001086 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001087 /* The property already exists in the font, so simply replace */
1088 /* the value of the property with the current value. */
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001089 fp = font->props + *propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001090
David Turnerb1b47622002-05-21 21:17:43 +00001091 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001092 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001093 case BDF_ATOM:
1094 /* Delete the current atom if it exists. */
1095 FT_FREE( fp->value.atom );
1096
David Turnerc0f9c4a2007-02-12 14:55:03 +00001097 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001098 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001099 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001100 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001101 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001102 break;
1103
1104 case BDF_INTEGER:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001105 fp->value.l = _bdf_atol( value );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001106 break;
1107
1108 case BDF_CARDINAL:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001109 fp->value.ul = _bdf_atoul( value );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001110 break;
David Turnerd490e372002-05-28 23:40:37 +00001111
David Turnerb1b47622002-05-21 21:17:43 +00001112 default:
1113 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001114 }
David Turnerd490e372002-05-28 23:40:37 +00001115
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001116 goto Exit;
1117 }
1118
1119 /* See whether this property type exists yet or not. */
1120 /* If not, create it. */
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001121 propid = ft_hash_str_lookup( name, &(font->proptbl) );
Werner Lemberg4441f7b2016-12-26 17:08:17 +01001122 if ( !propid )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001123 {
1124 error = bdf_create_property( name, BDF_ATOM, font );
1125 if ( error )
1126 goto Exit;
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001127 propid = ft_hash_str_lookup( name, &(font->proptbl) );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001128 }
1129
Werner Lembergb6b26f42016-06-09 06:53:48 +02001130 /* Allocate another property if this is overflowing. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001131 if ( font->props_used == font->props_size )
1132 {
1133 if ( font->props_size == 0 )
1134 {
1135 if ( FT_NEW_ARRAY( font->props, 1 ) )
1136 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001137 }
1138 else
1139 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001140 if ( FT_RENEW_ARRAY( font->props,
1141 font->props_size,
1142 font->props_size + 1 ) )
1143 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001144 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001145
David Turner993a8d02002-05-18 12:03:43 +00001146 fp = font->props + font->props_size;
Werner Lemberg2ecf89b2016-09-28 19:06:21 +02001147 FT_ZERO( fp );
David Turner993a8d02002-05-18 12:03:43 +00001148 font->props_size++;
1149 }
1150
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001151 if ( *propid >= _num_bdf_properties )
1152 prop = font->user_props + ( *propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001153 else
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001154 prop = (bdf_property_t*)_bdf_properties + *propid;
David Turner993a8d02002-05-18 12:03:43 +00001155
1156 fp = font->props + font->props_used;
1157
1158 fp->name = prop->name;
1159 fp->format = prop->format;
1160 fp->builtin = prop->builtin;
1161
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001162 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001163 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001164 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001165 fp->value.atom = 0;
1166 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001167 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001168 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001169 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001170 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001171 break;
David Turner993a8d02002-05-18 12:03:43 +00001172
1173 case BDF_INTEGER:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001174 fp->value.l = _bdf_atol( value );
David Turner993a8d02002-05-18 12:03:43 +00001175 break;
1176
1177 case BDF_CARDINAL:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001178 fp->value.ul = _bdf_atoul( value );
David Turner993a8d02002-05-18 12:03:43 +00001179 break;
David Turner993a8d02002-05-18 12:03:43 +00001180 }
1181
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001182 /* If the property happens to be a comment, then it doesn't need */
1183 /* to be added to the internal hash table. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001184 if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 )
Werner Lemberg370aea82010-06-08 08:37:11 +02001185 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001186 /* Add the property to the font property table. */
Werner Lemberg609546c2015-12-20 07:17:29 +01001187 error = ft_hash_str_insert( fp->name,
1188 font->props_used,
1189 (FT_Hash)font->internal,
1190 memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001191 if ( error )
1192 goto Exit;
1193 }
David Turner993a8d02002-05-18 12:03:43 +00001194
1195 font->props_used++;
1196
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001197 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1198 /* property needs to be located if it exists in the property list, the */
1199 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1200 /* present, and the SPACING property should override the default */
1201 /* spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001202 if ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001203 font->default_char = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001204 else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001205 font->font_ascent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001206 else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001207 font->font_descent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001208 else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001209 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001210 if ( !fp->value.atom )
1211 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001212 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001213 error = FT_THROW( Invalid_File_Format );
Werner Lembergb66efef2009-03-12 08:07:49 +00001214 goto Exit;
1215 }
1216
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001217 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001218 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001219 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001220 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001221 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001222 font->spacing = BDF_CHARCELL;
1223 }
1224
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001225 Exit:
1226 return error;
David Turner993a8d02002-05-18 12:03:43 +00001227 }
1228
David Turner993a8d02002-05-18 12:03:43 +00001229
David Turnerb1b47622002-05-21 21:17:43 +00001230 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001231 {
1232 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1233 };
1234
1235
1236 /* Actually parse the glyph info and bitmaps. */
1237 static FT_Error
1238 _bdf_parse_glyphs( char* line,
1239 unsigned long linelen,
1240 unsigned long lineno,
1241 void* call_data,
1242 void* client_data )
1243 {
1244 int c, mask_index;
1245 char* s;
1246 unsigned char* bp;
1247 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001248
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001249 _bdf_parse_t* p;
1250 bdf_glyph_t* glyph;
1251 bdf_font_t* font;
1252
1253 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001254 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001255
Werner Lemberg319c00d2003-04-23 19:48:24 +00001256 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001257 FT_UNUSED( lineno ); /* only used in debug mode */
1258
1259
Werner Lemberg319c00d2003-04-23 19:48:24 +00001260 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001261
1262 font = p->font;
1263 memory = font->memory;
1264
1265 /* Check for a comment. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001266 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001267 {
1268 linelen -= 7;
1269
1270 s = line + 7;
1271 if ( *s != 0 )
1272 {
1273 s++;
1274 linelen--;
1275 }
1276 error = _bdf_add_comment( p->font, s, linelen );
1277 goto Exit;
1278 }
1279
1280 /* The very first thing expected is the number of glyphs. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001281 if ( !( p->flags & BDF_GLYPHS_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001282 {
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001283 if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001284 {
1285 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001286 error = FT_THROW( Missing_Chars_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001287 goto Exit;
1288 }
1289
David Turner68df4f72005-03-15 18:18:57 +00001290 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001291 if ( error )
1292 goto Exit;
Ben Wagnera512b0f2015-12-14 09:19:52 +01001293 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001294
Werner Lemberge1ca18d2015-10-17 11:51:27 +02001295 /* We need at least 20 bytes per glyph. */
1296 if ( p->cnt > p->size / 20 )
1297 {
Werner Lemberg797ca5a2015-10-17 11:57:16 +02001298 p->cnt = font->glyphs_size = p->size / 20;
Werner Lemberge1ca18d2015-10-17 11:51:27 +02001299 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG17, p->cnt ));
1300 }
1301
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001302 /* Make sure the number of glyphs is non-zero. */
1303 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001304 font->glyphs_size = 64;
1305
Werner Lemberga08b2172007-03-28 07:17:17 +00001306 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1307 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001308 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001309 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001310 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001311 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001312 goto Exit;
1313 }
1314
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001315 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1316 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001317
Werner Lemberg758587d2016-01-12 22:20:06 +01001318 p->flags |= BDF_GLYPHS_;
David Turner993a8d02002-05-18 12:03:43 +00001319
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001320 goto Exit;
1321 }
1322
1323 /* Check for the ENDFONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001324 if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001325 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001326 if ( p->flags & BDF_GLYPH_BITS_ )
Werner Lembergaf834612014-11-22 13:29:10 +01001327 {
1328 /* Missing ENDCHAR field. */
1329 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1330 error = FT_THROW( Corrupted_Font_Glyphs );
1331 goto Exit;
1332 }
1333
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001334 /* Sort the glyphs by encoding. */
1335 ft_qsort( (char *)font->glyphs,
1336 font->glyphs_used,
1337 sizeof ( bdf_glyph_t ),
1338 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001339
Werner Lemberg758587d2016-01-12 22:20:06 +01001340 p->flags &= ~BDF_START_;
David Turner993a8d02002-05-18 12:03:43 +00001341
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001342 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001343 }
1344
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001345 /* Check for the ENDCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001346 if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001347 {
1348 p->glyph_enc = 0;
Werner Lemberg758587d2016-01-12 22:20:06 +01001349 p->flags &= ~BDF_GLYPH_BITS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001350
1351 goto Exit;
1352 }
1353
Werner Lemberg96ddc672011-06-29 09:15:54 +02001354 /* Check whether a glyph is being scanned but should be */
1355 /* ignored because it is an unencoded glyph. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001356 if ( ( p->flags & BDF_GLYPH_ ) &&
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001357 p->glyph_enc == -1 &&
1358 p->opts->keep_unencoded == 0 )
1359 goto Exit;
1360
1361 /* Check for the STARTCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001362 if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001363 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001364 if ( p->flags & BDF_GLYPH_BITS_ )
Werner Lembergb1857472015-10-17 14:21:41 +02001365 {
1366 /* Missing ENDCHAR field. */
1367 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1368 error = FT_THROW( Missing_Startchar_Field );
1369 goto Exit;
1370 }
1371
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001372 /* Set the character name in the parse info first until the */
1373 /* encoding can be checked for an unencoded character. */
1374 FT_FREE( p->glyph_name );
1375
David Turner68df4f72005-03-15 18:18:57 +00001376 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001377 if ( error )
1378 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001379
David Turner68df4f72005-03-15 18:18:57 +00001380 _bdf_list_shift( &p->list, 1 );
1381
1382 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001383
Werner Lembergba03af62007-05-30 13:57:02 +00001384 if ( !s )
1385 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001386 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001387 error = FT_THROW( Invalid_File_Format );
Werner Lembergba03af62007-05-30 13:57:02 +00001388 goto Exit;
1389 }
1390
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001391 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1392 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001393
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001394 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1395
Werner Lemberg758587d2016-01-12 22:20:06 +01001396 p->flags |= BDF_GLYPH_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001397
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001398 FT_TRACE4(( DBGMSG1, lineno, s ));
1399
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001400 goto Exit;
1401 }
1402
1403 /* Check for the ENCODING field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001404 if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001405 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001406 if ( !( p->flags & BDF_GLYPH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001407 {
1408 /* Missing STARTCHAR field. */
1409 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001410 error = FT_THROW( Missing_Startchar_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001411 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001412 }
1413
David Turner68df4f72005-03-15 18:18:57 +00001414 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001415 if ( error )
1416 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001417
Ben Wagnera512b0f2015-12-14 09:19:52 +01001418 p->glyph_enc = _bdf_atol( p->list.field[1] );
David Turner993a8d02002-05-18 12:03:43 +00001419
Werner Lemberg28dd2c42012-02-26 06:18:58 +01001420 /* Normalize negative encoding values. The specification only */
1421 /* allows -1, but we can be more generous here. */
1422 if ( p->glyph_enc < -1 )
1423 p->glyph_enc = -1;
1424
Werner Lemberg03242f52012-02-26 06:52:56 +01001425 /* Check for alternative encoding format. */
1426 if ( p->glyph_enc == -1 && p->list.used > 2 )
Ben Wagnera512b0f2015-12-14 09:19:52 +01001427 p->glyph_enc = _bdf_atol( p->list.field[2] );
Werner Lemberg03242f52012-02-26 06:52:56 +01001428
Werner Lemberg7f2e4f42012-12-15 09:39:41 +01001429 if ( p->glyph_enc < -1 )
1430 p->glyph_enc = -1;
1431
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001432 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1433
Werner Lemberged54e432011-11-27 16:39:53 +01001434 /* Check that the encoding is in the Unicode range because */
1435 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lemberg07bdb6e2012-12-15 02:02:23 +01001436 if ( p->glyph_enc > 0 &&
1437 (size_t)p->glyph_enc >= sizeof ( p->have ) /
1438 sizeof ( unsigned long ) * 32 )
David Turner481838e2006-02-23 12:40:14 +00001439 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001440 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001441 error = FT_THROW( Invalid_File_Format );
David Turner481838e2006-02-23 12:40:14 +00001442 goto Exit;
1443 }
1444
Werner Lemberg96ddc672011-06-29 09:15:54 +02001445 /* Check whether this encoding has already been encountered. */
1446 /* If it has then change it to unencoded so it gets added if */
1447 /* indicated. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001448 if ( p->glyph_enc >= 0 )
1449 {
1450 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1451 {
1452 /* Emit a message saying a glyph has been moved to the */
1453 /* unencoded area. */
1454 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1455 p->glyph_enc, p->glyph_name ));
1456 p->glyph_enc = -1;
1457 font->modified = 1;
1458 }
1459 else
1460 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1461 }
1462
1463 if ( p->glyph_enc >= 0 )
1464 {
1465 /* Make sure there are enough glyphs allocated in case the */
1466 /* number of characters happen to be wrong. */
1467 if ( font->glyphs_used == font->glyphs_size )
1468 {
1469 if ( FT_RENEW_ARRAY( font->glyphs,
1470 font->glyphs_size,
1471 font->glyphs_size + 64 ) )
1472 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001473
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001474 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001475 }
1476
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001477 glyph = font->glyphs + font->glyphs_used++;
1478 glyph->name = p->glyph_name;
1479 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001480
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001481 /* Reset the initial glyph info. */
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001482 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001483 }
1484 else
1485 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001486 /* Unencoded glyph. Check whether it should */
1487 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001488 if ( p->opts->keep_unencoded != 0 )
1489 {
1490 /* Allocate the next unencoded glyph. */
1491 if ( font->unencoded_used == font->unencoded_size )
1492 {
David Turner68df4f72005-03-15 18:18:57 +00001493 if ( FT_RENEW_ARRAY( font->unencoded ,
1494 font->unencoded_size,
1495 font->unencoded_size + 4 ) )
1496 goto Exit;
1497
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001498 font->unencoded_size += 4;
1499 }
1500
1501 glyph = font->unencoded + font->unencoded_used;
1502 glyph->name = p->glyph_name;
Werner Lemberg3c374c82015-02-22 09:16:53 +01001503 glyph->encoding = (long)font->unencoded_used++;
Werner Lemberg4a150132015-11-25 07:53:49 +01001504
1505 /* Reset the initial glyph info. */
1506 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001507 }
1508 else
Werner Lemberg94cacac2015-11-15 04:45:42 +01001509 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001510 /* Free up the glyph name if the unencoded shouldn't be */
1511 /* kept. */
1512 FT_FREE( p->glyph_name );
Werner Lemberg94cacac2015-11-15 04:45:42 +01001513 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001514
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001515 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001516 }
1517
1518 /* Clear the flags that might be added when width and height are */
1519 /* checked for consistency. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001520 p->flags &= ~( BDF_GLYPH_WIDTH_CHECK_ | BDF_GLYPH_HEIGHT_CHECK_ );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001521
Werner Lemberg758587d2016-01-12 22:20:06 +01001522 p->flags |= BDF_ENCODING_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001523
1524 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001525 }
1526
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001527 /* Point at the glyph being constructed. */
1528 if ( p->glyph_enc == -1 )
1529 glyph = font->unencoded + ( font->unencoded_used - 1 );
1530 else
1531 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001532
Werner Lemberg96ddc672011-06-29 09:15:54 +02001533 /* Check whether a bitmap is being constructed. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001534 if ( p->flags & BDF_BITMAP_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001535 {
1536 /* If there are more rows than are specified in the glyph metrics, */
1537 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001538 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001539 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001540 if ( !( p->flags & BDF_GLYPH_HEIGHT_CHECK_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001541 {
1542 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001543 p->flags |= BDF_GLYPH_HEIGHT_CHECK_;
David Turner993a8d02002-05-18 12:03:43 +00001544 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001545 }
1546
1547 goto Exit;
1548 }
1549
1550 /* Only collect the number of nibbles indicated by the glyph */
1551 /* metrics. If there are more columns, they are simply ignored. */
1552 nibbles = glyph->bpr << 1;
1553 bp = glyph->bitmap + p->row * glyph->bpr;
1554
David Turnerb698eed2006-02-23 14:50:13 +00001555 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001556 {
1557 c = line[i];
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001558 if ( !sbitset( hdigits, c ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001559 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001560 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001561 if ( i + 1 < nibbles && ( i & 1 ) )
1562 *++bp = 0;
1563 }
1564
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001565 /* If any line has not enough columns, */
1566 /* indicate they have been padded with zero bits. */
1567 if ( i < nibbles &&
Werner Lemberg758587d2016-01-12 22:20:06 +01001568 !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001569 {
1570 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001571 p->flags |= BDF_GLYPH_WIDTH_CHECK_;
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001572 font->modified = 1;
1573 }
1574
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001575 /* Remove possible garbage at the right. */
1576 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001577 if ( glyph->bbx.width )
1578 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001579
1580 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001581 if ( i == nibbles &&
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001582 sbitset( hdigits, line[nibbles] ) &&
Werner Lemberg758587d2016-01-12 22:20:06 +01001583 !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001584 {
1585 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001586 p->flags |= BDF_GLYPH_WIDTH_CHECK_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001587 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001588 }
1589
1590 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001591 goto Exit;
1592 }
David Turner993a8d02002-05-18 12:03:43 +00001593
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001594 /* Expect the SWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001595 if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001596 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001597 if ( !( p->flags & BDF_ENCODING_ ) )
Werner Lemberg4086fb72012-03-01 08:55:40 +01001598 goto Missing_Encoding;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001599
David Turner68df4f72005-03-15 18:18:57 +00001600 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001601 if ( error )
1602 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001603
Ben Wagnera512b0f2015-12-14 09:19:52 +01001604 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1] );
Werner Lemberg758587d2016-01-12 22:20:06 +01001605 p->flags |= BDF_SWIDTH_;
David Turner993a8d02002-05-18 12:03:43 +00001606
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001607 goto Exit;
1608 }
David Turner993a8d02002-05-18 12:03:43 +00001609
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001610 /* Expect the DWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001611 if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001612 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001613 if ( !( p->flags & BDF_ENCODING_ ) )
Werner Lemberg4086fb72012-03-01 08:55:40 +01001614 goto Missing_Encoding;
1615
David Turner68df4f72005-03-15 18:18:57 +00001616 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001617 if ( error )
1618 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001619
Ben Wagnera512b0f2015-12-14 09:19:52 +01001620 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001621
Werner Lemberg758587d2016-01-12 22:20:06 +01001622 if ( !( p->flags & BDF_SWIDTH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001623 {
1624 /* Missing SWIDTH field. Emit an auto correction message and set */
1625 /* the scalable width from the device width. */
1626 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1627
Werner Lemberg02d4d592002-05-28 22:38:05 +00001628 glyph->swidth = (unsigned short)FT_MulDiv(
1629 glyph->dwidth, 72000L,
1630 (FT_Long)( font->point_size *
1631 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001632 }
1633
Werner Lemberg758587d2016-01-12 22:20:06 +01001634 p->flags |= BDF_DWIDTH_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001635 goto Exit;
1636 }
David Turner993a8d02002-05-18 12:03:43 +00001637
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001638 /* Expect the BBX field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001639 if ( _bdf_strncmp( line, "BBX", 3 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001640 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001641 if ( !( p->flags & BDF_ENCODING_ ) )
Werner Lemberg4086fb72012-03-01 08:55:40 +01001642 goto Missing_Encoding;
1643
David Turner68df4f72005-03-15 18:18:57 +00001644 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001645 if ( error )
1646 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001647
Ben Wagnera512b0f2015-12-14 09:19:52 +01001648 glyph->bbx.width = _bdf_atous( p->list.field[1] );
1649 glyph->bbx.height = _bdf_atous( p->list.field[2] );
1650 glyph->bbx.x_offset = _bdf_atos( p->list.field[3] );
1651 glyph->bbx.y_offset = _bdf_atos( p->list.field[4] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001652
1653 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001654 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1655 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001656
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001657 /* Determine the overall font bounding box as the characters are */
1658 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001659 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1660 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001661
David Turnerb1b47622002-05-21 21:17:43 +00001662 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001663
Werner Lembergdfa46192004-03-05 09:26:24 +00001664 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1665 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1666 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001667
Werner Lemberg758587d2016-01-12 22:20:06 +01001668 if ( !( p->flags & BDF_DWIDTH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001669 {
1670 /* Missing DWIDTH field. Emit an auto correction message and set */
1671 /* the device width to the glyph width. */
1672 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1673 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001674 }
1675
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001676 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1677 /* value if necessary. */
1678 if ( p->opts->correct_metrics != 0 )
1679 {
1680 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001681 unsigned short sw = (unsigned short)FT_MulDiv(
1682 glyph->dwidth, 72000L,
1683 (FT_Long)( font->point_size *
1684 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001685
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001686
1687 if ( sw != glyph->swidth )
1688 {
1689 glyph->swidth = sw;
1690
1691 if ( p->glyph_enc == -1 )
1692 _bdf_set_glyph_modified( font->umod,
1693 font->unencoded_used - 1 );
1694 else
1695 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1696
Werner Lemberg758587d2016-01-12 22:20:06 +01001697 p->flags |= BDF_SWIDTH_ADJ_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001698 font->modified = 1;
1699 }
David Turner993a8d02002-05-18 12:03:43 +00001700 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001701
Werner Lemberg758587d2016-01-12 22:20:06 +01001702 p->flags |= BDF_BBX_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001703 goto Exit;
1704 }
David Turner993a8d02002-05-18 12:03:43 +00001705
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001706 /* And finally, gather up the bitmap. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001707 if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001708 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001709 unsigned long bitmap_size;
1710
1711
Werner Lemberg758587d2016-01-12 22:20:06 +01001712 if ( !( p->flags & BDF_BBX_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001713 {
1714 /* Missing BBX field. */
1715 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001716 error = FT_THROW( Missing_Bbx_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001717 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001718 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001719
1720 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001721 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001722
1723 bitmap_size = glyph->bpr * glyph->bbx.height;
Werner Lembergc4cad302012-03-08 20:11:37 +01001724 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
Werner Lemberg26170df2006-03-26 07:19:07 +00001725 {
1726 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001727 error = FT_THROW( Bbx_Too_Big );
Werner Lemberg26170df2006-03-26 07:19:07 +00001728 goto Exit;
1729 }
1730 else
1731 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001732
1733 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1734 goto Exit;
1735
1736 p->row = 0;
Werner Lemberg758587d2016-01-12 22:20:06 +01001737 p->flags |= BDF_BITMAP_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001738
1739 goto Exit;
1740 }
1741
Werner Lemberge01406b2011-11-25 09:44:28 +01001742 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001743 error = FT_THROW( Invalid_File_Format );
Werner Lemberg4086fb72012-03-01 08:55:40 +01001744 goto Exit;
1745
1746 Missing_Encoding:
1747 /* Missing ENCODING field. */
1748 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001749 error = FT_THROW( Missing_Encoding_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001750
1751 Exit:
Werner Lemberg758587d2016-01-12 22:20:06 +01001752 if ( error && ( p->flags & BDF_GLYPH_ ) )
Werner Lembergf4c94d42010-06-19 16:08:31 +02001753 FT_FREE( p->glyph_name );
1754
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001755 return error;
David Turner993a8d02002-05-18 12:03:43 +00001756 }
1757
David Turner993a8d02002-05-18 12:03:43 +00001758
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001759 /* Load the font properties. */
1760 static FT_Error
1761 _bdf_parse_properties( char* line,
1762 unsigned long linelen,
1763 unsigned long lineno,
1764 void* call_data,
1765 void* client_data )
1766 {
1767 unsigned long vlen;
1768 _bdf_line_func_t* next;
1769 _bdf_parse_t* p;
1770 char* name;
1771 char* value;
1772 char nbuf[128];
Werner Lemberge3c93012013-03-14 11:21:17 +01001773 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001774
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001775 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001776
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001777
1778 next = (_bdf_line_func_t *)call_data;
1779 p = (_bdf_parse_t *) client_data;
1780
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001781 /* Check for the end of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001782 if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001783 {
1784 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1785 /* encountered yet, then make sure they are added as properties and */
1786 /* make sure they are set from the font bounding box info. */
1787 /* */
1788 /* This is *always* done regardless of the options, because X11 */
1789 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001790 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001791 {
1792 p->font->font_ascent = p->font->bbx.ascent;
1793 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001794 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
1795 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001796 if ( error )
1797 goto Exit;
1798
1799 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1800 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001801 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001802
Werner Lemberg428c2e42003-04-25 05:35:04 +00001803 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001804 {
1805 p->font->font_descent = p->font->bbx.descent;
1806 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001807 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
1808 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001809 if ( error )
1810 goto Exit;
1811
1812 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1813 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001814 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001815
Werner Lemberg758587d2016-01-12 22:20:06 +01001816 p->flags &= ~BDF_PROPS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001817 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001818
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001819 goto Exit;
1820 }
David Turner993a8d02002-05-18 12:03:43 +00001821
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001822 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001823 if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001824 goto Exit;
1825
1826 /* Handle COMMENT fields and properties in a special way to preserve */
1827 /* the spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001828 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001829 {
David Turner993a8d02002-05-18 12:03:43 +00001830 name = value = line;
1831 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001832 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001833 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01001834 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001835 if ( error )
1836 goto Exit;
1837 }
1838 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1839 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001840 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001841 if ( error )
1842 goto Exit;
1843 }
1844 else
1845 {
David Turner68df4f72005-03-15 18:18:57 +00001846 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001847 if ( error )
1848 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001849 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001850
David Turner68df4f72005-03-15 18:18:57 +00001851 _bdf_list_shift( &p->list, 1 );
1852 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001853
Werner Lemberge01406b2011-11-25 09:44:28 +01001854 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001855 if ( error )
1856 goto Exit;
1857 }
1858
1859 Exit:
1860 return error;
David Turner993a8d02002-05-18 12:03:43 +00001861 }
1862
David Turner993a8d02002-05-18 12:03:43 +00001863
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001864 /* Load the font header. */
1865 static FT_Error
1866 _bdf_parse_start( char* line,
1867 unsigned long linelen,
1868 unsigned long lineno,
1869 void* call_data,
1870 void* client_data )
1871 {
1872 unsigned long slen;
1873 _bdf_line_func_t* next;
1874 _bdf_parse_t* p;
1875 bdf_font_t* font;
1876 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001877
David Turnerd490e372002-05-28 23:40:37 +00001878 FT_Memory memory = NULL;
Werner Lemberge3c93012013-03-14 11:21:17 +01001879 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001880
1881 FT_UNUSED( lineno ); /* only used in debug mode */
1882
1883
1884 next = (_bdf_line_func_t *)call_data;
1885 p = (_bdf_parse_t *) client_data;
1886
1887 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00001888 memory = p->font->memory;
1889
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001890 /* Check for a comment. This is done to handle those fonts that have */
1891 /* comments before the STARTFONT line for some reason. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001892 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001893 {
1894 if ( p->opts->keep_comments != 0 && p->font != 0 )
1895 {
1896 linelen -= 7;
1897
1898 s = line + 7;
1899 if ( *s != 0 )
1900 {
1901 s++;
1902 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00001903 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001904
1905 error = _bdf_add_comment( p->font, s, linelen );
1906 if ( error )
1907 goto Exit;
1908 /* here font is not defined! */
1909 }
1910
1911 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001912 }
1913
Werner Lemberg758587d2016-01-12 22:20:06 +01001914 if ( !( p->flags & BDF_START_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001915 {
1916 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00001917
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001918 if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001919 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01001920 /* we don't emit an error message since this code gets */
1921 /* explicitly caught one level higher */
Werner Lemberg059bc332013-03-14 10:27:35 +01001922 error = FT_THROW( Missing_Startfont_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001923 goto Exit;
1924 }
David Turner993a8d02002-05-18 12:03:43 +00001925
Werner Lemberg758587d2016-01-12 22:20:06 +01001926 p->flags = BDF_START_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001927 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00001928
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001929 if ( FT_NEW( font ) )
1930 goto Exit;
1931 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00001932
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001933 font->memory = p->memory;
1934 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00001935
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001936 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001937 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001938 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00001939
David Turner993a8d02002-05-18 12:03:43 +00001940
Werner Lemberg7ce6c432015-12-22 05:39:58 +01001941 error = ft_hash_str_init( &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001942 if ( error )
1943 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00001944 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001945 i < _num_bdf_properties; i++, prop++ )
1946 {
Werner Lemberg609546c2015-12-20 07:17:29 +01001947 error = ft_hash_str_insert( prop->name, i,
1948 &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001949 if ( error )
1950 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001951 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001952 }
1953
Werner Lemberg31343562015-12-19 17:02:13 +01001954 if ( FT_ALLOC( p->font->internal, sizeof ( FT_HashRec ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001955 goto Exit;
Werner Lemberg7ce6c432015-12-22 05:39:58 +01001956 error = ft_hash_str_init( (FT_Hash)p->font->internal, memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001957 if ( error )
1958 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00001959 p->font->spacing = p->opts->font_spacing;
1960 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001961
1962 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001963 }
1964
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001965 /* Check for the start of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001966 if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001967 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001968 if ( !( p->flags & BDF_FONT_BBX_ ) )
Werner Lembergfb690292010-06-23 10:00:52 +02001969 {
1970 /* Missing the FONTBOUNDINGBOX field. */
1971 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001972 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergfb690292010-06-23 10:00:52 +02001973 goto Exit;
1974 }
1975
David Turner68df4f72005-03-15 18:18:57 +00001976 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001977 if ( error )
1978 goto Exit;
Werner Lembergb6b26f42016-06-09 06:53:48 +02001979
Werner Lembergb66efef2009-03-12 08:07:49 +00001980 /* at this point, `p->font' can't be NULL */
Ben Wagnera512b0f2015-12-14 09:19:52 +01001981 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1] );
Werner Lembergb6b26f42016-06-09 06:53:48 +02001982 /* We need at least 4 bytes per property. */
1983 if ( p->cnt > p->size / 4 )
1984 {
1985 p->font->props_size = 0;
1986
1987 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "STARTPROPERTIES" ));
1988 error = FT_THROW( Invalid_Argument );
1989 goto Exit;
1990 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001991
1992 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
Werner Lemberg9b6b5752012-12-15 01:34:41 +01001993 {
1994 p->font->props_size = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001995 goto Exit;
Werner Lemberg9b6b5752012-12-15 01:34:41 +01001996 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001997
Werner Lemberg758587d2016-01-12 22:20:06 +01001998 p->flags |= BDF_PROPS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001999 *next = _bdf_parse_properties;
2000
2001 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002002 }
2003
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002004 /* Check for the FONTBOUNDINGBOX field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002005 if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002006 {
Werner Lemberg758587d2016-01-12 22:20:06 +01002007 if ( !( p->flags & BDF_SIZE_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002008 {
2009 /* Missing the SIZE field. */
2010 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002011 error = FT_THROW( Missing_Size_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002012 goto Exit;
2013 }
2014
David Turner68df4f72005-03-15 18:18:57 +00002015 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002016 if ( error )
2017 goto Exit;
2018
Ben Wagnera512b0f2015-12-14 09:19:52 +01002019 p->font->bbx.width = _bdf_atous( p->list.field[1] );
2020 p->font->bbx.height = _bdf_atous( p->list.field[2] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002021
Ben Wagnera512b0f2015-12-14 09:19:52 +01002022 p->font->bbx.x_offset = _bdf_atos( p->list.field[3] );
2023 p->font->bbx.y_offset = _bdf_atos( p->list.field[4] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002024
David Turnerd490e372002-05-28 23:40:37 +00002025 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002026 p->font->bbx.y_offset );
2027
2028 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002029
Werner Lemberg758587d2016-01-12 22:20:06 +01002030 p->flags |= BDF_FONT_BBX_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002031
2032 goto Exit;
2033 }
2034
2035 /* The next thing to check for is the FONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002036 if ( _bdf_strncmp( line, "FONT", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002037 {
David Turner68df4f72005-03-15 18:18:57 +00002038 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002039 if ( error )
2040 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002041 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002042
David Turner68df4f72005-03-15 18:18:57 +00002043 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002044
2045 if ( !s )
2046 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002047 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002048 error = FT_THROW( Invalid_File_Format );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002049 goto Exit;
2050 }
2051
Werner Lembergfb690292010-06-23 10:00:52 +02002052 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2053 FT_FREE( p->font->name );
2054
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002055 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2056 goto Exit;
2057 FT_MEM_COPY( p->font->name, s, slen + 1 );
2058
2059 /* If the font name is an XLFD name, set the spacing to the one in */
2060 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002061 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002062 if ( error )
2063 goto Exit;
2064
Werner Lemberg758587d2016-01-12 22:20:06 +01002065 p->flags |= BDF_FONT_NAME_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002066
2067 goto Exit;
2068 }
2069
2070 /* Check for the SIZE field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002071 if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002072 {
Werner Lemberg758587d2016-01-12 22:20:06 +01002073 if ( !( p->flags & BDF_FONT_NAME_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002074 {
2075 /* Missing the FONT field. */
2076 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002077 error = FT_THROW( Missing_Font_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002078 goto Exit;
2079 }
2080
David Turner68df4f72005-03-15 18:18:57 +00002081 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002082 if ( error )
2083 goto Exit;
2084
Ben Wagnera512b0f2015-12-14 09:19:52 +01002085 p->font->point_size = _bdf_atoul( p->list.field[1] );
2086 p->font->resolution_x = _bdf_atoul( p->list.field[2] );
2087 p->font->resolution_y = _bdf_atoul( p->list.field[3] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002088
2089 /* Check for the bits per pixel field. */
2090 if ( p->list.used == 5 )
2091 {
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002092 unsigned short bpp;
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002093
2094
Ben Wagnera512b0f2015-12-14 09:19:52 +01002095 bpp = (unsigned short)_bdf_atos( p->list.field[4] );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002096
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002097 /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
2098 if ( bpp > 4 )
2099 p->font->bpp = 8;
2100 else if ( bpp > 2 )
2101 p->font->bpp = 4;
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002102 else if ( bpp > 1 )
2103 p->font->bpp = 2;
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002104 else
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002105 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002106
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002107 if ( p->font->bpp != bpp )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002108 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002109 }
2110 else
2111 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002112
Werner Lemberg758587d2016-01-12 22:20:06 +01002113 p->flags |= BDF_SIZE_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002114
2115 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002116 }
2117
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002118 /* Check for the CHARS field -- font properties are optional */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002119 if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002120 {
2121 char nbuf[128];
2122
2123
Werner Lemberg758587d2016-01-12 22:20:06 +01002124 if ( !( p->flags & BDF_FONT_BBX_ ) )
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002125 {
2126 /* Missing the FONTBOUNDINGBOX field. */
2127 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002128 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002129 goto Exit;
2130 }
2131
2132 /* Add the two standard X11 properties which are required */
2133 /* for compiling fonts. */
2134 p->font->font_ascent = p->font->bbx.ascent;
2135 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002136 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2137 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002138 if ( error )
2139 goto Exit;
2140 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2141
2142 p->font->font_descent = p->font->bbx.descent;
2143 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002144 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2145 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002146 if ( error )
2147 goto Exit;
2148 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2149
2150 p->font->modified = 1;
2151
2152 *next = _bdf_parse_glyphs;
2153
2154 /* A special return value. */
2155 error = -1;
2156 goto Exit;
2157 }
2158
Werner Lemberge01406b2011-11-25 09:44:28 +01002159 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002160 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002161
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002162 Exit:
2163 return error;
2164 }
David Turner993a8d02002-05-18 12:03:43 +00002165
2166
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002167 /*************************************************************************/
2168 /* */
2169 /* API. */
2170 /* */
2171 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002172
David Turner993a8d02002-05-18 12:03:43 +00002173
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002174 FT_LOCAL_DEF( FT_Error )
2175 bdf_load_font( FT_Stream stream,
2176 FT_Memory extmemory,
2177 bdf_options_t* opts,
2178 bdf_font_t* *font )
2179 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002180 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002181 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002182
Sean McBride7be2a942014-02-08 13:55:38 +01002183 FT_Memory memory = extmemory; /* needed for FT_NEW */
2184 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002185
2186
David Turner68df4f72005-03-15 18:18:57 +00002187 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002188 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002189
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002190 memory = NULL;
2191 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2192 p->minlb = 32767;
Werner Lemberge1ca18d2015-10-17 11:51:27 +02002193 p->size = stream->size;
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002194 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002195
David Turner68df4f72005-03-15 18:18:57 +00002196 _bdf_list_init( &p->list, extmemory );
2197
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002198 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002199 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002200 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002201 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002202
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002203 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002204 {
2205 /* If the font is not proportional, set the font's monowidth */
2206 /* field to the width of the font bounding box. */
David Turner993a8d02002-05-18 12:03:43 +00002207
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002208 if ( p->font->spacing != BDF_PROPORTIONAL )
2209 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002210
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002211 /* If the number of glyphs loaded is not that of the original count, */
2212 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002213 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002214 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002215 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2216 p->font->glyphs_used + p->font->unencoded_used ));
2217 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002218 }
2219
2220 /* Once the font has been loaded, adjust the overall font metrics if */
2221 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002222 if ( p->opts->correct_metrics != 0 &&
2223 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002224 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002225 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002226 {
2227 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002228 p->font->bbx.width, p->maxrb - p->minlb ));
2229 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2230 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002231 }
2232
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002233 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002234 {
2235 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002236 p->font->bbx.x_offset, p->minlb ));
2237 p->font->bbx.x_offset = p->minlb;
2238 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002239 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002240
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002241 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002242 {
2243 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002244 p->font->bbx.ascent, p->maxas ));
2245 p->font->bbx.ascent = p->maxas;
2246 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002247 }
2248
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002249 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002250 {
2251 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002252 p->font->bbx.descent, p->maxds ));
2253 p->font->bbx.descent = p->maxds;
2254 p->font->bbx.y_offset = (short)( -p->maxds );
2255 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002256 }
2257
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002258 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002259 {
2260 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002261 p->font->bbx.height, p->maxas + p->maxds ));
2262 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002263 }
2264
Werner Lemberg758587d2016-01-12 22:20:06 +01002265 if ( p->flags & BDF_SWIDTH_ADJ_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002266 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2267 }
David Turner993a8d02002-05-18 12:03:43 +00002268 }
2269
Werner Lemberg758587d2016-01-12 22:20:06 +01002270 if ( p->flags & BDF_START_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002271 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002272 /* The ENDFONT field was never reached or did not exist. */
Werner Lemberg758587d2016-01-12 22:20:06 +01002273 if ( !( p->flags & BDF_GLYPHS_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002274 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002275 /* Error happened while parsing header. */
2276 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002277 error = FT_THROW( Corrupted_Font_Header );
Bungeman65d89802015-10-15 23:50:16 +02002278 goto Fail;
Werner Lemberge01406b2011-11-25 09:44:28 +01002279 }
2280 else
2281 {
2282 /* Error happened when parsing glyphs. */
2283 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002284 error = FT_THROW( Corrupted_Font_Glyphs );
Bungeman65d89802015-10-15 23:50:16 +02002285 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002286 }
David Turner993a8d02002-05-18 12:03:43 +00002287 }
2288
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002289 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002290 {
2291 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002292 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002293
Werner Lemberg370aea82010-06-08 08:37:11 +02002294 if ( p->font->comments_len > 0 )
2295 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002296 if ( FT_RENEW_ARRAY( p->font->comments,
2297 p->font->comments_len,
2298 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002299 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002300
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002301 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002302 }
David Turner993a8d02002-05-18 12:03:43 +00002303 }
Werner Lemberg5d664b62016-12-17 20:47:42 +01002304 else if ( !error )
Werner Lemberg059bc332013-03-14 10:27:35 +01002305 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002306
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002307 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002308
2309 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002310 if ( p )
2311 {
David Turner68df4f72005-03-15 18:18:57 +00002312 _bdf_list_done( &p->list );
2313
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002314 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002315
Werner Lemberg4a150132015-11-25 07:53:49 +01002316 FT_FREE( p->glyph_name );
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002317 FT_FREE( p );
2318 }
2319
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002320 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002321
2322 Fail:
2323 bdf_free_font( p->font );
2324
2325 memory = extmemory;
2326
2327 FT_FREE( p->font );
2328
2329 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002330 }
David Turner993a8d02002-05-18 12:03:43 +00002331
2332
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002333 FT_LOCAL_DEF( void )
2334 bdf_free_font( bdf_font_t* font )
2335 {
2336 bdf_property_t* prop;
2337 unsigned long i;
2338 bdf_glyph_t* glyphs;
2339 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002340
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002341
2342 if ( font == 0 )
2343 return;
David Turner993a8d02002-05-18 12:03:43 +00002344
2345 memory = font->memory;
2346
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002347 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002348
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002349 /* Free up the internal hash table of property names. */
2350 if ( font->internal )
2351 {
Werner Lemberg7ce6c432015-12-22 05:39:58 +01002352 ft_hash_str_free( (FT_Hash)font->internal, memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002353 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002354 }
2355
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002356 /* Free up the comment info. */
2357 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002358
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002359 /* Free up the properties. */
2360 for ( i = 0; i < font->props_size; i++ )
2361 {
2362 if ( font->props[i].format == BDF_ATOM )
2363 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002364 }
2365
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002366 FT_FREE( font->props );
2367
2368 /* Free up the character info. */
2369 for ( i = 0, glyphs = font->glyphs;
2370 i < font->glyphs_used; i++, glyphs++ )
2371 {
2372 FT_FREE( glyphs->name );
2373 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002374 }
2375
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002376 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2377 i++, glyphs++ )
2378 {
2379 FT_FREE( glyphs->name );
2380 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002381 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002382
2383 FT_FREE( font->glyphs );
2384 FT_FREE( font->unencoded );
2385
2386 /* Free up the overflow storage if it was used. */
2387 for ( i = 0, glyphs = font->overflow.glyphs;
2388 i < font->overflow.glyphs_used; i++, glyphs++ )
2389 {
2390 FT_FREE( glyphs->name );
2391 FT_FREE( glyphs->bitmap );
2392 }
2393
2394 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002395
2396 /* bdf_cleanup */
Werner Lemberg7ce6c432015-12-22 05:39:58 +01002397 ft_hash_str_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002398
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002399 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002400 for ( prop = font->user_props, i = 0;
2401 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002402 {
2403 FT_FREE( prop->name );
2404 if ( prop->format == BDF_ATOM )
2405 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002406 }
David Turner993a8d02002-05-18 12:03:43 +00002407
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002408 FT_FREE( font->user_props );
2409
2410 /* FREE( font ); */ /* XXX Fixme */
2411 }
David Turner993a8d02002-05-18 12:03:43 +00002412
2413
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002414 FT_LOCAL_DEF( bdf_property_t * )
2415 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002416 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002417 {
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002418 size_t* propid;
David Turner993a8d02002-05-18 12:03:43 +00002419
David Turner993a8d02002-05-18 12:03:43 +00002420
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002421 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002422 return 0;
2423
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002424 propid = ft_hash_str_lookup( name, (FT_Hash)font->internal );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002425
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002426 return propid ? ( font->props + *propid ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002427 }
2428
2429
2430/* END */