blob: 63813f7edc9cc981996aa7f178b1207339b07ebf [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
34#include <ft2build.h>
35
Werner Lemberg02d4d592002-05-28 22:38:05 +000036#include FT_FREETYPE_H
David Turner993a8d02002-05-18 12:03:43 +000037#include FT_INTERNAL_DEBUG_H
38#include FT_INTERNAL_STREAM_H
39#include FT_INTERNAL_OBJECTS_H
40
41#include "bdf.h"
David Turner993a8d02002-05-18 12:03:43 +000042#include "bdferror.h"
43
David Turner993a8d02002-05-18 12:03:43 +000044
Werner Lemberg9ac90602018-06-03 09:01:17 +020045 /**************************************************************************
46 *
47 * The macro FT_COMPONENT is used in trace mode. It is an implicit
48 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
49 * messages during execution.
50 */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000051#undef FT_COMPONENT
Werner Lemberga0dd16f2018-08-15 18:13:17 +020052#define FT_COMPONENT bdflib
David Turner993a8d02002-05-18 12:03:43 +000053
David Turner993a8d02002-05-18 12:03:43 +000054
Werner Lemberg9ac90602018-06-03 09:01:17 +020055 /**************************************************************************
56 *
57 * Default BDF font options.
58 *
59 */
David Turner993a8d02002-05-18 12:03:43 +000060
David Turner993a8d02002-05-18 12:03:43 +000061
David Turnerb1b47622002-05-21 21:17:43 +000062 static const bdf_options_t _bdf_opts =
Werner Lemberg7cf4d372002-05-21 14:13:01 +000063 {
David Turner993a8d02002-05-18 12:03:43 +000064 1, /* Correct metrics. */
65 1, /* Preserve unencoded glyphs. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000066 0, /* Preserve comments. */
67 BDF_PROPORTIONAL /* Default spacing. */
68 };
David Turner993a8d02002-05-18 12:03:43 +000069
David Turner993a8d02002-05-18 12:03:43 +000070
Werner Lemberg9ac90602018-06-03 09:01:17 +020071 /**************************************************************************
72 *
73 * Builtin BDF font properties.
74 *
75 */
David Turner993a8d02002-05-18 12:03:43 +000076
Werner Lemberg7cf4d372002-05-21 14:13:01 +000077 /* List of most properties that might appear in a font. Doesn't include */
78 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
David Turner993a8d02002-05-18 12:03:43 +000079
David Turnerb1b47622002-05-21 21:17:43 +000080 static const bdf_property_t _bdf_properties[] =
David Turner993a8d02002-05-18 12:03:43 +000081 {
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -040082 { "ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
83 { "AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
84 { "AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
85 { "AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
86 { "CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
87 { "CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
88 { "CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
89 { "CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
90 { "COMMENT", BDF_ATOM, 1, { 0 } },
91 { "COPYRIGHT", BDF_ATOM, 1, { 0 } },
92 { "DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
93 { "DESTINATION", BDF_CARDINAL, 1, { 0 } },
94 { "DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
95 { "END_SPACE", BDF_INTEGER, 1, { 0 } },
96 { "FACE_NAME", BDF_ATOM, 1, { 0 } },
97 { "FAMILY_NAME", BDF_ATOM, 1, { 0 } },
98 { "FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
99 { "FONT", BDF_ATOM, 1, { 0 } },
100 { "FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
101 { "FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
102 { "FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
103 { "FOUNDRY", BDF_ATOM, 1, { 0 } },
104 { "FULL_NAME", BDF_ATOM, 1, { 0 } },
105 { "ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
106 { "MAX_SPACE", BDF_INTEGER, 1, { 0 } },
107 { "MIN_SPACE", BDF_INTEGER, 1, { 0 } },
108 { "NORM_SPACE", BDF_INTEGER, 1, { 0 } },
109 { "NOTICE", BDF_ATOM, 1, { 0 } },
110 { "PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
111 { "POINT_SIZE", BDF_INTEGER, 1, { 0 } },
112 { "QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
113 { "RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
114 { "RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
115 { "RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
116 { "RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
117 { "RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
118 { "RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
119 { "RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
120 { "RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
121 { "RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
122 { "RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
123 { "RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
124 { "RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
125 { "RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
126 { "RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
127 { "RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
128 { "RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
129 { "RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
130 { "RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
131 { "RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
132 { "RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
133 { "RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
134 { "RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
135 { "RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
136 { "RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
137 { "RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
138 { "RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
139 { "RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
140 { "RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
141 { "RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
142 { "RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
143 { "RESOLUTION", BDF_INTEGER, 1, { 0 } },
144 { "RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
145 { "RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
146 { "SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
147 { "SLANT", BDF_ATOM, 1, { 0 } },
148 { "SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
149 { "SPACING", BDF_ATOM, 1, { 0 } },
150 { "STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
151 { "STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
152 { "SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
153 { "SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
154 { "SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
155 { "SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
156 { "SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
157 { "SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
158 { "UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
159 { "UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
160 { "WEIGHT", BDF_CARDINAL, 1, { 0 } },
161 { "WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
162 { "X_HEIGHT", BDF_INTEGER, 1, { 0 } },
163 { "_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
164 { "_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000165 };
David Turner993a8d02002-05-18 12:03:43 +0000166
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000167 static const unsigned long
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000168 _num_bdf_properties = sizeof ( _bdf_properties ) /
169 sizeof ( _bdf_properties[0] );
David Turner993a8d02002-05-18 12:03:43 +0000170
171
Werner Lemberg2c4832d2014-11-07 07:42:33 +0100172 /* An auxiliary macro to parse properties, to be used in conditionals. */
173 /* It behaves like `strncmp' but also tests the following character */
174 /* whether it is a whitespace or NULL. */
175 /* `property' is a constant string of length `n' to compare with. */
176#define _bdf_strncmp( name, property, n ) \
177 ( ft_strncmp( name, property, n ) || \
178 !( name[n] == ' ' || \
179 name[n] == '\0' || \
180 name[n] == '\n' || \
181 name[n] == '\r' || \
182 name[n] == '\t' ) )
183
Werner Lemberge01406b2011-11-25 09:44:28 +0100184 /* Auto correction messages. */
185#define ACMSG1 "FONT_ASCENT property missing. " \
186 "Added `FONT_ASCENT %hd'.\n"
187#define ACMSG2 "FONT_DESCENT property missing. " \
188 "Added `FONT_DESCENT %hd'.\n"
189#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
190#define ACMSG4 "Font left bearing != actual left bearing. " \
191 "Old: %hd New: %hd.\n"
192#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
193#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
194#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
195#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
196#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
197#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
198#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -0400199#define ACMSG13 "Glyph %lu extra rows removed.\n"
200#define ACMSG14 "Glyph %lu extra columns removed.\n"
Werner Lemberge01406b2011-11-25 09:44:28 +0100201#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -0400202#define ACMSG16 "Glyph %lu missing columns padded with zero bits.\n"
Werner Lemberge1ca18d2015-10-17 11:51:27 +0200203#define ACMSG17 "Adjusting number of glyphs to %ld.\n"
Werner Lemberge01406b2011-11-25 09:44:28 +0100204
205 /* Error messages. */
206#define ERRMSG1 "[line %ld] Missing `%s' line.\n"
207#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
208#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
209#define ERRMSG4 "[line %ld] BBX too big.\n"
Alexei Podtelezhnikovaf9662e2018-08-15 22:58:11 -0400210#define ERRMSG5 "[line %ld] `%s' value too big.\n"
Werner Lemberge01406b2011-11-25 09:44:28 +0100211#define ERRMSG6 "[line %ld] Input line too long.\n"
212#define ERRMSG7 "[line %ld] Font name too long.\n"
213#define ERRMSG8 "[line %ld] Invalid `%s' value.\n"
214#define ERRMSG9 "[line %ld] Invalid keyword.\n"
215
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +0100216 /* Debug messages. */
217#define DBGMSG1 " [%6ld] %s" /* no \n */
218#define DBGMSG2 " (0x%lX)\n"
219
Werner Lemberge01406b2011-11-25 09:44:28 +0100220
Werner Lemberg9ac90602018-06-03 09:01:17 +0200221 /**************************************************************************
222 *
223 * Utility types and functions.
224 *
225 */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000226
227
228 /* Function type for parsing lines of a BDF font. */
229
230 typedef FT_Error
231 (*_bdf_line_func_t)( char* line,
232 unsigned long linelen,
233 unsigned long lineno,
234 void* call_data,
235 void* client_data );
236
237
238 /* List structure for splitting lines into fields. */
239
240 typedef struct _bdf_list_t_
241 {
242 char** field;
243 unsigned long size;
244 unsigned long used;
David Turner68df4f72005-03-15 18:18:57 +0000245 FT_Memory memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000246
247 } _bdf_list_t;
248
249
250 /* Structure used while loading BDF fonts. */
251
252 typedef struct _bdf_parse_t_
253 {
254 unsigned long flags;
255 unsigned long cnt;
256 unsigned long row;
257
258 short minlb;
259 short maxlb;
260 short maxrb;
261 short maxas;
262 short maxds;
263
264 short rbearing;
265
266 char* glyph_name;
267 long glyph_enc;
268
269 bdf_font_t* font;
270 bdf_options_t* opts;
271
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000272 _bdf_list_t list;
273
274 FT_Memory memory;
Werner Lemberge1ca18d2015-10-17 11:51:27 +0200275 unsigned long size; /* the stream size */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000276
277 } _bdf_parse_t;
278
279
Werner Lemberga08b2172007-03-28 07:17:17 +0000280#define setsbit( m, cc ) \
281 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
282#define sbitset( m, cc ) \
283 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000284
285
David Turner68df4f72005-03-15 18:18:57 +0000286 static void
287 _bdf_list_init( _bdf_list_t* list,
288 FT_Memory memory )
289 {
Werner Lembergebf55852005-03-16 01:49:54 +0000290 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000291 list->memory = memory;
292 }
293
Werner Lembergebf55852005-03-16 01:49:54 +0000294
David Turner68df4f72005-03-15 18:18:57 +0000295 static void
296 _bdf_list_done( _bdf_list_t* list )
297 {
298 FT_Memory memory = list->memory;
299
Werner Lembergebf55852005-03-16 01:49:54 +0000300
David Turner68df4f72005-03-15 18:18:57 +0000301 if ( memory )
302 {
303 FT_FREE( list->field );
Werner Lembergebf55852005-03-16 01:49:54 +0000304 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000305 }
306 }
307
308
309 static FT_Error
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900310 _bdf_list_ensure( _bdf_list_t* list,
311 unsigned long num_items ) /* same as _bdf_list_t.used */
David Turner68df4f72005-03-15 18:18:57 +0000312 {
Werner Lemberge3c93012013-03-14 11:21:17 +0100313 FT_Error error = FT_Err_Ok;
Werner Lembergebf55852005-03-16 01:49:54 +0000314
David Turner68df4f72005-03-15 18:18:57 +0000315
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900316 if ( num_items > list->size )
David Turner68df4f72005-03-15 18:18:57 +0000317 {
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900318 unsigned long oldsize = list->size; /* same as _bdf_list_t.size */
Werner Lembergcee5d592012-03-01 09:26:03 +0100319 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 5;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900320 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
321 FT_Memory memory = list->memory;
David Turner68df4f72005-03-15 18:18:57 +0000322
Werner Lembergebf55852005-03-16 01:49:54 +0000323
David Turner68df4f72005-03-15 18:18:57 +0000324 if ( oldsize == bigsize )
325 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100326 error = FT_THROW( Out_Of_Memory );
David Turner68df4f72005-03-15 18:18:57 +0000327 goto Exit;
328 }
329 else if ( newsize < oldsize || newsize > bigsize )
330 newsize = bigsize;
331
332 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
333 goto Exit;
334
335 list->size = newsize;
336 }
Werner Lembergebf55852005-03-16 01:49:54 +0000337
David Turner68df4f72005-03-15 18:18:57 +0000338 Exit:
339 return error;
340 }
341
342
343 static void
344 _bdf_list_shift( _bdf_list_t* list,
345 unsigned long n )
346 {
347 unsigned long i, u;
348
349
350 if ( list == 0 || list->used == 0 || n == 0 )
351 return;
352
353 if ( n >= list->used )
354 {
355 list->used = 0;
356 return;
357 }
358
359 for ( u = n, i = 0; u < list->used; i++, u++ )
360 list->field[i] = list->field[u];
361 list->used -= n;
362 }
363
364
Werner Lembergf4c94d42010-06-19 16:08:31 +0200365 /* An empty string for empty fields. */
366
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -0400367 static const char empty[] = ""; /* XXX eliminate this */
Werner Lembergf4c94d42010-06-19 16:08:31 +0200368
369
David Turner68df4f72005-03-15 18:18:57 +0000370 static char *
371 _bdf_list_join( _bdf_list_t* list,
372 int c,
373 unsigned long *alen )
374 {
375 unsigned long i, j;
Werner Lembergdc624ca2013-06-04 10:30:48 +0200376 char* dp;
David Turner68df4f72005-03-15 18:18:57 +0000377
378
379 *alen = 0;
380
381 if ( list == 0 || list->used == 0 )
382 return 0;
383
384 dp = list->field[0];
385 for ( i = j = 0; i < list->used; i++ )
386 {
Werner Lembergdc624ca2013-06-04 10:30:48 +0200387 char* fp = list->field[i];
388
389
David Turner68df4f72005-03-15 18:18:57 +0000390 while ( *fp )
391 dp[j++] = *fp++;
392
393 if ( i + 1 < list->used )
394 dp[j++] = (char)c;
395 }
Werner Lembergf4c94d42010-06-19 16:08:31 +0200396 if ( dp != empty )
397 dp[j] = 0;
David Turner68df4f72005-03-15 18:18:57 +0000398
399 *alen = j;
400 return dp;
401 }
402
403
Werner Lemberg03242f52012-02-26 06:52:56 +0100404 /* The code below ensures that we have at least 4 + 1 `field' */
405 /* elements in `list' (which are possibly NULL) so that we */
406 /* don't have to check the number of fields in most cases. */
407
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000408 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000409 _bdf_list_split( _bdf_list_t* list,
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -0400410 const char* separators,
David Turner68df4f72005-03-15 18:18:57 +0000411 char* line,
412 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000413 {
Werner Lemberg3c374c82015-02-22 09:16:53 +0100414 unsigned long final_empty;
415 int mult;
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -0400416 const char *sp, *end;
417 char *ep;
Werner Lemberg3c374c82015-02-22 09:16:53 +0100418 char seps[32];
419 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000420
421
422 /* Initialize the list. */
423 list->used = 0;
Werner Lembergd9c16592012-03-01 15:15:00 +0100424 if ( list->size )
425 {
426 list->field[0] = (char*)empty;
427 list->field[1] = (char*)empty;
428 list->field[2] = (char*)empty;
429 list->field[3] = (char*)empty;
Werner Lemberg649c6732012-03-16 21:12:41 +0100430 list->field[4] = (char*)empty;
Werner Lembergd9c16592012-03-01 15:15:00 +0100431 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000432
433 /* If the line is empty, then simply return. */
434 if ( linelen == 0 || line[0] == 0 )
435 goto Exit;
436
437 /* In the original code, if the `separators' parameter is NULL or */
438 /* empty, the list is split into individual bytes. We don't need */
439 /* this, so an error is signaled. */
440 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000441 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100442 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000443 goto Exit;
444 }
445
446 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000447 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000448
449 /* If the very last character of the separator string is a plus, then */
450 /* set the `mult' flag to indicate that multiple separators should be */
451 /* collapsed into one. */
452 for ( mult = 0, sp = separators; sp && *sp; sp++ )
453 {
454 if ( *sp == '+' && *( sp + 1 ) == 0 )
455 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000456 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000457 setsbit( seps, *sp );
458 }
459
460 /* Break the line up into fields. */
461 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
462 sp < end && *sp; )
463 {
464 /* Collect everything that is not a separator. */
465 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
466 ;
467
468 /* Resize the list if necessary. */
469 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000470 {
Werner Lembergebf55852005-03-16 01:49:54 +0000471 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000472 if ( error )
473 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000474 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000475
476 /* Assign the field appropriately. */
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -0400477 list->field[list->used++] = ( ep > sp ) ? (char*)sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000478
479 sp = ep;
480
481 if ( mult )
482 {
483 /* If multiple separators should be collapsed, do it now by */
484 /* setting all the separator characters to 0. */
485 for ( ; *ep && sbitset( seps, *ep ); ep++ )
486 *ep = 0;
487 }
488 else if ( *ep != 0 )
489 /* Don't collapse multiple separators by making them 0, so just */
490 /* make the one encountered 0. */
491 *ep++ = 0;
492
493 final_empty = ( ep > sp && *ep == 0 );
494 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000495 }
496
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000497 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000498 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000499 {
Werner Lembergebf55852005-03-16 01:49:54 +0000500 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000501 if ( error )
502 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000503 }
504
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000505 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000506 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000507
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000508 list->field[list->used] = 0;
509
510 Exit:
511 return error;
David Turner993a8d02002-05-18 12:03:43 +0000512 }
513
David Turner993a8d02002-05-18 12:03:43 +0000514
David Turner68df4f72005-03-15 18:18:57 +0000515#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000516
Werner Lembergebf55852005-03-16 01:49:54 +0000517
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000518 static FT_Error
519 _bdf_readstream( FT_Stream stream,
520 _bdf_line_func_t callback,
521 void* client_data,
522 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000523 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000524 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000525 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900526 int refill, hold, to_skip;
527 ptrdiff_t bytes, start, end, cursor, avail;
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -0400528 char* buf = NULL;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000529 FT_Memory memory = stream->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100530 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000531
David Turner993a8d02002-05-18 12:03:43 +0000532
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000533 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000534 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100535 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000536 goto Exit;
537 }
David Turner993a8d02002-05-18 12:03:43 +0000538
Werner Lembergebf55852005-03-16 01:49:54 +0000539 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000540 buf_size = 1024;
541
542 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000543 goto Exit;
544
Werner Lembergebf55852005-03-16 01:49:54 +0000545 cb = callback;
546 lineno = 1;
547 buf[0] = 0;
548 start = 0;
Werner Lembergebf55852005-03-16 01:49:54 +0000549 avail = 0;
550 cursor = 0;
551 refill = 1;
552 to_skip = NO_SKIP;
553 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000554
David Turner68df4f72005-03-15 18:18:57 +0000555 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000556 {
David Turner68df4f72005-03-15 18:18:57 +0000557 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000558 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +0200559 bytes = (ptrdiff_t)FT_Stream_TryRead(
560 stream, (FT_Byte*)buf + cursor,
Werner Lemberg3c374c82015-02-22 09:16:53 +0100561 buf_size - (unsigned long)cursor );
David Turner68df4f72005-03-15 18:18:57 +0000562 avail = cursor + bytes;
563 cursor = 0;
564 refill = 0;
565 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000566
David Turner68df4f72005-03-15 18:18:57 +0000567 end = start;
568
Werner Lembergebf55852005-03-16 01:49:54 +0000569 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000570 if ( start < avail && buf[start] == to_skip )
571 {
572 start += 1;
573 to_skip = NO_SKIP;
574 continue;
575 }
576
577 /* try to find the end of the line */
578 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
579 end++;
580
Werner Lembergebf55852005-03-16 01:49:54 +0000581 /* if we hit the end of the buffer, try shifting its content */
582 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000583 if ( end >= avail )
584 {
585 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
586 break; /* ignore it then exit */
587
588 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000589 {
Werner Lembergebf55852005-03-16 01:49:54 +0000590 /* this line is definitely too long; try resizing the input */
591 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000592 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000593
Werner Lembergebf55852005-03-16 01:49:54 +0000594
595 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000596 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100597 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +0100598 error = FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +0000599 goto Exit;
600 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000601
Werner Lembergebf55852005-03-16 01:49:54 +0000602 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000603 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
604 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000605
Werner Lemberg3c374c82015-02-22 09:16:53 +0100606 cursor = (ptrdiff_t)buf_size;
David Turner68df4f72005-03-15 18:18:57 +0000607 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000608 }
609 else
610 {
David Turner68df4f72005-03-15 18:18:57 +0000611 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000612
Werner Lemberg04e547b2013-04-03 07:37:56 +0200613 FT_MEM_MOVE( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000614
David Turner68df4f72005-03-15 18:18:57 +0000615 cursor = bytes;
616 avail -= bytes;
617 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000618 }
David Turner68df4f72005-03-15 18:18:57 +0000619 refill = 1;
620 continue;
David Turner993a8d02002-05-18 12:03:43 +0000621 }
David Turner68df4f72005-03-15 18:18:57 +0000622
623 /* Temporarily NUL-terminate the line. */
624 hold = buf[end];
625 buf[end] = 0;
626
Werner Lemberg0098d552014-12-07 11:03:57 +0100627 /* XXX: Use encoding independent value for 0x1A */
628 if ( buf[start] != '#' && buf[start] != 0x1A && end > start )
David Turner68df4f72005-03-15 18:18:57 +0000629 {
Werner Lemberga9f6f852012-12-17 09:08:09 +0100630 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergebf55852005-03-16 01:49:54 +0000631 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200632 /* Redo if we have encountered CHARS without properties. */
633 if ( error == -1 )
Werner Lemberga9f6f852012-12-17 09:08:09 +0100634 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200635 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000636 if ( error )
637 break;
638 }
639
640 lineno += 1;
641 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000642 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000643
644 if ( hold == '\n' )
645 to_skip = '\r';
646 else if ( hold == '\r' )
647 to_skip = '\n';
648 else
649 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000650 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000651
David Turner68df4f72005-03-15 18:18:57 +0000652 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000653
654 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000655 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000656 return error;
David Turner993a8d02002-05-18 12:03:43 +0000657 }
David Turner993a8d02002-05-18 12:03:43 +0000658
659
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000660 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000661
David Turnerb1b47622002-05-21 21:17:43 +0000662 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000663 {
David Turner993a8d02002-05-18 12:03:43 +0000664 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
668 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
Werner Lemberg0098d552014-12-07 11:03:57 +0100669 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000670 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
671 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg0098d552014-12-07 11:03:57 +0100672 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000673 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
674 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000675 };
David Turner993a8d02002-05-18 12:03:43 +0000676
David Turnerb1b47622002-05-21 21:17:43 +0000677 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000678 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
David Turner993a8d02002-05-18 12:03:43 +0000680 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
682 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000683 };
David Turner993a8d02002-05-18 12:03:43 +0000684
David Turnerb1b47622002-05-21 21:17:43 +0000685 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000686 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100687 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
688 0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000689 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
690 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000691 };
David Turner993a8d02002-05-18 12:03:43 +0000692
David Turner993a8d02002-05-18 12:03:43 +0000693
Ben Wagnera512b0f2015-12-14 09:19:52 +0100694 /* Routine to convert a decimal ASCII string to an unsigned long integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000695 static unsigned long
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -0400696 _bdf_atoul( const char* s )
David Turner993a8d02002-05-18 12:03:43 +0000697 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100698 unsigned long v;
David Turner993a8d02002-05-18 12:03:43 +0000699
700
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000701 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000702 return 0;
703
Ben Wagnera512b0f2015-12-14 09:19:52 +0100704 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200705 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100706 if ( v < ( FT_ULONG_MAX - 9 ) / 10 )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200707 v = v * 10 + a2i[(int)*s];
708 else
709 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100710 v = FT_ULONG_MAX;
Werner Lemberg47a03e92017-06-02 09:06:36 +0200711 break;
712 }
713 }
David Turner993a8d02002-05-18 12:03:43 +0000714
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000715 return v;
716 }
David Turner993a8d02002-05-18 12:03:43 +0000717
David Turner993a8d02002-05-18 12:03:43 +0000718
Ben Wagnera512b0f2015-12-14 09:19:52 +0100719 /* Routine to convert a decimal ASCII string to a signed long integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000720 static long
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -0400721 _bdf_atol( const char* s )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000722 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100723 long v, neg;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000724
725
726 if ( s == 0 || *s == 0 )
727 return 0;
728
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000729 /* Check for a minus sign. */
730 neg = 0;
731 if ( *s == '-' )
732 {
733 s++;
734 neg = 1;
735 }
736
Ben Wagnera512b0f2015-12-14 09:19:52 +0100737 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200738 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100739 if ( v < ( FT_LONG_MAX - 9 ) / 10 )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200740 v = v * 10 + a2i[(int)*s];
741 else
742 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100743 v = FT_LONG_MAX;
Werner Lemberg47a03e92017-06-02 09:06:36 +0200744 break;
745 }
746 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000747
748 return ( !neg ) ? v : -v;
749 }
750
751
Ben Wagnera512b0f2015-12-14 09:19:52 +0100752 /* Routine to convert a decimal ASCII string to an unsigned short integer. */
Werner Lembergb13945a2015-02-22 09:15:47 +0100753 static unsigned short
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -0400754 _bdf_atous( const char* s )
Werner Lembergb13945a2015-02-22 09:15:47 +0100755 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100756 unsigned short v;
Werner Lembergb13945a2015-02-22 09:15:47 +0100757
758
759 if ( s == 0 || *s == 0 )
760 return 0;
761
Ben Wagnera512b0f2015-12-14 09:19:52 +0100762 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200763 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100764 if ( v < ( FT_USHORT_MAX - 9 ) / 10 )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200765 v = (unsigned short)( v * 10 + a2i[(int)*s] );
766 else
767 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100768 v = FT_USHORT_MAX;
Werner Lemberg47a03e92017-06-02 09:06:36 +0200769 break;
770 }
771 }
Werner Lembergb13945a2015-02-22 09:15:47 +0100772
773 return v;
774 }
775
776
Ben Wagnera512b0f2015-12-14 09:19:52 +0100777 /* Routine to convert a decimal ASCII string to a signed short integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000778 static short
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -0400779 _bdf_atos( const char* s )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000780 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100781 short v, neg;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000782
783
784 if ( s == 0 || *s == 0 )
785 return 0;
786
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000787 /* Check for a minus. */
788 neg = 0;
789 if ( *s == '-' )
790 {
791 s++;
792 neg = 1;
793 }
794
Ben Wagnera512b0f2015-12-14 09:19:52 +0100795 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200796 {
797 if ( v < ( SHRT_MAX - 9 ) / 10 )
798 v = (short)( v * 10 + a2i[(int)*s] );
799 else
800 {
801 v = SHRT_MAX;
802 break;
803 }
804 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000805
Werner Lemberg233302a2002-05-22 05:41:06 +0000806 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000807 }
808
809
810 /* Routine to compare two glyphs by encoding so they can be sorted. */
811 static int
812 by_encoding( const void* a,
813 const void* b )
814 {
815 bdf_glyph_t *c1, *c2;
816
817
818 c1 = (bdf_glyph_t *)a;
819 c2 = (bdf_glyph_t *)b;
820
821 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000822 return -1;
David Turner68df4f72005-03-15 18:18:57 +0000823
824 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000825 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000826
David Turner993a8d02002-05-18 12:03:43 +0000827 return 0;
David Turner993a8d02002-05-18 12:03:43 +0000828 }
829
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000830
831 static FT_Error
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -0400832 bdf_create_property( const char* name,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000833 int format,
834 bdf_font_t* font )
835 {
suzuki toshiya704f4d72009-09-13 00:50:14 +0900836 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000837 bdf_property_t* p;
838 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100839 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000840
841
Werner Lemberg96ddc672011-06-29 09:15:54 +0200842 /* First check whether the property has */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000843 /* already been added or not. If it has, then */
844 /* simply ignore it. */
Werner Lemberg609546c2015-12-20 07:17:29 +0100845 if ( ft_hash_str_lookup( name, &(font->proptbl) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000846 goto Exit;
847
David Turner68df4f72005-03-15 18:18:57 +0000848 if ( FT_RENEW_ARRAY( font->user_props,
849 font->nuser_props,
850 font->nuser_props + 1 ) )
851 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000852
853 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +0000854 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000855
suzuki toshiya704f4d72009-09-13 00:50:14 +0900856 n = ft_strlen( name ) + 1;
857 if ( n > FT_ULONG_MAX )
Werner Lemberg059bc332013-03-14 10:27:35 +0100858 return FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +0000859
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000860 if ( FT_NEW_ARRAY( p->name, n ) )
861 goto Exit;
862
863 FT_MEM_COPY( (char *)p->name, name, n );
864
865 p->format = format;
866 p->builtin = 0;
867
868 n = _num_bdf_properties + font->nuser_props;
869
Werner Lemberg609546c2015-12-20 07:17:29 +0100870 error = ft_hash_str_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000871 if ( error )
872 goto Exit;
873
874 font->nuser_props++;
875
876 Exit:
David Turner993a8d02002-05-18 12:03:43 +0000877 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000878 }
David Turner993a8d02002-05-18 12:03:43 +0000879
880
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100881 FT_LOCAL_DEF( bdf_property_t* )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000882 bdf_get_property( char* name,
883 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +0000884 {
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100885 size_t* propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000886
887
888 if ( name == 0 || *name == 0 )
889 return 0;
890
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100891 if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000892 return 0;
893
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100894 if ( *propid >= _num_bdf_properties )
895 return font->user_props + ( *propid - _num_bdf_properties );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000896
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100897 return (bdf_property_t*)_bdf_properties + *propid;
David Turner993a8d02002-05-18 12:03:43 +0000898 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000899
900
Werner Lemberg9ac90602018-06-03 09:01:17 +0200901 /**************************************************************************
902 *
903 * BDF font file parsing flags and functions.
904 *
905 */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000906
907
908 /* Parse flags. */
909
Werner Lemberg758587d2016-01-12 22:20:06 +0100910#define BDF_START_ 0x0001U
911#define BDF_FONT_NAME_ 0x0002U
912#define BDF_SIZE_ 0x0004U
913#define BDF_FONT_BBX_ 0x0008U
914#define BDF_PROPS_ 0x0010U
915#define BDF_GLYPHS_ 0x0020U
916#define BDF_GLYPH_ 0x0040U
917#define BDF_ENCODING_ 0x0080U
918#define BDF_SWIDTH_ 0x0100U
919#define BDF_DWIDTH_ 0x0200U
920#define BDF_BBX_ 0x0400U
921#define BDF_BITMAP_ 0x0800U
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000922
Werner Lemberg758587d2016-01-12 22:20:06 +0100923#define BDF_SWIDTH_ADJ_ 0x1000U
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000924
Werner Lemberg758587d2016-01-12 22:20:06 +0100925#define BDF_GLYPH_BITS_ ( BDF_GLYPH_ | \
926 BDF_ENCODING_ | \
927 BDF_SWIDTH_ | \
928 BDF_DWIDTH_ | \
929 BDF_BBX_ | \
930 BDF_BITMAP_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000931
Werner Lemberg758587d2016-01-12 22:20:06 +0100932#define BDF_GLYPH_WIDTH_CHECK_ 0x40000000UL
933#define BDF_GLYPH_HEIGHT_CHECK_ 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000934
935
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000936 static FT_Error
937 _bdf_add_comment( bdf_font_t* font,
938 char* comment,
939 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +0000940 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000941 char* cp;
942 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100943 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000944
945
David Turner68df4f72005-03-15 18:18:57 +0000946 if ( FT_RENEW_ARRAY( font->comments,
947 font->comments_len,
948 font->comments_len + len + 1 ) )
949 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000950
951 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +0000952
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000953 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +0000954 cp[len] = '\n';
955
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000956 font->comments_len += len + 1;
957
958 Exit:
959 return error;
David Turner993a8d02002-05-18 12:03:43 +0000960 }
961
David Turner993a8d02002-05-18 12:03:43 +0000962
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000963 /* Set the spacing from the font name if it exists, or set it to the */
964 /* default specified in the options. */
965 static FT_Error
966 _bdf_set_default_spacing( bdf_font_t* font,
Werner Lemberge01406b2011-11-25 09:44:28 +0100967 bdf_options_t* opts,
968 unsigned long lineno )
David Turner993a8d02002-05-18 12:03:43 +0000969 {
suzuki toshiya704f4d72009-09-13 00:50:14 +0900970 size_t len;
971 char name[256];
972 _bdf_list_t list;
973 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100974 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000975
Dave Arnoldc3782492013-06-05 19:57:55 +0200976 FT_UNUSED( lineno ); /* only used in debug mode */
977
David Turner993a8d02002-05-18 12:03:43 +0000978
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000979 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
980 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100981 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000982 goto Exit;
983 }
David Turner993a8d02002-05-18 12:03:43 +0000984
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000985 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +0000986
David Turner68df4f72005-03-15 18:18:57 +0000987 _bdf_list_init( &list, memory );
988
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000989 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +0000990
suzuki toshiya704f4d72009-09-13 00:50:14 +0900991 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +0000992 /* Limit ourselves to 256 characters in the font name. */
993 if ( len >= 256 )
994 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100995 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +0100996 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +0000997 goto Exit;
998 }
999
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001000 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001001
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001002 error = _bdf_list_split( &list, "-", name, (unsigned long)len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001003 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001004 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001005
1006 if ( list.used == 15 )
1007 {
1008 switch ( list.field[11][0] )
1009 {
1010 case 'C':
1011 case 'c':
1012 font->spacing = BDF_CHARCELL;
1013 break;
1014 case 'M':
1015 case 'm':
1016 font->spacing = BDF_MONOWIDTH;
1017 break;
1018 case 'P':
1019 case 'p':
1020 font->spacing = BDF_PROPORTIONAL;
1021 break;
David Turner993a8d02002-05-18 12:03:43 +00001022 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001023 }
1024
David Turner68df4f72005-03-15 18:18:57 +00001025 Fail:
1026 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001027
1028 Exit:
1029 return error;
David Turner993a8d02002-05-18 12:03:43 +00001030 }
David Turner993a8d02002-05-18 12:03:43 +00001031
1032
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001033 /* Determine whether the property is an atom or not. If it is, then */
1034 /* clean it up so the double quotes are removed if they exist. */
1035 static int
1036 _bdf_is_atom( char* line,
1037 unsigned long linelen,
1038 char** name,
1039 char** value,
1040 bdf_font_t* font )
1041 {
1042 int hold;
1043 char *sp, *ep;
1044 bdf_property_t* p;
1045
David Turner993a8d02002-05-18 12:03:43 +00001046
1047 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001048
1049 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001050 ep++;
1051
1052 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001053 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001054 {
1055 hold = *ep;
1056 *ep = 0;
1057 }
1058
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001059 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001060
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001061 /* Restore the character that was saved before any return can happen. */
1062 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001063 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001064
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001065 /* If the property exists and is not an atom, just return here. */
1066 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001067 return 0;
1068
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001069 /* The property is an atom. Trim all leading and trailing whitespace */
1070 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001071 sp = ep;
1072 ep = line + linelen;
1073
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001074 /* Trim the leading whitespace if it exists. */
Werner Lemberg320d4972012-02-24 18:06:46 +01001075 if ( *sp )
1076 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001077 while ( *sp &&
1078 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001079 sp++;
1080
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001081 /* Trim the leading double quote if it exists. */
1082 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001083 sp++;
1084 *value = sp;
1085
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001086 /* Trim the trailing whitespace if it exists. */
1087 while ( ep > sp &&
1088 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001089 *--ep = 0;
1090
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001091 /* Trim the trailing double quote if it exists. */
1092 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001093 *--ep = 0;
1094
1095 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001096 }
David Turner993a8d02002-05-18 12:03:43 +00001097
1098
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001099 static FT_Error
Werner Lemberge01406b2011-11-25 09:44:28 +01001100 _bdf_add_property( bdf_font_t* font,
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001101 const char* name,
Werner Lemberge01406b2011-11-25 09:44:28 +01001102 char* value,
1103 unsigned long lineno )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001104 {
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001105 size_t* propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001106 bdf_property_t *prop, *fp;
1107 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001108 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001109
Dave Arnoldc3782492013-06-05 19:57:55 +02001110 FT_UNUSED( lineno ); /* only used in debug mode */
1111
David Turner993a8d02002-05-18 12:03:43 +00001112
Werner Lemberg96ddc672011-06-29 09:15:54 +02001113 /* First, check whether the property already exists in the font. */
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001114 if ( ( propid = ft_hash_str_lookup( name,
1115 (FT_Hash)font->internal ) ) != NULL )
David Turner993a8d02002-05-18 12:03:43 +00001116 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001117 /* The property already exists in the font, so simply replace */
1118 /* the value of the property with the current value. */
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001119 fp = font->props + *propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001120
David Turnerb1b47622002-05-21 21:17:43 +00001121 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001122 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001123 case BDF_ATOM:
1124 /* Delete the current atom if it exists. */
1125 FT_FREE( fp->value.atom );
1126
David Turnerc0f9c4a2007-02-12 14:55:03 +00001127 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001128 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001129 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001130 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001131 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001132 break;
1133
1134 case BDF_INTEGER:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001135 fp->value.l = _bdf_atol( value );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001136 break;
1137
1138 case BDF_CARDINAL:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001139 fp->value.ul = _bdf_atoul( value );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001140 break;
David Turnerd490e372002-05-28 23:40:37 +00001141
David Turnerb1b47622002-05-21 21:17:43 +00001142 default:
1143 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001144 }
David Turnerd490e372002-05-28 23:40:37 +00001145
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001146 goto Exit;
1147 }
1148
1149 /* See whether this property type exists yet or not. */
1150 /* If not, create it. */
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001151 propid = ft_hash_str_lookup( name, &(font->proptbl) );
Werner Lemberg4441f7b2016-12-26 17:08:17 +01001152 if ( !propid )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001153 {
1154 error = bdf_create_property( name, BDF_ATOM, font );
1155 if ( error )
1156 goto Exit;
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001157 propid = ft_hash_str_lookup( name, &(font->proptbl) );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001158 }
1159
Werner Lembergb6b26f42016-06-09 06:53:48 +02001160 /* Allocate another property if this is overflowing. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001161 if ( font->props_used == font->props_size )
1162 {
1163 if ( font->props_size == 0 )
1164 {
1165 if ( FT_NEW_ARRAY( font->props, 1 ) )
1166 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001167 }
1168 else
1169 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001170 if ( FT_RENEW_ARRAY( font->props,
1171 font->props_size,
1172 font->props_size + 1 ) )
1173 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001174 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001175
David Turner993a8d02002-05-18 12:03:43 +00001176 fp = font->props + font->props_size;
Werner Lemberg2ecf89b2016-09-28 19:06:21 +02001177 FT_ZERO( fp );
David Turner993a8d02002-05-18 12:03:43 +00001178 font->props_size++;
1179 }
1180
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001181 if ( *propid >= _num_bdf_properties )
1182 prop = font->user_props + ( *propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001183 else
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001184 prop = (bdf_property_t*)_bdf_properties + *propid;
David Turner993a8d02002-05-18 12:03:43 +00001185
1186 fp = font->props + font->props_used;
1187
1188 fp->name = prop->name;
1189 fp->format = prop->format;
1190 fp->builtin = prop->builtin;
1191
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001192 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001193 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001194 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001195 fp->value.atom = 0;
1196 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001197 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001198 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001199 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001200 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001201 break;
David Turner993a8d02002-05-18 12:03:43 +00001202
1203 case BDF_INTEGER:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001204 fp->value.l = _bdf_atol( value );
David Turner993a8d02002-05-18 12:03:43 +00001205 break;
1206
1207 case BDF_CARDINAL:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001208 fp->value.ul = _bdf_atoul( value );
David Turner993a8d02002-05-18 12:03:43 +00001209 break;
David Turner993a8d02002-05-18 12:03:43 +00001210 }
1211
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001212 /* If the property happens to be a comment, then it doesn't need */
1213 /* to be added to the internal hash table. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001214 if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 )
Werner Lemberg370aea82010-06-08 08:37:11 +02001215 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001216 /* Add the property to the font property table. */
Werner Lemberg609546c2015-12-20 07:17:29 +01001217 error = ft_hash_str_insert( fp->name,
1218 font->props_used,
1219 (FT_Hash)font->internal,
1220 memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001221 if ( error )
1222 goto Exit;
1223 }
David Turner993a8d02002-05-18 12:03:43 +00001224
1225 font->props_used++;
1226
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001227 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1228 /* property needs to be located if it exists in the property list, the */
1229 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1230 /* present, and the SPACING property should override the default */
1231 /* spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001232 if ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 )
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001233 font->default_char = fp->value.ul;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001234 else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001235 font->font_ascent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001236 else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001237 font->font_descent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001238 else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001239 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001240 if ( !fp->value.atom )
1241 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001242 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001243 error = FT_THROW( Invalid_File_Format );
Werner Lembergb66efef2009-03-12 08:07:49 +00001244 goto Exit;
1245 }
1246
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001247 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001248 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001249 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001250 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001251 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001252 font->spacing = BDF_CHARCELL;
1253 }
1254
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001255 Exit:
1256 return error;
David Turner993a8d02002-05-18 12:03:43 +00001257 }
1258
David Turner993a8d02002-05-18 12:03:43 +00001259
David Turnerb1b47622002-05-21 21:17:43 +00001260 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001261 {
1262 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1263 };
1264
1265
Werner Lembergf1b61832018-12-04 11:51:15 +01001266 static FT_Error
1267 _bdf_parse_end( char* line,
1268 unsigned long linelen,
1269 unsigned long lineno,
1270 void* call_data,
1271 void* client_data )
1272 {
1273 /* a no-op; we ignore everything after `ENDFONT' */
1274
1275 FT_UNUSED( line );
1276 FT_UNUSED( linelen );
1277 FT_UNUSED( lineno );
1278 FT_UNUSED( call_data );
1279 FT_UNUSED( client_data );
1280
1281 return FT_Err_Ok;
1282 }
1283
1284
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001285 /* Actually parse the glyph info and bitmaps. */
1286 static FT_Error
1287 _bdf_parse_glyphs( char* line,
1288 unsigned long linelen,
1289 unsigned long lineno,
1290 void* call_data,
1291 void* client_data )
1292 {
1293 int c, mask_index;
1294 char* s;
1295 unsigned char* bp;
1296 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001297
Werner Lembergf1b61832018-12-04 11:51:15 +01001298 _bdf_line_func_t* next;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001299 _bdf_parse_t* p;
1300 bdf_glyph_t* glyph;
1301 bdf_font_t* font;
1302
1303 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001304 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001305
1306 FT_UNUSED( lineno ); /* only used in debug mode */
1307
1308
Werner Lembergf1b61832018-12-04 11:51:15 +01001309 next = (_bdf_line_func_t *)call_data;
1310 p = (_bdf_parse_t *) client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001311
1312 font = p->font;
1313 memory = font->memory;
1314
1315 /* Check for a comment. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001316 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001317 {
1318 linelen -= 7;
1319
1320 s = line + 7;
1321 if ( *s != 0 )
1322 {
1323 s++;
1324 linelen--;
1325 }
1326 error = _bdf_add_comment( p->font, s, linelen );
1327 goto Exit;
1328 }
1329
1330 /* The very first thing expected is the number of glyphs. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001331 if ( !( p->flags & BDF_GLYPHS_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001332 {
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001333 if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001334 {
1335 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001336 error = FT_THROW( Missing_Chars_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001337 goto Exit;
1338 }
1339
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001340 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001341 if ( error )
1342 goto Exit;
Ben Wagnera512b0f2015-12-14 09:19:52 +01001343 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001344
Werner Lemberge1ca18d2015-10-17 11:51:27 +02001345 /* We need at least 20 bytes per glyph. */
1346 if ( p->cnt > p->size / 20 )
1347 {
Werner Lemberg797ca5a2015-10-17 11:57:16 +02001348 p->cnt = font->glyphs_size = p->size / 20;
Werner Lemberge1ca18d2015-10-17 11:51:27 +02001349 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG17, p->cnt ));
1350 }
1351
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001352 /* Make sure the number of glyphs is non-zero. */
1353 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001354 font->glyphs_size = 64;
1355
Werner Lemberga08b2172007-03-28 07:17:17 +00001356 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1357 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001358 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001359 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001360 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001361 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001362 goto Exit;
1363 }
1364
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001365 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1366 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001367
Werner Lemberg758587d2016-01-12 22:20:06 +01001368 p->flags |= BDF_GLYPHS_;
David Turner993a8d02002-05-18 12:03:43 +00001369
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001370 goto Exit;
1371 }
1372
1373 /* Check for the ENDFONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001374 if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001375 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001376 if ( p->flags & BDF_GLYPH_BITS_ )
Werner Lembergaf834612014-11-22 13:29:10 +01001377 {
1378 /* Missing ENDCHAR field. */
1379 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1380 error = FT_THROW( Corrupted_Font_Glyphs );
1381 goto Exit;
1382 }
1383
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001384 /* Sort the glyphs by encoding. */
1385 ft_qsort( (char *)font->glyphs,
1386 font->glyphs_used,
1387 sizeof ( bdf_glyph_t ),
1388 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001389
Werner Lemberg758587d2016-01-12 22:20:06 +01001390 p->flags &= ~BDF_START_;
Werner Lembergf1b61832018-12-04 11:51:15 +01001391 *next = _bdf_parse_end;
David Turner993a8d02002-05-18 12:03:43 +00001392
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001393 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001394 }
1395
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001396 /* Check for the ENDCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001397 if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001398 {
1399 p->glyph_enc = 0;
Werner Lemberg758587d2016-01-12 22:20:06 +01001400 p->flags &= ~BDF_GLYPH_BITS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001401
1402 goto Exit;
1403 }
1404
Werner Lemberg96ddc672011-06-29 09:15:54 +02001405 /* Check whether a glyph is being scanned but should be */
1406 /* ignored because it is an unencoded glyph. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001407 if ( ( p->flags & BDF_GLYPH_ ) &&
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001408 p->glyph_enc == -1 &&
1409 p->opts->keep_unencoded == 0 )
1410 goto Exit;
1411
1412 /* Check for the STARTCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001413 if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001414 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001415 if ( p->flags & BDF_GLYPH_BITS_ )
Werner Lembergb1857472015-10-17 14:21:41 +02001416 {
1417 /* Missing ENDCHAR field. */
1418 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1419 error = FT_THROW( Missing_Startchar_Field );
1420 goto Exit;
1421 }
1422
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001423 /* Set the character name in the parse info first until the */
1424 /* encoding can be checked for an unencoded character. */
1425 FT_FREE( p->glyph_name );
1426
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001427 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001428 if ( error )
1429 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001430
David Turner68df4f72005-03-15 18:18:57 +00001431 _bdf_list_shift( &p->list, 1 );
1432
1433 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001434
Werner Lembergba03af62007-05-30 13:57:02 +00001435 if ( !s )
1436 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001437 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001438 error = FT_THROW( Invalid_File_Format );
Werner Lembergba03af62007-05-30 13:57:02 +00001439 goto Exit;
1440 }
1441
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001442 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1443 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001444
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001445 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1446
Werner Lemberg758587d2016-01-12 22:20:06 +01001447 p->flags |= BDF_GLYPH_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001448
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001449 FT_TRACE4(( DBGMSG1, lineno, s ));
1450
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001451 goto Exit;
1452 }
1453
1454 /* Check for the ENCODING field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001455 if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001456 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001457 if ( !( p->flags & BDF_GLYPH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001458 {
1459 /* Missing STARTCHAR field. */
1460 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001461 error = FT_THROW( Missing_Startchar_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001462 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001463 }
1464
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001465 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001466 if ( error )
1467 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001468
Ben Wagnera512b0f2015-12-14 09:19:52 +01001469 p->glyph_enc = _bdf_atol( p->list.field[1] );
David Turner993a8d02002-05-18 12:03:43 +00001470
Werner Lemberg28dd2c42012-02-26 06:18:58 +01001471 /* Normalize negative encoding values. The specification only */
1472 /* allows -1, but we can be more generous here. */
1473 if ( p->glyph_enc < -1 )
1474 p->glyph_enc = -1;
1475
Werner Lemberg03242f52012-02-26 06:52:56 +01001476 /* Check for alternative encoding format. */
1477 if ( p->glyph_enc == -1 && p->list.used > 2 )
Ben Wagnera512b0f2015-12-14 09:19:52 +01001478 p->glyph_enc = _bdf_atol( p->list.field[2] );
Werner Lemberg03242f52012-02-26 06:52:56 +01001479
Alexei Podtelezhnikov923fcbc2018-08-15 22:50:06 -04001480 if ( p->glyph_enc < -1 || p->glyph_enc >= 0x110000L )
Werner Lemberg7f2e4f42012-12-15 09:39:41 +01001481 p->glyph_enc = -1;
1482
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001483 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1484
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001485 if ( p->glyph_enc >= 0 )
1486 {
1487 /* Make sure there are enough glyphs allocated in case the */
1488 /* number of characters happen to be wrong. */
1489 if ( font->glyphs_used == font->glyphs_size )
1490 {
1491 if ( FT_RENEW_ARRAY( font->glyphs,
1492 font->glyphs_size,
1493 font->glyphs_size + 64 ) )
1494 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001495
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001496 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001497 }
1498
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001499 glyph = font->glyphs + font->glyphs_used++;
1500 glyph->name = p->glyph_name;
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001501 glyph->encoding = (unsigned long)p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001502
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001503 /* Reset the initial glyph info. */
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001504 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001505 }
1506 else
1507 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001508 /* Unencoded glyph. Check whether it should */
1509 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001510 if ( p->opts->keep_unencoded != 0 )
1511 {
1512 /* Allocate the next unencoded glyph. */
1513 if ( font->unencoded_used == font->unencoded_size )
1514 {
David Turner68df4f72005-03-15 18:18:57 +00001515 if ( FT_RENEW_ARRAY( font->unencoded ,
1516 font->unencoded_size,
1517 font->unencoded_size + 4 ) )
1518 goto Exit;
1519
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001520 font->unencoded_size += 4;
1521 }
1522
1523 glyph = font->unencoded + font->unencoded_used;
1524 glyph->name = p->glyph_name;
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001525 glyph->encoding = font->unencoded_used++;
Werner Lemberg4a150132015-11-25 07:53:49 +01001526
1527 /* Reset the initial glyph info. */
1528 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001529 }
1530 else
Werner Lemberg94cacac2015-11-15 04:45:42 +01001531 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001532 /* Free up the glyph name if the unencoded shouldn't be */
1533 /* kept. */
1534 FT_FREE( p->glyph_name );
Werner Lemberg94cacac2015-11-15 04:45:42 +01001535 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001536
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001537 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001538 }
1539
1540 /* Clear the flags that might be added when width and height are */
1541 /* checked for consistency. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001542 p->flags &= ~( BDF_GLYPH_WIDTH_CHECK_ | BDF_GLYPH_HEIGHT_CHECK_ );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001543
Werner Lemberg758587d2016-01-12 22:20:06 +01001544 p->flags |= BDF_ENCODING_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001545
1546 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001547 }
1548
Armin Hasitzka0f6be062018-06-17 20:27:42 +02001549 if ( !( p->flags & BDF_ENCODING_ ) )
1550 goto Missing_Encoding;
1551
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001552 /* Point at the glyph being constructed. */
1553 if ( p->glyph_enc == -1 )
1554 glyph = font->unencoded + ( font->unencoded_used - 1 );
1555 else
1556 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001557
Werner Lemberg96ddc672011-06-29 09:15:54 +02001558 /* Check whether a bitmap is being constructed. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001559 if ( p->flags & BDF_BITMAP_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001560 {
1561 /* If there are more rows than are specified in the glyph metrics, */
1562 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001563 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001564 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001565 if ( !( p->flags & BDF_GLYPH_HEIGHT_CHECK_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001566 {
1567 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001568 p->flags |= BDF_GLYPH_HEIGHT_CHECK_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001569 }
1570
1571 goto Exit;
1572 }
1573
1574 /* Only collect the number of nibbles indicated by the glyph */
1575 /* metrics. If there are more columns, they are simply ignored. */
1576 nibbles = glyph->bpr << 1;
1577 bp = glyph->bitmap + p->row * glyph->bpr;
1578
David Turnerb698eed2006-02-23 14:50:13 +00001579 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001580 {
1581 c = line[i];
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001582 if ( !sbitset( hdigits, c ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001583 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001584 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001585 if ( i + 1 < nibbles && ( i & 1 ) )
1586 *++bp = 0;
1587 }
1588
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001589 /* If any line has not enough columns, */
1590 /* indicate they have been padded with zero bits. */
1591 if ( i < nibbles &&
Werner Lemberg758587d2016-01-12 22:20:06 +01001592 !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001593 {
1594 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001595 p->flags |= BDF_GLYPH_WIDTH_CHECK_;
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001596 }
1597
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001598 /* Remove possible garbage at the right. */
1599 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001600 if ( glyph->bbx.width )
1601 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001602
1603 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001604 if ( i == nibbles &&
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001605 sbitset( hdigits, line[nibbles] ) &&
Werner Lemberg758587d2016-01-12 22:20:06 +01001606 !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001607 {
1608 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001609 p->flags |= BDF_GLYPH_WIDTH_CHECK_;
David Turner993a8d02002-05-18 12:03:43 +00001610 }
1611
1612 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001613 goto Exit;
1614 }
David Turner993a8d02002-05-18 12:03:43 +00001615
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001616 /* Expect the SWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001617 if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001618 {
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001619 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001620 if ( error )
1621 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001622
Ben Wagnera512b0f2015-12-14 09:19:52 +01001623 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1] );
Werner Lemberg758587d2016-01-12 22:20:06 +01001624 p->flags |= BDF_SWIDTH_;
David Turner993a8d02002-05-18 12:03:43 +00001625
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001626 goto Exit;
1627 }
David Turner993a8d02002-05-18 12:03:43 +00001628
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001629 /* Expect the DWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001630 if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001631 {
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001632 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001633 if ( error )
1634 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001635
Ben Wagnera512b0f2015-12-14 09:19:52 +01001636 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001637
Werner Lemberg758587d2016-01-12 22:20:06 +01001638 if ( !( p->flags & BDF_SWIDTH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001639 {
1640 /* Missing SWIDTH field. Emit an auto correction message and set */
1641 /* the scalable width from the device width. */
1642 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1643
Werner Lemberg02d4d592002-05-28 22:38:05 +00001644 glyph->swidth = (unsigned short)FT_MulDiv(
1645 glyph->dwidth, 72000L,
1646 (FT_Long)( font->point_size *
1647 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001648 }
1649
Werner Lemberg758587d2016-01-12 22:20:06 +01001650 p->flags |= BDF_DWIDTH_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001651 goto Exit;
1652 }
David Turner993a8d02002-05-18 12:03:43 +00001653
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001654 /* Expect the BBX field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001655 if ( _bdf_strncmp( line, "BBX", 3 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001656 {
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001657 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001658 if ( error )
1659 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001660
Ben Wagnera512b0f2015-12-14 09:19:52 +01001661 glyph->bbx.width = _bdf_atous( p->list.field[1] );
1662 glyph->bbx.height = _bdf_atous( p->list.field[2] );
1663 glyph->bbx.x_offset = _bdf_atos( p->list.field[3] );
1664 glyph->bbx.y_offset = _bdf_atos( p->list.field[4] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001665
1666 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001667 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1668 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001669
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001670 /* Determine the overall font bounding box as the characters are */
1671 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001672 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1673 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001674
David Turnerb1b47622002-05-21 21:17:43 +00001675 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001676
Werner Lembergdfa46192004-03-05 09:26:24 +00001677 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1678 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1679 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001680
Werner Lemberg758587d2016-01-12 22:20:06 +01001681 if ( !( p->flags & BDF_DWIDTH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001682 {
1683 /* Missing DWIDTH field. Emit an auto correction message and set */
1684 /* the device width to the glyph width. */
1685 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1686 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001687 }
1688
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001689 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1690 /* value if necessary. */
1691 if ( p->opts->correct_metrics != 0 )
1692 {
1693 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001694 unsigned short sw = (unsigned short)FT_MulDiv(
1695 glyph->dwidth, 72000L,
1696 (FT_Long)( font->point_size *
1697 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001698
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001699
1700 if ( sw != glyph->swidth )
1701 {
1702 glyph->swidth = sw;
1703
Werner Lemberg758587d2016-01-12 22:20:06 +01001704 p->flags |= BDF_SWIDTH_ADJ_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001705 }
David Turner993a8d02002-05-18 12:03:43 +00001706 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001707
Werner Lemberg758587d2016-01-12 22:20:06 +01001708 p->flags |= BDF_BBX_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001709 goto Exit;
1710 }
David Turner993a8d02002-05-18 12:03:43 +00001711
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001712 /* And finally, gather up the bitmap. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001713 if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001714 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001715 unsigned long bitmap_size;
1716
1717
Werner Lemberg758587d2016-01-12 22:20:06 +01001718 if ( !( p->flags & BDF_BBX_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001719 {
1720 /* Missing BBX field. */
1721 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001722 error = FT_THROW( Missing_Bbx_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001723 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001724 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001725
1726 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001727 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001728
1729 bitmap_size = glyph->bpr * glyph->bbx.height;
Werner Lembergc4cad302012-03-08 20:11:37 +01001730 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
Werner Lemberg26170df2006-03-26 07:19:07 +00001731 {
1732 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001733 error = FT_THROW( Bbx_Too_Big );
Werner Lemberg26170df2006-03-26 07:19:07 +00001734 goto Exit;
1735 }
1736 else
1737 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001738
1739 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1740 goto Exit;
1741
1742 p->row = 0;
Werner Lemberg758587d2016-01-12 22:20:06 +01001743 p->flags |= BDF_BITMAP_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001744
1745 goto Exit;
1746 }
1747
Werner Lemberge01406b2011-11-25 09:44:28 +01001748 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001749 error = FT_THROW( Invalid_File_Format );
Werner Lemberg4086fb72012-03-01 08:55:40 +01001750 goto Exit;
1751
1752 Missing_Encoding:
1753 /* Missing ENCODING field. */
1754 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001755 error = FT_THROW( Missing_Encoding_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001756
1757 Exit:
Werner Lemberg758587d2016-01-12 22:20:06 +01001758 if ( error && ( p->flags & BDF_GLYPH_ ) )
Werner Lembergf4c94d42010-06-19 16:08:31 +02001759 FT_FREE( p->glyph_name );
1760
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001761 return error;
David Turner993a8d02002-05-18 12:03:43 +00001762 }
1763
David Turner993a8d02002-05-18 12:03:43 +00001764
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001765 /* Load the font properties. */
1766 static FT_Error
1767 _bdf_parse_properties( char* line,
1768 unsigned long linelen,
1769 unsigned long lineno,
1770 void* call_data,
1771 void* client_data )
1772 {
1773 unsigned long vlen;
1774 _bdf_line_func_t* next;
1775 _bdf_parse_t* p;
1776 char* name;
1777 char* value;
1778 char nbuf[128];
Werner Lemberge3c93012013-03-14 11:21:17 +01001779 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001780
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001781 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001782
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001783
1784 next = (_bdf_line_func_t *)call_data;
1785 p = (_bdf_parse_t *) client_data;
1786
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001787 /* Check for the end of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001788 if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001789 {
1790 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1791 /* encountered yet, then make sure they are added as properties and */
1792 /* make sure they are set from the font bounding box info. */
1793 /* */
1794 /* This is *always* done regardless of the options, because X11 */
1795 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001796 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001797 {
1798 p->font->font_ascent = p->font->bbx.ascent;
1799 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001800 error = _bdf_add_property( p->font, "FONT_ASCENT",
Werner Lemberge01406b2011-11-25 09:44:28 +01001801 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001802 if ( error )
1803 goto Exit;
1804
1805 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
David Turner993a8d02002-05-18 12:03:43 +00001806 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001807
Werner Lemberg428c2e42003-04-25 05:35:04 +00001808 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001809 {
1810 p->font->font_descent = p->font->bbx.descent;
1811 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001812 error = _bdf_add_property( p->font, "FONT_DESCENT",
Werner Lemberge01406b2011-11-25 09:44:28 +01001813 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001814 if ( error )
1815 goto Exit;
1816
1817 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
David Turner993a8d02002-05-18 12:03:43 +00001818 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001819
Werner Lemberg758587d2016-01-12 22:20:06 +01001820 p->flags &= ~BDF_PROPS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001821 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001822
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001823 goto Exit;
1824 }
David Turner993a8d02002-05-18 12:03:43 +00001825
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001826 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001827 if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001828 goto Exit;
1829
1830 /* Handle COMMENT fields and properties in a special way to preserve */
1831 /* the spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001832 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001833 {
David Turner993a8d02002-05-18 12:03:43 +00001834 name = value = line;
1835 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001836 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001837 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01001838 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001839 if ( error )
1840 goto Exit;
1841 }
1842 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1843 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001844 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001845 if ( error )
1846 goto Exit;
1847 }
1848 else
1849 {
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001850 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001851 if ( error )
1852 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001853 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001854
David Turner68df4f72005-03-15 18:18:57 +00001855 _bdf_list_shift( &p->list, 1 );
1856 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001857
Werner Lemberge01406b2011-11-25 09:44:28 +01001858 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001859 if ( error )
1860 goto Exit;
1861 }
1862
1863 Exit:
1864 return error;
David Turner993a8d02002-05-18 12:03:43 +00001865 }
1866
David Turner993a8d02002-05-18 12:03:43 +00001867
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001868 /* Load the font header. */
1869 static FT_Error
1870 _bdf_parse_start( char* line,
1871 unsigned long linelen,
1872 unsigned long lineno,
1873 void* call_data,
1874 void* client_data )
1875 {
1876 unsigned long slen;
1877 _bdf_line_func_t* next;
1878 _bdf_parse_t* p;
1879 bdf_font_t* font;
1880 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001881
David Turnerd490e372002-05-28 23:40:37 +00001882 FT_Memory memory = NULL;
Werner Lemberge3c93012013-03-14 11:21:17 +01001883 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001884
1885 FT_UNUSED( lineno ); /* only used in debug mode */
1886
1887
1888 next = (_bdf_line_func_t *)call_data;
1889 p = (_bdf_parse_t *) client_data;
1890
1891 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00001892 memory = p->font->memory;
1893
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001894 /* Check for a comment. This is done to handle those fonts that have */
1895 /* comments before the STARTFONT line for some reason. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001896 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001897 {
1898 if ( p->opts->keep_comments != 0 && p->font != 0 )
1899 {
1900 linelen -= 7;
1901
1902 s = line + 7;
1903 if ( *s != 0 )
1904 {
1905 s++;
1906 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00001907 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001908
1909 error = _bdf_add_comment( p->font, s, linelen );
1910 if ( error )
1911 goto Exit;
1912 /* here font is not defined! */
1913 }
1914
1915 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001916 }
1917
Werner Lemberg758587d2016-01-12 22:20:06 +01001918 if ( !( p->flags & BDF_START_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001919 {
1920 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00001921
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001922 if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001923 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01001924 /* we don't emit an error message since this code gets */
1925 /* explicitly caught one level higher */
Werner Lemberg059bc332013-03-14 10:27:35 +01001926 error = FT_THROW( Missing_Startfont_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001927 goto Exit;
1928 }
David Turner993a8d02002-05-18 12:03:43 +00001929
Werner Lemberg758587d2016-01-12 22:20:06 +01001930 p->flags = BDF_START_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001931 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00001932
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001933 if ( FT_NEW( font ) )
1934 goto Exit;
1935 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00001936
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001937 font->memory = p->memory;
1938 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00001939
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001940 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001941 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001942 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00001943
David Turner993a8d02002-05-18 12:03:43 +00001944
Werner Lemberg7ce6c432015-12-22 05:39:58 +01001945 error = ft_hash_str_init( &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001946 if ( error )
1947 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00001948 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001949 i < _num_bdf_properties; i++, prop++ )
1950 {
Werner Lemberg609546c2015-12-20 07:17:29 +01001951 error = ft_hash_str_insert( prop->name, i,
1952 &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001953 if ( error )
1954 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001955 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001956 }
1957
Werner Lemberg31343562015-12-19 17:02:13 +01001958 if ( FT_ALLOC( p->font->internal, sizeof ( FT_HashRec ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001959 goto Exit;
Werner Lemberg7ce6c432015-12-22 05:39:58 +01001960 error = ft_hash_str_init( (FT_Hash)p->font->internal, memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001961 if ( error )
1962 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00001963 p->font->spacing = p->opts->font_spacing;
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001964 p->font->default_char = ~0UL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001965
1966 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001967 }
1968
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001969 /* Check for the start of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001970 if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001971 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001972 if ( !( p->flags & BDF_FONT_BBX_ ) )
Werner Lembergfb690292010-06-23 10:00:52 +02001973 {
1974 /* Missing the FONTBOUNDINGBOX field. */
1975 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001976 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergfb690292010-06-23 10:00:52 +02001977 goto Exit;
1978 }
1979
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04001980 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001981 if ( error )
1982 goto Exit;
Werner Lembergb6b26f42016-06-09 06:53:48 +02001983
Werner Lembergb66efef2009-03-12 08:07:49 +00001984 /* at this point, `p->font' can't be NULL */
Ben Wagnera512b0f2015-12-14 09:19:52 +01001985 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1] );
Werner Lembergb6b26f42016-06-09 06:53:48 +02001986 /* We need at least 4 bytes per property. */
1987 if ( p->cnt > p->size / 4 )
1988 {
1989 p->font->props_size = 0;
1990
1991 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "STARTPROPERTIES" ));
1992 error = FT_THROW( Invalid_Argument );
1993 goto Exit;
1994 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001995
1996 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
Werner Lemberg9b6b5752012-12-15 01:34:41 +01001997 {
1998 p->font->props_size = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001999 goto Exit;
Werner Lemberg9b6b5752012-12-15 01:34:41 +01002000 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002001
Werner Lemberg758587d2016-01-12 22:20:06 +01002002 p->flags |= BDF_PROPS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002003 *next = _bdf_parse_properties;
2004
2005 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002006 }
2007
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002008 /* Check for the FONTBOUNDINGBOX field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002009 if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002010 {
Werner Lemberg758587d2016-01-12 22:20:06 +01002011 if ( !( p->flags & BDF_SIZE_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002012 {
2013 /* Missing the SIZE field. */
2014 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002015 error = FT_THROW( Missing_Size_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002016 goto Exit;
2017 }
2018
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04002019 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002020 if ( error )
2021 goto Exit;
2022
Ben Wagnera512b0f2015-12-14 09:19:52 +01002023 p->font->bbx.width = _bdf_atous( p->list.field[1] );
2024 p->font->bbx.height = _bdf_atous( p->list.field[2] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002025
Ben Wagnera512b0f2015-12-14 09:19:52 +01002026 p->font->bbx.x_offset = _bdf_atos( p->list.field[3] );
2027 p->font->bbx.y_offset = _bdf_atos( p->list.field[4] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002028
David Turnerd490e372002-05-28 23:40:37 +00002029 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002030 p->font->bbx.y_offset );
2031
2032 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002033
Werner Lemberg758587d2016-01-12 22:20:06 +01002034 p->flags |= BDF_FONT_BBX_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002035
2036 goto Exit;
2037 }
2038
2039 /* The next thing to check for is the FONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002040 if ( _bdf_strncmp( line, "FONT", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002041 {
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04002042 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002043 if ( error )
2044 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002045 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002046
David Turner68df4f72005-03-15 18:18:57 +00002047 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002048
2049 if ( !s )
2050 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002051 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002052 error = FT_THROW( Invalid_File_Format );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002053 goto Exit;
2054 }
2055
Werner Lembergfb690292010-06-23 10:00:52 +02002056 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2057 FT_FREE( p->font->name );
2058
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002059 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2060 goto Exit;
2061 FT_MEM_COPY( p->font->name, s, slen + 1 );
2062
2063 /* If the font name is an XLFD name, set the spacing to the one in */
2064 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002065 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002066 if ( error )
2067 goto Exit;
2068
Werner Lemberg758587d2016-01-12 22:20:06 +01002069 p->flags |= BDF_FONT_NAME_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002070
2071 goto Exit;
2072 }
2073
2074 /* Check for the SIZE field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002075 if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002076 {
Werner Lemberg758587d2016-01-12 22:20:06 +01002077 if ( !( p->flags & BDF_FONT_NAME_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002078 {
2079 /* Missing the FONT field. */
2080 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002081 error = FT_THROW( Missing_Font_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002082 goto Exit;
2083 }
2084
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04002085 error = _bdf_list_split( &p->list, " +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002086 if ( error )
2087 goto Exit;
2088
Ben Wagnera512b0f2015-12-14 09:19:52 +01002089 p->font->point_size = _bdf_atoul( p->list.field[1] );
2090 p->font->resolution_x = _bdf_atoul( p->list.field[2] );
2091 p->font->resolution_y = _bdf_atoul( p->list.field[3] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002092
2093 /* Check for the bits per pixel field. */
2094 if ( p->list.used == 5 )
2095 {
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002096 unsigned short bpp;
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002097
2098
Ben Wagnera512b0f2015-12-14 09:19:52 +01002099 bpp = (unsigned short)_bdf_atos( p->list.field[4] );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002100
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002101 /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
2102 if ( bpp > 4 )
2103 p->font->bpp = 8;
2104 else if ( bpp > 2 )
2105 p->font->bpp = 4;
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002106 else if ( bpp > 1 )
2107 p->font->bpp = 2;
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002108 else
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002109 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002110
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002111 if ( p->font->bpp != bpp )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002112 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002113 }
2114 else
2115 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002116
Werner Lemberg758587d2016-01-12 22:20:06 +01002117 p->flags |= BDF_SIZE_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002118
2119 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002120 }
2121
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002122 /* Check for the CHARS field -- font properties are optional */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002123 if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002124 {
2125 char nbuf[128];
2126
2127
Werner Lemberg758587d2016-01-12 22:20:06 +01002128 if ( !( p->flags & BDF_FONT_BBX_ ) )
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002129 {
2130 /* Missing the FONTBOUNDINGBOX field. */
2131 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002132 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002133 goto Exit;
2134 }
2135
2136 /* Add the two standard X11 properties which are required */
2137 /* for compiling fonts. */
2138 p->font->font_ascent = p->font->bbx.ascent;
2139 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04002140 error = _bdf_add_property( p->font, "FONT_ASCENT",
Werner Lemberge01406b2011-11-25 09:44:28 +01002141 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002142 if ( error )
2143 goto Exit;
2144 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2145
2146 p->font->font_descent = p->font->bbx.descent;
2147 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Alexei Podtelezhnikovafaf3f12019-06-10 22:27:39 -04002148 error = _bdf_add_property( p->font, "FONT_DESCENT",
Werner Lemberge01406b2011-11-25 09:44:28 +01002149 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002150 if ( error )
2151 goto Exit;
2152 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2153
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002154 *next = _bdf_parse_glyphs;
2155
2156 /* A special return value. */
2157 error = -1;
2158 goto Exit;
2159 }
2160
Werner Lemberge01406b2011-11-25 09:44:28 +01002161 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002162 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002163
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002164 Exit:
2165 return error;
2166 }
David Turner993a8d02002-05-18 12:03:43 +00002167
2168
Werner Lemberg9ac90602018-06-03 09:01:17 +02002169 /**************************************************************************
2170 *
2171 * API.
2172 *
2173 */
David Turner993a8d02002-05-18 12:03:43 +00002174
David Turner993a8d02002-05-18 12:03:43 +00002175
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002176 FT_LOCAL_DEF( FT_Error )
2177 bdf_load_font( FT_Stream stream,
2178 FT_Memory extmemory,
2179 bdf_options_t* opts,
2180 bdf_font_t* *font )
2181 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002182 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002183 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002184
Sean McBride7be2a942014-02-08 13:55:38 +01002185 FT_Memory memory = extmemory; /* needed for FT_NEW */
2186 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002187
2188
David Turner68df4f72005-03-15 18:18:57 +00002189 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002190 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002191
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002192 memory = NULL;
2193 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2194 p->minlb = 32767;
Werner Lemberge1ca18d2015-10-17 11:51:27 +02002195 p->size = stream->size;
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002196 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002197
David Turner68df4f72005-03-15 18:18:57 +00002198 _bdf_list_init( &p->list, extmemory );
2199
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002200 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002201 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002202 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002203 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002204
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002205 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002206 {
2207 /* If the font is not proportional, set the font's monowidth */
2208 /* field to the width of the font bounding box. */
David Turner993a8d02002-05-18 12:03:43 +00002209
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002210 if ( p->font->spacing != BDF_PROPORTIONAL )
2211 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002212
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002213 /* If the number of glyphs loaded is not that of the original count, */
2214 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002215 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002216 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002217 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2218 p->font->glyphs_used + p->font->unencoded_used ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002219 }
2220
2221 /* Once the font has been loaded, adjust the overall font metrics if */
2222 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002223 if ( p->opts->correct_metrics != 0 &&
2224 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002225 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002226 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002227 {
2228 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002229 p->font->bbx.width, p->maxrb - p->minlb ));
2230 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
David Turner993a8d02002-05-18 12:03:43 +00002231 }
2232
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002233 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002234 {
2235 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002236 p->font->bbx.x_offset, p->minlb ));
2237 p->font->bbx.x_offset = p->minlb;
David Turner993a8d02002-05-18 12:03:43 +00002238 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002239
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002240 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002241 {
2242 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002243 p->font->bbx.ascent, p->maxas ));
2244 p->font->bbx.ascent = p->maxas;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002245 }
2246
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002247 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002248 {
2249 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002250 p->font->bbx.descent, p->maxds ));
2251 p->font->bbx.descent = p->maxds;
2252 p->font->bbx.y_offset = (short)( -p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002253 }
2254
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002255 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002256 {
2257 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002258 p->font->bbx.height, p->maxas + p->maxds ));
2259 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002260 }
2261
Werner Lemberg758587d2016-01-12 22:20:06 +01002262 if ( p->flags & BDF_SWIDTH_ADJ_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002263 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2264 }
David Turner993a8d02002-05-18 12:03:43 +00002265 }
2266
Werner Lemberg758587d2016-01-12 22:20:06 +01002267 if ( p->flags & BDF_START_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002268 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002269 /* The ENDFONT field was never reached or did not exist. */
Werner Lemberg758587d2016-01-12 22:20:06 +01002270 if ( !( p->flags & BDF_GLYPHS_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002271 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002272 /* Error happened while parsing header. */
2273 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002274 error = FT_THROW( Corrupted_Font_Header );
Bungeman65d89802015-10-15 23:50:16 +02002275 goto Fail;
Werner Lemberge01406b2011-11-25 09:44:28 +01002276 }
2277 else
2278 {
2279 /* Error happened when parsing glyphs. */
2280 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002281 error = FT_THROW( Corrupted_Font_Glyphs );
Bungeman65d89802015-10-15 23:50:16 +02002282 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002283 }
David Turner993a8d02002-05-18 12:03:43 +00002284 }
2285
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002286 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002287 {
2288 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002289 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002290
Werner Lemberg370aea82010-06-08 08:37:11 +02002291 if ( p->font->comments_len > 0 )
2292 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002293 if ( FT_RENEW_ARRAY( p->font->comments,
2294 p->font->comments_len,
2295 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002296 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002297
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002298 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002299 }
David Turner993a8d02002-05-18 12:03:43 +00002300 }
Werner Lemberg5d664b62016-12-17 20:47:42 +01002301 else if ( !error )
Werner Lemberg059bc332013-03-14 10:27:35 +01002302 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002303
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002304 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002305
2306 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002307 if ( p )
2308 {
David Turner68df4f72005-03-15 18:18:57 +00002309 _bdf_list_done( &p->list );
2310
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002311 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002312
Werner Lemberg4a150132015-11-25 07:53:49 +01002313 FT_FREE( p->glyph_name );
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002314 FT_FREE( p );
2315 }
2316
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002317 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002318
2319 Fail:
2320 bdf_free_font( p->font );
2321
2322 memory = extmemory;
2323
2324 FT_FREE( p->font );
2325
2326 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002327 }
David Turner993a8d02002-05-18 12:03:43 +00002328
2329
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002330 FT_LOCAL_DEF( void )
2331 bdf_free_font( bdf_font_t* font )
2332 {
2333 bdf_property_t* prop;
2334 unsigned long i;
2335 bdf_glyph_t* glyphs;
2336 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002337
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002338
2339 if ( font == 0 )
2340 return;
David Turner993a8d02002-05-18 12:03:43 +00002341
2342 memory = font->memory;
2343
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002344 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002345
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002346 /* Free up the internal hash table of property names. */
2347 if ( font->internal )
2348 {
Werner Lemberg7ce6c432015-12-22 05:39:58 +01002349 ft_hash_str_free( (FT_Hash)font->internal, memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002350 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002351 }
2352
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002353 /* Free up the comment info. */
2354 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002355
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002356 /* Free up the properties. */
2357 for ( i = 0; i < font->props_size; i++ )
2358 {
2359 if ( font->props[i].format == BDF_ATOM )
2360 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002361 }
2362
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002363 FT_FREE( font->props );
2364
2365 /* Free up the character info. */
2366 for ( i = 0, glyphs = font->glyphs;
2367 i < font->glyphs_used; i++, glyphs++ )
2368 {
2369 FT_FREE( glyphs->name );
2370 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002371 }
2372
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002373 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2374 i++, glyphs++ )
2375 {
2376 FT_FREE( glyphs->name );
2377 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002378 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002379
2380 FT_FREE( font->glyphs );
2381 FT_FREE( font->unencoded );
2382
David Turner993a8d02002-05-18 12:03:43 +00002383 /* bdf_cleanup */
Werner Lemberg7ce6c432015-12-22 05:39:58 +01002384 ft_hash_str_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002385
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002386 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002387 for ( prop = font->user_props, i = 0;
2388 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002389 {
2390 FT_FREE( prop->name );
2391 if ( prop->format == BDF_ATOM )
2392 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002393 }
David Turner993a8d02002-05-18 12:03:43 +00002394
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002395 FT_FREE( font->user_props );
2396
2397 /* FREE( font ); */ /* XXX Fixme */
2398 }
David Turner993a8d02002-05-18 12:03:43 +00002399
2400
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002401 FT_LOCAL_DEF( bdf_property_t * )
2402 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002403 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002404 {
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002405 size_t* propid;
David Turner993a8d02002-05-18 12:03:43 +00002406
David Turner993a8d02002-05-18 12:03:43 +00002407
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002408 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002409 return 0;
2410
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002411 propid = ft_hash_str_lookup( name, (FT_Hash)font->internal );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002412
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002413 return propid ? ( font->props + *propid ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002414 }
2415
2416
2417/* END */