blob: 75ebe3f06e9f5cf32c58436321115fda270c7438 [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 Lemberge01406b2011-11-25 09:44:28 +0100193#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
194#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
331 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
332 goto Exit;
333
334 list->size = newsize;
335 }
Werner Lembergebf55852005-03-16 01:49:54 +0000336
David Turner68df4f72005-03-15 18:18:57 +0000337 Exit:
338 return error;
339 }
340
341
342 static void
343 _bdf_list_shift( _bdf_list_t* list,
344 unsigned long n )
345 {
346 unsigned long i, u;
347
348
349 if ( list == 0 || list->used == 0 || n == 0 )
350 return;
351
352 if ( n >= list->used )
353 {
354 list->used = 0;
355 return;
356 }
357
358 for ( u = n, i = 0; u < list->used; i++, u++ )
359 list->field[i] = list->field[u];
360 list->used -= n;
361 }
362
363
Werner Lembergf4c94d42010-06-19 16:08:31 +0200364 /* An empty string for empty fields. */
365
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
541 if ( FT_NEW_ARRAY( 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;
David Turner68df4f72005-03-15 18:18:57 +0000602 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
603 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. */
810 static int
811 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
David Turner68df4f72005-03-15 18:18:57 +0000847 if ( FT_RENEW_ARRAY( font->user_props,
848 font->nuser_props,
849 font->nuser_props + 1 ) )
850 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000851
852 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +0000853 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000854
suzuki toshiya704f4d72009-09-13 00:50:14 +0900855 n = ft_strlen( name ) + 1;
856 if ( n > FT_ULONG_MAX )
Werner Lemberg059bc332013-03-14 10:27:35 +0100857 return FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +0000858
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000859 if ( FT_NEW_ARRAY( p->name, n ) )
860 goto Exit;
861
862 FT_MEM_COPY( (char *)p->name, name, n );
863
864 p->format = format;
865 p->builtin = 0;
866
867 n = _num_bdf_properties + font->nuser_props;
868
Werner Lemberg609546c2015-12-20 07:17:29 +0100869 error = ft_hash_str_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000870 if ( error )
871 goto Exit;
872
873 font->nuser_props++;
874
875 Exit:
David Turner993a8d02002-05-18 12:03:43 +0000876 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000877 }
David Turner993a8d02002-05-18 12:03:43 +0000878
879
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100880 FT_LOCAL_DEF( bdf_property_t* )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000881 bdf_get_property( char* name,
882 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +0000883 {
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100884 size_t* propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000885
886
887 if ( name == 0 || *name == 0 )
888 return 0;
889
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100890 if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000891 return 0;
892
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100893 if ( *propid >= _num_bdf_properties )
894 return font->user_props + ( *propid - _num_bdf_properties );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000895
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100896 return (bdf_property_t*)_bdf_properties + *propid;
David Turner993a8d02002-05-18 12:03:43 +0000897 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000898
899
Werner Lemberg9ac90602018-06-03 09:01:17 +0200900 /**************************************************************************
901 *
902 * BDF font file parsing flags and functions.
903 *
904 */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000905
906
907 /* Parse flags. */
908
Werner Lemberg758587d2016-01-12 22:20:06 +0100909#define BDF_START_ 0x0001U
910#define BDF_FONT_NAME_ 0x0002U
911#define BDF_SIZE_ 0x0004U
912#define BDF_FONT_BBX_ 0x0008U
913#define BDF_PROPS_ 0x0010U
914#define BDF_GLYPHS_ 0x0020U
915#define BDF_GLYPH_ 0x0040U
916#define BDF_ENCODING_ 0x0080U
917#define BDF_SWIDTH_ 0x0100U
918#define BDF_DWIDTH_ 0x0200U
919#define BDF_BBX_ 0x0400U
920#define BDF_BITMAP_ 0x0800U
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000921
Werner Lemberg758587d2016-01-12 22:20:06 +0100922#define BDF_SWIDTH_ADJ_ 0x1000U
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000923
Werner Lemberg758587d2016-01-12 22:20:06 +0100924#define BDF_GLYPH_BITS_ ( BDF_GLYPH_ | \
925 BDF_ENCODING_ | \
926 BDF_SWIDTH_ | \
927 BDF_DWIDTH_ | \
928 BDF_BBX_ | \
929 BDF_BITMAP_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000930
Werner Lemberg758587d2016-01-12 22:20:06 +0100931#define BDF_GLYPH_WIDTH_CHECK_ 0x40000000UL
932#define BDF_GLYPH_HEIGHT_CHECK_ 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000933
934
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000935 static FT_Error
936 _bdf_add_comment( bdf_font_t* font,
937 char* comment,
938 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +0000939 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000940 char* cp;
941 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100942 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000943
944
David Turner68df4f72005-03-15 18:18:57 +0000945 if ( FT_RENEW_ARRAY( font->comments,
946 font->comments_len,
947 font->comments_len + len + 1 ) )
948 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000949
950 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +0000951
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000952 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +0000953 cp[len] = '\n';
954
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000955 font->comments_len += len + 1;
956
957 Exit:
958 return error;
David Turner993a8d02002-05-18 12:03:43 +0000959 }
960
David Turner993a8d02002-05-18 12:03:43 +0000961
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000962 /* Set the spacing from the font name if it exists, or set it to the */
963 /* default specified in the options. */
964 static FT_Error
965 _bdf_set_default_spacing( bdf_font_t* font,
Werner Lemberge01406b2011-11-25 09:44:28 +0100966 bdf_options_t* opts,
967 unsigned long lineno )
David Turner993a8d02002-05-18 12:03:43 +0000968 {
suzuki toshiya704f4d72009-09-13 00:50:14 +0900969 size_t len;
970 char name[256];
971 _bdf_list_t list;
972 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100973 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000974
Dave Arnoldc3782492013-06-05 19:57:55 +0200975 FT_UNUSED( lineno ); /* only used in debug mode */
976
David Turner993a8d02002-05-18 12:03:43 +0000977
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000978 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
979 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100980 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000981 goto Exit;
982 }
David Turner993a8d02002-05-18 12:03:43 +0000983
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000984 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +0000985
David Turner68df4f72005-03-15 18:18:57 +0000986 _bdf_list_init( &list, memory );
987
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000988 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +0000989
suzuki toshiya704f4d72009-09-13 00:50:14 +0900990 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +0000991 /* Limit ourselves to 256 characters in the font name. */
992 if ( len >= 256 )
993 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100994 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +0100995 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +0000996 goto Exit;
997 }
998
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000999 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001000
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001001 error = _bdf_list_split( &list, "-", name, (unsigned long)len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001002 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001003 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001004
1005 if ( list.used == 15 )
1006 {
1007 switch ( list.field[11][0] )
1008 {
1009 case 'C':
1010 case 'c':
1011 font->spacing = BDF_CHARCELL;
1012 break;
1013 case 'M':
1014 case 'm':
1015 font->spacing = BDF_MONOWIDTH;
1016 break;
1017 case 'P':
1018 case 'p':
1019 font->spacing = BDF_PROPORTIONAL;
1020 break;
David Turner993a8d02002-05-18 12:03:43 +00001021 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001022 }
1023
David Turner68df4f72005-03-15 18:18:57 +00001024 Fail:
1025 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001026
1027 Exit:
1028 return error;
David Turner993a8d02002-05-18 12:03:43 +00001029 }
David Turner993a8d02002-05-18 12:03:43 +00001030
1031
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001032 /* Determine whether the property is an atom or not. If it is, then */
1033 /* clean it up so the double quotes are removed if they exist. */
1034 static int
1035 _bdf_is_atom( char* line,
1036 unsigned long linelen,
1037 char** name,
1038 char** value,
1039 bdf_font_t* font )
1040 {
1041 int hold;
1042 char *sp, *ep;
1043 bdf_property_t* p;
1044
David Turner993a8d02002-05-18 12:03:43 +00001045
1046 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001047
1048 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001049 ep++;
1050
1051 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001052 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001053 {
1054 hold = *ep;
1055 *ep = 0;
1056 }
1057
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001058 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001059
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001060 /* Restore the character that was saved before any return can happen. */
1061 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001062 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001063
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001064 /* If the property exists and is not an atom, just return here. */
1065 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001066 return 0;
1067
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001068 /* The property is an atom. Trim all leading and trailing whitespace */
1069 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001070 sp = ep;
1071 ep = line + linelen;
1072
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001073 /* Trim the leading whitespace if it exists. */
Werner Lemberg320d4972012-02-24 18:06:46 +01001074 if ( *sp )
1075 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001076 while ( *sp &&
1077 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001078 sp++;
1079
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001080 /* Trim the leading double quote if it exists. */
1081 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001082 sp++;
1083 *value = sp;
1084
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001085 /* Trim the trailing whitespace if it exists. */
1086 while ( ep > sp &&
1087 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001088 *--ep = 0;
1089
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001090 /* Trim the trailing double quote if it exists. */
1091 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001092 *--ep = 0;
1093
1094 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001095 }
David Turner993a8d02002-05-18 12:03:43 +00001096
1097
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001098 static FT_Error
Werner Lemberge01406b2011-11-25 09:44:28 +01001099 _bdf_add_property( bdf_font_t* font,
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001100 const char* name,
Werner Lemberge01406b2011-11-25 09:44:28 +01001101 char* value,
1102 unsigned long lineno )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001103 {
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001104 size_t* propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001105 bdf_property_t *prop, *fp;
1106 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001107 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001108
Dave Arnoldc3782492013-06-05 19:57:55 +02001109 FT_UNUSED( lineno ); /* only used in debug mode */
1110
David Turner993a8d02002-05-18 12:03:43 +00001111
Werner Lemberg96ddc672011-06-29 09:15:54 +02001112 /* First, check whether the property already exists in the font. */
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001113 if ( ( propid = ft_hash_str_lookup( name,
1114 (FT_Hash)font->internal ) ) != NULL )
David Turner993a8d02002-05-18 12:03:43 +00001115 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001116 /* The property already exists in the font, so simply replace */
1117 /* the value of the property with the current value. */
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001118 fp = font->props + *propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001119
David Turnerb1b47622002-05-21 21:17:43 +00001120 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001121 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001122 case BDF_ATOM:
1123 /* Delete the current atom if it exists. */
1124 FT_FREE( fp->value.atom );
1125
David Turnerc0f9c4a2007-02-12 14:55:03 +00001126 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001127 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001128 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001129 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001130 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001131 break;
1132
1133 case BDF_INTEGER:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001134 fp->value.l = _bdf_atol( value );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001135 break;
1136
1137 case BDF_CARDINAL:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001138 fp->value.ul = _bdf_atoul( value );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001139 break;
David Turnerd490e372002-05-28 23:40:37 +00001140
David Turnerb1b47622002-05-21 21:17:43 +00001141 default:
1142 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001143 }
David Turnerd490e372002-05-28 23:40:37 +00001144
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001145 goto Exit;
1146 }
1147
1148 /* See whether this property type exists yet or not. */
1149 /* If not, create it. */
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001150 propid = ft_hash_str_lookup( name, &(font->proptbl) );
Werner Lemberg4441f7b2016-12-26 17:08:17 +01001151 if ( !propid )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001152 {
1153 error = bdf_create_property( name, BDF_ATOM, font );
1154 if ( error )
1155 goto Exit;
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001156 propid = ft_hash_str_lookup( name, &(font->proptbl) );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001157 }
1158
Werner Lembergb6b26f42016-06-09 06:53:48 +02001159 /* Allocate another property if this is overflowing. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001160 if ( font->props_used == font->props_size )
1161 {
1162 if ( font->props_size == 0 )
1163 {
1164 if ( FT_NEW_ARRAY( font->props, 1 ) )
1165 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001166 }
1167 else
1168 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001169 if ( FT_RENEW_ARRAY( font->props,
1170 font->props_size,
1171 font->props_size + 1 ) )
1172 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001173 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001174
David Turner993a8d02002-05-18 12:03:43 +00001175 fp = font->props + font->props_size;
Werner Lemberg2ecf89b2016-09-28 19:06:21 +02001176 FT_ZERO( fp );
David Turner993a8d02002-05-18 12:03:43 +00001177 font->props_size++;
1178 }
1179
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001180 if ( *propid >= _num_bdf_properties )
1181 prop = font->user_props + ( *propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001182 else
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001183 prop = (bdf_property_t*)_bdf_properties + *propid;
David Turner993a8d02002-05-18 12:03:43 +00001184
1185 fp = font->props + font->props_used;
1186
1187 fp->name = prop->name;
1188 fp->format = prop->format;
1189 fp->builtin = prop->builtin;
1190
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001191 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001192 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001193 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001194 fp->value.atom = 0;
1195 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001196 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001197 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001198 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001199 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001200 break;
David Turner993a8d02002-05-18 12:03:43 +00001201
1202 case BDF_INTEGER:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001203 fp->value.l = _bdf_atol( value );
David Turner993a8d02002-05-18 12:03:43 +00001204 break;
1205
1206 case BDF_CARDINAL:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001207 fp->value.ul = _bdf_atoul( value );
David Turner993a8d02002-05-18 12:03:43 +00001208 break;
David Turner993a8d02002-05-18 12:03:43 +00001209 }
1210
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001211 /* If the property happens to be a comment, then it doesn't need */
1212 /* to be added to the internal hash table. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001213 if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 )
Werner Lemberg370aea82010-06-08 08:37:11 +02001214 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001215 /* Add the property to the font property table. */
Werner Lemberg609546c2015-12-20 07:17:29 +01001216 error = ft_hash_str_insert( fp->name,
1217 font->props_used,
1218 (FT_Hash)font->internal,
1219 memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001220 if ( error )
1221 goto Exit;
1222 }
David Turner993a8d02002-05-18 12:03:43 +00001223
1224 font->props_used++;
1225
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001226 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1227 /* property needs to be located if it exists in the property list, the */
1228 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1229 /* present, and the SPACING property should override the default */
1230 /* spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001231 if ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 )
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001232 font->default_char = fp->value.ul;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001233 else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001234 font->font_ascent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001235 else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001236 font->font_descent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001237 else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001238 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001239 if ( !fp->value.atom )
1240 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001241 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001242 error = FT_THROW( Invalid_File_Format );
Werner Lembergb66efef2009-03-12 08:07:49 +00001243 goto Exit;
1244 }
1245
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001246 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001247 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001248 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001249 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001250 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001251 font->spacing = BDF_CHARCELL;
1252 }
1253
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001254 Exit:
1255 return error;
David Turner993a8d02002-05-18 12:03:43 +00001256 }
1257
David Turner993a8d02002-05-18 12:03:43 +00001258
David Turnerb1b47622002-05-21 21:17:43 +00001259 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001260 {
1261 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1262 };
1263
1264
Werner Lembergf1b61832018-12-04 11:51:15 +01001265 static FT_Error
1266 _bdf_parse_end( char* line,
1267 unsigned long linelen,
1268 unsigned long lineno,
1269 void* call_data,
1270 void* client_data )
1271 {
1272 /* a no-op; we ignore everything after `ENDFONT' */
1273
1274 FT_UNUSED( line );
1275 FT_UNUSED( linelen );
1276 FT_UNUSED( lineno );
1277 FT_UNUSED( call_data );
1278 FT_UNUSED( client_data );
1279
1280 return FT_Err_Ok;
1281 }
1282
1283
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001284 /* Actually parse the glyph info and bitmaps. */
1285 static FT_Error
1286 _bdf_parse_glyphs( char* line,
1287 unsigned long linelen,
1288 unsigned long lineno,
1289 void* call_data,
1290 void* client_data )
1291 {
1292 int c, mask_index;
1293 char* s;
1294 unsigned char* bp;
1295 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001296
Werner Lembergf1b61832018-12-04 11:51:15 +01001297 _bdf_line_func_t* next;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001298 _bdf_parse_t* p;
1299 bdf_glyph_t* glyph;
1300 bdf_font_t* font;
1301
1302 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001303 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001304
1305 FT_UNUSED( lineno ); /* only used in debug mode */
1306
1307
Werner Lembergf1b61832018-12-04 11:51:15 +01001308 next = (_bdf_line_func_t *)call_data;
1309 p = (_bdf_parse_t *) client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001310
1311 font = p->font;
1312 memory = font->memory;
1313
1314 /* Check for a comment. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001315 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001316 {
1317 linelen -= 7;
1318
1319 s = line + 7;
1320 if ( *s != 0 )
1321 {
1322 s++;
1323 linelen--;
1324 }
1325 error = _bdf_add_comment( p->font, s, linelen );
1326 goto Exit;
1327 }
1328
1329 /* The very first thing expected is the number of glyphs. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001330 if ( !( p->flags & BDF_GLYPHS_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001331 {
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001332 if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001333 {
1334 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001335 error = FT_THROW( Missing_Chars_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001336 goto Exit;
1337 }
1338
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001339 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001340 if ( error )
1341 goto Exit;
Ben Wagnera512b0f2015-12-14 09:19:52 +01001342 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001343
Werner Lemberge1ca18d2015-10-17 11:51:27 +02001344 /* We need at least 20 bytes per glyph. */
1345 if ( p->cnt > p->size / 20 )
1346 {
Werner Lemberg797ca5a2015-10-17 11:57:16 +02001347 p->cnt = font->glyphs_size = p->size / 20;
Werner Lemberge1ca18d2015-10-17 11:51:27 +02001348 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG17, p->cnt ));
1349 }
1350
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001351 /* Make sure the number of glyphs is non-zero. */
1352 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001353 font->glyphs_size = 64;
1354
Werner Lemberga08b2172007-03-28 07:17:17 +00001355 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1356 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001357 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001358 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001359 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001360 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001361 goto Exit;
1362 }
1363
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001364 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1365 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001366
Werner Lemberg758587d2016-01-12 22:20:06 +01001367 p->flags |= BDF_GLYPHS_;
David Turner993a8d02002-05-18 12:03:43 +00001368
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001369 goto Exit;
1370 }
1371
1372 /* Check for the ENDFONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001373 if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001374 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001375 if ( p->flags & BDF_GLYPH_BITS_ )
Werner Lembergaf834612014-11-22 13:29:10 +01001376 {
1377 /* Missing ENDCHAR field. */
1378 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1379 error = FT_THROW( Corrupted_Font_Glyphs );
1380 goto Exit;
1381 }
1382
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001383 /* Sort the glyphs by encoding. */
1384 ft_qsort( (char *)font->glyphs,
1385 font->glyphs_used,
1386 sizeof ( bdf_glyph_t ),
1387 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001388
Werner Lemberg758587d2016-01-12 22:20:06 +01001389 p->flags &= ~BDF_START_;
Werner Lembergf1b61832018-12-04 11:51:15 +01001390 *next = _bdf_parse_end;
David Turner993a8d02002-05-18 12:03:43 +00001391
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001392 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001393 }
1394
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001395 /* Check for the ENDCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001396 if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001397 {
1398 p->glyph_enc = 0;
Werner Lemberg758587d2016-01-12 22:20:06 +01001399 p->flags &= ~BDF_GLYPH_BITS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001400
1401 goto Exit;
1402 }
1403
Werner Lemberg96ddc672011-06-29 09:15:54 +02001404 /* Check whether a glyph is being scanned but should be */
1405 /* ignored because it is an unencoded glyph. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001406 if ( ( p->flags & BDF_GLYPH_ ) &&
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001407 p->glyph_enc == -1 &&
1408 p->opts->keep_unencoded == 0 )
1409 goto Exit;
1410
1411 /* Check for the STARTCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001412 if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001413 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001414 if ( p->flags & BDF_GLYPH_BITS_ )
Werner Lembergb1857472015-10-17 14:21:41 +02001415 {
1416 /* Missing ENDCHAR field. */
1417 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1418 error = FT_THROW( Missing_Startchar_Field );
1419 goto Exit;
1420 }
1421
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001422 /* Set the character name in the parse info first until the */
1423 /* encoding can be checked for an unencoded character. */
1424 FT_FREE( p->glyph_name );
1425
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001426 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001427 if ( error )
1428 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001429
David Turner68df4f72005-03-15 18:18:57 +00001430 _bdf_list_shift( &p->list, 1 );
1431
1432 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001433
Werner Lembergba03af62007-05-30 13:57:02 +00001434 if ( !s )
1435 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001436 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001437 error = FT_THROW( Invalid_File_Format );
Werner Lembergba03af62007-05-30 13:57:02 +00001438 goto Exit;
1439 }
1440
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001441 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1442 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001443
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001444 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1445
Werner Lemberg758587d2016-01-12 22:20:06 +01001446 p->flags |= BDF_GLYPH_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001447
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001448 FT_TRACE4(( DBGMSG1, lineno, s ));
1449
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001450 goto Exit;
1451 }
1452
1453 /* Check for the ENCODING field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001454 if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001455 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001456 if ( !( p->flags & BDF_GLYPH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001457 {
1458 /* Missing STARTCHAR field. */
1459 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001460 error = FT_THROW( Missing_Startchar_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001461 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001462 }
1463
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001464 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001465 if ( error )
1466 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001467
Ben Wagnera512b0f2015-12-14 09:19:52 +01001468 p->glyph_enc = _bdf_atol( p->list.field[1] );
David Turner993a8d02002-05-18 12:03:43 +00001469
Werner Lemberg28dd2c42012-02-26 06:18:58 +01001470 /* Normalize negative encoding values. The specification only */
1471 /* allows -1, but we can be more generous here. */
1472 if ( p->glyph_enc < -1 )
1473 p->glyph_enc = -1;
1474
Werner Lemberg03242f52012-02-26 06:52:56 +01001475 /* Check for alternative encoding format. */
1476 if ( p->glyph_enc == -1 && p->list.used > 2 )
Ben Wagnera512b0f2015-12-14 09:19:52 +01001477 p->glyph_enc = _bdf_atol( p->list.field[2] );
Werner Lemberg03242f52012-02-26 06:52:56 +01001478
Alexei Podtelezhnikov923fcbc2018-08-15 22:50:06 -04001479 if ( p->glyph_enc < -1 || p->glyph_enc >= 0x110000L )
Werner Lemberg7f2e4f42012-12-15 09:39:41 +01001480 p->glyph_enc = -1;
1481
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001482 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1483
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001484 if ( p->glyph_enc >= 0 )
1485 {
1486 /* Make sure there are enough glyphs allocated in case the */
1487 /* number of characters happen to be wrong. */
1488 if ( font->glyphs_used == font->glyphs_size )
1489 {
1490 if ( FT_RENEW_ARRAY( font->glyphs,
1491 font->glyphs_size,
1492 font->glyphs_size + 64 ) )
1493 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001494
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001495 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001496 }
1497
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001498 glyph = font->glyphs + font->glyphs_used++;
1499 glyph->name = p->glyph_name;
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001500 glyph->encoding = (unsigned long)p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001501
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001502 /* Reset the initial glyph info. */
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001503 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001504 }
1505 else
1506 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001507 /* Unencoded glyph. Check whether it should */
1508 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001509 if ( p->opts->keep_unencoded != 0 )
1510 {
1511 /* Allocate the next unencoded glyph. */
1512 if ( font->unencoded_used == font->unencoded_size )
1513 {
David Turner68df4f72005-03-15 18:18:57 +00001514 if ( FT_RENEW_ARRAY( font->unencoded ,
1515 font->unencoded_size,
1516 font->unencoded_size + 4 ) )
1517 goto Exit;
1518
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001519 font->unencoded_size += 4;
1520 }
1521
1522 glyph = font->unencoded + font->unencoded_used;
1523 glyph->name = p->glyph_name;
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001524 glyph->encoding = font->unencoded_used++;
Werner Lemberg4a150132015-11-25 07:53:49 +01001525
1526 /* Reset the initial glyph info. */
1527 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001528 }
1529 else
Werner Lemberg94cacac2015-11-15 04:45:42 +01001530 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001531 /* Free up the glyph name if the unencoded shouldn't be */
1532 /* kept. */
1533 FT_FREE( p->glyph_name );
Werner Lemberg94cacac2015-11-15 04:45:42 +01001534 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001535
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001536 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001537 }
1538
1539 /* Clear the flags that might be added when width and height are */
1540 /* checked for consistency. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001541 p->flags &= ~( BDF_GLYPH_WIDTH_CHECK_ | BDF_GLYPH_HEIGHT_CHECK_ );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001542
Werner Lemberg758587d2016-01-12 22:20:06 +01001543 p->flags |= BDF_ENCODING_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001544
1545 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001546 }
1547
Armin Hasitzka0f6be062018-06-17 20:27:42 +02001548 if ( !( p->flags & BDF_ENCODING_ ) )
1549 goto Missing_Encoding;
1550
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001551 /* Point at the glyph being constructed. */
1552 if ( p->glyph_enc == -1 )
1553 glyph = font->unencoded + ( font->unencoded_used - 1 );
1554 else
1555 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001556
Werner Lemberg96ddc672011-06-29 09:15:54 +02001557 /* Check whether a bitmap is being constructed. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001558 if ( p->flags & BDF_BITMAP_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001559 {
1560 /* If there are more rows than are specified in the glyph metrics, */
1561 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001562 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001563 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001564 if ( !( p->flags & BDF_GLYPH_HEIGHT_CHECK_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001565 {
1566 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001567 p->flags |= BDF_GLYPH_HEIGHT_CHECK_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001568 }
1569
1570 goto Exit;
1571 }
1572
1573 /* Only collect the number of nibbles indicated by the glyph */
1574 /* metrics. If there are more columns, they are simply ignored. */
1575 nibbles = glyph->bpr << 1;
1576 bp = glyph->bitmap + p->row * glyph->bpr;
1577
David Turnerb698eed2006-02-23 14:50:13 +00001578 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001579 {
1580 c = line[i];
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001581 if ( !sbitset( hdigits, c ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001582 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001583 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001584 if ( i + 1 < nibbles && ( i & 1 ) )
1585 *++bp = 0;
1586 }
1587
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001588 /* If any line has not enough columns, */
1589 /* indicate they have been padded with zero bits. */
1590 if ( i < nibbles &&
Werner Lemberg758587d2016-01-12 22:20:06 +01001591 !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001592 {
1593 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001594 p->flags |= BDF_GLYPH_WIDTH_CHECK_;
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001595 }
1596
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001597 /* Remove possible garbage at the right. */
1598 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001599 if ( glyph->bbx.width )
1600 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001601
1602 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001603 if ( i == nibbles &&
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001604 sbitset( hdigits, line[nibbles] ) &&
Werner Lemberg758587d2016-01-12 22:20:06 +01001605 !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001606 {
1607 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001608 p->flags |= BDF_GLYPH_WIDTH_CHECK_;
David Turner993a8d02002-05-18 12:03:43 +00001609 }
1610
1611 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001612 goto Exit;
1613 }
David Turner993a8d02002-05-18 12:03:43 +00001614
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001615 /* Expect the SWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001616 if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001617 {
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001618 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001619 if ( error )
1620 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001621
Ben Wagnera512b0f2015-12-14 09:19:52 +01001622 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1] );
Werner Lemberg758587d2016-01-12 22:20:06 +01001623 p->flags |= BDF_SWIDTH_;
David Turner993a8d02002-05-18 12:03:43 +00001624
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001625 goto Exit;
1626 }
David Turner993a8d02002-05-18 12:03:43 +00001627
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001628 /* Expect the DWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001629 if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001630 {
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001631 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001632 if ( error )
1633 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001634
Ben Wagnera512b0f2015-12-14 09:19:52 +01001635 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001636
Werner Lemberg758587d2016-01-12 22:20:06 +01001637 if ( !( p->flags & BDF_SWIDTH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001638 {
1639 /* Missing SWIDTH field. Emit an auto correction message and set */
1640 /* the scalable width from the device width. */
1641 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1642
Werner Lemberg02d4d592002-05-28 22:38:05 +00001643 glyph->swidth = (unsigned short)FT_MulDiv(
1644 glyph->dwidth, 72000L,
1645 (FT_Long)( font->point_size *
1646 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001647 }
1648
Werner Lemberg758587d2016-01-12 22:20:06 +01001649 p->flags |= BDF_DWIDTH_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001650 goto Exit;
1651 }
David Turner993a8d02002-05-18 12:03:43 +00001652
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001653 /* Expect the BBX field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001654 if ( _bdf_strncmp( line, "BBX", 3 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001655 {
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001656 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001657 if ( error )
1658 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001659
Ben Wagnera512b0f2015-12-14 09:19:52 +01001660 glyph->bbx.width = _bdf_atous( p->list.field[1] );
1661 glyph->bbx.height = _bdf_atous( p->list.field[2] );
1662 glyph->bbx.x_offset = _bdf_atos( p->list.field[3] );
1663 glyph->bbx.y_offset = _bdf_atos( p->list.field[4] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001664
1665 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001666 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1667 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001668
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001669 /* Determine the overall font bounding box as the characters are */
1670 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001671 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1672 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001673
David Turnerb1b47622002-05-21 21:17:43 +00001674 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001675
Werner Lembergdfa46192004-03-05 09:26:24 +00001676 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1677 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1678 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001679
Werner Lemberg758587d2016-01-12 22:20:06 +01001680 if ( !( p->flags & BDF_DWIDTH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001681 {
1682 /* Missing DWIDTH field. Emit an auto correction message and set */
1683 /* the device width to the glyph width. */
1684 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1685 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001686 }
1687
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001688 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1689 /* value if necessary. */
1690 if ( p->opts->correct_metrics != 0 )
1691 {
1692 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001693 unsigned short sw = (unsigned short)FT_MulDiv(
1694 glyph->dwidth, 72000L,
1695 (FT_Long)( font->point_size *
1696 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001697
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001698
1699 if ( sw != glyph->swidth )
1700 {
1701 glyph->swidth = sw;
1702
Werner Lemberg758587d2016-01-12 22:20:06 +01001703 p->flags |= BDF_SWIDTH_ADJ_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001704 }
David Turner993a8d02002-05-18 12:03:43 +00001705 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001706
Werner Lemberg758587d2016-01-12 22:20:06 +01001707 p->flags |= BDF_BBX_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001708 goto Exit;
1709 }
David Turner993a8d02002-05-18 12:03:43 +00001710
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001711 /* And finally, gather up the bitmap. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001712 if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001713 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001714 unsigned long bitmap_size;
1715
1716
Werner Lemberg758587d2016-01-12 22:20:06 +01001717 if ( !( p->flags & BDF_BBX_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001718 {
1719 /* Missing BBX field. */
1720 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001721 error = FT_THROW( Missing_Bbx_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001722 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001723 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001724
1725 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001726 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001727
1728 bitmap_size = glyph->bpr * glyph->bbx.height;
Werner Lembergc4cad302012-03-08 20:11:37 +01001729 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
Werner Lemberg26170df2006-03-26 07:19:07 +00001730 {
1731 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001732 error = FT_THROW( Bbx_Too_Big );
Werner Lemberg26170df2006-03-26 07:19:07 +00001733 goto Exit;
1734 }
1735 else
1736 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001737
1738 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1739 goto Exit;
1740
1741 p->row = 0;
Werner Lemberg758587d2016-01-12 22:20:06 +01001742 p->flags |= BDF_BITMAP_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001743
1744 goto Exit;
1745 }
1746
Werner Lemberge01406b2011-11-25 09:44:28 +01001747 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001748 error = FT_THROW( Invalid_File_Format );
Werner Lemberg4086fb72012-03-01 08:55:40 +01001749 goto Exit;
1750
1751 Missing_Encoding:
1752 /* Missing ENCODING field. */
1753 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001754 error = FT_THROW( Missing_Encoding_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001755
1756 Exit:
Werner Lemberg758587d2016-01-12 22:20:06 +01001757 if ( error && ( p->flags & BDF_GLYPH_ ) )
Werner Lembergf4c94d42010-06-19 16:08:31 +02001758 FT_FREE( p->glyph_name );
1759
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001760 return error;
David Turner993a8d02002-05-18 12:03:43 +00001761 }
1762
David Turner993a8d02002-05-18 12:03:43 +00001763
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001764 /* Load the font properties. */
1765 static FT_Error
1766 _bdf_parse_properties( char* line,
1767 unsigned long linelen,
1768 unsigned long lineno,
1769 void* call_data,
1770 void* client_data )
1771 {
1772 unsigned long vlen;
1773 _bdf_line_func_t* next;
1774 _bdf_parse_t* p;
1775 char* name;
1776 char* value;
1777 char nbuf[128];
Werner Lemberge3c93012013-03-14 11:21:17 +01001778 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001779
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001780 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001781
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001782
1783 next = (_bdf_line_func_t *)call_data;
1784 p = (_bdf_parse_t *) client_data;
1785
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001786 /* Check for the end of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001787 if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001788 {
1789 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1790 /* encountered yet, then make sure they are added as properties and */
1791 /* make sure they are set from the font bounding box info. */
1792 /* */
1793 /* This is *always* done regardless of the options, because X11 */
1794 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001795 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001796 {
1797 p->font->font_ascent = p->font->bbx.ascent;
1798 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001799 error = _bdf_add_property( p->font, "FONT_ASCENT",
Werner Lemberge01406b2011-11-25 09:44:28 +01001800 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001801 if ( error )
1802 goto Exit;
1803
1804 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
David Turner993a8d02002-05-18 12:03:43 +00001805 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001806
Werner Lemberg428c2e42003-04-25 05:35:04 +00001807 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001808 {
1809 p->font->font_descent = p->font->bbx.descent;
1810 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001811 error = _bdf_add_property( p->font, "FONT_DESCENT",
Werner Lemberge01406b2011-11-25 09:44:28 +01001812 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001813 if ( error )
1814 goto Exit;
1815
1816 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
David Turner993a8d02002-05-18 12:03:43 +00001817 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001818
Werner Lemberg758587d2016-01-12 22:20:06 +01001819 p->flags &= ~BDF_PROPS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001820 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001821
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001822 goto Exit;
1823 }
David Turner993a8d02002-05-18 12:03:43 +00001824
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001825 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001826 if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001827 goto Exit;
1828
1829 /* Handle COMMENT fields and properties in a special way to preserve */
1830 /* the spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001831 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001832 {
David Turner993a8d02002-05-18 12:03:43 +00001833 name = value = line;
1834 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001835 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001836 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01001837 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001838 if ( error )
1839 goto Exit;
1840 }
1841 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1842 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001843 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001844 if ( error )
1845 goto Exit;
1846 }
1847 else
1848 {
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001849 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001850 if ( error )
1851 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001852 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001853
David Turner68df4f72005-03-15 18:18:57 +00001854 _bdf_list_shift( &p->list, 1 );
1855 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001856
Werner Lemberge01406b2011-11-25 09:44:28 +01001857 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001858 if ( error )
1859 goto Exit;
1860 }
1861
1862 Exit:
1863 return error;
David Turner993a8d02002-05-18 12:03:43 +00001864 }
1865
David Turner993a8d02002-05-18 12:03:43 +00001866
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001867 /* Load the font header. */
1868 static FT_Error
1869 _bdf_parse_start( char* line,
1870 unsigned long linelen,
1871 unsigned long lineno,
1872 void* call_data,
1873 void* client_data )
1874 {
1875 unsigned long slen;
1876 _bdf_line_func_t* next;
1877 _bdf_parse_t* p;
1878 bdf_font_t* font;
1879 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001880
David Turnerd490e372002-05-28 23:40:37 +00001881 FT_Memory memory = NULL;
Werner Lemberge3c93012013-03-14 11:21:17 +01001882 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001883
1884 FT_UNUSED( lineno ); /* only used in debug mode */
1885
1886
1887 next = (_bdf_line_func_t *)call_data;
1888 p = (_bdf_parse_t *) client_data;
1889
1890 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00001891 memory = p->font->memory;
1892
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001893 /* Check for a comment. This is done to handle those fonts that have */
1894 /* comments before the STARTFONT line for some reason. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001895 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001896 {
1897 if ( p->opts->keep_comments != 0 && p->font != 0 )
1898 {
1899 linelen -= 7;
1900
1901 s = line + 7;
1902 if ( *s != 0 )
1903 {
1904 s++;
1905 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00001906 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001907
1908 error = _bdf_add_comment( p->font, s, linelen );
1909 if ( error )
1910 goto Exit;
1911 /* here font is not defined! */
1912 }
1913
1914 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001915 }
1916
Werner Lemberg758587d2016-01-12 22:20:06 +01001917 if ( !( p->flags & BDF_START_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001918 {
1919 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00001920
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001921 if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001922 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01001923 /* we don't emit an error message since this code gets */
1924 /* explicitly caught one level higher */
Werner Lemberg059bc332013-03-14 10:27:35 +01001925 error = FT_THROW( Missing_Startfont_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001926 goto Exit;
1927 }
David Turner993a8d02002-05-18 12:03:43 +00001928
Werner Lemberg758587d2016-01-12 22:20:06 +01001929 p->flags = BDF_START_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001930 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00001931
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001932 if ( FT_NEW( font ) )
1933 goto Exit;
1934 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00001935
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001936 font->memory = p->memory;
1937 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00001938
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001939 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001940 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001941 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00001942
David Turner993a8d02002-05-18 12:03:43 +00001943
Werner Lemberg7ce6c432015-12-22 05:39:58 +01001944 error = ft_hash_str_init( &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001945 if ( error )
1946 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00001947 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001948 i < _num_bdf_properties; i++, prop++ )
1949 {
Werner Lemberg609546c2015-12-20 07:17:29 +01001950 error = ft_hash_str_insert( prop->name, i,
1951 &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001952 if ( error )
1953 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001954 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001955 }
1956
Werner Lemberg31343562015-12-19 17:02:13 +01001957 if ( FT_ALLOC( p->font->internal, sizeof ( FT_HashRec ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001958 goto Exit;
Werner Lemberg7ce6c432015-12-22 05:39:58 +01001959 error = ft_hash_str_init( (FT_Hash)p->font->internal, memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001960 if ( error )
1961 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00001962 p->font->spacing = p->opts->font_spacing;
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001963 p->font->default_char = ~0UL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001964
1965 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001966 }
1967
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001968 /* Check for the start of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001969 if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001970 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001971 if ( !( p->flags & BDF_FONT_BBX_ ) )
Werner Lembergfb690292010-06-23 10:00:52 +02001972 {
1973 /* Missing the FONTBOUNDINGBOX field. */
1974 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001975 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergfb690292010-06-23 10:00:52 +02001976 goto Exit;
1977 }
1978
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001979 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001980 if ( error )
1981 goto Exit;
Werner Lembergb6b26f42016-06-09 06:53:48 +02001982
Werner Lembergb66efef2009-03-12 08:07:49 +00001983 /* at this point, `p->font' can't be NULL */
Ben Wagnera512b0f2015-12-14 09:19:52 +01001984 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1] );
Werner Lembergb6b26f42016-06-09 06:53:48 +02001985 /* We need at least 4 bytes per property. */
1986 if ( p->cnt > p->size / 4 )
1987 {
1988 p->font->props_size = 0;
1989
1990 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "STARTPROPERTIES" ));
1991 error = FT_THROW( Invalid_Argument );
1992 goto Exit;
1993 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001994
1995 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
Werner Lemberg9b6b5752012-12-15 01:34:41 +01001996 {
1997 p->font->props_size = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001998 goto Exit;
Werner Lemberg9b6b5752012-12-15 01:34:41 +01001999 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002000
Werner Lemberg758587d2016-01-12 22:20:06 +01002001 p->flags |= BDF_PROPS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002002 *next = _bdf_parse_properties;
2003
2004 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002005 }
2006
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002007 /* Check for the FONTBOUNDINGBOX field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002008 if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002009 {
Werner Lemberg758587d2016-01-12 22:20:06 +01002010 if ( !( p->flags & BDF_SIZE_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002011 {
2012 /* Missing the SIZE field. */
2013 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002014 error = FT_THROW( Missing_Size_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002015 goto Exit;
2016 }
2017
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04002018 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002019 if ( error )
2020 goto Exit;
2021
Ben Wagnera512b0f2015-12-14 09:19:52 +01002022 p->font->bbx.width = _bdf_atous( p->list.field[1] );
2023 p->font->bbx.height = _bdf_atous( p->list.field[2] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002024
Ben Wagnera512b0f2015-12-14 09:19:52 +01002025 p->font->bbx.x_offset = _bdf_atos( p->list.field[3] );
2026 p->font->bbx.y_offset = _bdf_atos( p->list.field[4] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002027
David Turnerd490e372002-05-28 23:40:37 +00002028 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002029 p->font->bbx.y_offset );
2030
2031 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002032
Werner Lemberg758587d2016-01-12 22:20:06 +01002033 p->flags |= BDF_FONT_BBX_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002034
2035 goto Exit;
2036 }
2037
2038 /* The next thing to check for is the FONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002039 if ( _bdf_strncmp( line, "FONT", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002040 {
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04002041 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002042 if ( error )
2043 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002044 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002045
David Turner68df4f72005-03-15 18:18:57 +00002046 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002047
2048 if ( !s )
2049 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002050 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002051 error = FT_THROW( Invalid_File_Format );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002052 goto Exit;
2053 }
2054
Werner Lembergfb690292010-06-23 10:00:52 +02002055 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2056 FT_FREE( p->font->name );
2057
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002058 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2059 goto Exit;
2060 FT_MEM_COPY( p->font->name, s, slen + 1 );
2061
2062 /* If the font name is an XLFD name, set the spacing to the one in */
2063 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002064 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002065 if ( error )
2066 goto Exit;
2067
Werner Lemberg758587d2016-01-12 22:20:06 +01002068 p->flags |= BDF_FONT_NAME_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002069
2070 goto Exit;
2071 }
2072
2073 /* Check for the SIZE field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002074 if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002075 {
Werner Lemberg758587d2016-01-12 22:20:06 +01002076 if ( !( p->flags & BDF_FONT_NAME_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002077 {
2078 /* Missing the FONT field. */
2079 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002080 error = FT_THROW( Missing_Font_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002081 goto Exit;
2082 }
2083
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04002084 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002085 if ( error )
2086 goto Exit;
2087
Ben Wagnera512b0f2015-12-14 09:19:52 +01002088 p->font->point_size = _bdf_atoul( p->list.field[1] );
2089 p->font->resolution_x = _bdf_atoul( p->list.field[2] );
2090 p->font->resolution_y = _bdf_atoul( p->list.field[3] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002091
2092 /* Check for the bits per pixel field. */
2093 if ( p->list.used == 5 )
2094 {
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002095 unsigned short bpp;
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002096
2097
Ben Wagnera512b0f2015-12-14 09:19:52 +01002098 bpp = (unsigned short)_bdf_atos( p->list.field[4] );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002099
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002100 /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
2101 if ( bpp > 4 )
2102 p->font->bpp = 8;
2103 else if ( bpp > 2 )
2104 p->font->bpp = 4;
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002105 else if ( bpp > 1 )
2106 p->font->bpp = 2;
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002107 else
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002108 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002109
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002110 if ( p->font->bpp != bpp )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002111 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002112 }
2113 else
2114 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002115
Werner Lemberg758587d2016-01-12 22:20:06 +01002116 p->flags |= BDF_SIZE_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002117
2118 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002119 }
2120
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002121 /* Check for the CHARS field -- font properties are optional */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002122 if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002123 {
2124 char nbuf[128];
2125
2126
Werner Lemberg758587d2016-01-12 22:20:06 +01002127 if ( !( p->flags & BDF_FONT_BBX_ ) )
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002128 {
2129 /* Missing the FONTBOUNDINGBOX field. */
2130 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002131 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002132 goto Exit;
2133 }
2134
2135 /* Add the two standard X11 properties which are required */
2136 /* for compiling fonts. */
2137 p->font->font_ascent = p->font->bbx.ascent;
2138 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04002139 error = _bdf_add_property( p->font, "FONT_ASCENT",
Werner Lemberge01406b2011-11-25 09:44:28 +01002140 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002141 if ( error )
2142 goto Exit;
2143 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2144
2145 p->font->font_descent = p->font->bbx.descent;
2146 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04002147 error = _bdf_add_property( p->font, "FONT_DESCENT",
Werner Lemberge01406b2011-11-25 09:44:28 +01002148 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002149 if ( error )
2150 goto Exit;
2151 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2152
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002153 *next = _bdf_parse_glyphs;
2154
2155 /* A special return value. */
2156 error = -1;
2157 goto Exit;
2158 }
2159
Werner Lemberge01406b2011-11-25 09:44:28 +01002160 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002161 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002162
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002163 Exit:
2164 return error;
2165 }
David Turner993a8d02002-05-18 12:03:43 +00002166
2167
Werner Lemberg9ac90602018-06-03 09:01:17 +02002168 /**************************************************************************
2169 *
2170 * API.
2171 *
2172 */
David Turner993a8d02002-05-18 12:03:43 +00002173
David Turner993a8d02002-05-18 12:03:43 +00002174
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002175 FT_LOCAL_DEF( FT_Error )
2176 bdf_load_font( FT_Stream stream,
2177 FT_Memory extmemory,
2178 bdf_options_t* opts,
2179 bdf_font_t* *font )
2180 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002181 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002182 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002183
Sean McBride7be2a942014-02-08 13:55:38 +01002184 FT_Memory memory = extmemory; /* needed for FT_NEW */
2185 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002186
2187
David Turner68df4f72005-03-15 18:18:57 +00002188 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002189 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002190
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002191 memory = NULL;
2192 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2193 p->minlb = 32767;
Werner Lemberge1ca18d2015-10-17 11:51:27 +02002194 p->size = stream->size;
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002195 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002196
David Turner68df4f72005-03-15 18:18:57 +00002197 _bdf_list_init( &p->list, extmemory );
2198
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002199 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002200 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002201 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002202 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002203
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002204 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002205 {
2206 /* If the font is not proportional, set the font's monowidth */
2207 /* field to the width of the font bounding box. */
David Turner993a8d02002-05-18 12:03:43 +00002208
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002209 if ( p->font->spacing != BDF_PROPORTIONAL )
2210 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002211
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002212 /* If the number of glyphs loaded is not that of the original count, */
2213 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002214 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002215 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002216 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2217 p->font->glyphs_used + p->font->unencoded_used ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002218 }
2219
2220 /* Once the font has been loaded, adjust the overall font metrics if */
2221 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002222 if ( p->opts->correct_metrics != 0 &&
2223 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002224 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002225 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002226 {
2227 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002228 p->font->bbx.width, p->maxrb - p->minlb ));
2229 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
David Turner993a8d02002-05-18 12:03:43 +00002230 }
2231
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002232 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002233 {
2234 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002235 p->font->bbx.x_offset, p->minlb ));
2236 p->font->bbx.x_offset = p->minlb;
David Turner993a8d02002-05-18 12:03:43 +00002237 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002238
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002239 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002240 {
2241 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002242 p->font->bbx.ascent, p->maxas ));
2243 p->font->bbx.ascent = p->maxas;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002244 }
2245
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002246 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002247 {
2248 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002249 p->font->bbx.descent, p->maxds ));
2250 p->font->bbx.descent = p->maxds;
2251 p->font->bbx.y_offset = (short)( -p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002252 }
2253
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002254 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002255 {
2256 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002257 p->font->bbx.height, p->maxas + p->maxds ));
2258 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002259 }
2260
Werner Lemberg758587d2016-01-12 22:20:06 +01002261 if ( p->flags & BDF_SWIDTH_ADJ_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002262 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2263 }
David Turner993a8d02002-05-18 12:03:43 +00002264 }
2265
Werner Lemberg758587d2016-01-12 22:20:06 +01002266 if ( p->flags & BDF_START_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002267 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002268 /* The ENDFONT field was never reached or did not exist. */
Werner Lemberg758587d2016-01-12 22:20:06 +01002269 if ( !( p->flags & BDF_GLYPHS_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002270 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002271 /* Error happened while parsing header. */
2272 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002273 error = FT_THROW( Corrupted_Font_Header );
Bungeman65d89802015-10-15 23:50:16 +02002274 goto Fail;
Werner Lemberge01406b2011-11-25 09:44:28 +01002275 }
2276 else
2277 {
2278 /* Error happened when parsing glyphs. */
2279 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002280 error = FT_THROW( Corrupted_Font_Glyphs );
Bungeman65d89802015-10-15 23:50:16 +02002281 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002282 }
David Turner993a8d02002-05-18 12:03:43 +00002283 }
2284
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002285 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002286 {
2287 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002288 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002289
Werner Lemberg370aea82010-06-08 08:37:11 +02002290 if ( p->font->comments_len > 0 )
2291 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002292 if ( FT_RENEW_ARRAY( p->font->comments,
2293 p->font->comments_len,
2294 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002295 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002296
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002297 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002298 }
David Turner993a8d02002-05-18 12:03:43 +00002299 }
Werner Lemberg5d664b62016-12-17 20:47:42 +01002300 else if ( !error )
Werner Lemberg059bc332013-03-14 10:27:35 +01002301 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002302
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002303 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002304
2305 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002306 if ( p )
2307 {
David Turner68df4f72005-03-15 18:18:57 +00002308 _bdf_list_done( &p->list );
2309
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002310 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002311
Werner Lemberg4a150132015-11-25 07:53:49 +01002312 FT_FREE( p->glyph_name );
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002313 FT_FREE( p );
2314 }
2315
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002316 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002317
2318 Fail:
2319 bdf_free_font( p->font );
2320
2321 memory = extmemory;
2322
2323 FT_FREE( p->font );
2324
2325 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002326 }
David Turner993a8d02002-05-18 12:03:43 +00002327
2328
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002329 FT_LOCAL_DEF( void )
2330 bdf_free_font( bdf_font_t* font )
2331 {
2332 bdf_property_t* prop;
2333 unsigned long i;
2334 bdf_glyph_t* glyphs;
2335 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002336
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002337
2338 if ( font == 0 )
2339 return;
David Turner993a8d02002-05-18 12:03:43 +00002340
2341 memory = font->memory;
2342
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002343 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002344
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002345 /* Free up the internal hash table of property names. */
2346 if ( font->internal )
2347 {
Werner Lemberg7ce6c432015-12-22 05:39:58 +01002348 ft_hash_str_free( (FT_Hash)font->internal, memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002349 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002350 }
2351
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002352 /* Free up the comment info. */
2353 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002354
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002355 /* Free up the properties. */
2356 for ( i = 0; i < font->props_size; i++ )
2357 {
2358 if ( font->props[i].format == BDF_ATOM )
2359 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002360 }
2361
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002362 FT_FREE( font->props );
2363
2364 /* Free up the character info. */
2365 for ( i = 0, glyphs = font->glyphs;
2366 i < font->glyphs_used; i++, glyphs++ )
2367 {
2368 FT_FREE( glyphs->name );
2369 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002370 }
2371
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002372 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2373 i++, glyphs++ )
2374 {
2375 FT_FREE( glyphs->name );
2376 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002377 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002378
2379 FT_FREE( font->glyphs );
2380 FT_FREE( font->unencoded );
2381
David Turner993a8d02002-05-18 12:03:43 +00002382 /* bdf_cleanup */
Werner Lemberg7ce6c432015-12-22 05:39:58 +01002383 ft_hash_str_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002384
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002385 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002386 for ( prop = font->user_props, i = 0;
2387 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002388 {
2389 FT_FREE( prop->name );
2390 if ( prop->format == BDF_ATOM )
2391 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002392 }
David Turner993a8d02002-05-18 12:03:43 +00002393
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002394 FT_FREE( font->user_props );
2395
2396 /* FREE( font ); */ /* XXX Fixme */
2397 }
David Turner993a8d02002-05-18 12:03:43 +00002398
2399
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002400 FT_LOCAL_DEF( bdf_property_t * )
2401 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002402 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002403 {
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002404 size_t* propid;
David Turner993a8d02002-05-18 12:03:43 +00002405
David Turner993a8d02002-05-18 12:03:43 +00002406
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002407 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002408 return 0;
2409
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002410 propid = ft_hash_str_lookup( name, (FT_Hash)font->internal );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002411
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002412 return propid ? ( font->props + *propid ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002413 }
2414
2415
2416/* END */