blob: eebdbf85eb02436eb5551aac54ddd21814d14eb7 [file] [log] [blame]
David Turner993a8d02002-05-18 12:03:43 +00001/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
Alexei Podtelezhnikovefa2a3b2018-08-15 23:49:07 -04003 * 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
David Turner993a8d02002-05-18 12:03:43 +000034
David Turnere1339132020-06-08 13:31:55 +020035#include <freetype/freetype.h>
36#include <freetype/internal/ftdebug.h>
37#include <freetype/internal/ftstream.h>
38#include <freetype/internal/ftobjs.h>
David Turner993a8d02002-05-18 12:03:43 +000039
40#include "bdf.h"
David Turner993a8d02002-05-18 12:03:43 +000041#include "bdferror.h"
42
David Turner993a8d02002-05-18 12:03:43 +000043
Werner Lemberg9ac90602018-06-03 09:01:17 +020044 /**************************************************************************
45 *
46 * The macro FT_COMPONENT is used in trace mode. It is an implicit
47 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
48 * messages during execution.
49 */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000050#undef FT_COMPONENT
Werner Lemberga0dd16f2018-08-15 18:13:17 +020051#define FT_COMPONENT bdflib
David Turner993a8d02002-05-18 12:03:43 +000052
David Turner993a8d02002-05-18 12:03:43 +000053
Werner Lemberg9ac90602018-06-03 09:01:17 +020054 /**************************************************************************
55 *
56 * Default BDF font options.
57 *
58 */
David Turner993a8d02002-05-18 12:03:43 +000059
David Turner993a8d02002-05-18 12:03:43 +000060
David Turnerb1b47622002-05-21 21:17:43 +000061 static const bdf_options_t _bdf_opts =
Werner Lemberg7cf4d372002-05-21 14:13:01 +000062 {
David Turner993a8d02002-05-18 12:03:43 +000063 1, /* Correct metrics. */
64 1, /* Preserve unencoded glyphs. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000065 0, /* Preserve comments. */
66 BDF_PROPORTIONAL /* Default spacing. */
67 };
David Turner993a8d02002-05-18 12:03:43 +000068
David Turner993a8d02002-05-18 12:03:43 +000069
Werner Lemberg9ac90602018-06-03 09:01:17 +020070 /**************************************************************************
71 *
72 * Builtin BDF font properties.
73 *
74 */
David Turner993a8d02002-05-18 12:03:43 +000075
Werner Lemberg7cf4d372002-05-21 14:13:01 +000076 /* List of most properties that might appear in a font. Doesn't include */
77 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
David Turner993a8d02002-05-18 12:03:43 +000078
David Turnerb1b47622002-05-21 21:17:43 +000079 static const bdf_property_t _bdf_properties[] =
David Turner993a8d02002-05-18 12:03:43 +000080 {
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -040081 { "ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
82 { "AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
83 { "AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
84 { "AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
85 { "CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
86 { "CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
87 { "CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
88 { "CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
89 { "COMMENT", BDF_ATOM, 1, { 0 } },
90 { "COPYRIGHT", BDF_ATOM, 1, { 0 } },
91 { "DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
92 { "DESTINATION", BDF_CARDINAL, 1, { 0 } },
93 { "DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
94 { "END_SPACE", BDF_INTEGER, 1, { 0 } },
95 { "FACE_NAME", BDF_ATOM, 1, { 0 } },
96 { "FAMILY_NAME", BDF_ATOM, 1, { 0 } },
97 { "FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
98 { "FONT", BDF_ATOM, 1, { 0 } },
99 { "FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
100 { "FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
101 { "FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
102 { "FOUNDRY", BDF_ATOM, 1, { 0 } },
103 { "FULL_NAME", BDF_ATOM, 1, { 0 } },
104 { "ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
105 { "MAX_SPACE", BDF_INTEGER, 1, { 0 } },
106 { "MIN_SPACE", BDF_INTEGER, 1, { 0 } },
107 { "NORM_SPACE", BDF_INTEGER, 1, { 0 } },
108 { "NOTICE", BDF_ATOM, 1, { 0 } },
109 { "PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
110 { "POINT_SIZE", BDF_INTEGER, 1, { 0 } },
111 { "QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
112 { "RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
113 { "RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
114 { "RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
115 { "RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
116 { "RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
117 { "RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
118 { "RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
119 { "RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
120 { "RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
121 { "RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
122 { "RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
123 { "RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
124 { "RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
125 { "RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
126 { "RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
127 { "RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
128 { "RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
129 { "RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
130 { "RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
131 { "RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
132 { "RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
133 { "RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
134 { "RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
135 { "RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
136 { "RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
137 { "RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
138 { "RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
139 { "RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
140 { "RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
141 { "RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
142 { "RESOLUTION", BDF_INTEGER, 1, { 0 } },
143 { "RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
144 { "RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
145 { "SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
146 { "SLANT", BDF_ATOM, 1, { 0 } },
147 { "SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
148 { "SPACING", BDF_ATOM, 1, { 0 } },
149 { "STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
150 { "STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
151 { "SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
152 { "SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
153 { "SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
154 { "SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
155 { "SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
156 { "SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
157 { "UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
158 { "UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
159 { "WEIGHT", BDF_CARDINAL, 1, { 0 } },
160 { "WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
161 { "X_HEIGHT", BDF_INTEGER, 1, { 0 } },
162 { "_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
163 { "_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000164 };
David Turner993a8d02002-05-18 12:03:43 +0000165
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000166 static const unsigned long
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000167 _num_bdf_properties = sizeof ( _bdf_properties ) /
168 sizeof ( _bdf_properties[0] );
David Turner993a8d02002-05-18 12:03:43 +0000169
170
Werner Lemberg2c4832d2014-11-07 07:42:33 +0100171 /* An auxiliary macro to parse properties, to be used in conditionals. */
172 /* It behaves like `strncmp' but also tests the following character */
173 /* whether it is a whitespace or NULL. */
174 /* `property' is a constant string of length `n' to compare with. */
175#define _bdf_strncmp( name, property, n ) \
176 ( ft_strncmp( name, property, n ) || \
177 !( name[n] == ' ' || \
178 name[n] == '\0' || \
179 name[n] == '\n' || \
180 name[n] == '\r' || \
181 name[n] == '\t' ) )
182
Werner Lemberge01406b2011-11-25 09:44:28 +0100183 /* Auto correction messages. */
184#define ACMSG1 "FONT_ASCENT property missing. " \
185 "Added `FONT_ASCENT %hd'.\n"
186#define ACMSG2 "FONT_DESCENT property missing. " \
187 "Added `FONT_DESCENT %hd'.\n"
Priyesh Kumar6d9e6b22020-08-28 09:56:38 +0530188#define ACMSG3 "Font width != actual width. Old: %d New: %d.\n"
Werner Lemberge01406b2011-11-25 09:44:28 +0100189#define ACMSG4 "Font left bearing != actual left bearing. " \
190 "Old: %hd New: %hd.\n"
191#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
Priyesh Kumar6d9e6b22020-08-28 09:56:38 +0530192#define ACMSG6 "Font descent != actual descent. Old: %d New: %d.\n"
Werner Lemberg92db1492020-12-02 07:54:21 +0100193#define ACMSG7 "Font height != actual height. Old: %d New: %d.\n"
Werner Lemberge01406b2011-11-25 09:44:28 +0100194#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
195#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
196#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
197#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -0400198#define ACMSG13 "Glyph %lu extra rows removed.\n"
199#define ACMSG14 "Glyph %lu extra columns removed.\n"
Werner Lemberge01406b2011-11-25 09:44:28 +0100200#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -0400201#define ACMSG16 "Glyph %lu missing columns padded with zero bits.\n"
Werner Lemberge1ca18d2015-10-17 11:51:27 +0200202#define ACMSG17 "Adjusting number of glyphs to %ld.\n"
Werner Lemberge01406b2011-11-25 09:44:28 +0100203
204 /* Error messages. */
205#define ERRMSG1 "[line %ld] Missing `%s' line.\n"
206#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
207#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
208#define ERRMSG4 "[line %ld] BBX too big.\n"
Alexei Podtelezhnikovaf9662e2018-08-15 22:58:11 -0400209#define ERRMSG5 "[line %ld] `%s' value 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
Alexei Podtelezhnikov2f62d8e2021-05-07 09:33:41 -0400331 if ( FT_QRENEW_ARRAY( list->field, oldsize, newsize ) )
David Turner68df4f72005-03-15 18:18:57 +0000332 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
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -0400366 static const char empty[] = ""; /* XXX eliminate this */
Werner Lembergf4c94d42010-06-19 16:08:31 +0200367
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,
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -0400409 const char* separators,
David Turner68df4f72005-03-15 18:18:57 +0000410 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;
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -0400415 const char *sp, *end;
416 char *ep;
Werner Lemberg3c374c82015-02-22 09:16:53 +0100417 char seps[32];
418 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000419
420
421 /* Initialize the list. */
422 list->used = 0;
Werner Lembergd9c16592012-03-01 15:15:00 +0100423 if ( list->size )
424 {
425 list->field[0] = (char*)empty;
426 list->field[1] = (char*)empty;
427 list->field[2] = (char*)empty;
428 list->field[3] = (char*)empty;
Werner Lemberg649c6732012-03-16 21:12:41 +0100429 list->field[4] = (char*)empty;
Werner Lembergd9c16592012-03-01 15:15:00 +0100430 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000431
432 /* If the line is empty, then simply return. */
433 if ( linelen == 0 || line[0] == 0 )
434 goto Exit;
435
436 /* In the original code, if the `separators' parameter is NULL or */
437 /* empty, the list is split into individual bytes. We don't need */
438 /* this, so an error is signaled. */
439 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000440 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100441 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000442 goto Exit;
443 }
444
445 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000446 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000447
448 /* If the very last character of the separator string is a plus, then */
449 /* set the `mult' flag to indicate that multiple separators should be */
450 /* collapsed into one. */
451 for ( mult = 0, sp = separators; sp && *sp; sp++ )
452 {
453 if ( *sp == '+' && *( sp + 1 ) == 0 )
454 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000455 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000456 setsbit( seps, *sp );
457 }
458
459 /* Break the line up into fields. */
460 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
461 sp < end && *sp; )
462 {
463 /* Collect everything that is not a separator. */
464 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
465 ;
466
467 /* Resize the list if necessary. */
468 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000469 {
Werner Lembergebf55852005-03-16 01:49:54 +0000470 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000471 if ( error )
472 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000473 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000474
475 /* Assign the field appropriately. */
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -0400476 list->field[list->used++] = ( ep > sp ) ? (char*)sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000477
478 sp = ep;
479
480 if ( mult )
481 {
482 /* If multiple separators should be collapsed, do it now by */
483 /* setting all the separator characters to 0. */
484 for ( ; *ep && sbitset( seps, *ep ); ep++ )
485 *ep = 0;
486 }
487 else if ( *ep != 0 )
488 /* Don't collapse multiple separators by making them 0, so just */
489 /* make the one encountered 0. */
490 *ep++ = 0;
491
492 final_empty = ( ep > sp && *ep == 0 );
493 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000494 }
495
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000496 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000497 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000498 {
Werner Lembergebf55852005-03-16 01:49:54 +0000499 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000500 if ( error )
501 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000502 }
503
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000504 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000505 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000506
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000507 list->field[list->used] = 0;
508
509 Exit:
510 return error;
David Turner993a8d02002-05-18 12:03:43 +0000511 }
512
David Turner993a8d02002-05-18 12:03:43 +0000513
David Turner68df4f72005-03-15 18:18:57 +0000514#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000515
Werner Lembergebf55852005-03-16 01:49:54 +0000516
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000517 static FT_Error
518 _bdf_readstream( FT_Stream stream,
519 _bdf_line_func_t callback,
520 void* client_data,
521 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000522 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000523 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000524 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900525 int refill, hold, to_skip;
526 ptrdiff_t bytes, start, end, cursor, avail;
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -0400527 char* buf = NULL;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000528 FT_Memory memory = stream->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100529 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000530
David Turner993a8d02002-05-18 12:03:43 +0000531
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000532 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000533 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100534 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000535 goto Exit;
536 }
David Turner993a8d02002-05-18 12:03:43 +0000537
Werner Lembergebf55852005-03-16 01:49:54 +0000538 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000539 buf_size = 1024;
540
Alexei Podtelezhnikovc2d28312021-04-25 23:33:15 -0400541 if ( FT_QALLOC( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000542 goto Exit;
543
Werner Lembergebf55852005-03-16 01:49:54 +0000544 cb = callback;
545 lineno = 1;
546 buf[0] = 0;
547 start = 0;
Werner Lembergebf55852005-03-16 01:49:54 +0000548 avail = 0;
549 cursor = 0;
550 refill = 1;
551 to_skip = NO_SKIP;
552 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000553
David Turner68df4f72005-03-15 18:18:57 +0000554 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000555 {
David Turner68df4f72005-03-15 18:18:57 +0000556 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000557 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +0200558 bytes = (ptrdiff_t)FT_Stream_TryRead(
559 stream, (FT_Byte*)buf + cursor,
Werner Lemberg3c374c82015-02-22 09:16:53 +0100560 buf_size - (unsigned long)cursor );
David Turner68df4f72005-03-15 18:18:57 +0000561 avail = cursor + bytes;
562 cursor = 0;
563 refill = 0;
564 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000565
David Turner68df4f72005-03-15 18:18:57 +0000566 end = start;
567
Werner Lembergebf55852005-03-16 01:49:54 +0000568 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000569 if ( start < avail && buf[start] == to_skip )
570 {
571 start += 1;
572 to_skip = NO_SKIP;
573 continue;
574 }
575
576 /* try to find the end of the line */
577 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
578 end++;
579
Werner Lembergebf55852005-03-16 01:49:54 +0000580 /* if we hit the end of the buffer, try shifting its content */
581 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000582 if ( end >= avail )
583 {
584 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
585 break; /* ignore it then exit */
586
587 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000588 {
Werner Lembergebf55852005-03-16 01:49:54 +0000589 /* this line is definitely too long; try resizing the input */
590 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000591 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000592
Werner Lembergebf55852005-03-16 01:49:54 +0000593
594 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000595 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100596 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +0100597 error = FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +0000598 goto Exit;
599 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000600
Werner Lembergebf55852005-03-16 01:49:54 +0000601 new_size = buf_size * 2;
Alexei Podtelezhnikovc2d28312021-04-25 23:33:15 -0400602 if ( FT_QREALLOC( buf, buf_size, new_size ) )
David Turner68df4f72005-03-15 18:18:57 +0000603 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000604
Werner Lemberg3c374c82015-02-22 09:16:53 +0100605 cursor = (ptrdiff_t)buf_size;
David Turner68df4f72005-03-15 18:18:57 +0000606 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000607 }
608 else
609 {
David Turner68df4f72005-03-15 18:18:57 +0000610 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000611
Werner Lemberg04e547b2013-04-03 07:37:56 +0200612 FT_MEM_MOVE( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000613
David Turner68df4f72005-03-15 18:18:57 +0000614 cursor = bytes;
615 avail -= bytes;
616 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000617 }
David Turner68df4f72005-03-15 18:18:57 +0000618 refill = 1;
619 continue;
David Turner993a8d02002-05-18 12:03:43 +0000620 }
David Turner68df4f72005-03-15 18:18:57 +0000621
622 /* Temporarily NUL-terminate the line. */
623 hold = buf[end];
624 buf[end] = 0;
625
Werner Lemberg0098d552014-12-07 11:03:57 +0100626 /* XXX: Use encoding independent value for 0x1A */
627 if ( buf[start] != '#' && buf[start] != 0x1A && end > start )
David Turner68df4f72005-03-15 18:18:57 +0000628 {
Werner Lemberga9f6f852012-12-17 09:08:09 +0100629 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergebf55852005-03-16 01:49:54 +0000630 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200631 /* Redo if we have encountered CHARS without properties. */
632 if ( error == -1 )
Werner Lemberga9f6f852012-12-17 09:08:09 +0100633 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200634 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000635 if ( error )
636 break;
637 }
638
639 lineno += 1;
640 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000641 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000642
643 if ( hold == '\n' )
644 to_skip = '\r';
645 else if ( hold == '\r' )
646 to_skip = '\n';
647 else
648 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000649 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000650
David Turner68df4f72005-03-15 18:18:57 +0000651 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000652
653 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000654 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000655 return error;
David Turner993a8d02002-05-18 12:03:43 +0000656 }
David Turner993a8d02002-05-18 12:03:43 +0000657
658
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000659 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000660
David Turnerb1b47622002-05-21 21:17:43 +0000661 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000662 {
David Turner993a8d02002-05-18 12:03:43 +0000663 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
667 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
Werner Lemberg0098d552014-12-07 11:03:57 +0100668 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000669 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg0098d552014-12-07 11:03:57 +0100671 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000672 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
673 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000674 };
David Turner993a8d02002-05-18 12:03:43 +0000675
David Turnerb1b47622002-05-21 21:17:43 +0000676 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000677 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100678 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
David Turner993a8d02002-05-18 12:03:43 +0000679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
680 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000682 };
David Turner993a8d02002-05-18 12:03:43 +0000683
David Turnerb1b47622002-05-21 21:17:43 +0000684 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000685 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100686 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
687 0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000688 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
689 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000690 };
David Turner993a8d02002-05-18 12:03:43 +0000691
David Turner993a8d02002-05-18 12:03:43 +0000692
Ben Wagnera512b0f2015-12-14 09:19:52 +0100693 /* Routine to convert a decimal ASCII string to an unsigned long integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000694 static unsigned long
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -0400695 _bdf_atoul( const char* s )
David Turner993a8d02002-05-18 12:03:43 +0000696 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100697 unsigned long v;
David Turner993a8d02002-05-18 12:03:43 +0000698
699
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000700 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000701 return 0;
702
Ben Wagnera512b0f2015-12-14 09:19:52 +0100703 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200704 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100705 if ( v < ( FT_ULONG_MAX - 9 ) / 10 )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200706 v = v * 10 + a2i[(int)*s];
707 else
708 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100709 v = FT_ULONG_MAX;
Werner Lemberg47a03e92017-06-02 09:06:36 +0200710 break;
711 }
712 }
David Turner993a8d02002-05-18 12:03:43 +0000713
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000714 return v;
715 }
David Turner993a8d02002-05-18 12:03:43 +0000716
David Turner993a8d02002-05-18 12:03:43 +0000717
Ben Wagnera512b0f2015-12-14 09:19:52 +0100718 /* Routine to convert a decimal ASCII string to a signed long integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000719 static long
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -0400720 _bdf_atol( const char* s )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000721 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100722 long v, neg;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000723
724
725 if ( s == 0 || *s == 0 )
726 return 0;
727
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000728 /* Check for a minus sign. */
729 neg = 0;
730 if ( *s == '-' )
731 {
732 s++;
733 neg = 1;
734 }
735
Ben Wagnera512b0f2015-12-14 09:19:52 +0100736 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200737 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100738 if ( v < ( FT_LONG_MAX - 9 ) / 10 )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200739 v = v * 10 + a2i[(int)*s];
740 else
741 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100742 v = FT_LONG_MAX;
Werner Lemberg47a03e92017-06-02 09:06:36 +0200743 break;
744 }
745 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000746
747 return ( !neg ) ? v : -v;
748 }
749
750
Ben Wagnera512b0f2015-12-14 09:19:52 +0100751 /* Routine to convert a decimal ASCII string to an unsigned short integer. */
Werner Lembergb13945a2015-02-22 09:15:47 +0100752 static unsigned short
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -0400753 _bdf_atous( const char* s )
Werner Lembergb13945a2015-02-22 09:15:47 +0100754 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100755 unsigned short v;
Werner Lembergb13945a2015-02-22 09:15:47 +0100756
757
758 if ( s == 0 || *s == 0 )
759 return 0;
760
Ben Wagnera512b0f2015-12-14 09:19:52 +0100761 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200762 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100763 if ( v < ( FT_USHORT_MAX - 9 ) / 10 )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200764 v = (unsigned short)( v * 10 + a2i[(int)*s] );
765 else
766 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100767 v = FT_USHORT_MAX;
Werner Lemberg47a03e92017-06-02 09:06:36 +0200768 break;
769 }
770 }
Werner Lembergb13945a2015-02-22 09:15:47 +0100771
772 return v;
773 }
774
775
Ben Wagnera512b0f2015-12-14 09:19:52 +0100776 /* Routine to convert a decimal ASCII string to a signed short integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000777 static short
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -0400778 _bdf_atos( const char* s )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000779 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100780 short v, neg;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000781
782
783 if ( s == 0 || *s == 0 )
784 return 0;
785
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000786 /* Check for a minus. */
787 neg = 0;
788 if ( *s == '-' )
789 {
790 s++;
791 neg = 1;
792 }
793
Ben Wagnera512b0f2015-12-14 09:19:52 +0100794 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200795 {
796 if ( v < ( SHRT_MAX - 9 ) / 10 )
797 v = (short)( v * 10 + a2i[(int)*s] );
798 else
799 {
800 v = SHRT_MAX;
801 break;
802 }
803 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000804
Werner Lemberg233302a2002-05-22 05:41:06 +0000805 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000806 }
807
808
809 /* Routine to compare two glyphs by encoding so they can be sorted. */
Alexei Podtelezhnikov70fd20e2021-02-12 19:28:05 -0500810 FT_COMPARE_DEF( int )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000811 by_encoding( const void* a,
812 const void* b )
813 {
814 bdf_glyph_t *c1, *c2;
815
816
817 c1 = (bdf_glyph_t *)a;
818 c2 = (bdf_glyph_t *)b;
819
820 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000821 return -1;
David Turner68df4f72005-03-15 18:18:57 +0000822
823 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000824 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000825
David Turner993a8d02002-05-18 12:03:43 +0000826 return 0;
David Turner993a8d02002-05-18 12:03:43 +0000827 }
828
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000829
830 static FT_Error
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -0400831 bdf_create_property( const char* name,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000832 int format,
833 bdf_font_t* font )
834 {
suzuki toshiya704f4d72009-09-13 00:50:14 +0900835 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000836 bdf_property_t* p;
837 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100838 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000839
840
Werner Lemberg96ddc672011-06-29 09:15:54 +0200841 /* First check whether the property has */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000842 /* already been added or not. If it has, then */
843 /* simply ignore it. */
Werner Lemberg609546c2015-12-20 07:17:29 +0100844 if ( ft_hash_str_lookup( name, &(font->proptbl) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000845 goto Exit;
846
Alexei Podtelezhnikovec95f9c2021-05-02 18:30:22 -0400847 if ( FT_QRENEW_ARRAY( font->user_props,
848 font->nuser_props,
849 font->nuser_props + 1 ) )
David Turner68df4f72005-03-15 18:18:57 +0000850 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000851
852 p = font->user_props + font->nuser_props;
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
Alexei Podtelezhnikovc2d28312021-04-25 23:33:15 -0400858 if ( FT_QALLOC( p->name, n ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000859 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
Alexei Podtelezhnikovec95f9c2021-05-02 18:30:22 -0400944 if ( FT_QRENEW_ARRAY( font->comments,
945 font->comments_len,
946 font->comments_len + len + 1 ) )
David Turner68df4f72005-03-15 18:18:57 +0000947 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
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001000 error = _bdf_list_split( &list, "-", 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,
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001099 const char* name,
Werner Lemberge01406b2011-11-25 09:44:28 +01001100 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 {
Alexei Podtelezhnikovec95f9c2021-05-02 18:30:22 -04001161 if ( FT_QRENEW_ARRAY( font->props,
1162 font->props_size,
1163 font->props_size + 1 ) )
Alexei Podtelezhnikovc2d28312021-04-25 23:33:15 -04001164 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001165
David Turner993a8d02002-05-18 12:03:43 +00001166 fp = font->props + font->props_size;
David Turner993a8d02002-05-18 12:03:43 +00001167 font->props_size++;
1168 }
1169
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001170 if ( *propid >= _num_bdf_properties )
1171 prop = font->user_props + ( *propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001172 else
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001173 prop = (bdf_property_t*)_bdf_properties + *propid;
David Turner993a8d02002-05-18 12:03:43 +00001174
1175 fp = font->props + font->props_used;
1176
1177 fp->name = prop->name;
1178 fp->format = prop->format;
1179 fp->builtin = prop->builtin;
1180
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001181 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001182 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001183 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001184 fp->value.atom = 0;
1185 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001186 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001187 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001188 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001189 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001190 break;
David Turner993a8d02002-05-18 12:03:43 +00001191
1192 case BDF_INTEGER:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001193 fp->value.l = _bdf_atol( value );
David Turner993a8d02002-05-18 12:03:43 +00001194 break;
1195
1196 case BDF_CARDINAL:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001197 fp->value.ul = _bdf_atoul( value );
David Turner993a8d02002-05-18 12:03:43 +00001198 break;
David Turner993a8d02002-05-18 12:03:43 +00001199 }
1200
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001201 /* If the property happens to be a comment, then it doesn't need */
1202 /* to be added to the internal hash table. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001203 if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 )
Werner Lemberg370aea82010-06-08 08:37:11 +02001204 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001205 /* Add the property to the font property table. */
Werner Lemberg609546c2015-12-20 07:17:29 +01001206 error = ft_hash_str_insert( fp->name,
1207 font->props_used,
1208 (FT_Hash)font->internal,
1209 memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001210 if ( error )
1211 goto Exit;
1212 }
David Turner993a8d02002-05-18 12:03:43 +00001213
1214 font->props_used++;
1215
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001216 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1217 /* property needs to be located if it exists in the property list, the */
1218 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1219 /* present, and the SPACING property should override the default */
1220 /* spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001221 if ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 )
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001222 font->default_char = fp->value.ul;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001223 else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001224 font->font_ascent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001225 else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001226 font->font_descent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001227 else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001228 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001229 if ( !fp->value.atom )
1230 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001231 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001232 error = FT_THROW( Invalid_File_Format );
Werner Lembergb66efef2009-03-12 08:07:49 +00001233 goto Exit;
1234 }
1235
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001236 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001237 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001238 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001239 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001240 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001241 font->spacing = BDF_CHARCELL;
1242 }
1243
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001244 Exit:
1245 return error;
David Turner993a8d02002-05-18 12:03:43 +00001246 }
1247
David Turner993a8d02002-05-18 12:03:43 +00001248
David Turnerb1b47622002-05-21 21:17:43 +00001249 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001250 {
1251 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1252 };
1253
1254
Werner Lembergf1b61832018-12-04 11:51:15 +01001255 static FT_Error
1256 _bdf_parse_end( char* line,
1257 unsigned long linelen,
1258 unsigned long lineno,
1259 void* call_data,
1260 void* client_data )
1261 {
1262 /* a no-op; we ignore everything after `ENDFONT' */
1263
1264 FT_UNUSED( line );
1265 FT_UNUSED( linelen );
1266 FT_UNUSED( lineno );
1267 FT_UNUSED( call_data );
1268 FT_UNUSED( client_data );
1269
1270 return FT_Err_Ok;
1271 }
1272
1273
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001274 /* Actually parse the glyph info and bitmaps. */
1275 static FT_Error
1276 _bdf_parse_glyphs( char* line,
1277 unsigned long linelen,
1278 unsigned long lineno,
1279 void* call_data,
1280 void* client_data )
1281 {
1282 int c, mask_index;
1283 char* s;
1284 unsigned char* bp;
1285 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001286
Werner Lembergf1b61832018-12-04 11:51:15 +01001287 _bdf_line_func_t* next;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001288 _bdf_parse_t* p;
1289 bdf_glyph_t* glyph;
1290 bdf_font_t* font;
1291
1292 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001293 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001294
1295 FT_UNUSED( lineno ); /* only used in debug mode */
1296
1297
Werner Lembergf1b61832018-12-04 11:51:15 +01001298 next = (_bdf_line_func_t *)call_data;
1299 p = (_bdf_parse_t *) client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001300
1301 font = p->font;
1302 memory = font->memory;
1303
1304 /* Check for a comment. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001305 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001306 {
1307 linelen -= 7;
1308
1309 s = line + 7;
1310 if ( *s != 0 )
1311 {
1312 s++;
1313 linelen--;
1314 }
1315 error = _bdf_add_comment( p->font, s, linelen );
1316 goto Exit;
1317 }
1318
1319 /* The very first thing expected is the number of glyphs. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001320 if ( !( p->flags & BDF_GLYPHS_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001321 {
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001322 if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001323 {
1324 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001325 error = FT_THROW( Missing_Chars_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001326 goto Exit;
1327 }
1328
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001329 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001330 if ( error )
1331 goto Exit;
Ben Wagnera512b0f2015-12-14 09:19:52 +01001332 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001333
Werner Lemberge1ca18d2015-10-17 11:51:27 +02001334 /* We need at least 20 bytes per glyph. */
1335 if ( p->cnt > p->size / 20 )
1336 {
Werner Lemberg797ca5a2015-10-17 11:57:16 +02001337 p->cnt = font->glyphs_size = p->size / 20;
Werner Lemberge1ca18d2015-10-17 11:51:27 +02001338 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG17, p->cnt ));
1339 }
1340
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001341 /* Make sure the number of glyphs is non-zero. */
1342 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001343 font->glyphs_size = 64;
1344
Werner Lemberga08b2172007-03-28 07:17:17 +00001345 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1346 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001347 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001348 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001349 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001350 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001351 goto Exit;
1352 }
1353
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001354 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1355 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001356
Werner Lemberg758587d2016-01-12 22:20:06 +01001357 p->flags |= BDF_GLYPHS_;
David Turner993a8d02002-05-18 12:03:43 +00001358
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001359 goto Exit;
1360 }
1361
1362 /* Check for the ENDFONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001363 if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001364 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001365 if ( p->flags & BDF_GLYPH_BITS_ )
Werner Lembergaf834612014-11-22 13:29:10 +01001366 {
1367 /* Missing ENDCHAR field. */
1368 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1369 error = FT_THROW( Corrupted_Font_Glyphs );
1370 goto Exit;
1371 }
1372
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001373 /* Sort the glyphs by encoding. */
1374 ft_qsort( (char *)font->glyphs,
1375 font->glyphs_used,
1376 sizeof ( bdf_glyph_t ),
1377 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001378
Werner Lemberg758587d2016-01-12 22:20:06 +01001379 p->flags &= ~BDF_START_;
Werner Lembergf1b61832018-12-04 11:51:15 +01001380 *next = _bdf_parse_end;
David Turner993a8d02002-05-18 12:03:43 +00001381
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001382 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001383 }
1384
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001385 /* Check for the ENDCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001386 if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001387 {
1388 p->glyph_enc = 0;
Werner Lemberg758587d2016-01-12 22:20:06 +01001389 p->flags &= ~BDF_GLYPH_BITS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001390
1391 goto Exit;
1392 }
1393
Werner Lemberg96ddc672011-06-29 09:15:54 +02001394 /* Check whether a glyph is being scanned but should be */
1395 /* ignored because it is an unencoded glyph. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001396 if ( ( p->flags & BDF_GLYPH_ ) &&
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001397 p->glyph_enc == -1 &&
1398 p->opts->keep_unencoded == 0 )
1399 goto Exit;
1400
1401 /* Check for the STARTCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001402 if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001403 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001404 if ( p->flags & BDF_GLYPH_BITS_ )
Werner Lembergb1857472015-10-17 14:21:41 +02001405 {
1406 /* Missing ENDCHAR field. */
1407 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1408 error = FT_THROW( Missing_Startchar_Field );
1409 goto Exit;
1410 }
1411
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001412 /* Set the character name in the parse info first until the */
1413 /* encoding can be checked for an unencoded character. */
1414 FT_FREE( p->glyph_name );
1415
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001416 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001417 if ( error )
1418 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001419
David Turner68df4f72005-03-15 18:18:57 +00001420 _bdf_list_shift( &p->list, 1 );
1421
1422 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001423
Werner Lembergba03af62007-05-30 13:57:02 +00001424 if ( !s )
1425 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001426 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001427 error = FT_THROW( Invalid_File_Format );
Werner Lembergba03af62007-05-30 13:57:02 +00001428 goto Exit;
1429 }
1430
Alexei Podtelezhnikovc2d28312021-04-25 23:33:15 -04001431 if ( FT_QALLOC( p->glyph_name, slen + 1 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001432 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001433
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001434 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1435
Werner Lemberg758587d2016-01-12 22:20:06 +01001436 p->flags |= BDF_GLYPH_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001437
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001438 FT_TRACE4(( DBGMSG1, lineno, s ));
1439
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001440 goto Exit;
1441 }
1442
1443 /* Check for the ENCODING field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001444 if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001445 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001446 if ( !( p->flags & BDF_GLYPH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001447 {
1448 /* Missing STARTCHAR field. */
1449 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001450 error = FT_THROW( Missing_Startchar_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001451 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001452 }
1453
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001454 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001455 if ( error )
1456 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001457
Ben Wagnera512b0f2015-12-14 09:19:52 +01001458 p->glyph_enc = _bdf_atol( p->list.field[1] );
David Turner993a8d02002-05-18 12:03:43 +00001459
Werner Lemberg28dd2c42012-02-26 06:18:58 +01001460 /* Normalize negative encoding values. The specification only */
1461 /* allows -1, but we can be more generous here. */
1462 if ( p->glyph_enc < -1 )
1463 p->glyph_enc = -1;
1464
Werner Lemberg03242f52012-02-26 06:52:56 +01001465 /* Check for alternative encoding format. */
1466 if ( p->glyph_enc == -1 && p->list.used > 2 )
Ben Wagnera512b0f2015-12-14 09:19:52 +01001467 p->glyph_enc = _bdf_atol( p->list.field[2] );
Werner Lemberg03242f52012-02-26 06:52:56 +01001468
Alexei Podtelezhnikov923fcbc2018-08-15 22:50:06 -04001469 if ( p->glyph_enc < -1 || p->glyph_enc >= 0x110000L )
Werner Lemberg7f2e4f42012-12-15 09:39:41 +01001470 p->glyph_enc = -1;
1471
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001472 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1473
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001474 if ( p->glyph_enc >= 0 )
1475 {
1476 /* Make sure there are enough glyphs allocated in case the */
1477 /* number of characters happen to be wrong. */
1478 if ( font->glyphs_used == font->glyphs_size )
1479 {
1480 if ( FT_RENEW_ARRAY( font->glyphs,
1481 font->glyphs_size,
1482 font->glyphs_size + 64 ) )
1483 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001484
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001485 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001486 }
1487
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001488 glyph = font->glyphs + font->glyphs_used++;
1489 glyph->name = p->glyph_name;
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001490 glyph->encoding = (unsigned long)p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001491
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001492 /* Reset the initial glyph info. */
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001493 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001494 }
1495 else
1496 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001497 /* Unencoded glyph. Check whether it should */
1498 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001499 if ( p->opts->keep_unencoded != 0 )
1500 {
1501 /* Allocate the next unencoded glyph. */
1502 if ( font->unencoded_used == font->unencoded_size )
1503 {
David Turner68df4f72005-03-15 18:18:57 +00001504 if ( FT_RENEW_ARRAY( font->unencoded ,
1505 font->unencoded_size,
1506 font->unencoded_size + 4 ) )
1507 goto Exit;
1508
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001509 font->unencoded_size += 4;
1510 }
1511
1512 glyph = font->unencoded + font->unencoded_used;
1513 glyph->name = p->glyph_name;
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001514 glyph->encoding = font->unencoded_used++;
Werner Lemberg4a150132015-11-25 07:53:49 +01001515
1516 /* Reset the initial glyph info. */
1517 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001518 }
1519 else
Werner Lemberg94cacac2015-11-15 04:45:42 +01001520 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001521 /* Free up the glyph name if the unencoded shouldn't be */
1522 /* kept. */
1523 FT_FREE( p->glyph_name );
Werner Lemberg94cacac2015-11-15 04:45:42 +01001524 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001525
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001526 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001527 }
1528
1529 /* Clear the flags that might be added when width and height are */
1530 /* checked for consistency. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001531 p->flags &= ~( BDF_GLYPH_WIDTH_CHECK_ | BDF_GLYPH_HEIGHT_CHECK_ );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001532
Werner Lemberg758587d2016-01-12 22:20:06 +01001533 p->flags |= BDF_ENCODING_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001534
1535 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001536 }
1537
Armin Hasitzka0f6be062018-06-17 20:27:42 +02001538 if ( !( p->flags & BDF_ENCODING_ ) )
1539 goto Missing_Encoding;
1540
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001541 /* Point at the glyph being constructed. */
1542 if ( p->glyph_enc == -1 )
1543 glyph = font->unencoded + ( font->unencoded_used - 1 );
1544 else
1545 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001546
Werner Lemberg96ddc672011-06-29 09:15:54 +02001547 /* Check whether a bitmap is being constructed. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001548 if ( p->flags & BDF_BITMAP_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001549 {
1550 /* If there are more rows than are specified in the glyph metrics, */
1551 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001552 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001553 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001554 if ( !( p->flags & BDF_GLYPH_HEIGHT_CHECK_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001555 {
1556 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001557 p->flags |= BDF_GLYPH_HEIGHT_CHECK_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001558 }
1559
1560 goto Exit;
1561 }
1562
1563 /* Only collect the number of nibbles indicated by the glyph */
1564 /* metrics. If there are more columns, they are simply ignored. */
1565 nibbles = glyph->bpr << 1;
1566 bp = glyph->bitmap + p->row * glyph->bpr;
1567
David Turnerb698eed2006-02-23 14:50:13 +00001568 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001569 {
1570 c = line[i];
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001571 if ( !sbitset( hdigits, c ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001572 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001573 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001574 if ( i + 1 < nibbles && ( i & 1 ) )
1575 *++bp = 0;
1576 }
1577
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001578 /* If any line has not enough columns, */
1579 /* indicate they have been padded with zero bits. */
1580 if ( i < nibbles &&
Werner Lemberg758587d2016-01-12 22:20:06 +01001581 !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001582 {
1583 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001584 p->flags |= BDF_GLYPH_WIDTH_CHECK_;
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001585 }
1586
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001587 /* Remove possible garbage at the right. */
1588 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001589 if ( glyph->bbx.width )
1590 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001591
1592 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001593 if ( i == nibbles &&
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001594 sbitset( hdigits, line[nibbles] ) &&
Werner Lemberg758587d2016-01-12 22:20:06 +01001595 !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001596 {
1597 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001598 p->flags |= BDF_GLYPH_WIDTH_CHECK_;
David Turner993a8d02002-05-18 12:03:43 +00001599 }
1600
1601 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001602 goto Exit;
1603 }
David Turner993a8d02002-05-18 12:03:43 +00001604
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001605 /* Expect the SWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001606 if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001607 {
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001608 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001609 if ( error )
1610 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001611
Alexei Podtelezhnikov892e7ea2021-09-21 14:39:21 +00001612 glyph->swidth = _bdf_atous( p->list.field[1] );
Werner Lemberg758587d2016-01-12 22:20:06 +01001613 p->flags |= BDF_SWIDTH_;
David Turner993a8d02002-05-18 12:03:43 +00001614
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001615 goto Exit;
1616 }
David Turner993a8d02002-05-18 12:03:43 +00001617
Alexei Podtelezhnikov90b14882021-09-22 20:20:04 -04001618 /* Expect the DWIDTH (device width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001619 if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001620 {
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001621 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001622 if ( error )
1623 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001624
Alexei Podtelezhnikov892e7ea2021-09-21 14:39:21 +00001625 glyph->dwidth = _bdf_atous( p->list.field[1] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001626
Werner Lemberg758587d2016-01-12 22:20:06 +01001627 if ( !( p->flags & BDF_SWIDTH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001628 {
1629 /* Missing SWIDTH field. Emit an auto correction message and set */
1630 /* the scalable width from the device width. */
1631 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1632
Werner Lemberg02d4d592002-05-28 22:38:05 +00001633 glyph->swidth = (unsigned short)FT_MulDiv(
1634 glyph->dwidth, 72000L,
1635 (FT_Long)( font->point_size *
1636 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001637 }
1638
Werner Lemberg758587d2016-01-12 22:20:06 +01001639 p->flags |= BDF_DWIDTH_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001640 goto Exit;
1641 }
David Turner993a8d02002-05-18 12:03:43 +00001642
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001643 /* Expect the BBX field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001644 if ( _bdf_strncmp( line, "BBX", 3 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001645 {
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001646 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001647 if ( error )
1648 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001649
Ben Wagnera512b0f2015-12-14 09:19:52 +01001650 glyph->bbx.width = _bdf_atous( p->list.field[1] );
1651 glyph->bbx.height = _bdf_atous( p->list.field[2] );
1652 glyph->bbx.x_offset = _bdf_atos( p->list.field[3] );
1653 glyph->bbx.y_offset = _bdf_atos( p->list.field[4] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001654
1655 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001656 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1657 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001658
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001659 /* Determine the overall font bounding box as the characters are */
1660 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001661 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1662 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001663
David Turnerb1b47622002-05-21 21:17:43 +00001664 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001665
Werner Lembergdfa46192004-03-05 09:26:24 +00001666 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1667 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1668 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001669
Werner Lemberg758587d2016-01-12 22:20:06 +01001670 if ( !( p->flags & BDF_DWIDTH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001671 {
1672 /* Missing DWIDTH field. Emit an auto correction message and set */
1673 /* the device width to the glyph width. */
1674 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1675 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001676 }
1677
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001678 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1679 /* value if necessary. */
1680 if ( p->opts->correct_metrics != 0 )
1681 {
1682 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001683 unsigned short sw = (unsigned short)FT_MulDiv(
1684 glyph->dwidth, 72000L,
1685 (FT_Long)( font->point_size *
1686 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001687
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001688
1689 if ( sw != glyph->swidth )
1690 {
1691 glyph->swidth = sw;
1692
Werner Lemberg758587d2016-01-12 22:20:06 +01001693 p->flags |= BDF_SWIDTH_ADJ_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001694 }
David Turner993a8d02002-05-18 12:03:43 +00001695 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001696
Werner Lemberg758587d2016-01-12 22:20:06 +01001697 p->flags |= BDF_BBX_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001698 goto Exit;
1699 }
David Turner993a8d02002-05-18 12:03:43 +00001700
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001701 /* And finally, gather up the bitmap. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001702 if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001703 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001704 unsigned long bitmap_size;
1705
1706
Werner Lemberg758587d2016-01-12 22:20:06 +01001707 if ( !( p->flags & BDF_BBX_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001708 {
1709 /* Missing BBX field. */
1710 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001711 error = FT_THROW( Missing_Bbx_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001712 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001713 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001714
1715 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001716 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001717
1718 bitmap_size = glyph->bpr * glyph->bbx.height;
Werner Lembergc4cad302012-03-08 20:11:37 +01001719 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
Werner Lemberg26170df2006-03-26 07:19:07 +00001720 {
1721 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001722 error = FT_THROW( Bbx_Too_Big );
Werner Lemberg26170df2006-03-26 07:19:07 +00001723 goto Exit;
1724 }
1725 else
1726 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001727
Alexei Podtelezhnikovc2d28312021-04-25 23:33:15 -04001728 if ( FT_ALLOC( glyph->bitmap, glyph->bytes ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001729 goto Exit;
1730
1731 p->row = 0;
Werner Lemberg758587d2016-01-12 22:20:06 +01001732 p->flags |= BDF_BITMAP_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001733
1734 goto Exit;
1735 }
1736
Werner Lemberge01406b2011-11-25 09:44:28 +01001737 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001738 error = FT_THROW( Invalid_File_Format );
Werner Lemberg4086fb72012-03-01 08:55:40 +01001739 goto Exit;
1740
1741 Missing_Encoding:
1742 /* Missing ENCODING field. */
1743 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001744 error = FT_THROW( Missing_Encoding_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001745
1746 Exit:
Werner Lemberg758587d2016-01-12 22:20:06 +01001747 if ( error && ( p->flags & BDF_GLYPH_ ) )
Werner Lembergf4c94d42010-06-19 16:08:31 +02001748 FT_FREE( p->glyph_name );
1749
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001750 return error;
David Turner993a8d02002-05-18 12:03:43 +00001751 }
1752
David Turner993a8d02002-05-18 12:03:43 +00001753
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001754 /* Load the font properties. */
1755 static FT_Error
1756 _bdf_parse_properties( char* line,
1757 unsigned long linelen,
1758 unsigned long lineno,
1759 void* call_data,
1760 void* client_data )
1761 {
1762 unsigned long vlen;
1763 _bdf_line_func_t* next;
1764 _bdf_parse_t* p;
1765 char* name;
1766 char* value;
1767 char nbuf[128];
Werner Lemberge3c93012013-03-14 11:21:17 +01001768 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001769
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001770 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001771
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001772
1773 next = (_bdf_line_func_t *)call_data;
1774 p = (_bdf_parse_t *) client_data;
1775
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001776 /* Check for the end of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001777 if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001778 {
1779 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1780 /* encountered yet, then make sure they are added as properties and */
1781 /* make sure they are set from the font bounding box info. */
1782 /* */
1783 /* This is *always* done regardless of the options, because X11 */
1784 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001785 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001786 {
1787 p->font->font_ascent = p->font->bbx.ascent;
1788 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001789 error = _bdf_add_property( p->font, "FONT_ASCENT",
Werner Lemberge01406b2011-11-25 09:44:28 +01001790 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001791 if ( error )
1792 goto Exit;
1793
1794 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
David Turner993a8d02002-05-18 12:03:43 +00001795 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001796
Werner Lemberg428c2e42003-04-25 05:35:04 +00001797 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001798 {
1799 p->font->font_descent = p->font->bbx.descent;
1800 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001801 error = _bdf_add_property( p->font, "FONT_DESCENT",
Werner Lemberge01406b2011-11-25 09:44:28 +01001802 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001803 if ( error )
1804 goto Exit;
1805
1806 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
David Turner993a8d02002-05-18 12:03:43 +00001807 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001808
Werner Lemberg758587d2016-01-12 22:20:06 +01001809 p->flags &= ~BDF_PROPS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001810 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001811
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001812 goto Exit;
1813 }
David Turner993a8d02002-05-18 12:03:43 +00001814
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001815 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001816 if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001817 goto Exit;
1818
1819 /* Handle COMMENT fields and properties in a special way to preserve */
1820 /* the spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001821 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001822 {
David Turner993a8d02002-05-18 12:03:43 +00001823 name = value = line;
1824 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001825 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001826 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01001827 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001828 if ( error )
1829 goto Exit;
1830 }
1831 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1832 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001833 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001834 if ( error )
1835 goto Exit;
1836 }
1837 else
1838 {
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001839 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001840 if ( error )
1841 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001842 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001843
David Turner68df4f72005-03-15 18:18:57 +00001844 _bdf_list_shift( &p->list, 1 );
1845 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001846
Werner Lemberge01406b2011-11-25 09:44:28 +01001847 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001848 if ( error )
1849 goto Exit;
1850 }
1851
1852 Exit:
1853 return error;
David Turner993a8d02002-05-18 12:03:43 +00001854 }
1855
David Turner993a8d02002-05-18 12:03:43 +00001856
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001857 /* Load the font header. */
1858 static FT_Error
1859 _bdf_parse_start( char* line,
1860 unsigned long linelen,
1861 unsigned long lineno,
1862 void* call_data,
1863 void* client_data )
1864 {
1865 unsigned long slen;
1866 _bdf_line_func_t* next;
1867 _bdf_parse_t* p;
1868 bdf_font_t* font;
1869 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001870
David Turnerd490e372002-05-28 23:40:37 +00001871 FT_Memory memory = NULL;
Werner Lemberge3c93012013-03-14 11:21:17 +01001872 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001873
1874 FT_UNUSED( lineno ); /* only used in debug mode */
1875
1876
1877 next = (_bdf_line_func_t *)call_data;
1878 p = (_bdf_parse_t *) client_data;
1879
1880 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00001881 memory = p->font->memory;
1882
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001883 /* Check for a comment. This is done to handle those fonts that have */
1884 /* comments before the STARTFONT line for some reason. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001885 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001886 {
1887 if ( p->opts->keep_comments != 0 && p->font != 0 )
1888 {
1889 linelen -= 7;
1890
1891 s = line + 7;
1892 if ( *s != 0 )
1893 {
1894 s++;
1895 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00001896 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001897
1898 error = _bdf_add_comment( p->font, s, linelen );
1899 if ( error )
1900 goto Exit;
1901 /* here font is not defined! */
1902 }
1903
1904 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001905 }
1906
Werner Lemberg758587d2016-01-12 22:20:06 +01001907 if ( !( p->flags & BDF_START_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001908 {
1909 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00001910
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001911 if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001912 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01001913 /* we don't emit an error message since this code gets */
1914 /* explicitly caught one level higher */
Werner Lemberg059bc332013-03-14 10:27:35 +01001915 error = FT_THROW( Missing_Startfont_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001916 goto Exit;
1917 }
David Turner993a8d02002-05-18 12:03:43 +00001918
Werner Lemberg758587d2016-01-12 22:20:06 +01001919 p->flags = BDF_START_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001920 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00001921
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001922 if ( FT_NEW( font ) )
1923 goto Exit;
1924 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00001925
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001926 font->memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00001927
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001928 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001929 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001930 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00001931
David Turner993a8d02002-05-18 12:03:43 +00001932
Werner Lemberg7ce6c432015-12-22 05:39:58 +01001933 error = ft_hash_str_init( &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001934 if ( error )
1935 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00001936 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001937 i < _num_bdf_properties; i++, prop++ )
1938 {
Werner Lemberg609546c2015-12-20 07:17:29 +01001939 error = ft_hash_str_insert( prop->name, i,
1940 &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001941 if ( error )
1942 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001943 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001944 }
1945
Werner Lemberg31343562015-12-19 17:02:13 +01001946 if ( FT_ALLOC( p->font->internal, sizeof ( FT_HashRec ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001947 goto Exit;
Werner Lemberg7ce6c432015-12-22 05:39:58 +01001948 error = ft_hash_str_init( (FT_Hash)p->font->internal, memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001949 if ( error )
1950 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00001951 p->font->spacing = p->opts->font_spacing;
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001952 p->font->default_char = ~0UL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001953
1954 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001955 }
1956
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001957 /* Check for the start of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001958 if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001959 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001960 if ( !( p->flags & BDF_FONT_BBX_ ) )
Werner Lembergfb690292010-06-23 10:00:52 +02001961 {
1962 /* Missing the FONTBOUNDINGBOX field. */
1963 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001964 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergfb690292010-06-23 10:00:52 +02001965 goto Exit;
1966 }
1967
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001968 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001969 if ( error )
1970 goto Exit;
Werner Lembergb6b26f42016-06-09 06:53:48 +02001971
Werner Lembergb66efef2009-03-12 08:07:49 +00001972 /* at this point, `p->font' can't be NULL */
Ben Wagnera512b0f2015-12-14 09:19:52 +01001973 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1] );
Werner Lembergb6b26f42016-06-09 06:53:48 +02001974 /* We need at least 4 bytes per property. */
1975 if ( p->cnt > p->size / 4 )
1976 {
1977 p->font->props_size = 0;
1978
1979 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "STARTPROPERTIES" ));
1980 error = FT_THROW( Invalid_Argument );
1981 goto Exit;
1982 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001983
1984 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
Werner Lemberg9b6b5752012-12-15 01:34:41 +01001985 {
1986 p->font->props_size = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001987 goto Exit;
Werner Lemberg9b6b5752012-12-15 01:34:41 +01001988 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001989
Werner Lemberg758587d2016-01-12 22:20:06 +01001990 p->flags |= BDF_PROPS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001991 *next = _bdf_parse_properties;
1992
1993 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001994 }
1995
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001996 /* Check for the FONTBOUNDINGBOX field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001997 if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001998 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001999 if ( !( p->flags & BDF_SIZE_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002000 {
2001 /* Missing the SIZE field. */
2002 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002003 error = FT_THROW( Missing_Size_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002004 goto Exit;
2005 }
2006
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04002007 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002008 if ( error )
2009 goto Exit;
2010
Ben Wagnera512b0f2015-12-14 09:19:52 +01002011 p->font->bbx.width = _bdf_atous( p->list.field[1] );
2012 p->font->bbx.height = _bdf_atous( p->list.field[2] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002013
Ben Wagnera512b0f2015-12-14 09:19:52 +01002014 p->font->bbx.x_offset = _bdf_atos( p->list.field[3] );
2015 p->font->bbx.y_offset = _bdf_atos( p->list.field[4] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002016
David Turnerd490e372002-05-28 23:40:37 +00002017 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002018 p->font->bbx.y_offset );
2019
2020 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002021
Werner Lemberg758587d2016-01-12 22:20:06 +01002022 p->flags |= BDF_FONT_BBX_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002023
2024 goto Exit;
2025 }
2026
2027 /* The next thing to check for is the FONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002028 if ( _bdf_strncmp( line, "FONT", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002029 {
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04002030 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002031 if ( error )
2032 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002033 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002034
David Turner68df4f72005-03-15 18:18:57 +00002035 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002036
2037 if ( !s )
2038 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002039 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002040 error = FT_THROW( Invalid_File_Format );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002041 goto Exit;
2042 }
2043
Werner Lembergfb690292010-06-23 10:00:52 +02002044 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2045 FT_FREE( p->font->name );
2046
Alexei Podtelezhnikovc2d28312021-04-25 23:33:15 -04002047 if ( FT_QALLOC( p->font->name, slen + 1 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002048 goto Exit;
2049 FT_MEM_COPY( p->font->name, s, slen + 1 );
2050
2051 /* If the font name is an XLFD name, set the spacing to the one in */
2052 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002053 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002054 if ( error )
2055 goto Exit;
2056
Werner Lemberg758587d2016-01-12 22:20:06 +01002057 p->flags |= BDF_FONT_NAME_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002058
2059 goto Exit;
2060 }
2061
2062 /* Check for the SIZE field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002063 if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002064 {
Werner Lemberg758587d2016-01-12 22:20:06 +01002065 if ( !( p->flags & BDF_FONT_NAME_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002066 {
2067 /* Missing the FONT field. */
2068 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002069 error = FT_THROW( Missing_Font_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002070 goto Exit;
2071 }
2072
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04002073 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002074 if ( error )
2075 goto Exit;
2076
Ben Wagnera512b0f2015-12-14 09:19:52 +01002077 p->font->point_size = _bdf_atoul( p->list.field[1] );
2078 p->font->resolution_x = _bdf_atoul( p->list.field[2] );
2079 p->font->resolution_y = _bdf_atoul( p->list.field[3] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002080
2081 /* Check for the bits per pixel field. */
2082 if ( p->list.used == 5 )
2083 {
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002084 unsigned short bpp;
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002085
2086
Alexei Podtelezhnikov892e7ea2021-09-21 14:39:21 +00002087 bpp = _bdf_atous( p->list.field[4] );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002088
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002089 /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
2090 if ( bpp > 4 )
2091 p->font->bpp = 8;
2092 else if ( bpp > 2 )
2093 p->font->bpp = 4;
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002094 else if ( bpp > 1 )
2095 p->font->bpp = 2;
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002096 else
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002097 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002098
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002099 if ( p->font->bpp != bpp )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002100 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002101 }
2102 else
2103 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002104
Werner Lemberg758587d2016-01-12 22:20:06 +01002105 p->flags |= BDF_SIZE_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002106
2107 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002108 }
2109
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002110 /* Check for the CHARS field -- font properties are optional */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002111 if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002112 {
2113 char nbuf[128];
2114
2115
Werner Lemberg758587d2016-01-12 22:20:06 +01002116 if ( !( p->flags & BDF_FONT_BBX_ ) )
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002117 {
2118 /* Missing the FONTBOUNDINGBOX field. */
2119 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002120 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002121 goto Exit;
2122 }
2123
2124 /* Add the two standard X11 properties which are required */
2125 /* for compiling fonts. */
2126 p->font->font_ascent = p->font->bbx.ascent;
2127 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04002128 error = _bdf_add_property( p->font, "FONT_ASCENT",
Werner Lemberge01406b2011-11-25 09:44:28 +01002129 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002130 if ( error )
2131 goto Exit;
2132 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2133
2134 p->font->font_descent = p->font->bbx.descent;
2135 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04002136 error = _bdf_add_property( p->font, "FONT_DESCENT",
Werner Lemberge01406b2011-11-25 09:44:28 +01002137 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002138 if ( error )
2139 goto Exit;
2140 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2141
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002142 *next = _bdf_parse_glyphs;
2143
2144 /* A special return value. */
2145 error = -1;
2146 goto Exit;
2147 }
2148
Werner Lemberge01406b2011-11-25 09:44:28 +01002149 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002150 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002151
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002152 Exit:
2153 return error;
2154 }
David Turner993a8d02002-05-18 12:03:43 +00002155
2156
Werner Lemberg9ac90602018-06-03 09:01:17 +02002157 /**************************************************************************
2158 *
2159 * API.
2160 *
2161 */
David Turner993a8d02002-05-18 12:03:43 +00002162
David Turner993a8d02002-05-18 12:03:43 +00002163
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002164 FT_LOCAL_DEF( FT_Error )
2165 bdf_load_font( FT_Stream stream,
Alexei Podtelezhnikov0a6f0f82021-09-02 22:52:21 -04002166 FT_Memory memory,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002167 bdf_options_t* opts,
2168 bdf_font_t* *font )
2169 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002170 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002171 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002172
Sean McBride7be2a942014-02-08 13:55:38 +01002173 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002174
2175
David Turner68df4f72005-03-15 18:18:57 +00002176 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002177 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002178
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002179 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2180 p->minlb = 32767;
Werner Lemberge1ca18d2015-10-17 11:51:27 +02002181 p->size = stream->size;
Alexei Podtelezhnikov0a6f0f82021-09-02 22:52:21 -04002182 p->memory = memory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002183
Alexei Podtelezhnikov0a6f0f82021-09-02 22:52:21 -04002184 _bdf_list_init( &p->list, memory );
David Turner68df4f72005-03-15 18:18:57 +00002185
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002186 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002187 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002188 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002189 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002190
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002191 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002192 {
2193 /* If the font is not proportional, set the font's monowidth */
2194 /* field to the width of the font bounding box. */
David Turner993a8d02002-05-18 12:03:43 +00002195
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002196 if ( p->font->spacing != BDF_PROPORTIONAL )
2197 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002198
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002199 /* If the number of glyphs loaded is not that of the original count, */
2200 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002201 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002202 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002203 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2204 p->font->glyphs_used + p->font->unencoded_used ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002205 }
2206
2207 /* Once the font has been loaded, adjust the overall font metrics if */
2208 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002209 if ( p->opts->correct_metrics != 0 &&
2210 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002211 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002212 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002213 {
2214 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002215 p->font->bbx.width, p->maxrb - p->minlb ));
2216 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
David Turner993a8d02002-05-18 12:03:43 +00002217 }
2218
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002219 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002220 {
2221 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002222 p->font->bbx.x_offset, p->minlb ));
2223 p->font->bbx.x_offset = p->minlb;
David Turner993a8d02002-05-18 12:03:43 +00002224 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002225
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002226 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002227 {
2228 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002229 p->font->bbx.ascent, p->maxas ));
2230 p->font->bbx.ascent = p->maxas;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002231 }
2232
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002233 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002234 {
2235 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002236 p->font->bbx.descent, p->maxds ));
2237 p->font->bbx.descent = p->maxds;
2238 p->font->bbx.y_offset = (short)( -p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002239 }
2240
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002241 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002242 {
2243 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002244 p->font->bbx.height, p->maxas + p->maxds ));
2245 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002246 }
2247
Werner Lemberg758587d2016-01-12 22:20:06 +01002248 if ( p->flags & BDF_SWIDTH_ADJ_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002249 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2250 }
David Turner993a8d02002-05-18 12:03:43 +00002251 }
2252
Werner Lemberg758587d2016-01-12 22:20:06 +01002253 if ( p->flags & BDF_START_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002254 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002255 /* The ENDFONT field was never reached or did not exist. */
Werner Lemberg758587d2016-01-12 22:20:06 +01002256 if ( !( p->flags & BDF_GLYPHS_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002257 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002258 /* Error happened while parsing header. */
2259 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002260 error = FT_THROW( Corrupted_Font_Header );
Bungeman65d89802015-10-15 23:50:16 +02002261 goto Fail;
Werner Lemberge01406b2011-11-25 09:44:28 +01002262 }
2263 else
2264 {
2265 /* Error happened when parsing glyphs. */
2266 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002267 error = FT_THROW( Corrupted_Font_Glyphs );
Bungeman65d89802015-10-15 23:50:16 +02002268 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002269 }
David Turner993a8d02002-05-18 12:03:43 +00002270 }
2271
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002272 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002273 {
2274 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg370aea82010-06-08 08:37:11 +02002275 if ( p->font->comments_len > 0 )
2276 {
Alexei Podtelezhnikovec95f9c2021-05-02 18:30:22 -04002277 if ( FT_QRENEW_ARRAY( p->font->comments,
2278 p->font->comments_len,
2279 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002280 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002281
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002282 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002283 }
David Turner993a8d02002-05-18 12:03:43 +00002284 }
Werner Lemberg5d664b62016-12-17 20:47:42 +01002285 else if ( !error )
Werner Lemberg059bc332013-03-14 10:27:35 +01002286 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002287
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002288 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002289
2290 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002291 if ( p )
2292 {
David Turner68df4f72005-03-15 18:18:57 +00002293 _bdf_list_done( &p->list );
2294
Werner Lemberg4a150132015-11-25 07:53:49 +01002295 FT_FREE( p->glyph_name );
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002296 FT_FREE( p );
2297 }
2298
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002299 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002300
2301 Fail:
2302 bdf_free_font( p->font );
2303
Werner Lembergb10e45a2006-06-08 07:32:56 +00002304 FT_FREE( p->font );
2305
2306 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002307 }
David Turner993a8d02002-05-18 12:03:43 +00002308
2309
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002310 FT_LOCAL_DEF( void )
2311 bdf_free_font( bdf_font_t* font )
2312 {
2313 bdf_property_t* prop;
2314 unsigned long i;
2315 bdf_glyph_t* glyphs;
2316 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002317
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002318
2319 if ( font == 0 )
2320 return;
David Turner993a8d02002-05-18 12:03:43 +00002321
2322 memory = font->memory;
2323
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002324 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002325
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002326 /* Free up the internal hash table of property names. */
2327 if ( font->internal )
2328 {
Werner Lemberg7ce6c432015-12-22 05:39:58 +01002329 ft_hash_str_free( (FT_Hash)font->internal, memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002330 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002331 }
2332
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002333 /* Free up the comment info. */
2334 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002335
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002336 /* Free up the properties. */
2337 for ( i = 0; i < font->props_size; i++ )
2338 {
2339 if ( font->props[i].format == BDF_ATOM )
2340 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002341 }
2342
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002343 FT_FREE( font->props );
2344
2345 /* Free up the character info. */
2346 for ( i = 0, glyphs = font->glyphs;
2347 i < font->glyphs_used; i++, glyphs++ )
2348 {
2349 FT_FREE( glyphs->name );
2350 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002351 }
2352
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002353 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2354 i++, glyphs++ )
2355 {
2356 FT_FREE( glyphs->name );
2357 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002358 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002359
2360 FT_FREE( font->glyphs );
2361 FT_FREE( font->unencoded );
2362
David Turner993a8d02002-05-18 12:03:43 +00002363 /* bdf_cleanup */
Werner Lemberg7ce6c432015-12-22 05:39:58 +01002364 ft_hash_str_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002365
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002366 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002367 for ( prop = font->user_props, i = 0;
2368 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002369 {
2370 FT_FREE( prop->name );
2371 if ( prop->format == BDF_ATOM )
2372 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002373 }
David Turner993a8d02002-05-18 12:03:43 +00002374
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002375 FT_FREE( font->user_props );
2376
2377 /* FREE( font ); */ /* XXX Fixme */
2378 }
David Turner993a8d02002-05-18 12:03:43 +00002379
2380
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002381 FT_LOCAL_DEF( bdf_property_t * )
2382 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002383 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002384 {
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002385 size_t* propid;
David Turner993a8d02002-05-18 12:03:43 +00002386
David Turner993a8d02002-05-18 12:03:43 +00002387
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002388 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002389 return 0;
2390
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002391 propid = ft_hash_str_lookup( name, (FT_Hash)font->internal );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002392
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002393 return propid ? ( font->props + *propid ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002394 }
2395
2396
2397/* END */