blob: 95ab17151dab3275ea14852c457ce66b57dda710 [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 Lemberg9ac90602018-06-03 09:01:17 +020025 /**************************************************************************
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 */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000032
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 Lemberg9ac90602018-06-03 09:01:17 +020045 /**************************************************************************
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 */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000051#undef FT_COMPONENT
Werner Lemberga0dd16f2018-08-15 18:13:17 +020052#define FT_COMPONENT bdflib
David Turner993a8d02002-05-18 12:03:43 +000053
David Turner993a8d02002-05-18 12:03:43 +000054
Werner Lemberg9ac90602018-06-03 09:01:17 +020055 /**************************************************************************
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 Lemberg9ac90602018-06-03 09:01:17 +020071 /**************************************************************************
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"
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -0400199#define ACMSG13 "Glyph %lu extra rows removed.\n"
200#define ACMSG14 "Glyph %lu extra columns removed.\n"
Werner Lemberge01406b2011-11-25 09:44:28 +0100201#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -0400202#define ACMSG16 "Glyph %lu missing columns padded with zero bits.\n"
Werner Lemberge1ca18d2015-10-17 11:51:27 +0200203#define ACMSG17 "Adjusting number of glyphs to %ld.\n"
Werner Lemberge01406b2011-11-25 09:44:28 +0100204
205 /* Error messages. */
206#define ERRMSG1 "[line %ld] Missing `%s' line.\n"
207#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
208#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
209#define ERRMSG4 "[line %ld] BBX too big.\n"
Werner Lemberge01406b2011-11-25 09:44:28 +0100210#define ERRMSG6 "[line %ld] Input line too long.\n"
211#define ERRMSG7 "[line %ld] Font name too long.\n"
212#define ERRMSG8 "[line %ld] Invalid `%s' value.\n"
213#define ERRMSG9 "[line %ld] Invalid keyword.\n"
214
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +0100215 /* Debug messages. */
216#define DBGMSG1 " [%6ld] %s" /* no \n */
217#define DBGMSG2 " (0x%lX)\n"
218
Werner Lemberge01406b2011-11-25 09:44:28 +0100219
Werner Lemberg9ac90602018-06-03 09:01:17 +0200220 /**************************************************************************
221 *
222 * Utility types and functions.
223 *
224 */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000225
226
227 /* Function type for parsing lines of a BDF font. */
228
229 typedef FT_Error
230 (*_bdf_line_func_t)( char* line,
231 unsigned long linelen,
232 unsigned long lineno,
233 void* call_data,
234 void* client_data );
235
236
237 /* List structure for splitting lines into fields. */
238
239 typedef struct _bdf_list_t_
240 {
241 char** field;
242 unsigned long size;
243 unsigned long used;
David Turner68df4f72005-03-15 18:18:57 +0000244 FT_Memory memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000245
246 } _bdf_list_t;
247
248
249 /* Structure used while loading BDF fonts. */
250
251 typedef struct _bdf_parse_t_
252 {
253 unsigned long flags;
254 unsigned long cnt;
255 unsigned long row;
256
257 short minlb;
258 short maxlb;
259 short maxrb;
260 short maxas;
261 short maxds;
262
263 short rbearing;
264
265 char* glyph_name;
266 long glyph_enc;
267
268 bdf_font_t* font;
269 bdf_options_t* opts;
270
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000271 _bdf_list_t list;
272
273 FT_Memory memory;
Werner Lemberge1ca18d2015-10-17 11:51:27 +0200274 unsigned long size; /* the stream size */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000275
276 } _bdf_parse_t;
277
278
Werner Lemberga08b2172007-03-28 07:17:17 +0000279#define setsbit( m, cc ) \
280 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
281#define sbitset( m, cc ) \
282 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000283
284
David Turner68df4f72005-03-15 18:18:57 +0000285 static void
286 _bdf_list_init( _bdf_list_t* list,
287 FT_Memory memory )
288 {
Werner Lembergebf55852005-03-16 01:49:54 +0000289 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000290 list->memory = memory;
291 }
292
Werner Lembergebf55852005-03-16 01:49:54 +0000293
David Turner68df4f72005-03-15 18:18:57 +0000294 static void
295 _bdf_list_done( _bdf_list_t* list )
296 {
297 FT_Memory memory = list->memory;
298
Werner Lembergebf55852005-03-16 01:49:54 +0000299
David Turner68df4f72005-03-15 18:18:57 +0000300 if ( memory )
301 {
302 FT_FREE( list->field );
Werner Lembergebf55852005-03-16 01:49:54 +0000303 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000304 }
305 }
306
307
308 static FT_Error
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900309 _bdf_list_ensure( _bdf_list_t* list,
310 unsigned long num_items ) /* same as _bdf_list_t.used */
David Turner68df4f72005-03-15 18:18:57 +0000311 {
Werner Lemberge3c93012013-03-14 11:21:17 +0100312 FT_Error error = FT_Err_Ok;
Werner Lembergebf55852005-03-16 01:49:54 +0000313
David Turner68df4f72005-03-15 18:18:57 +0000314
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900315 if ( num_items > list->size )
David Turner68df4f72005-03-15 18:18:57 +0000316 {
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900317 unsigned long oldsize = list->size; /* same as _bdf_list_t.size */
Werner Lembergcee5d592012-03-01 09:26:03 +0100318 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 5;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900319 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
320 FT_Memory memory = list->memory;
David Turner68df4f72005-03-15 18:18:57 +0000321
Werner Lembergebf55852005-03-16 01:49:54 +0000322
David Turner68df4f72005-03-15 18:18:57 +0000323 if ( oldsize == bigsize )
324 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100325 error = FT_THROW( Out_Of_Memory );
David Turner68df4f72005-03-15 18:18:57 +0000326 goto Exit;
327 }
328 else if ( newsize < oldsize || newsize > bigsize )
329 newsize = bigsize;
330
331 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
332 goto Exit;
333
334 list->size = newsize;
335 }
Werner Lembergebf55852005-03-16 01:49:54 +0000336
David Turner68df4f72005-03-15 18:18:57 +0000337 Exit:
338 return error;
339 }
340
341
342 static void
343 _bdf_list_shift( _bdf_list_t* list,
344 unsigned long n )
345 {
346 unsigned long i, u;
347
348
349 if ( list == 0 || list->used == 0 || n == 0 )
350 return;
351
352 if ( n >= list->used )
353 {
354 list->used = 0;
355 return;
356 }
357
358 for ( u = n, i = 0; u < list->used; i++, u++ )
359 list->field[i] = list->field[u];
360 list->used -= n;
361 }
362
363
Werner Lembergf4c94d42010-06-19 16:08:31 +0200364 /* An empty string for empty fields. */
365
366 static const char empty[1] = { 0 }; /* XXX eliminate this */
367
368
David Turner68df4f72005-03-15 18:18:57 +0000369 static char *
370 _bdf_list_join( _bdf_list_t* list,
371 int c,
372 unsigned long *alen )
373 {
374 unsigned long i, j;
Werner Lembergdc624ca2013-06-04 10:30:48 +0200375 char* dp;
David Turner68df4f72005-03-15 18:18:57 +0000376
377
378 *alen = 0;
379
380 if ( list == 0 || list->used == 0 )
381 return 0;
382
383 dp = list->field[0];
384 for ( i = j = 0; i < list->used; i++ )
385 {
Werner Lembergdc624ca2013-06-04 10:30:48 +0200386 char* fp = list->field[i];
387
388
David Turner68df4f72005-03-15 18:18:57 +0000389 while ( *fp )
390 dp[j++] = *fp++;
391
392 if ( i + 1 < list->used )
393 dp[j++] = (char)c;
394 }
Werner Lembergf4c94d42010-06-19 16:08:31 +0200395 if ( dp != empty )
396 dp[j] = 0;
David Turner68df4f72005-03-15 18:18:57 +0000397
398 *alen = j;
399 return dp;
400 }
401
402
Werner Lemberg03242f52012-02-26 06:52:56 +0100403 /* The code below ensures that we have at least 4 + 1 `field' */
404 /* elements in `list' (which are possibly NULL) so that we */
405 /* don't have to check the number of fields in most cases. */
406
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000407 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000408 _bdf_list_split( _bdf_list_t* list,
409 char* separators,
410 char* line,
411 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000412 {
Werner Lemberg3c374c82015-02-22 09:16:53 +0100413 unsigned long final_empty;
414 int mult;
415 char *sp, *ep, *end;
416 char seps[32];
417 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000418
419
420 /* Initialize the list. */
421 list->used = 0;
Werner Lembergd9c16592012-03-01 15:15:00 +0100422 if ( list->size )
423 {
424 list->field[0] = (char*)empty;
425 list->field[1] = (char*)empty;
426 list->field[2] = (char*)empty;
427 list->field[3] = (char*)empty;
Werner Lemberg649c6732012-03-16 21:12:41 +0100428 list->field[4] = (char*)empty;
Werner Lembergd9c16592012-03-01 15:15:00 +0100429 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000430
431 /* If the line is empty, then simply return. */
432 if ( linelen == 0 || line[0] == 0 )
433 goto Exit;
434
435 /* In the original code, if the `separators' parameter is NULL or */
436 /* empty, the list is split into individual bytes. We don't need */
437 /* this, so an error is signaled. */
438 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000439 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100440 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000441 goto Exit;
442 }
443
444 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000445 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000446
447 /* If the very last character of the separator string is a plus, then */
448 /* set the `mult' flag to indicate that multiple separators should be */
449 /* collapsed into one. */
450 for ( mult = 0, sp = separators; sp && *sp; sp++ )
451 {
452 if ( *sp == '+' && *( sp + 1 ) == 0 )
453 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000454 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000455 setsbit( seps, *sp );
456 }
457
458 /* Break the line up into fields. */
459 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
460 sp < end && *sp; )
461 {
462 /* Collect everything that is not a separator. */
463 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
464 ;
465
466 /* Resize the list if necessary. */
467 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000468 {
Werner Lembergebf55852005-03-16 01:49:54 +0000469 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000470 if ( error )
471 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000472 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000473
474 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000475 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000476
477 sp = ep;
478
479 if ( mult )
480 {
481 /* If multiple separators should be collapsed, do it now by */
482 /* setting all the separator characters to 0. */
483 for ( ; *ep && sbitset( seps, *ep ); ep++ )
484 *ep = 0;
485 }
486 else if ( *ep != 0 )
487 /* Don't collapse multiple separators by making them 0, so just */
488 /* make the one encountered 0. */
489 *ep++ = 0;
490
491 final_empty = ( ep > sp && *ep == 0 );
492 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000493 }
494
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000495 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000496 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000497 {
Werner Lembergebf55852005-03-16 01:49:54 +0000498 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000499 if ( error )
500 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000501 }
502
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000503 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000504 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000505
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000506 list->field[list->used] = 0;
507
508 Exit:
509 return error;
David Turner993a8d02002-05-18 12:03:43 +0000510 }
511
David Turner993a8d02002-05-18 12:03:43 +0000512
David Turner68df4f72005-03-15 18:18:57 +0000513#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000514
Werner Lembergebf55852005-03-16 01:49:54 +0000515
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000516 static FT_Error
517 _bdf_readstream( FT_Stream stream,
518 _bdf_line_func_t callback,
519 void* client_data,
520 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000521 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000522 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000523 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900524 int refill, hold, to_skip;
525 ptrdiff_t bytes, start, end, cursor, avail;
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -0400526 char* buf = NULL;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000527 FT_Memory memory = stream->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100528 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000529
David Turner993a8d02002-05-18 12:03:43 +0000530
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000531 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000532 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100533 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000534 goto Exit;
535 }
David Turner993a8d02002-05-18 12:03:43 +0000536
Werner Lembergebf55852005-03-16 01:49:54 +0000537 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000538 buf_size = 1024;
539
540 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000541 goto Exit;
542
Werner Lembergebf55852005-03-16 01:49:54 +0000543 cb = callback;
544 lineno = 1;
545 buf[0] = 0;
546 start = 0;
Werner Lembergebf55852005-03-16 01:49:54 +0000547 avail = 0;
548 cursor = 0;
549 refill = 1;
550 to_skip = NO_SKIP;
551 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000552
David Turner68df4f72005-03-15 18:18:57 +0000553 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000554 {
David Turner68df4f72005-03-15 18:18:57 +0000555 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000556 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +0200557 bytes = (ptrdiff_t)FT_Stream_TryRead(
558 stream, (FT_Byte*)buf + cursor,
Werner Lemberg3c374c82015-02-22 09:16:53 +0100559 buf_size - (unsigned long)cursor );
David Turner68df4f72005-03-15 18:18:57 +0000560 avail = cursor + bytes;
561 cursor = 0;
562 refill = 0;
563 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000564
David Turner68df4f72005-03-15 18:18:57 +0000565 end = start;
566
Werner Lembergebf55852005-03-16 01:49:54 +0000567 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000568 if ( start < avail && buf[start] == to_skip )
569 {
570 start += 1;
571 to_skip = NO_SKIP;
572 continue;
573 }
574
575 /* try to find the end of the line */
576 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
577 end++;
578
Werner Lembergebf55852005-03-16 01:49:54 +0000579 /* if we hit the end of the buffer, try shifting its content */
580 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000581 if ( end >= avail )
582 {
583 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
584 break; /* ignore it then exit */
585
586 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000587 {
Werner Lembergebf55852005-03-16 01:49:54 +0000588 /* this line is definitely too long; try resizing the input */
589 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000590 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000591
Werner Lembergebf55852005-03-16 01:49:54 +0000592
593 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000594 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100595 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +0100596 error = FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +0000597 goto Exit;
598 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000599
Werner Lembergebf55852005-03-16 01:49:54 +0000600 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000601 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
602 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000603
Werner Lemberg3c374c82015-02-22 09:16:53 +0100604 cursor = (ptrdiff_t)buf_size;
David Turner68df4f72005-03-15 18:18:57 +0000605 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000606 }
607 else
608 {
David Turner68df4f72005-03-15 18:18:57 +0000609 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000610
Werner Lemberg04e547b2013-04-03 07:37:56 +0200611 FT_MEM_MOVE( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000612
David Turner68df4f72005-03-15 18:18:57 +0000613 cursor = bytes;
614 avail -= bytes;
615 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000616 }
David Turner68df4f72005-03-15 18:18:57 +0000617 refill = 1;
618 continue;
David Turner993a8d02002-05-18 12:03:43 +0000619 }
David Turner68df4f72005-03-15 18:18:57 +0000620
621 /* Temporarily NUL-terminate the line. */
622 hold = buf[end];
623 buf[end] = 0;
624
Werner Lemberg0098d552014-12-07 11:03:57 +0100625 /* XXX: Use encoding independent value for 0x1A */
626 if ( buf[start] != '#' && buf[start] != 0x1A && end > start )
David Turner68df4f72005-03-15 18:18:57 +0000627 {
Werner Lemberga9f6f852012-12-17 09:08:09 +0100628 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergebf55852005-03-16 01:49:54 +0000629 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200630 /* Redo if we have encountered CHARS without properties. */
631 if ( error == -1 )
Werner Lemberga9f6f852012-12-17 09:08:09 +0100632 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200633 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000634 if ( error )
635 break;
636 }
637
638 lineno += 1;
639 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000640 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000641
642 if ( hold == '\n' )
643 to_skip = '\r';
644 else if ( hold == '\r' )
645 to_skip = '\n';
646 else
647 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000648 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000649
David Turner68df4f72005-03-15 18:18:57 +0000650 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000651
652 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000653 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000654 return error;
David Turner993a8d02002-05-18 12:03:43 +0000655 }
David Turner993a8d02002-05-18 12:03:43 +0000656
657
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000658 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000659
David Turnerb1b47622002-05-21 21:17:43 +0000660 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000661 {
David Turner993a8d02002-05-18 12:03:43 +0000662 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
663 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
664 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
665 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
666 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
Werner Lemberg0098d552014-12-07 11:03:57 +0100667 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000668 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,
Werner Lemberg0098d552014-12-07 11:03:57 +0100670 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000671 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
672 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000673 };
David Turner993a8d02002-05-18 12:03:43 +0000674
David Turnerb1b47622002-05-21 21:17:43 +0000675 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000676 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100677 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
David Turner993a8d02002-05-18 12:03:43 +0000678 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
680 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000681 };
David Turner993a8d02002-05-18 12:03:43 +0000682
David Turnerb1b47622002-05-21 21:17:43 +0000683 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000684 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100685 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
686 0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000687 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
688 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000689 };
David Turner993a8d02002-05-18 12:03:43 +0000690
David Turner993a8d02002-05-18 12:03:43 +0000691
Ben Wagnera512b0f2015-12-14 09:19:52 +0100692 /* Routine to convert a decimal ASCII string to an unsigned long integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000693 static unsigned long
Ben Wagnera512b0f2015-12-14 09:19:52 +0100694 _bdf_atoul( char* s )
David Turner993a8d02002-05-18 12:03:43 +0000695 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100696 unsigned long v;
David Turner993a8d02002-05-18 12:03:43 +0000697
698
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000699 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000700 return 0;
701
Ben Wagnera512b0f2015-12-14 09:19:52 +0100702 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200703 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100704 if ( v < ( FT_ULONG_MAX - 9 ) / 10 )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200705 v = v * 10 + a2i[(int)*s];
706 else
707 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100708 v = FT_ULONG_MAX;
Werner Lemberg47a03e92017-06-02 09:06:36 +0200709 break;
710 }
711 }
David Turner993a8d02002-05-18 12:03:43 +0000712
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000713 return v;
714 }
David Turner993a8d02002-05-18 12:03:43 +0000715
David Turner993a8d02002-05-18 12:03:43 +0000716
Ben Wagnera512b0f2015-12-14 09:19:52 +0100717 /* Routine to convert a decimal ASCII string to a signed long integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000718 static long
Ben Wagnera512b0f2015-12-14 09:19:52 +0100719 _bdf_atol( char* s )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000720 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100721 long v, neg;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000722
723
724 if ( s == 0 || *s == 0 )
725 return 0;
726
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000727 /* Check for a minus sign. */
728 neg = 0;
729 if ( *s == '-' )
730 {
731 s++;
732 neg = 1;
733 }
734
Ben Wagnera512b0f2015-12-14 09:19:52 +0100735 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200736 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100737 if ( v < ( FT_LONG_MAX - 9 ) / 10 )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200738 v = v * 10 + a2i[(int)*s];
739 else
740 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100741 v = FT_LONG_MAX;
Werner Lemberg47a03e92017-06-02 09:06:36 +0200742 break;
743 }
744 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000745
746 return ( !neg ) ? v : -v;
747 }
748
749
Ben Wagnera512b0f2015-12-14 09:19:52 +0100750 /* Routine to convert a decimal ASCII string to an unsigned short integer. */
Werner Lembergb13945a2015-02-22 09:15:47 +0100751 static unsigned short
Ben Wagnera512b0f2015-12-14 09:19:52 +0100752 _bdf_atous( char* s )
Werner Lembergb13945a2015-02-22 09:15:47 +0100753 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100754 unsigned short v;
Werner Lembergb13945a2015-02-22 09:15:47 +0100755
756
757 if ( s == 0 || *s == 0 )
758 return 0;
759
Ben Wagnera512b0f2015-12-14 09:19:52 +0100760 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200761 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100762 if ( v < ( FT_USHORT_MAX - 9 ) / 10 )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200763 v = (unsigned short)( v * 10 + a2i[(int)*s] );
764 else
765 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100766 v = FT_USHORT_MAX;
Werner Lemberg47a03e92017-06-02 09:06:36 +0200767 break;
768 }
769 }
Werner Lembergb13945a2015-02-22 09:15:47 +0100770
771 return v;
772 }
773
774
Ben Wagnera512b0f2015-12-14 09:19:52 +0100775 /* Routine to convert a decimal ASCII string to a signed short integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000776 static short
Ben Wagnera512b0f2015-12-14 09:19:52 +0100777 _bdf_atos( char* s )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000778 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100779 short v, neg;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000780
781
782 if ( s == 0 || *s == 0 )
783 return 0;
784
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000785 /* Check for a minus. */
786 neg = 0;
787 if ( *s == '-' )
788 {
789 s++;
790 neg = 1;
791 }
792
Ben Wagnera512b0f2015-12-14 09:19:52 +0100793 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200794 {
795 if ( v < ( SHRT_MAX - 9 ) / 10 )
796 v = (short)( v * 10 + a2i[(int)*s] );
797 else
798 {
799 v = SHRT_MAX;
800 break;
801 }
802 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000803
Werner Lemberg233302a2002-05-22 05:41:06 +0000804 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000805 }
806
807
808 /* Routine to compare two glyphs by encoding so they can be sorted. */
809 static int
810 by_encoding( const void* a,
811 const void* b )
812 {
813 bdf_glyph_t *c1, *c2;
814
815
816 c1 = (bdf_glyph_t *)a;
817 c2 = (bdf_glyph_t *)b;
818
819 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000820 return -1;
David Turner68df4f72005-03-15 18:18:57 +0000821
822 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000823 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000824
David Turner993a8d02002-05-18 12:03:43 +0000825 return 0;
David Turner993a8d02002-05-18 12:03:43 +0000826 }
827
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000828
829 static FT_Error
830 bdf_create_property( char* name,
831 int format,
832 bdf_font_t* font )
833 {
suzuki toshiya704f4d72009-09-13 00:50:14 +0900834 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000835 bdf_property_t* p;
836 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100837 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000838
839
Werner Lemberg96ddc672011-06-29 09:15:54 +0200840 /* First check whether the property has */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000841 /* already been added or not. If it has, then */
842 /* simply ignore it. */
Werner Lemberg609546c2015-12-20 07:17:29 +0100843 if ( ft_hash_str_lookup( name, &(font->proptbl) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000844 goto Exit;
845
David Turner68df4f72005-03-15 18:18:57 +0000846 if ( FT_RENEW_ARRAY( font->user_props,
847 font->nuser_props,
848 font->nuser_props + 1 ) )
849 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000850
851 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +0000852 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000853
suzuki toshiya704f4d72009-09-13 00:50:14 +0900854 n = ft_strlen( name ) + 1;
855 if ( n > FT_ULONG_MAX )
Werner Lemberg059bc332013-03-14 10:27:35 +0100856 return FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +0000857
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000858 if ( FT_NEW_ARRAY( p->name, n ) )
859 goto Exit;
860
861 FT_MEM_COPY( (char *)p->name, name, n );
862
863 p->format = format;
864 p->builtin = 0;
865
866 n = _num_bdf_properties + font->nuser_props;
867
Werner Lemberg609546c2015-12-20 07:17:29 +0100868 error = ft_hash_str_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000869 if ( error )
870 goto Exit;
871
872 font->nuser_props++;
873
874 Exit:
David Turner993a8d02002-05-18 12:03:43 +0000875 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000876 }
David Turner993a8d02002-05-18 12:03:43 +0000877
878
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100879 FT_LOCAL_DEF( bdf_property_t* )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000880 bdf_get_property( char* name,
881 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +0000882 {
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100883 size_t* propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000884
885
886 if ( name == 0 || *name == 0 )
887 return 0;
888
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100889 if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000890 return 0;
891
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100892 if ( *propid >= _num_bdf_properties )
893 return font->user_props + ( *propid - _num_bdf_properties );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000894
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100895 return (bdf_property_t*)_bdf_properties + *propid;
David Turner993a8d02002-05-18 12:03:43 +0000896 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000897
898
Werner Lemberg9ac90602018-06-03 09:01:17 +0200899 /**************************************************************************
900 *
901 * BDF font file parsing flags and functions.
902 *
903 */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000904
905
906 /* Parse flags. */
907
Werner Lemberg758587d2016-01-12 22:20:06 +0100908#define BDF_START_ 0x0001U
909#define BDF_FONT_NAME_ 0x0002U
910#define BDF_SIZE_ 0x0004U
911#define BDF_FONT_BBX_ 0x0008U
912#define BDF_PROPS_ 0x0010U
913#define BDF_GLYPHS_ 0x0020U
914#define BDF_GLYPH_ 0x0040U
915#define BDF_ENCODING_ 0x0080U
916#define BDF_SWIDTH_ 0x0100U
917#define BDF_DWIDTH_ 0x0200U
918#define BDF_BBX_ 0x0400U
919#define BDF_BITMAP_ 0x0800U
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000920
Werner Lemberg758587d2016-01-12 22:20:06 +0100921#define BDF_SWIDTH_ADJ_ 0x1000U
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000922
Werner Lemberg758587d2016-01-12 22:20:06 +0100923#define BDF_GLYPH_BITS_ ( BDF_GLYPH_ | \
924 BDF_ENCODING_ | \
925 BDF_SWIDTH_ | \
926 BDF_DWIDTH_ | \
927 BDF_BBX_ | \
928 BDF_BITMAP_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000929
Werner Lemberg758587d2016-01-12 22:20:06 +0100930#define BDF_GLYPH_WIDTH_CHECK_ 0x40000000UL
931#define BDF_GLYPH_HEIGHT_CHECK_ 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000932
933
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000934 static FT_Error
935 _bdf_add_comment( bdf_font_t* font,
936 char* comment,
937 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +0000938 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000939 char* cp;
940 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100941 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000942
943
David Turner68df4f72005-03-15 18:18:57 +0000944 if ( FT_RENEW_ARRAY( font->comments,
945 font->comments_len,
946 font->comments_len + len + 1 ) )
947 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000948
949 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +0000950
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000951 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +0000952 cp[len] = '\n';
953
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000954 font->comments_len += len + 1;
955
956 Exit:
957 return error;
David Turner993a8d02002-05-18 12:03:43 +0000958 }
959
David Turner993a8d02002-05-18 12:03:43 +0000960
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000961 /* Set the spacing from the font name if it exists, or set it to the */
962 /* default specified in the options. */
963 static FT_Error
964 _bdf_set_default_spacing( bdf_font_t* font,
Werner Lemberge01406b2011-11-25 09:44:28 +0100965 bdf_options_t* opts,
966 unsigned long lineno )
David Turner993a8d02002-05-18 12:03:43 +0000967 {
suzuki toshiya704f4d72009-09-13 00:50:14 +0900968 size_t len;
969 char name[256];
970 _bdf_list_t list;
971 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100972 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000973
Dave Arnoldc3782492013-06-05 19:57:55 +0200974 FT_UNUSED( lineno ); /* only used in debug mode */
975
David Turner993a8d02002-05-18 12:03:43 +0000976
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000977 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
978 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100979 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000980 goto Exit;
981 }
David Turner993a8d02002-05-18 12:03:43 +0000982
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000983 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +0000984
David Turner68df4f72005-03-15 18:18:57 +0000985 _bdf_list_init( &list, memory );
986
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000987 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +0000988
suzuki toshiya704f4d72009-09-13 00:50:14 +0900989 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +0000990 /* Limit ourselves to 256 characters in the font name. */
991 if ( len >= 256 )
992 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100993 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +0100994 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +0000995 goto Exit;
996 }
997
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000998 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +0000999
Werner Lembergbadf3172013-06-06 09:16:38 +02001000 error = _bdf_list_split( &list, (char *)"-", name, (unsigned long)len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001001 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001002 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001003
1004 if ( list.used == 15 )
1005 {
1006 switch ( list.field[11][0] )
1007 {
1008 case 'C':
1009 case 'c':
1010 font->spacing = BDF_CHARCELL;
1011 break;
1012 case 'M':
1013 case 'm':
1014 font->spacing = BDF_MONOWIDTH;
1015 break;
1016 case 'P':
1017 case 'p':
1018 font->spacing = BDF_PROPORTIONAL;
1019 break;
David Turner993a8d02002-05-18 12:03:43 +00001020 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001021 }
1022
David Turner68df4f72005-03-15 18:18:57 +00001023 Fail:
1024 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001025
1026 Exit:
1027 return error;
David Turner993a8d02002-05-18 12:03:43 +00001028 }
David Turner993a8d02002-05-18 12:03:43 +00001029
1030
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001031 /* Determine whether the property is an atom or not. If it is, then */
1032 /* clean it up so the double quotes are removed if they exist. */
1033 static int
1034 _bdf_is_atom( char* line,
1035 unsigned long linelen,
1036 char** name,
1037 char** value,
1038 bdf_font_t* font )
1039 {
1040 int hold;
1041 char *sp, *ep;
1042 bdf_property_t* p;
1043
David Turner993a8d02002-05-18 12:03:43 +00001044
1045 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001046
1047 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001048 ep++;
1049
1050 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001051 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001052 {
1053 hold = *ep;
1054 *ep = 0;
1055 }
1056
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001057 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001058
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001059 /* Restore the character that was saved before any return can happen. */
1060 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001061 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001062
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001063 /* If the property exists and is not an atom, just return here. */
1064 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001065 return 0;
1066
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001067 /* The property is an atom. Trim all leading and trailing whitespace */
1068 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001069 sp = ep;
1070 ep = line + linelen;
1071
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001072 /* Trim the leading whitespace if it exists. */
Werner Lemberg320d4972012-02-24 18:06:46 +01001073 if ( *sp )
1074 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001075 while ( *sp &&
1076 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001077 sp++;
1078
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001079 /* Trim the leading double quote if it exists. */
1080 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001081 sp++;
1082 *value = sp;
1083
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001084 /* Trim the trailing whitespace if it exists. */
1085 while ( ep > sp &&
1086 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001087 *--ep = 0;
1088
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001089 /* Trim the trailing double quote if it exists. */
1090 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001091 *--ep = 0;
1092
1093 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001094 }
David Turner993a8d02002-05-18 12:03:43 +00001095
1096
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001097 static FT_Error
Werner Lemberge01406b2011-11-25 09:44:28 +01001098 _bdf_add_property( bdf_font_t* font,
1099 char* name,
1100 char* value,
1101 unsigned long lineno )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001102 {
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001103 size_t* propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001104 bdf_property_t *prop, *fp;
1105 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001106 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001107
Dave Arnoldc3782492013-06-05 19:57:55 +02001108 FT_UNUSED( lineno ); /* only used in debug mode */
1109
David Turner993a8d02002-05-18 12:03:43 +00001110
Werner Lemberg96ddc672011-06-29 09:15:54 +02001111 /* First, check whether the property already exists in the font. */
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001112 if ( ( propid = ft_hash_str_lookup( name,
1113 (FT_Hash)font->internal ) ) != NULL )
David Turner993a8d02002-05-18 12:03:43 +00001114 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001115 /* The property already exists in the font, so simply replace */
1116 /* the value of the property with the current value. */
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001117 fp = font->props + *propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001118
David Turnerb1b47622002-05-21 21:17:43 +00001119 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001120 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001121 case BDF_ATOM:
1122 /* Delete the current atom if it exists. */
1123 FT_FREE( fp->value.atom );
1124
David Turnerc0f9c4a2007-02-12 14:55:03 +00001125 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001126 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001127 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001128 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001129 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001130 break;
1131
1132 case BDF_INTEGER:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001133 fp->value.l = _bdf_atol( value );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001134 break;
1135
1136 case BDF_CARDINAL:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001137 fp->value.ul = _bdf_atoul( value );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001138 break;
David Turnerd490e372002-05-28 23:40:37 +00001139
David Turnerb1b47622002-05-21 21:17:43 +00001140 default:
1141 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001142 }
David Turnerd490e372002-05-28 23:40:37 +00001143
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001144 goto Exit;
1145 }
1146
1147 /* See whether this property type exists yet or not. */
1148 /* If not, create it. */
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001149 propid = ft_hash_str_lookup( name, &(font->proptbl) );
Werner Lemberg4441f7b2016-12-26 17:08:17 +01001150 if ( !propid )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001151 {
1152 error = bdf_create_property( name, BDF_ATOM, font );
1153 if ( error )
1154 goto Exit;
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001155 propid = ft_hash_str_lookup( name, &(font->proptbl) );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001156 }
1157
Werner Lembergb6b26f42016-06-09 06:53:48 +02001158 /* Allocate another property if this is overflowing. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001159 if ( font->props_used == font->props_size )
1160 {
1161 if ( font->props_size == 0 )
1162 {
1163 if ( FT_NEW_ARRAY( font->props, 1 ) )
1164 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001165 }
1166 else
1167 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001168 if ( FT_RENEW_ARRAY( font->props,
1169 font->props_size,
1170 font->props_size + 1 ) )
1171 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001172 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001173
David Turner993a8d02002-05-18 12:03:43 +00001174 fp = font->props + font->props_size;
Werner Lemberg2ecf89b2016-09-28 19:06:21 +02001175 FT_ZERO( fp );
David Turner993a8d02002-05-18 12:03:43 +00001176 font->props_size++;
1177 }
1178
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001179 if ( *propid >= _num_bdf_properties )
1180 prop = font->user_props + ( *propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001181 else
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001182 prop = (bdf_property_t*)_bdf_properties + *propid;
David Turner993a8d02002-05-18 12:03:43 +00001183
1184 fp = font->props + font->props_used;
1185
1186 fp->name = prop->name;
1187 fp->format = prop->format;
1188 fp->builtin = prop->builtin;
1189
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001190 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001191 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001192 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001193 fp->value.atom = 0;
1194 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001195 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001196 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001197 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001198 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001199 break;
David Turner993a8d02002-05-18 12:03:43 +00001200
1201 case BDF_INTEGER:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001202 fp->value.l = _bdf_atol( value );
David Turner993a8d02002-05-18 12:03:43 +00001203 break;
1204
1205 case BDF_CARDINAL:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001206 fp->value.ul = _bdf_atoul( value );
David Turner993a8d02002-05-18 12:03:43 +00001207 break;
David Turner993a8d02002-05-18 12:03:43 +00001208 }
1209
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001210 /* If the property happens to be a comment, then it doesn't need */
1211 /* to be added to the internal hash table. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001212 if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 )
Werner Lemberg370aea82010-06-08 08:37:11 +02001213 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001214 /* Add the property to the font property table. */
Werner Lemberg609546c2015-12-20 07:17:29 +01001215 error = ft_hash_str_insert( fp->name,
1216 font->props_used,
1217 (FT_Hash)font->internal,
1218 memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001219 if ( error )
1220 goto Exit;
1221 }
David Turner993a8d02002-05-18 12:03:43 +00001222
1223 font->props_used++;
1224
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001225 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1226 /* property needs to be located if it exists in the property list, the */
1227 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1228 /* present, and the SPACING property should override the default */
1229 /* spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001230 if ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 )
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001231 font->default_char = fp->value.ul;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001232 else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001233 font->font_ascent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001234 else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001235 font->font_descent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001236 else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001237 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001238 if ( !fp->value.atom )
1239 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001240 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001241 error = FT_THROW( Invalid_File_Format );
Werner Lembergb66efef2009-03-12 08:07:49 +00001242 goto Exit;
1243 }
1244
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001245 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001246 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001247 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001248 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001249 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001250 font->spacing = BDF_CHARCELL;
1251 }
1252
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001253 Exit:
1254 return error;
David Turner993a8d02002-05-18 12:03:43 +00001255 }
1256
David Turner993a8d02002-05-18 12:03:43 +00001257
David Turnerb1b47622002-05-21 21:17:43 +00001258 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001259 {
1260 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1261 };
1262
1263
1264 /* Actually parse the glyph info and bitmaps. */
1265 static FT_Error
1266 _bdf_parse_glyphs( char* line,
1267 unsigned long linelen,
1268 unsigned long lineno,
1269 void* call_data,
1270 void* client_data )
1271 {
1272 int c, mask_index;
1273 char* s;
1274 unsigned char* bp;
1275 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001276
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001277 _bdf_parse_t* p;
1278 bdf_glyph_t* glyph;
1279 bdf_font_t* font;
1280
1281 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001282 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001283
Werner Lemberg319c00d2003-04-23 19:48:24 +00001284 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001285 FT_UNUSED( lineno ); /* only used in debug mode */
1286
1287
Werner Lemberg319c00d2003-04-23 19:48:24 +00001288 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001289
1290 font = p->font;
1291 memory = font->memory;
1292
1293 /* Check for a comment. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001294 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001295 {
1296 linelen -= 7;
1297
1298 s = line + 7;
1299 if ( *s != 0 )
1300 {
1301 s++;
1302 linelen--;
1303 }
1304 error = _bdf_add_comment( p->font, s, linelen );
1305 goto Exit;
1306 }
1307
1308 /* The very first thing expected is the number of glyphs. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001309 if ( !( p->flags & BDF_GLYPHS_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001310 {
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001311 if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001312 {
1313 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001314 error = FT_THROW( Missing_Chars_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001315 goto Exit;
1316 }
1317
David Turner68df4f72005-03-15 18:18:57 +00001318 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001319 if ( error )
1320 goto Exit;
Ben Wagnera512b0f2015-12-14 09:19:52 +01001321 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001322
Werner Lemberge1ca18d2015-10-17 11:51:27 +02001323 /* We need at least 20 bytes per glyph. */
1324 if ( p->cnt > p->size / 20 )
1325 {
Werner Lemberg797ca5a2015-10-17 11:57:16 +02001326 p->cnt = font->glyphs_size = p->size / 20;
Werner Lemberge1ca18d2015-10-17 11:51:27 +02001327 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG17, p->cnt ));
1328 }
1329
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001330 /* Make sure the number of glyphs is non-zero. */
1331 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001332 font->glyphs_size = 64;
1333
Werner Lemberga08b2172007-03-28 07:17:17 +00001334 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1335 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001336 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001337 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001338 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001339 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001340 goto Exit;
1341 }
1342
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001343 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1344 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001345
Werner Lemberg758587d2016-01-12 22:20:06 +01001346 p->flags |= BDF_GLYPHS_;
David Turner993a8d02002-05-18 12:03:43 +00001347
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001348 goto Exit;
1349 }
1350
1351 /* Check for the ENDFONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001352 if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001353 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001354 if ( p->flags & BDF_GLYPH_BITS_ )
Werner Lembergaf834612014-11-22 13:29:10 +01001355 {
1356 /* Missing ENDCHAR field. */
1357 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1358 error = FT_THROW( Corrupted_Font_Glyphs );
1359 goto Exit;
1360 }
1361
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001362 /* Sort the glyphs by encoding. */
1363 ft_qsort( (char *)font->glyphs,
1364 font->glyphs_used,
1365 sizeof ( bdf_glyph_t ),
1366 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001367
Werner Lemberg758587d2016-01-12 22:20:06 +01001368 p->flags &= ~BDF_START_;
David Turner993a8d02002-05-18 12:03:43 +00001369
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001370 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001371 }
1372
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001373 /* Check for the ENDCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001374 if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001375 {
1376 p->glyph_enc = 0;
Werner Lemberg758587d2016-01-12 22:20:06 +01001377 p->flags &= ~BDF_GLYPH_BITS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001378
1379 goto Exit;
1380 }
1381
Werner Lemberg96ddc672011-06-29 09:15:54 +02001382 /* Check whether a glyph is being scanned but should be */
1383 /* ignored because it is an unencoded glyph. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001384 if ( ( p->flags & BDF_GLYPH_ ) &&
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001385 p->glyph_enc == -1 &&
1386 p->opts->keep_unencoded == 0 )
1387 goto Exit;
1388
1389 /* Check for the STARTCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001390 if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001391 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001392 if ( p->flags & BDF_GLYPH_BITS_ )
Werner Lembergb1857472015-10-17 14:21:41 +02001393 {
1394 /* Missing ENDCHAR field. */
1395 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1396 error = FT_THROW( Missing_Startchar_Field );
1397 goto Exit;
1398 }
1399
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001400 /* Set the character name in the parse info first until the */
1401 /* encoding can be checked for an unencoded character. */
1402 FT_FREE( p->glyph_name );
1403
David Turner68df4f72005-03-15 18:18:57 +00001404 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001405 if ( error )
1406 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001407
David Turner68df4f72005-03-15 18:18:57 +00001408 _bdf_list_shift( &p->list, 1 );
1409
1410 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001411
Werner Lembergba03af62007-05-30 13:57:02 +00001412 if ( !s )
1413 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001414 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001415 error = FT_THROW( Invalid_File_Format );
Werner Lembergba03af62007-05-30 13:57:02 +00001416 goto Exit;
1417 }
1418
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001419 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1420 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001421
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001422 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1423
Werner Lemberg758587d2016-01-12 22:20:06 +01001424 p->flags |= BDF_GLYPH_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001425
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001426 FT_TRACE4(( DBGMSG1, lineno, s ));
1427
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001428 goto Exit;
1429 }
1430
1431 /* Check for the ENCODING field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001432 if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001433 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001434 if ( !( p->flags & BDF_GLYPH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001435 {
1436 /* Missing STARTCHAR field. */
1437 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001438 error = FT_THROW( Missing_Startchar_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001439 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001440 }
1441
David Turner68df4f72005-03-15 18:18:57 +00001442 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001443 if ( error )
1444 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001445
Ben Wagnera512b0f2015-12-14 09:19:52 +01001446 p->glyph_enc = _bdf_atol( p->list.field[1] );
David Turner993a8d02002-05-18 12:03:43 +00001447
Werner Lemberg28dd2c42012-02-26 06:18:58 +01001448 /* Normalize negative encoding values. The specification only */
1449 /* allows -1, but we can be more generous here. */
1450 if ( p->glyph_enc < -1 )
1451 p->glyph_enc = -1;
1452
Werner Lemberg03242f52012-02-26 06:52:56 +01001453 /* Check for alternative encoding format. */
1454 if ( p->glyph_enc == -1 && p->list.used > 2 )
Ben Wagnera512b0f2015-12-14 09:19:52 +01001455 p->glyph_enc = _bdf_atol( p->list.field[2] );
Werner Lemberg03242f52012-02-26 06:52:56 +01001456
Alexei Podtelezhnikov923fcbc2018-08-15 22:50:06 -04001457 if ( p->glyph_enc < -1 || p->glyph_enc >= 0x110000L )
Werner Lemberg7f2e4f42012-12-15 09:39:41 +01001458 p->glyph_enc = -1;
1459
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001460 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1461
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001462 if ( p->glyph_enc >= 0 )
1463 {
1464 /* Make sure there are enough glyphs allocated in case the */
1465 /* number of characters happen to be wrong. */
1466 if ( font->glyphs_used == font->glyphs_size )
1467 {
1468 if ( FT_RENEW_ARRAY( font->glyphs,
1469 font->glyphs_size,
1470 font->glyphs_size + 64 ) )
1471 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001472
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001473 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001474 }
1475
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001476 glyph = font->glyphs + font->glyphs_used++;
1477 glyph->name = p->glyph_name;
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001478 glyph->encoding = (unsigned long)p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001479
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001480 /* Reset the initial glyph info. */
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001481 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001482 }
1483 else
1484 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001485 /* Unencoded glyph. Check whether it should */
1486 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001487 if ( p->opts->keep_unencoded != 0 )
1488 {
1489 /* Allocate the next unencoded glyph. */
1490 if ( font->unencoded_used == font->unencoded_size )
1491 {
David Turner68df4f72005-03-15 18:18:57 +00001492 if ( FT_RENEW_ARRAY( font->unencoded ,
1493 font->unencoded_size,
1494 font->unencoded_size + 4 ) )
1495 goto Exit;
1496
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001497 font->unencoded_size += 4;
1498 }
1499
1500 glyph = font->unencoded + font->unencoded_used;
1501 glyph->name = p->glyph_name;
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001502 glyph->encoding = font->unencoded_used++;
Werner Lemberg4a150132015-11-25 07:53:49 +01001503
1504 /* Reset the initial glyph info. */
1505 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001506 }
1507 else
Werner Lemberg94cacac2015-11-15 04:45:42 +01001508 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001509 /* Free up the glyph name if the unencoded shouldn't be */
1510 /* kept. */
1511 FT_FREE( p->glyph_name );
Werner Lemberg94cacac2015-11-15 04:45:42 +01001512 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001513
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001514 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001515 }
1516
1517 /* Clear the flags that might be added when width and height are */
1518 /* checked for consistency. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001519 p->flags &= ~( BDF_GLYPH_WIDTH_CHECK_ | BDF_GLYPH_HEIGHT_CHECK_ );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001520
Werner Lemberg758587d2016-01-12 22:20:06 +01001521 p->flags |= BDF_ENCODING_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001522
1523 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001524 }
1525
Armin Hasitzka0f6be062018-06-17 20:27:42 +02001526 if ( !( p->flags & BDF_ENCODING_ ) )
1527 goto Missing_Encoding;
1528
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001529 /* Point at the glyph being constructed. */
1530 if ( p->glyph_enc == -1 )
1531 glyph = font->unencoded + ( font->unencoded_used - 1 );
1532 else
1533 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001534
Werner Lemberg96ddc672011-06-29 09:15:54 +02001535 /* Check whether a bitmap is being constructed. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001536 if ( p->flags & BDF_BITMAP_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001537 {
1538 /* If there are more rows than are specified in the glyph metrics, */
1539 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001540 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001541 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001542 if ( !( p->flags & BDF_GLYPH_HEIGHT_CHECK_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001543 {
1544 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001545 p->flags |= BDF_GLYPH_HEIGHT_CHECK_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001546 }
1547
1548 goto Exit;
1549 }
1550
1551 /* Only collect the number of nibbles indicated by the glyph */
1552 /* metrics. If there are more columns, they are simply ignored. */
1553 nibbles = glyph->bpr << 1;
1554 bp = glyph->bitmap + p->row * glyph->bpr;
1555
David Turnerb698eed2006-02-23 14:50:13 +00001556 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001557 {
1558 c = line[i];
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001559 if ( !sbitset( hdigits, c ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001560 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001561 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001562 if ( i + 1 < nibbles && ( i & 1 ) )
1563 *++bp = 0;
1564 }
1565
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001566 /* If any line has not enough columns, */
1567 /* indicate they have been padded with zero bits. */
1568 if ( i < nibbles &&
Werner Lemberg758587d2016-01-12 22:20:06 +01001569 !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001570 {
1571 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001572 p->flags |= BDF_GLYPH_WIDTH_CHECK_;
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001573 }
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_;
David Turner993a8d02002-05-18 12:03:43 +00001587 }
1588
1589 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001590 goto Exit;
1591 }
David Turner993a8d02002-05-18 12:03:43 +00001592
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001593 /* Expect the SWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001594 if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001595 {
David Turner68df4f72005-03-15 18:18:57 +00001596 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001597 if ( error )
1598 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001599
Ben Wagnera512b0f2015-12-14 09:19:52 +01001600 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1] );
Werner Lemberg758587d2016-01-12 22:20:06 +01001601 p->flags |= BDF_SWIDTH_;
David Turner993a8d02002-05-18 12:03:43 +00001602
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001603 goto Exit;
1604 }
David Turner993a8d02002-05-18 12:03:43 +00001605
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001606 /* Expect the DWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001607 if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001608 {
David Turner68df4f72005-03-15 18:18:57 +00001609 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001610 if ( error )
1611 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001612
Ben Wagnera512b0f2015-12-14 09:19:52 +01001613 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001614
Werner Lemberg758587d2016-01-12 22:20:06 +01001615 if ( !( p->flags & BDF_SWIDTH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001616 {
1617 /* Missing SWIDTH field. Emit an auto correction message and set */
1618 /* the scalable width from the device width. */
1619 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1620
Werner Lemberg02d4d592002-05-28 22:38:05 +00001621 glyph->swidth = (unsigned short)FT_MulDiv(
1622 glyph->dwidth, 72000L,
1623 (FT_Long)( font->point_size *
1624 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001625 }
1626
Werner Lemberg758587d2016-01-12 22:20:06 +01001627 p->flags |= BDF_DWIDTH_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001628 goto Exit;
1629 }
David Turner993a8d02002-05-18 12:03:43 +00001630
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001631 /* Expect the BBX field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001632 if ( _bdf_strncmp( line, "BBX", 3 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001633 {
David Turner68df4f72005-03-15 18:18:57 +00001634 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001635 if ( error )
1636 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001637
Ben Wagnera512b0f2015-12-14 09:19:52 +01001638 glyph->bbx.width = _bdf_atous( p->list.field[1] );
1639 glyph->bbx.height = _bdf_atous( p->list.field[2] );
1640 glyph->bbx.x_offset = _bdf_atos( p->list.field[3] );
1641 glyph->bbx.y_offset = _bdf_atos( p->list.field[4] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001642
1643 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001644 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1645 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001646
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001647 /* Determine the overall font bounding box as the characters are */
1648 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001649 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1650 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001651
David Turnerb1b47622002-05-21 21:17:43 +00001652 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001653
Werner Lembergdfa46192004-03-05 09:26:24 +00001654 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1655 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1656 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001657
Werner Lemberg758587d2016-01-12 22:20:06 +01001658 if ( !( p->flags & BDF_DWIDTH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001659 {
1660 /* Missing DWIDTH field. Emit an auto correction message and set */
1661 /* the device width to the glyph width. */
1662 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1663 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001664 }
1665
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001666 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1667 /* value if necessary. */
1668 if ( p->opts->correct_metrics != 0 )
1669 {
1670 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001671 unsigned short sw = (unsigned short)FT_MulDiv(
1672 glyph->dwidth, 72000L,
1673 (FT_Long)( font->point_size *
1674 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001675
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001676
1677 if ( sw != glyph->swidth )
1678 {
1679 glyph->swidth = sw;
1680
Werner Lemberg758587d2016-01-12 22:20:06 +01001681 p->flags |= BDF_SWIDTH_ADJ_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001682 }
David Turner993a8d02002-05-18 12:03:43 +00001683 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001684
Werner Lemberg758587d2016-01-12 22:20:06 +01001685 p->flags |= BDF_BBX_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001686 goto Exit;
1687 }
David Turner993a8d02002-05-18 12:03:43 +00001688
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001689 /* And finally, gather up the bitmap. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001690 if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001691 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001692 unsigned long bitmap_size;
1693
1694
Werner Lemberg758587d2016-01-12 22:20:06 +01001695 if ( !( p->flags & BDF_BBX_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001696 {
1697 /* Missing BBX field. */
1698 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001699 error = FT_THROW( Missing_Bbx_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001700 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001701 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001702
1703 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001704 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001705
1706 bitmap_size = glyph->bpr * glyph->bbx.height;
Werner Lembergc4cad302012-03-08 20:11:37 +01001707 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
Werner Lemberg26170df2006-03-26 07:19:07 +00001708 {
1709 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001710 error = FT_THROW( Bbx_Too_Big );
Werner Lemberg26170df2006-03-26 07:19:07 +00001711 goto Exit;
1712 }
1713 else
1714 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001715
1716 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1717 goto Exit;
1718
1719 p->row = 0;
Werner Lemberg758587d2016-01-12 22:20:06 +01001720 p->flags |= BDF_BITMAP_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001721
1722 goto Exit;
1723 }
1724
Werner Lemberge01406b2011-11-25 09:44:28 +01001725 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001726 error = FT_THROW( Invalid_File_Format );
Werner Lemberg4086fb72012-03-01 08:55:40 +01001727 goto Exit;
1728
1729 Missing_Encoding:
1730 /* Missing ENCODING field. */
1731 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001732 error = FT_THROW( Missing_Encoding_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001733
1734 Exit:
Werner Lemberg758587d2016-01-12 22:20:06 +01001735 if ( error && ( p->flags & BDF_GLYPH_ ) )
Werner Lembergf4c94d42010-06-19 16:08:31 +02001736 FT_FREE( p->glyph_name );
1737
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001738 return error;
David Turner993a8d02002-05-18 12:03:43 +00001739 }
1740
David Turner993a8d02002-05-18 12:03:43 +00001741
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001742 /* Load the font properties. */
1743 static FT_Error
1744 _bdf_parse_properties( char* line,
1745 unsigned long linelen,
1746 unsigned long lineno,
1747 void* call_data,
1748 void* client_data )
1749 {
1750 unsigned long vlen;
1751 _bdf_line_func_t* next;
1752 _bdf_parse_t* p;
1753 char* name;
1754 char* value;
1755 char nbuf[128];
Werner Lemberge3c93012013-03-14 11:21:17 +01001756 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001757
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001758 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001759
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001760
1761 next = (_bdf_line_func_t *)call_data;
1762 p = (_bdf_parse_t *) client_data;
1763
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001764 /* Check for the end of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001765 if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001766 {
1767 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1768 /* encountered yet, then make sure they are added as properties and */
1769 /* make sure they are set from the font bounding box info. */
1770 /* */
1771 /* This is *always* done regardless of the options, because X11 */
1772 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001773 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001774 {
1775 p->font->font_ascent = p->font->bbx.ascent;
1776 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001777 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
1778 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001779 if ( error )
1780 goto Exit;
1781
1782 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
David Turner993a8d02002-05-18 12:03:43 +00001783 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001784
Werner Lemberg428c2e42003-04-25 05:35:04 +00001785 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001786 {
1787 p->font->font_descent = p->font->bbx.descent;
1788 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001789 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
1790 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001791 if ( error )
1792 goto Exit;
1793
1794 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
David Turner993a8d02002-05-18 12:03:43 +00001795 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001796
Werner Lemberg758587d2016-01-12 22:20:06 +01001797 p->flags &= ~BDF_PROPS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001798 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001799
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001800 goto Exit;
1801 }
David Turner993a8d02002-05-18 12:03:43 +00001802
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001803 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001804 if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001805 goto Exit;
1806
1807 /* Handle COMMENT fields and properties in a special way to preserve */
1808 /* the spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001809 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001810 {
David Turner993a8d02002-05-18 12:03:43 +00001811 name = value = line;
1812 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001813 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001814 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01001815 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001816 if ( error )
1817 goto Exit;
1818 }
1819 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1820 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001821 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001822 if ( error )
1823 goto Exit;
1824 }
1825 else
1826 {
David Turner68df4f72005-03-15 18:18:57 +00001827 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001828 if ( error )
1829 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001830 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001831
David Turner68df4f72005-03-15 18:18:57 +00001832 _bdf_list_shift( &p->list, 1 );
1833 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001834
Werner Lemberge01406b2011-11-25 09:44:28 +01001835 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001836 if ( error )
1837 goto Exit;
1838 }
1839
1840 Exit:
1841 return error;
David Turner993a8d02002-05-18 12:03:43 +00001842 }
1843
David Turner993a8d02002-05-18 12:03:43 +00001844
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001845 /* Load the font header. */
1846 static FT_Error
1847 _bdf_parse_start( char* line,
1848 unsigned long linelen,
1849 unsigned long lineno,
1850 void* call_data,
1851 void* client_data )
1852 {
1853 unsigned long slen;
1854 _bdf_line_func_t* next;
1855 _bdf_parse_t* p;
1856 bdf_font_t* font;
1857 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001858
David Turnerd490e372002-05-28 23:40:37 +00001859 FT_Memory memory = NULL;
Werner Lemberge3c93012013-03-14 11:21:17 +01001860 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001861
1862 FT_UNUSED( lineno ); /* only used in debug mode */
1863
1864
1865 next = (_bdf_line_func_t *)call_data;
1866 p = (_bdf_parse_t *) client_data;
1867
1868 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00001869 memory = p->font->memory;
1870
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001871 /* Check for a comment. This is done to handle those fonts that have */
1872 /* comments before the STARTFONT line for some reason. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001873 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001874 {
1875 if ( p->opts->keep_comments != 0 && p->font != 0 )
1876 {
1877 linelen -= 7;
1878
1879 s = line + 7;
1880 if ( *s != 0 )
1881 {
1882 s++;
1883 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00001884 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001885
1886 error = _bdf_add_comment( p->font, s, linelen );
1887 if ( error )
1888 goto Exit;
1889 /* here font is not defined! */
1890 }
1891
1892 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001893 }
1894
Werner Lemberg758587d2016-01-12 22:20:06 +01001895 if ( !( p->flags & BDF_START_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001896 {
1897 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00001898
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001899 if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001900 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01001901 /* we don't emit an error message since this code gets */
1902 /* explicitly caught one level higher */
Werner Lemberg059bc332013-03-14 10:27:35 +01001903 error = FT_THROW( Missing_Startfont_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001904 goto Exit;
1905 }
David Turner993a8d02002-05-18 12:03:43 +00001906
Werner Lemberg758587d2016-01-12 22:20:06 +01001907 p->flags = BDF_START_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001908 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00001909
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001910 if ( FT_NEW( font ) )
1911 goto Exit;
1912 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00001913
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001914 font->memory = p->memory;
1915 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00001916
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001917 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001918 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001919 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00001920
David Turner993a8d02002-05-18 12:03:43 +00001921
Werner Lemberg7ce6c432015-12-22 05:39:58 +01001922 error = ft_hash_str_init( &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001923 if ( error )
1924 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00001925 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001926 i < _num_bdf_properties; i++, prop++ )
1927 {
Werner Lemberg609546c2015-12-20 07:17:29 +01001928 error = ft_hash_str_insert( prop->name, i,
1929 &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001930 if ( error )
1931 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001932 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001933 }
1934
Werner Lemberg31343562015-12-19 17:02:13 +01001935 if ( FT_ALLOC( p->font->internal, sizeof ( FT_HashRec ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001936 goto Exit;
Werner Lemberg7ce6c432015-12-22 05:39:58 +01001937 error = ft_hash_str_init( (FT_Hash)p->font->internal, memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001938 if ( error )
1939 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00001940 p->font->spacing = p->opts->font_spacing;
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001941 p->font->default_char = ~0UL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001942
1943 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001944 }
1945
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001946 /* Check for the start of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001947 if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001948 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001949 if ( !( p->flags & BDF_FONT_BBX_ ) )
Werner Lembergfb690292010-06-23 10:00:52 +02001950 {
1951 /* Missing the FONTBOUNDINGBOX field. */
1952 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001953 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergfb690292010-06-23 10:00:52 +02001954 goto Exit;
1955 }
1956
David Turner68df4f72005-03-15 18:18:57 +00001957 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001958 if ( error )
1959 goto Exit;
Werner Lembergb6b26f42016-06-09 06:53:48 +02001960
Werner Lembergb66efef2009-03-12 08:07:49 +00001961 /* at this point, `p->font' can't be NULL */
Ben Wagnera512b0f2015-12-14 09:19:52 +01001962 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1] );
Werner Lembergb6b26f42016-06-09 06:53:48 +02001963 /* We need at least 4 bytes per property. */
1964 if ( p->cnt > p->size / 4 )
1965 {
1966 p->font->props_size = 0;
1967
1968 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "STARTPROPERTIES" ));
1969 error = FT_THROW( Invalid_Argument );
1970 goto Exit;
1971 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001972
1973 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
Werner Lemberg9b6b5752012-12-15 01:34:41 +01001974 {
1975 p->font->props_size = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001976 goto Exit;
Werner Lemberg9b6b5752012-12-15 01:34:41 +01001977 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001978
Werner Lemberg758587d2016-01-12 22:20:06 +01001979 p->flags |= BDF_PROPS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001980 *next = _bdf_parse_properties;
1981
1982 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001983 }
1984
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001985 /* Check for the FONTBOUNDINGBOX field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001986 if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001987 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001988 if ( !( p->flags & BDF_SIZE_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001989 {
1990 /* Missing the SIZE field. */
1991 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001992 error = FT_THROW( Missing_Size_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001993 goto Exit;
1994 }
1995
David Turner68df4f72005-03-15 18:18:57 +00001996 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001997 if ( error )
1998 goto Exit;
1999
Ben Wagnera512b0f2015-12-14 09:19:52 +01002000 p->font->bbx.width = _bdf_atous( p->list.field[1] );
2001 p->font->bbx.height = _bdf_atous( p->list.field[2] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002002
Ben Wagnera512b0f2015-12-14 09:19:52 +01002003 p->font->bbx.x_offset = _bdf_atos( p->list.field[3] );
2004 p->font->bbx.y_offset = _bdf_atos( p->list.field[4] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002005
David Turnerd490e372002-05-28 23:40:37 +00002006 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002007 p->font->bbx.y_offset );
2008
2009 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002010
Werner Lemberg758587d2016-01-12 22:20:06 +01002011 p->flags |= BDF_FONT_BBX_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002012
2013 goto Exit;
2014 }
2015
2016 /* The next thing to check for is the FONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002017 if ( _bdf_strncmp( line, "FONT", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002018 {
David Turner68df4f72005-03-15 18:18:57 +00002019 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002020 if ( error )
2021 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002022 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002023
David Turner68df4f72005-03-15 18:18:57 +00002024 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002025
2026 if ( !s )
2027 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002028 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002029 error = FT_THROW( Invalid_File_Format );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002030 goto Exit;
2031 }
2032
Werner Lembergfb690292010-06-23 10:00:52 +02002033 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2034 FT_FREE( p->font->name );
2035
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002036 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2037 goto Exit;
2038 FT_MEM_COPY( p->font->name, s, slen + 1 );
2039
2040 /* If the font name is an XLFD name, set the spacing to the one in */
2041 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002042 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002043 if ( error )
2044 goto Exit;
2045
Werner Lemberg758587d2016-01-12 22:20:06 +01002046 p->flags |= BDF_FONT_NAME_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002047
2048 goto Exit;
2049 }
2050
2051 /* Check for the SIZE field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002052 if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002053 {
Werner Lemberg758587d2016-01-12 22:20:06 +01002054 if ( !( p->flags & BDF_FONT_NAME_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002055 {
2056 /* Missing the FONT field. */
2057 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002058 error = FT_THROW( Missing_Font_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002059 goto Exit;
2060 }
2061
David Turner68df4f72005-03-15 18:18:57 +00002062 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002063 if ( error )
2064 goto Exit;
2065
Ben Wagnera512b0f2015-12-14 09:19:52 +01002066 p->font->point_size = _bdf_atoul( p->list.field[1] );
2067 p->font->resolution_x = _bdf_atoul( p->list.field[2] );
2068 p->font->resolution_y = _bdf_atoul( p->list.field[3] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002069
2070 /* Check for the bits per pixel field. */
2071 if ( p->list.used == 5 )
2072 {
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002073 unsigned short bpp;
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002074
2075
Ben Wagnera512b0f2015-12-14 09:19:52 +01002076 bpp = (unsigned short)_bdf_atos( p->list.field[4] );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002077
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002078 /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
2079 if ( bpp > 4 )
2080 p->font->bpp = 8;
2081 else if ( bpp > 2 )
2082 p->font->bpp = 4;
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002083 else if ( bpp > 1 )
2084 p->font->bpp = 2;
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002085 else
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002086 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002087
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002088 if ( p->font->bpp != bpp )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002089 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002090 }
2091 else
2092 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002093
Werner Lemberg758587d2016-01-12 22:20:06 +01002094 p->flags |= BDF_SIZE_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002095
2096 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002097 }
2098
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002099 /* Check for the CHARS field -- font properties are optional */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002100 if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002101 {
2102 char nbuf[128];
2103
2104
Werner Lemberg758587d2016-01-12 22:20:06 +01002105 if ( !( p->flags & BDF_FONT_BBX_ ) )
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002106 {
2107 /* Missing the FONTBOUNDINGBOX field. */
2108 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002109 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002110 goto Exit;
2111 }
2112
2113 /* Add the two standard X11 properties which are required */
2114 /* for compiling fonts. */
2115 p->font->font_ascent = p->font->bbx.ascent;
2116 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002117 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2118 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002119 if ( error )
2120 goto Exit;
2121 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2122
2123 p->font->font_descent = p->font->bbx.descent;
2124 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002125 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2126 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002127 if ( error )
2128 goto Exit;
2129 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2130
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002131 *next = _bdf_parse_glyphs;
2132
2133 /* A special return value. */
2134 error = -1;
2135 goto Exit;
2136 }
2137
Werner Lemberge01406b2011-11-25 09:44:28 +01002138 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002139 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002140
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002141 Exit:
2142 return error;
2143 }
David Turner993a8d02002-05-18 12:03:43 +00002144
2145
Werner Lemberg9ac90602018-06-03 09:01:17 +02002146 /**************************************************************************
2147 *
2148 * API.
2149 *
2150 */
David Turner993a8d02002-05-18 12:03:43 +00002151
David Turner993a8d02002-05-18 12:03:43 +00002152
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002153 FT_LOCAL_DEF( FT_Error )
2154 bdf_load_font( FT_Stream stream,
2155 FT_Memory extmemory,
2156 bdf_options_t* opts,
2157 bdf_font_t* *font )
2158 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002159 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002160 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002161
Sean McBride7be2a942014-02-08 13:55:38 +01002162 FT_Memory memory = extmemory; /* needed for FT_NEW */
2163 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002164
2165
David Turner68df4f72005-03-15 18:18:57 +00002166 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002167 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002168
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002169 memory = NULL;
2170 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2171 p->minlb = 32767;
Werner Lemberge1ca18d2015-10-17 11:51:27 +02002172 p->size = stream->size;
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002173 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002174
David Turner68df4f72005-03-15 18:18:57 +00002175 _bdf_list_init( &p->list, extmemory );
2176
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002177 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002178 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002179 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002180 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002181
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002182 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002183 {
2184 /* If the font is not proportional, set the font's monowidth */
2185 /* field to the width of the font bounding box. */
David Turner993a8d02002-05-18 12:03:43 +00002186
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002187 if ( p->font->spacing != BDF_PROPORTIONAL )
2188 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002189
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002190 /* If the number of glyphs loaded is not that of the original count, */
2191 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002192 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002193 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002194 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2195 p->font->glyphs_used + p->font->unencoded_used ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002196 }
2197
2198 /* Once the font has been loaded, adjust the overall font metrics if */
2199 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002200 if ( p->opts->correct_metrics != 0 &&
2201 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002202 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002203 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002204 {
2205 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002206 p->font->bbx.width, p->maxrb - p->minlb ));
2207 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
David Turner993a8d02002-05-18 12:03:43 +00002208 }
2209
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002210 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002211 {
2212 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002213 p->font->bbx.x_offset, p->minlb ));
2214 p->font->bbx.x_offset = p->minlb;
David Turner993a8d02002-05-18 12:03:43 +00002215 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002216
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002217 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002218 {
2219 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002220 p->font->bbx.ascent, p->maxas ));
2221 p->font->bbx.ascent = p->maxas;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002222 }
2223
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002224 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002225 {
2226 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002227 p->font->bbx.descent, p->maxds ));
2228 p->font->bbx.descent = p->maxds;
2229 p->font->bbx.y_offset = (short)( -p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002230 }
2231
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002232 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002233 {
2234 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002235 p->font->bbx.height, p->maxas + p->maxds ));
2236 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002237 }
2238
Werner Lemberg758587d2016-01-12 22:20:06 +01002239 if ( p->flags & BDF_SWIDTH_ADJ_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002240 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2241 }
David Turner993a8d02002-05-18 12:03:43 +00002242 }
2243
Werner Lemberg758587d2016-01-12 22:20:06 +01002244 if ( p->flags & BDF_START_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002245 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002246 /* The ENDFONT field was never reached or did not exist. */
Werner Lemberg758587d2016-01-12 22:20:06 +01002247 if ( !( p->flags & BDF_GLYPHS_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002248 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002249 /* Error happened while parsing header. */
2250 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002251 error = FT_THROW( Corrupted_Font_Header );
Bungeman65d89802015-10-15 23:50:16 +02002252 goto Fail;
Werner Lemberge01406b2011-11-25 09:44:28 +01002253 }
2254 else
2255 {
2256 /* Error happened when parsing glyphs. */
2257 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002258 error = FT_THROW( Corrupted_Font_Glyphs );
Bungeman65d89802015-10-15 23:50:16 +02002259 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002260 }
David Turner993a8d02002-05-18 12:03:43 +00002261 }
2262
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002263 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002264 {
2265 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002266 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002267
Werner Lemberg370aea82010-06-08 08:37:11 +02002268 if ( p->font->comments_len > 0 )
2269 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002270 if ( FT_RENEW_ARRAY( p->font->comments,
2271 p->font->comments_len,
2272 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002273 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002274
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002275 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002276 }
David Turner993a8d02002-05-18 12:03:43 +00002277 }
Werner Lemberg5d664b62016-12-17 20:47:42 +01002278 else if ( !error )
Werner Lemberg059bc332013-03-14 10:27:35 +01002279 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002280
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002281 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002282
2283 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002284 if ( p )
2285 {
David Turner68df4f72005-03-15 18:18:57 +00002286 _bdf_list_done( &p->list );
2287
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002288 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002289
Werner Lemberg4a150132015-11-25 07:53:49 +01002290 FT_FREE( p->glyph_name );
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002291 FT_FREE( p );
2292 }
2293
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002294 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002295
2296 Fail:
2297 bdf_free_font( p->font );
2298
2299 memory = extmemory;
2300
2301 FT_FREE( p->font );
2302
2303 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002304 }
David Turner993a8d02002-05-18 12:03:43 +00002305
2306
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002307 FT_LOCAL_DEF( void )
2308 bdf_free_font( bdf_font_t* font )
2309 {
2310 bdf_property_t* prop;
2311 unsigned long i;
2312 bdf_glyph_t* glyphs;
2313 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002314
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002315
2316 if ( font == 0 )
2317 return;
David Turner993a8d02002-05-18 12:03:43 +00002318
2319 memory = font->memory;
2320
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002321 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002322
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002323 /* Free up the internal hash table of property names. */
2324 if ( font->internal )
2325 {
Werner Lemberg7ce6c432015-12-22 05:39:58 +01002326 ft_hash_str_free( (FT_Hash)font->internal, memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002327 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002328 }
2329
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002330 /* Free up the comment info. */
2331 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002332
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002333 /* Free up the properties. */
2334 for ( i = 0; i < font->props_size; i++ )
2335 {
2336 if ( font->props[i].format == BDF_ATOM )
2337 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002338 }
2339
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002340 FT_FREE( font->props );
2341
2342 /* Free up the character info. */
2343 for ( i = 0, glyphs = font->glyphs;
2344 i < font->glyphs_used; i++, glyphs++ )
2345 {
2346 FT_FREE( glyphs->name );
2347 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002348 }
2349
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002350 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2351 i++, glyphs++ )
2352 {
2353 FT_FREE( glyphs->name );
2354 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002355 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002356
2357 FT_FREE( font->glyphs );
2358 FT_FREE( font->unencoded );
2359
David Turner993a8d02002-05-18 12:03:43 +00002360 /* bdf_cleanup */
Werner Lemberg7ce6c432015-12-22 05:39:58 +01002361 ft_hash_str_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002362
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002363 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002364 for ( prop = font->user_props, i = 0;
2365 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002366 {
2367 FT_FREE( prop->name );
2368 if ( prop->format == BDF_ATOM )
2369 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002370 }
David Turner993a8d02002-05-18 12:03:43 +00002371
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002372 FT_FREE( font->user_props );
2373
2374 /* FREE( font ); */ /* XXX Fixme */
2375 }
David Turner993a8d02002-05-18 12:03:43 +00002376
2377
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002378 FT_LOCAL_DEF( bdf_property_t * )
2379 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002380 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002381 {
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002382 size_t* propid;
David Turner993a8d02002-05-18 12:03:43 +00002383
David Turner993a8d02002-05-18 12:03:43 +00002384
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002385 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002386 return 0;
2387
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002388 propid = ft_hash_str_lookup( name, (FT_Hash)font->internal );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002389
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002390 return propid ? ( font->props + *propid ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002391 }
2392
2393
2394/* END */