blob: 1fbb9893510587a92b578a7f9e1e48b0f2cd3bd8 [file] [log] [blame]
David Turner993a8d02002-05-18 12:03:43 +00001/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
Alexei Podtelezhnikovaf9662e2018-08-15 22:58:11 -04003 * Copyright 2001-2018
Werner Lemberg442bfb82007-02-12 21:44:10 +00004 * Francesco Zappa Nardelli
David Turner993a8d02002-05-18 12:03:43 +00005 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
Werner Lemberg9ac90602018-06-03 09:01:17 +020025 /**************************************************************************
26 *
27 * This file is based on bdf.c,v 1.22 2000/03/16 20:08:50
28 *
29 * taken from Mark Leisher's xmbdfed package
30 *
31 */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000032
David Turner993a8d02002-05-18 12:03:43 +000033
34#include <ft2build.h>
35
Werner Lemberg02d4d592002-05-28 22:38:05 +000036#include FT_FREETYPE_H
David Turner993a8d02002-05-18 12:03:43 +000037#include FT_INTERNAL_DEBUG_H
38#include FT_INTERNAL_STREAM_H
39#include FT_INTERNAL_OBJECTS_H
40
41#include "bdf.h"
David Turner993a8d02002-05-18 12:03:43 +000042#include "bdferror.h"
43
David Turner993a8d02002-05-18 12:03:43 +000044
Werner Lemberg9ac90602018-06-03 09:01:17 +020045 /**************************************************************************
46 *
47 * The macro FT_COMPONENT is used in trace mode. It is an implicit
48 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
49 * messages during execution.
50 */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000051#undef FT_COMPONENT
Werner Lemberga0dd16f2018-08-15 18:13:17 +020052#define FT_COMPONENT bdflib
David Turner993a8d02002-05-18 12:03:43 +000053
David Turner993a8d02002-05-18 12:03:43 +000054
Werner Lemberg9ac90602018-06-03 09:01:17 +020055 /**************************************************************************
56 *
57 * Default BDF font options.
58 *
59 */
David Turner993a8d02002-05-18 12:03:43 +000060
David Turner993a8d02002-05-18 12:03:43 +000061
David Turnerb1b47622002-05-21 21:17:43 +000062 static const bdf_options_t _bdf_opts =
Werner Lemberg7cf4d372002-05-21 14:13:01 +000063 {
David Turner993a8d02002-05-18 12:03:43 +000064 1, /* Correct metrics. */
65 1, /* Preserve unencoded glyphs. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000066 0, /* Preserve comments. */
67 BDF_PROPORTIONAL /* Default spacing. */
68 };
David Turner993a8d02002-05-18 12:03:43 +000069
David Turner993a8d02002-05-18 12:03:43 +000070
Werner Lemberg9ac90602018-06-03 09:01:17 +020071 /**************************************************************************
72 *
73 * Builtin BDF font properties.
74 *
75 */
David Turner993a8d02002-05-18 12:03:43 +000076
Werner Lemberg7cf4d372002-05-21 14:13:01 +000077 /* List of most properties that might appear in a font. Doesn't include */
78 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
David Turner993a8d02002-05-18 12:03:43 +000079
David Turnerb1b47622002-05-21 21:17:43 +000080 static const bdf_property_t _bdf_properties[] =
David Turner993a8d02002-05-18 12:03:43 +000081 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +000082 { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
83 { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
84 { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
85 { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
86 { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
87 { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
88 { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
89 { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
90 { (char *)"COMMENT", BDF_ATOM, 1, { 0 } },
91 { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } },
92 { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
93 { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } },
94 { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
95 { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } },
96 { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } },
97 { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } },
98 { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
99 { (char *)"FONT", BDF_ATOM, 1, { 0 } },
100 { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
101 { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
102 { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
103 { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } },
104 { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } },
105 { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
106 { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } },
107 { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } },
108 { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } },
109 { (char *)"NOTICE", BDF_ATOM, 1, { 0 } },
110 { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
111 { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } },
112 { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
113 { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
114 { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
115 { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
116 { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
117 { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
118 { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
119 { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
120 { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
121 { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
122 { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
123 { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
124 { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
125 { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
126 { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
127 { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
128 { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
129 { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
130 { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
131 { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
132 { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
133 { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
134 { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
135 { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
136 { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
137 { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
138 { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
139 { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
140 { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
141 { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
142 { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
143 { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } },
144 { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
145 { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
146 { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
147 { (char *)"SLANT", BDF_ATOM, 1, { 0 } },
148 { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
149 { (char *)"SPACING", BDF_ATOM, 1, { 0 } },
150 { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
151 { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
152 { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
153 { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
154 { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
155 { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
156 { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
157 { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
158 { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
159 { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
160 { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } },
161 { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
162 { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } },
163 { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
164 { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
165 };
David Turner993a8d02002-05-18 12:03:43 +0000166
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000167 static const unsigned long
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000168 _num_bdf_properties = sizeof ( _bdf_properties ) /
169 sizeof ( _bdf_properties[0] );
David Turner993a8d02002-05-18 12:03:43 +0000170
171
Werner Lemberg2c4832d2014-11-07 07:42:33 +0100172 /* An auxiliary macro to parse properties, to be used in conditionals. */
173 /* It behaves like `strncmp' but also tests the following character */
174 /* whether it is a whitespace or NULL. */
175 /* `property' is a constant string of length `n' to compare with. */
176#define _bdf_strncmp( name, property, n ) \
177 ( ft_strncmp( name, property, n ) || \
178 !( name[n] == ' ' || \
179 name[n] == '\0' || \
180 name[n] == '\n' || \
181 name[n] == '\r' || \
182 name[n] == '\t' ) )
183
Werner Lemberge01406b2011-11-25 09:44:28 +0100184 /* Auto correction messages. */
185#define ACMSG1 "FONT_ASCENT property missing. " \
186 "Added `FONT_ASCENT %hd'.\n"
187#define ACMSG2 "FONT_DESCENT property missing. " \
188 "Added `FONT_DESCENT %hd'.\n"
189#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
190#define ACMSG4 "Font left bearing != actual left bearing. " \
191 "Old: %hd New: %hd.\n"
192#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
193#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
194#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
195#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
196#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
197#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
198#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -0400199#define ACMSG13 "Glyph %lu extra rows removed.\n"
200#define ACMSG14 "Glyph %lu extra columns removed.\n"
Werner Lemberge01406b2011-11-25 09:44:28 +0100201#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -0400202#define ACMSG16 "Glyph %lu missing columns padded with zero bits.\n"
Werner Lemberge1ca18d2015-10-17 11:51:27 +0200203#define ACMSG17 "Adjusting number of glyphs to %ld.\n"
Werner Lemberge01406b2011-11-25 09:44:28 +0100204
205 /* Error messages. */
206#define ERRMSG1 "[line %ld] Missing `%s' line.\n"
207#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
208#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
209#define ERRMSG4 "[line %ld] BBX too big.\n"
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
367 static const char empty[1] = { 0 }; /* XXX eliminate this */
368
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,
410 char* separators,
411 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;
416 char *sp, *ep, *end;
417 char seps[32];
418 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000419
420
421 /* Initialize the list. */
422 list->used = 0;
Werner Lembergd9c16592012-03-01 15:15:00 +0100423 if ( list->size )
424 {
425 list->field[0] = (char*)empty;
426 list->field[1] = (char*)empty;
427 list->field[2] = (char*)empty;
428 list->field[3] = (char*)empty;
Werner Lemberg649c6732012-03-16 21:12:41 +0100429 list->field[4] = (char*)empty;
Werner Lembergd9c16592012-03-01 15:15:00 +0100430 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000431
432 /* If the line is empty, then simply return. */
433 if ( linelen == 0 || line[0] == 0 )
434 goto Exit;
435
436 /* In the original code, if the `separators' parameter is NULL or */
437 /* empty, the list is split into individual bytes. We don't need */
438 /* this, so an error is signaled. */
439 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000440 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100441 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000442 goto Exit;
443 }
444
445 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000446 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000447
448 /* If the very last character of the separator string is a plus, then */
449 /* set the `mult' flag to indicate that multiple separators should be */
450 /* collapsed into one. */
451 for ( mult = 0, sp = separators; sp && *sp; sp++ )
452 {
453 if ( *sp == '+' && *( sp + 1 ) == 0 )
454 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000455 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000456 setsbit( seps, *sp );
457 }
458
459 /* Break the line up into fields. */
460 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
461 sp < end && *sp; )
462 {
463 /* Collect everything that is not a separator. */
464 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
465 ;
466
467 /* Resize the list if necessary. */
468 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000469 {
Werner Lembergebf55852005-03-16 01:49:54 +0000470 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000471 if ( error )
472 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000473 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000474
475 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000476 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000477
478 sp = ep;
479
480 if ( mult )
481 {
482 /* If multiple separators should be collapsed, do it now by */
483 /* setting all the separator characters to 0. */
484 for ( ; *ep && sbitset( seps, *ep ); ep++ )
485 *ep = 0;
486 }
487 else if ( *ep != 0 )
488 /* Don't collapse multiple separators by making them 0, so just */
489 /* make the one encountered 0. */
490 *ep++ = 0;
491
492 final_empty = ( ep > sp && *ep == 0 );
493 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000494 }
495
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000496 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000497 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000498 {
Werner Lembergebf55852005-03-16 01:49:54 +0000499 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000500 if ( error )
501 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000502 }
503
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000504 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000505 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000506
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000507 list->field[list->used] = 0;
508
509 Exit:
510 return error;
David Turner993a8d02002-05-18 12:03:43 +0000511 }
512
David Turner993a8d02002-05-18 12:03:43 +0000513
David Turner68df4f72005-03-15 18:18:57 +0000514#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000515
Werner Lembergebf55852005-03-16 01:49:54 +0000516
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000517 static FT_Error
518 _bdf_readstream( FT_Stream stream,
519 _bdf_line_func_t callback,
520 void* client_data,
521 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000522 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000523 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000524 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900525 int refill, hold, to_skip;
526 ptrdiff_t bytes, start, end, cursor, avail;
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -0400527 char* buf = NULL;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000528 FT_Memory memory = stream->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100529 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000530
David Turner993a8d02002-05-18 12:03:43 +0000531
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000532 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000533 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100534 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000535 goto Exit;
536 }
David Turner993a8d02002-05-18 12:03:43 +0000537
Werner Lembergebf55852005-03-16 01:49:54 +0000538 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000539 buf_size = 1024;
540
541 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000542 goto Exit;
543
Werner Lembergebf55852005-03-16 01:49:54 +0000544 cb = callback;
545 lineno = 1;
546 buf[0] = 0;
547 start = 0;
Werner Lembergebf55852005-03-16 01:49:54 +0000548 avail = 0;
549 cursor = 0;
550 refill = 1;
551 to_skip = NO_SKIP;
552 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000553
David Turner68df4f72005-03-15 18:18:57 +0000554 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000555 {
David Turner68df4f72005-03-15 18:18:57 +0000556 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000557 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +0200558 bytes = (ptrdiff_t)FT_Stream_TryRead(
559 stream, (FT_Byte*)buf + cursor,
Werner Lemberg3c374c82015-02-22 09:16:53 +0100560 buf_size - (unsigned long)cursor );
David Turner68df4f72005-03-15 18:18:57 +0000561 avail = cursor + bytes;
562 cursor = 0;
563 refill = 0;
564 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000565
David Turner68df4f72005-03-15 18:18:57 +0000566 end = start;
567
Werner Lembergebf55852005-03-16 01:49:54 +0000568 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000569 if ( start < avail && buf[start] == to_skip )
570 {
571 start += 1;
572 to_skip = NO_SKIP;
573 continue;
574 }
575
576 /* try to find the end of the line */
577 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
578 end++;
579
Werner Lembergebf55852005-03-16 01:49:54 +0000580 /* if we hit the end of the buffer, try shifting its content */
581 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000582 if ( end >= avail )
583 {
584 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
585 break; /* ignore it then exit */
586
587 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000588 {
Werner Lembergebf55852005-03-16 01:49:54 +0000589 /* this line is definitely too long; try resizing the input */
590 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000591 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000592
Werner Lembergebf55852005-03-16 01:49:54 +0000593
594 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000595 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100596 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +0100597 error = FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +0000598 goto Exit;
599 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000600
Werner Lembergebf55852005-03-16 01:49:54 +0000601 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000602 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
603 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000604
Werner Lemberg3c374c82015-02-22 09:16:53 +0100605 cursor = (ptrdiff_t)buf_size;
David Turner68df4f72005-03-15 18:18:57 +0000606 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000607 }
608 else
609 {
David Turner68df4f72005-03-15 18:18:57 +0000610 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000611
Werner Lemberg04e547b2013-04-03 07:37:56 +0200612 FT_MEM_MOVE( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000613
David Turner68df4f72005-03-15 18:18:57 +0000614 cursor = bytes;
615 avail -= bytes;
616 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000617 }
David Turner68df4f72005-03-15 18:18:57 +0000618 refill = 1;
619 continue;
David Turner993a8d02002-05-18 12:03:43 +0000620 }
David Turner68df4f72005-03-15 18:18:57 +0000621
622 /* Temporarily NUL-terminate the line. */
623 hold = buf[end];
624 buf[end] = 0;
625
Werner Lemberg0098d552014-12-07 11:03:57 +0100626 /* XXX: Use encoding independent value for 0x1A */
627 if ( buf[start] != '#' && buf[start] != 0x1A && end > start )
David Turner68df4f72005-03-15 18:18:57 +0000628 {
Werner Lemberga9f6f852012-12-17 09:08:09 +0100629 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergebf55852005-03-16 01:49:54 +0000630 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200631 /* Redo if we have encountered CHARS without properties. */
632 if ( error == -1 )
Werner Lemberga9f6f852012-12-17 09:08:09 +0100633 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200634 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000635 if ( error )
636 break;
637 }
638
639 lineno += 1;
640 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000641 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000642
643 if ( hold == '\n' )
644 to_skip = '\r';
645 else if ( hold == '\r' )
646 to_skip = '\n';
647 else
648 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000649 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000650
David Turner68df4f72005-03-15 18:18:57 +0000651 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000652
653 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000654 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000655 return error;
David Turner993a8d02002-05-18 12:03:43 +0000656 }
David Turner993a8d02002-05-18 12:03:43 +0000657
658
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000659 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000660
David Turnerb1b47622002-05-21 21:17:43 +0000661 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000662 {
David Turner993a8d02002-05-18 12:03:43 +0000663 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
664 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
665 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
666 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
667 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
Werner Lemberg0098d552014-12-07 11:03:57 +0100668 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000669 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg0098d552014-12-07 11:03:57 +0100671 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000672 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
673 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000674 };
David Turner993a8d02002-05-18 12:03:43 +0000675
David Turnerb1b47622002-05-21 21:17:43 +0000676 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000677 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100678 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
David Turner993a8d02002-05-18 12:03:43 +0000679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
680 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000682 };
David Turner993a8d02002-05-18 12:03:43 +0000683
David Turnerb1b47622002-05-21 21:17:43 +0000684 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000685 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100686 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
687 0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000688 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
689 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000690 };
David Turner993a8d02002-05-18 12:03:43 +0000691
David Turner993a8d02002-05-18 12:03:43 +0000692
Ben Wagnera512b0f2015-12-14 09:19:52 +0100693 /* Routine to convert a decimal ASCII string to an unsigned long integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000694 static unsigned long
Ben Wagnera512b0f2015-12-14 09:19:52 +0100695 _bdf_atoul( char* s )
David Turner993a8d02002-05-18 12:03:43 +0000696 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100697 unsigned long v;
David Turner993a8d02002-05-18 12:03:43 +0000698
699
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000700 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000701 return 0;
702
Ben Wagnera512b0f2015-12-14 09:19:52 +0100703 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200704 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100705 if ( v < ( FT_ULONG_MAX - 9 ) / 10 )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200706 v = v * 10 + a2i[(int)*s];
707 else
708 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100709 v = FT_ULONG_MAX;
Werner Lemberg47a03e92017-06-02 09:06:36 +0200710 break;
711 }
712 }
David Turner993a8d02002-05-18 12:03:43 +0000713
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000714 return v;
715 }
David Turner993a8d02002-05-18 12:03:43 +0000716
David Turner993a8d02002-05-18 12:03:43 +0000717
Ben Wagnera512b0f2015-12-14 09:19:52 +0100718 /* Routine to convert a decimal ASCII string to a signed long integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000719 static long
Ben Wagnera512b0f2015-12-14 09:19:52 +0100720 _bdf_atol( char* s )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000721 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100722 long v, neg;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000723
724
725 if ( s == 0 || *s == 0 )
726 return 0;
727
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000728 /* Check for a minus sign. */
729 neg = 0;
730 if ( *s == '-' )
731 {
732 s++;
733 neg = 1;
734 }
735
Ben Wagnera512b0f2015-12-14 09:19:52 +0100736 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200737 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100738 if ( v < ( FT_LONG_MAX - 9 ) / 10 )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200739 v = v * 10 + a2i[(int)*s];
740 else
741 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100742 v = FT_LONG_MAX;
Werner Lemberg47a03e92017-06-02 09:06:36 +0200743 break;
744 }
745 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000746
747 return ( !neg ) ? v : -v;
748 }
749
750
Ben Wagnera512b0f2015-12-14 09:19:52 +0100751 /* Routine to convert a decimal ASCII string to an unsigned short integer. */
Werner Lembergb13945a2015-02-22 09:15:47 +0100752 static unsigned short
Ben Wagnera512b0f2015-12-14 09:19:52 +0100753 _bdf_atous( char* s )
Werner Lembergb13945a2015-02-22 09:15:47 +0100754 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100755 unsigned short v;
Werner Lembergb13945a2015-02-22 09:15:47 +0100756
757
758 if ( s == 0 || *s == 0 )
759 return 0;
760
Ben Wagnera512b0f2015-12-14 09:19:52 +0100761 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200762 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100763 if ( v < ( FT_USHORT_MAX - 9 ) / 10 )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200764 v = (unsigned short)( v * 10 + a2i[(int)*s] );
765 else
766 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100767 v = FT_USHORT_MAX;
Werner Lemberg47a03e92017-06-02 09:06:36 +0200768 break;
769 }
770 }
Werner Lembergb13945a2015-02-22 09:15:47 +0100771
772 return v;
773 }
774
775
Ben Wagnera512b0f2015-12-14 09:19:52 +0100776 /* Routine to convert a decimal ASCII string to a signed short integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000777 static short
Ben Wagnera512b0f2015-12-14 09:19:52 +0100778 _bdf_atos( char* s )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000779 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100780 short v, neg;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000781
782
783 if ( s == 0 || *s == 0 )
784 return 0;
785
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000786 /* Check for a minus. */
787 neg = 0;
788 if ( *s == '-' )
789 {
790 s++;
791 neg = 1;
792 }
793
Ben Wagnera512b0f2015-12-14 09:19:52 +0100794 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200795 {
796 if ( v < ( SHRT_MAX - 9 ) / 10 )
797 v = (short)( v * 10 + a2i[(int)*s] );
798 else
799 {
800 v = SHRT_MAX;
801 break;
802 }
803 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000804
Werner Lemberg233302a2002-05-22 05:41:06 +0000805 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000806 }
807
808
809 /* Routine to compare two glyphs by encoding so they can be sorted. */
810 static int
811 by_encoding( const void* a,
812 const void* b )
813 {
814 bdf_glyph_t *c1, *c2;
815
816
817 c1 = (bdf_glyph_t *)a;
818 c2 = (bdf_glyph_t *)b;
819
820 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000821 return -1;
David Turner68df4f72005-03-15 18:18:57 +0000822
823 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000824 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000825
David Turner993a8d02002-05-18 12:03:43 +0000826 return 0;
David Turner993a8d02002-05-18 12:03:43 +0000827 }
828
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000829
830 static FT_Error
831 bdf_create_property( char* name,
832 int format,
833 bdf_font_t* font )
834 {
suzuki toshiya704f4d72009-09-13 00:50:14 +0900835 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000836 bdf_property_t* p;
837 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100838 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000839
840
Werner Lemberg96ddc672011-06-29 09:15:54 +0200841 /* First check whether the property has */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000842 /* already been added or not. If it has, then */
843 /* simply ignore it. */
Werner Lemberg609546c2015-12-20 07:17:29 +0100844 if ( ft_hash_str_lookup( name, &(font->proptbl) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000845 goto Exit;
846
David Turner68df4f72005-03-15 18:18:57 +0000847 if ( FT_RENEW_ARRAY( font->user_props,
848 font->nuser_props,
849 font->nuser_props + 1 ) )
850 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000851
852 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +0000853 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000854
suzuki toshiya704f4d72009-09-13 00:50:14 +0900855 n = ft_strlen( name ) + 1;
856 if ( n > FT_ULONG_MAX )
Werner Lemberg059bc332013-03-14 10:27:35 +0100857 return FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +0000858
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000859 if ( FT_NEW_ARRAY( p->name, n ) )
860 goto Exit;
861
862 FT_MEM_COPY( (char *)p->name, name, n );
863
864 p->format = format;
865 p->builtin = 0;
866
867 n = _num_bdf_properties + font->nuser_props;
868
Werner Lemberg609546c2015-12-20 07:17:29 +0100869 error = ft_hash_str_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000870 if ( error )
871 goto Exit;
872
873 font->nuser_props++;
874
875 Exit:
David Turner993a8d02002-05-18 12:03:43 +0000876 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000877 }
David Turner993a8d02002-05-18 12:03:43 +0000878
879
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100880 FT_LOCAL_DEF( bdf_property_t* )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000881 bdf_get_property( char* name,
882 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +0000883 {
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100884 size_t* propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000885
886
887 if ( name == 0 || *name == 0 )
888 return 0;
889
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100890 if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000891 return 0;
892
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100893 if ( *propid >= _num_bdf_properties )
894 return font->user_props + ( *propid - _num_bdf_properties );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000895
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100896 return (bdf_property_t*)_bdf_properties + *propid;
David Turner993a8d02002-05-18 12:03:43 +0000897 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000898
899
Werner Lemberg9ac90602018-06-03 09:01:17 +0200900 /**************************************************************************
901 *
902 * BDF font file parsing flags and functions.
903 *
904 */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000905
906
907 /* Parse flags. */
908
Werner Lemberg758587d2016-01-12 22:20:06 +0100909#define BDF_START_ 0x0001U
910#define BDF_FONT_NAME_ 0x0002U
911#define BDF_SIZE_ 0x0004U
912#define BDF_FONT_BBX_ 0x0008U
913#define BDF_PROPS_ 0x0010U
914#define BDF_GLYPHS_ 0x0020U
915#define BDF_GLYPH_ 0x0040U
916#define BDF_ENCODING_ 0x0080U
917#define BDF_SWIDTH_ 0x0100U
918#define BDF_DWIDTH_ 0x0200U
919#define BDF_BBX_ 0x0400U
920#define BDF_BITMAP_ 0x0800U
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000921
Werner Lemberg758587d2016-01-12 22:20:06 +0100922#define BDF_SWIDTH_ADJ_ 0x1000U
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000923
Werner Lemberg758587d2016-01-12 22:20:06 +0100924#define BDF_GLYPH_BITS_ ( BDF_GLYPH_ | \
925 BDF_ENCODING_ | \
926 BDF_SWIDTH_ | \
927 BDF_DWIDTH_ | \
928 BDF_BBX_ | \
929 BDF_BITMAP_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000930
Werner Lemberg758587d2016-01-12 22:20:06 +0100931#define BDF_GLYPH_WIDTH_CHECK_ 0x40000000UL
932#define BDF_GLYPH_HEIGHT_CHECK_ 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000933
934
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000935 static FT_Error
936 _bdf_add_comment( bdf_font_t* font,
937 char* comment,
938 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +0000939 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000940 char* cp;
941 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100942 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000943
944
David Turner68df4f72005-03-15 18:18:57 +0000945 if ( FT_RENEW_ARRAY( font->comments,
946 font->comments_len,
947 font->comments_len + len + 1 ) )
948 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000949
950 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +0000951
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000952 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +0000953 cp[len] = '\n';
954
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000955 font->comments_len += len + 1;
956
957 Exit:
958 return error;
David Turner993a8d02002-05-18 12:03:43 +0000959 }
960
David Turner993a8d02002-05-18 12:03:43 +0000961
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000962 /* Set the spacing from the font name if it exists, or set it to the */
963 /* default specified in the options. */
964 static FT_Error
965 _bdf_set_default_spacing( bdf_font_t* font,
Werner Lemberge01406b2011-11-25 09:44:28 +0100966 bdf_options_t* opts,
967 unsigned long lineno )
David Turner993a8d02002-05-18 12:03:43 +0000968 {
suzuki toshiya704f4d72009-09-13 00:50:14 +0900969 size_t len;
970 char name[256];
971 _bdf_list_t list;
972 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100973 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000974
Dave Arnoldc3782492013-06-05 19:57:55 +0200975 FT_UNUSED( lineno ); /* only used in debug mode */
976
David Turner993a8d02002-05-18 12:03:43 +0000977
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000978 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
979 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100980 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000981 goto Exit;
982 }
David Turner993a8d02002-05-18 12:03:43 +0000983
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000984 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +0000985
David Turner68df4f72005-03-15 18:18:57 +0000986 _bdf_list_init( &list, memory );
987
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000988 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +0000989
suzuki toshiya704f4d72009-09-13 00:50:14 +0900990 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +0000991 /* Limit ourselves to 256 characters in the font name. */
992 if ( len >= 256 )
993 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100994 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +0100995 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +0000996 goto Exit;
997 }
998
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000999 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001000
Werner Lembergbadf3172013-06-06 09:16:38 +02001001 error = _bdf_list_split( &list, (char *)"-", name, (unsigned long)len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001002 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001003 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001004
1005 if ( list.used == 15 )
1006 {
1007 switch ( list.field[11][0] )
1008 {
1009 case 'C':
1010 case 'c':
1011 font->spacing = BDF_CHARCELL;
1012 break;
1013 case 'M':
1014 case 'm':
1015 font->spacing = BDF_MONOWIDTH;
1016 break;
1017 case 'P':
1018 case 'p':
1019 font->spacing = BDF_PROPORTIONAL;
1020 break;
David Turner993a8d02002-05-18 12:03:43 +00001021 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001022 }
1023
David Turner68df4f72005-03-15 18:18:57 +00001024 Fail:
1025 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001026
1027 Exit:
1028 return error;
David Turner993a8d02002-05-18 12:03:43 +00001029 }
David Turner993a8d02002-05-18 12:03:43 +00001030
1031
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001032 /* Determine whether the property is an atom or not. If it is, then */
1033 /* clean it up so the double quotes are removed if they exist. */
1034 static int
1035 _bdf_is_atom( char* line,
1036 unsigned long linelen,
1037 char** name,
1038 char** value,
1039 bdf_font_t* font )
1040 {
1041 int hold;
1042 char *sp, *ep;
1043 bdf_property_t* p;
1044
David Turner993a8d02002-05-18 12:03:43 +00001045
1046 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001047
1048 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001049 ep++;
1050
1051 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001052 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001053 {
1054 hold = *ep;
1055 *ep = 0;
1056 }
1057
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001058 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001059
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001060 /* Restore the character that was saved before any return can happen. */
1061 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001062 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001063
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001064 /* If the property exists and is not an atom, just return here. */
1065 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001066 return 0;
1067
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001068 /* The property is an atom. Trim all leading and trailing whitespace */
1069 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001070 sp = ep;
1071 ep = line + linelen;
1072
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001073 /* Trim the leading whitespace if it exists. */
Werner Lemberg320d4972012-02-24 18:06:46 +01001074 if ( *sp )
1075 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001076 while ( *sp &&
1077 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001078 sp++;
1079
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001080 /* Trim the leading double quote if it exists. */
1081 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001082 sp++;
1083 *value = sp;
1084
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001085 /* Trim the trailing whitespace if it exists. */
1086 while ( ep > sp &&
1087 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001088 *--ep = 0;
1089
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001090 /* Trim the trailing double quote if it exists. */
1091 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001092 *--ep = 0;
1093
1094 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001095 }
David Turner993a8d02002-05-18 12:03:43 +00001096
1097
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001098 static FT_Error
Werner Lemberge01406b2011-11-25 09:44:28 +01001099 _bdf_add_property( bdf_font_t* font,
1100 char* name,
1101 char* value,
1102 unsigned long lineno )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001103 {
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001104 size_t* propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001105 bdf_property_t *prop, *fp;
1106 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001107 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001108
Dave Arnoldc3782492013-06-05 19:57:55 +02001109 FT_UNUSED( lineno ); /* only used in debug mode */
1110
David Turner993a8d02002-05-18 12:03:43 +00001111
Werner Lemberg96ddc672011-06-29 09:15:54 +02001112 /* First, check whether the property already exists in the font. */
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001113 if ( ( propid = ft_hash_str_lookup( name,
1114 (FT_Hash)font->internal ) ) != NULL )
David Turner993a8d02002-05-18 12:03:43 +00001115 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001116 /* The property already exists in the font, so simply replace */
1117 /* the value of the property with the current value. */
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001118 fp = font->props + *propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001119
David Turnerb1b47622002-05-21 21:17:43 +00001120 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001121 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001122 case BDF_ATOM:
1123 /* Delete the current atom if it exists. */
1124 FT_FREE( fp->value.atom );
1125
David Turnerc0f9c4a2007-02-12 14:55:03 +00001126 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001127 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001128 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001129 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001130 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001131 break;
1132
1133 case BDF_INTEGER:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001134 fp->value.l = _bdf_atol( value );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001135 break;
1136
1137 case BDF_CARDINAL:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001138 fp->value.ul = _bdf_atoul( value );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001139 break;
David Turnerd490e372002-05-28 23:40:37 +00001140
David Turnerb1b47622002-05-21 21:17:43 +00001141 default:
1142 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001143 }
David Turnerd490e372002-05-28 23:40:37 +00001144
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001145 goto Exit;
1146 }
1147
1148 /* See whether this property type exists yet or not. */
1149 /* If not, create it. */
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001150 propid = ft_hash_str_lookup( name, &(font->proptbl) );
Werner Lemberg4441f7b2016-12-26 17:08:17 +01001151 if ( !propid )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001152 {
1153 error = bdf_create_property( name, BDF_ATOM, font );
1154 if ( error )
1155 goto Exit;
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001156 propid = ft_hash_str_lookup( name, &(font->proptbl) );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001157 }
1158
Werner Lembergb6b26f42016-06-09 06:53:48 +02001159 /* Allocate another property if this is overflowing. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001160 if ( font->props_used == font->props_size )
1161 {
1162 if ( font->props_size == 0 )
1163 {
1164 if ( FT_NEW_ARRAY( font->props, 1 ) )
1165 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001166 }
1167 else
1168 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001169 if ( FT_RENEW_ARRAY( font->props,
1170 font->props_size,
1171 font->props_size + 1 ) )
1172 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001173 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001174
David Turner993a8d02002-05-18 12:03:43 +00001175 fp = font->props + font->props_size;
Werner Lemberg2ecf89b2016-09-28 19:06:21 +02001176 FT_ZERO( fp );
David Turner993a8d02002-05-18 12:03:43 +00001177 font->props_size++;
1178 }
1179
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001180 if ( *propid >= _num_bdf_properties )
1181 prop = font->user_props + ( *propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001182 else
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001183 prop = (bdf_property_t*)_bdf_properties + *propid;
David Turner993a8d02002-05-18 12:03:43 +00001184
1185 fp = font->props + font->props_used;
1186
1187 fp->name = prop->name;
1188 fp->format = prop->format;
1189 fp->builtin = prop->builtin;
1190
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001191 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001192 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001193 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001194 fp->value.atom = 0;
1195 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001196 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001197 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001198 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001199 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001200 break;
David Turner993a8d02002-05-18 12:03:43 +00001201
1202 case BDF_INTEGER:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001203 fp->value.l = _bdf_atol( value );
David Turner993a8d02002-05-18 12:03:43 +00001204 break;
1205
1206 case BDF_CARDINAL:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001207 fp->value.ul = _bdf_atoul( value );
David Turner993a8d02002-05-18 12:03:43 +00001208 break;
David Turner993a8d02002-05-18 12:03:43 +00001209 }
1210
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001211 /* If the property happens to be a comment, then it doesn't need */
1212 /* to be added to the internal hash table. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001213 if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 )
Werner Lemberg370aea82010-06-08 08:37:11 +02001214 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001215 /* Add the property to the font property table. */
Werner Lemberg609546c2015-12-20 07:17:29 +01001216 error = ft_hash_str_insert( fp->name,
1217 font->props_used,
1218 (FT_Hash)font->internal,
1219 memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001220 if ( error )
1221 goto Exit;
1222 }
David Turner993a8d02002-05-18 12:03:43 +00001223
1224 font->props_used++;
1225
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001226 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1227 /* property needs to be located if it exists in the property list, the */
1228 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1229 /* present, and the SPACING property should override the default */
1230 /* spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001231 if ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 )
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001232 font->default_char = fp->value.ul;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001233 else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001234 font->font_ascent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001235 else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001236 font->font_descent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001237 else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001238 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001239 if ( !fp->value.atom )
1240 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001241 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001242 error = FT_THROW( Invalid_File_Format );
Werner Lembergb66efef2009-03-12 08:07:49 +00001243 goto Exit;
1244 }
1245
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001246 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001247 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001248 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001249 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001250 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001251 font->spacing = BDF_CHARCELL;
1252 }
1253
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001254 Exit:
1255 return error;
David Turner993a8d02002-05-18 12:03:43 +00001256 }
1257
David Turner993a8d02002-05-18 12:03:43 +00001258
David Turnerb1b47622002-05-21 21:17:43 +00001259 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001260 {
1261 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1262 };
1263
1264
1265 /* Actually parse the glyph info and bitmaps. */
1266 static FT_Error
1267 _bdf_parse_glyphs( char* line,
1268 unsigned long linelen,
1269 unsigned long lineno,
1270 void* call_data,
1271 void* client_data )
1272 {
1273 int c, mask_index;
1274 char* s;
1275 unsigned char* bp;
1276 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001277
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001278 _bdf_parse_t* p;
1279 bdf_glyph_t* glyph;
1280 bdf_font_t* font;
1281
1282 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001283 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001284
Werner Lemberg319c00d2003-04-23 19:48:24 +00001285 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001286 FT_UNUSED( lineno ); /* only used in debug mode */
1287
1288
Werner Lemberg319c00d2003-04-23 19:48:24 +00001289 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001290
1291 font = p->font;
1292 memory = font->memory;
1293
1294 /* Check for a comment. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001295 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001296 {
1297 linelen -= 7;
1298
1299 s = line + 7;
1300 if ( *s != 0 )
1301 {
1302 s++;
1303 linelen--;
1304 }
1305 error = _bdf_add_comment( p->font, s, linelen );
1306 goto Exit;
1307 }
1308
1309 /* The very first thing expected is the number of glyphs. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001310 if ( !( p->flags & BDF_GLYPHS_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001311 {
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001312 if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001313 {
1314 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001315 error = FT_THROW( Missing_Chars_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001316 goto Exit;
1317 }
1318
David Turner68df4f72005-03-15 18:18:57 +00001319 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001320 if ( error )
1321 goto Exit;
Ben Wagnera512b0f2015-12-14 09:19:52 +01001322 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001323
Werner Lemberge1ca18d2015-10-17 11:51:27 +02001324 /* We need at least 20 bytes per glyph. */
1325 if ( p->cnt > p->size / 20 )
1326 {
Werner Lemberg797ca5a2015-10-17 11:57:16 +02001327 p->cnt = font->glyphs_size = p->size / 20;
Werner Lemberge1ca18d2015-10-17 11:51:27 +02001328 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG17, p->cnt ));
1329 }
1330
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001331 /* Make sure the number of glyphs is non-zero. */
1332 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001333 font->glyphs_size = 64;
1334
Werner Lemberga08b2172007-03-28 07:17:17 +00001335 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1336 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001337 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001338 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001339 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001340 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001341 goto Exit;
1342 }
1343
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001344 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1345 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001346
Werner Lemberg758587d2016-01-12 22:20:06 +01001347 p->flags |= BDF_GLYPHS_;
David Turner993a8d02002-05-18 12:03:43 +00001348
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001349 goto Exit;
1350 }
1351
1352 /* Check for the ENDFONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001353 if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001354 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001355 if ( p->flags & BDF_GLYPH_BITS_ )
Werner Lembergaf834612014-11-22 13:29:10 +01001356 {
1357 /* Missing ENDCHAR field. */
1358 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1359 error = FT_THROW( Corrupted_Font_Glyphs );
1360 goto Exit;
1361 }
1362
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001363 /* Sort the glyphs by encoding. */
1364 ft_qsort( (char *)font->glyphs,
1365 font->glyphs_used,
1366 sizeof ( bdf_glyph_t ),
1367 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001368
Werner Lemberg758587d2016-01-12 22:20:06 +01001369 p->flags &= ~BDF_START_;
David Turner993a8d02002-05-18 12:03:43 +00001370
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001371 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001372 }
1373
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001374 /* Check for the ENDCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001375 if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001376 {
1377 p->glyph_enc = 0;
Werner Lemberg758587d2016-01-12 22:20:06 +01001378 p->flags &= ~BDF_GLYPH_BITS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001379
1380 goto Exit;
1381 }
1382
Werner Lemberg96ddc672011-06-29 09:15:54 +02001383 /* Check whether a glyph is being scanned but should be */
1384 /* ignored because it is an unencoded glyph. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001385 if ( ( p->flags & BDF_GLYPH_ ) &&
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001386 p->glyph_enc == -1 &&
1387 p->opts->keep_unencoded == 0 )
1388 goto Exit;
1389
1390 /* Check for the STARTCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001391 if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001392 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001393 if ( p->flags & BDF_GLYPH_BITS_ )
Werner Lembergb1857472015-10-17 14:21:41 +02001394 {
1395 /* Missing ENDCHAR field. */
1396 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1397 error = FT_THROW( Missing_Startchar_Field );
1398 goto Exit;
1399 }
1400
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001401 /* Set the character name in the parse info first until the */
1402 /* encoding can be checked for an unencoded character. */
1403 FT_FREE( p->glyph_name );
1404
David Turner68df4f72005-03-15 18:18:57 +00001405 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001406 if ( error )
1407 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001408
David Turner68df4f72005-03-15 18:18:57 +00001409 _bdf_list_shift( &p->list, 1 );
1410
1411 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001412
Werner Lembergba03af62007-05-30 13:57:02 +00001413 if ( !s )
1414 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001415 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001416 error = FT_THROW( Invalid_File_Format );
Werner Lembergba03af62007-05-30 13:57:02 +00001417 goto Exit;
1418 }
1419
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001420 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1421 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001422
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001423 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1424
Werner Lemberg758587d2016-01-12 22:20:06 +01001425 p->flags |= BDF_GLYPH_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001426
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001427 FT_TRACE4(( DBGMSG1, lineno, s ));
1428
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001429 goto Exit;
1430 }
1431
1432 /* Check for the ENCODING field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001433 if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001434 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001435 if ( !( p->flags & BDF_GLYPH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001436 {
1437 /* Missing STARTCHAR field. */
1438 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001439 error = FT_THROW( Missing_Startchar_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001440 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001441 }
1442
David Turner68df4f72005-03-15 18:18:57 +00001443 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001444 if ( error )
1445 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001446
Ben Wagnera512b0f2015-12-14 09:19:52 +01001447 p->glyph_enc = _bdf_atol( p->list.field[1] );
David Turner993a8d02002-05-18 12:03:43 +00001448
Werner Lemberg28dd2c42012-02-26 06:18:58 +01001449 /* Normalize negative encoding values. The specification only */
1450 /* allows -1, but we can be more generous here. */
1451 if ( p->glyph_enc < -1 )
1452 p->glyph_enc = -1;
1453
Werner Lemberg03242f52012-02-26 06:52:56 +01001454 /* Check for alternative encoding format. */
1455 if ( p->glyph_enc == -1 && p->list.used > 2 )
Ben Wagnera512b0f2015-12-14 09:19:52 +01001456 p->glyph_enc = _bdf_atol( p->list.field[2] );
Werner Lemberg03242f52012-02-26 06:52:56 +01001457
Alexei Podtelezhnikov923fcbc2018-08-15 22:50:06 -04001458 if ( p->glyph_enc < -1 || p->glyph_enc >= 0x110000L )
Werner Lemberg7f2e4f42012-12-15 09:39:41 +01001459 p->glyph_enc = -1;
1460
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001461 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1462
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001463 if ( p->glyph_enc >= 0 )
1464 {
1465 /* Make sure there are enough glyphs allocated in case the */
1466 /* number of characters happen to be wrong. */
1467 if ( font->glyphs_used == font->glyphs_size )
1468 {
1469 if ( FT_RENEW_ARRAY( font->glyphs,
1470 font->glyphs_size,
1471 font->glyphs_size + 64 ) )
1472 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001473
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001474 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001475 }
1476
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001477 glyph = font->glyphs + font->glyphs_used++;
1478 glyph->name = p->glyph_name;
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001479 glyph->encoding = (unsigned long)p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001480
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001481 /* Reset the initial glyph info. */
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001482 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001483 }
1484 else
1485 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001486 /* Unencoded glyph. Check whether it should */
1487 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001488 if ( p->opts->keep_unencoded != 0 )
1489 {
1490 /* Allocate the next unencoded glyph. */
1491 if ( font->unencoded_used == font->unencoded_size )
1492 {
David Turner68df4f72005-03-15 18:18:57 +00001493 if ( FT_RENEW_ARRAY( font->unencoded ,
1494 font->unencoded_size,
1495 font->unencoded_size + 4 ) )
1496 goto Exit;
1497
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001498 font->unencoded_size += 4;
1499 }
1500
1501 glyph = font->unencoded + font->unencoded_used;
1502 glyph->name = p->glyph_name;
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001503 glyph->encoding = font->unencoded_used++;
Werner Lemberg4a150132015-11-25 07:53:49 +01001504
1505 /* Reset the initial glyph info. */
1506 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001507 }
1508 else
Werner Lemberg94cacac2015-11-15 04:45:42 +01001509 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001510 /* Free up the glyph name if the unencoded shouldn't be */
1511 /* kept. */
1512 FT_FREE( p->glyph_name );
Werner Lemberg94cacac2015-11-15 04:45:42 +01001513 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001514
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001515 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001516 }
1517
1518 /* Clear the flags that might be added when width and height are */
1519 /* checked for consistency. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001520 p->flags &= ~( BDF_GLYPH_WIDTH_CHECK_ | BDF_GLYPH_HEIGHT_CHECK_ );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001521
Werner Lemberg758587d2016-01-12 22:20:06 +01001522 p->flags |= BDF_ENCODING_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001523
1524 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001525 }
1526
Armin Hasitzka0f6be062018-06-17 20:27:42 +02001527 if ( !( p->flags & BDF_ENCODING_ ) )
1528 goto Missing_Encoding;
1529
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001530 /* Point at the glyph being constructed. */
1531 if ( p->glyph_enc == -1 )
1532 glyph = font->unencoded + ( font->unencoded_used - 1 );
1533 else
1534 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001535
Werner Lemberg96ddc672011-06-29 09:15:54 +02001536 /* Check whether a bitmap is being constructed. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001537 if ( p->flags & BDF_BITMAP_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001538 {
1539 /* If there are more rows than are specified in the glyph metrics, */
1540 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001541 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001542 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001543 if ( !( p->flags & BDF_GLYPH_HEIGHT_CHECK_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001544 {
1545 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001546 p->flags |= BDF_GLYPH_HEIGHT_CHECK_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001547 }
1548
1549 goto Exit;
1550 }
1551
1552 /* Only collect the number of nibbles indicated by the glyph */
1553 /* metrics. If there are more columns, they are simply ignored. */
1554 nibbles = glyph->bpr << 1;
1555 bp = glyph->bitmap + p->row * glyph->bpr;
1556
David Turnerb698eed2006-02-23 14:50:13 +00001557 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001558 {
1559 c = line[i];
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001560 if ( !sbitset( hdigits, c ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001561 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001562 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001563 if ( i + 1 < nibbles && ( i & 1 ) )
1564 *++bp = 0;
1565 }
1566
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001567 /* If any line has not enough columns, */
1568 /* indicate they have been padded with zero bits. */
1569 if ( i < nibbles &&
Werner Lemberg758587d2016-01-12 22:20:06 +01001570 !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001571 {
1572 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001573 p->flags |= BDF_GLYPH_WIDTH_CHECK_;
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001574 }
1575
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001576 /* Remove possible garbage at the right. */
1577 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001578 if ( glyph->bbx.width )
1579 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001580
1581 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001582 if ( i == nibbles &&
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001583 sbitset( hdigits, line[nibbles] ) &&
Werner Lemberg758587d2016-01-12 22:20:06 +01001584 !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001585 {
1586 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001587 p->flags |= BDF_GLYPH_WIDTH_CHECK_;
David Turner993a8d02002-05-18 12:03:43 +00001588 }
1589
1590 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001591 goto Exit;
1592 }
David Turner993a8d02002-05-18 12:03:43 +00001593
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001594 /* Expect the SWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001595 if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001596 {
David Turner68df4f72005-03-15 18:18:57 +00001597 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001598 if ( error )
1599 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001600
Ben Wagnera512b0f2015-12-14 09:19:52 +01001601 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1] );
Werner Lemberg758587d2016-01-12 22:20:06 +01001602 p->flags |= BDF_SWIDTH_;
David Turner993a8d02002-05-18 12:03:43 +00001603
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001604 goto Exit;
1605 }
David Turner993a8d02002-05-18 12:03:43 +00001606
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001607 /* Expect the DWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001608 if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001609 {
David Turner68df4f72005-03-15 18:18:57 +00001610 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001611 if ( error )
1612 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001613
Ben Wagnera512b0f2015-12-14 09:19:52 +01001614 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001615
Werner Lemberg758587d2016-01-12 22:20:06 +01001616 if ( !( p->flags & BDF_SWIDTH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001617 {
1618 /* Missing SWIDTH field. Emit an auto correction message and set */
1619 /* the scalable width from the device width. */
1620 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1621
Werner Lemberg02d4d592002-05-28 22:38:05 +00001622 glyph->swidth = (unsigned short)FT_MulDiv(
1623 glyph->dwidth, 72000L,
1624 (FT_Long)( font->point_size *
1625 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001626 }
1627
Werner Lemberg758587d2016-01-12 22:20:06 +01001628 p->flags |= BDF_DWIDTH_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001629 goto Exit;
1630 }
David Turner993a8d02002-05-18 12:03:43 +00001631
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001632 /* Expect the BBX field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001633 if ( _bdf_strncmp( line, "BBX", 3 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001634 {
David Turner68df4f72005-03-15 18:18:57 +00001635 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001636 if ( error )
1637 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001638
Ben Wagnera512b0f2015-12-14 09:19:52 +01001639 glyph->bbx.width = _bdf_atous( p->list.field[1] );
1640 glyph->bbx.height = _bdf_atous( p->list.field[2] );
1641 glyph->bbx.x_offset = _bdf_atos( p->list.field[3] );
1642 glyph->bbx.y_offset = _bdf_atos( p->list.field[4] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001643
1644 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001645 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1646 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001647
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001648 /* Determine the overall font bounding box as the characters are */
1649 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001650 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1651 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001652
David Turnerb1b47622002-05-21 21:17:43 +00001653 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001654
Werner Lembergdfa46192004-03-05 09:26:24 +00001655 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1656 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1657 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001658
Werner Lemberg758587d2016-01-12 22:20:06 +01001659 if ( !( p->flags & BDF_DWIDTH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001660 {
1661 /* Missing DWIDTH field. Emit an auto correction message and set */
1662 /* the device width to the glyph width. */
1663 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1664 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001665 }
1666
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001667 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1668 /* value if necessary. */
1669 if ( p->opts->correct_metrics != 0 )
1670 {
1671 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001672 unsigned short sw = (unsigned short)FT_MulDiv(
1673 glyph->dwidth, 72000L,
1674 (FT_Long)( font->point_size *
1675 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001676
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001677
1678 if ( sw != glyph->swidth )
1679 {
1680 glyph->swidth = sw;
1681
Werner Lemberg758587d2016-01-12 22:20:06 +01001682 p->flags |= BDF_SWIDTH_ADJ_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001683 }
David Turner993a8d02002-05-18 12:03:43 +00001684 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001685
Werner Lemberg758587d2016-01-12 22:20:06 +01001686 p->flags |= BDF_BBX_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001687 goto Exit;
1688 }
David Turner993a8d02002-05-18 12:03:43 +00001689
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001690 /* And finally, gather up the bitmap. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001691 if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001692 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001693 unsigned long bitmap_size;
1694
1695
Werner Lemberg758587d2016-01-12 22:20:06 +01001696 if ( !( p->flags & BDF_BBX_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001697 {
1698 /* Missing BBX field. */
1699 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001700 error = FT_THROW( Missing_Bbx_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001701 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001702 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001703
1704 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001705 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001706
1707 bitmap_size = glyph->bpr * glyph->bbx.height;
Werner Lembergc4cad302012-03-08 20:11:37 +01001708 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
Werner Lemberg26170df2006-03-26 07:19:07 +00001709 {
1710 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001711 error = FT_THROW( Bbx_Too_Big );
Werner Lemberg26170df2006-03-26 07:19:07 +00001712 goto Exit;
1713 }
1714 else
1715 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001716
1717 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1718 goto Exit;
1719
1720 p->row = 0;
Werner Lemberg758587d2016-01-12 22:20:06 +01001721 p->flags |= BDF_BITMAP_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001722
1723 goto Exit;
1724 }
1725
Werner Lemberge01406b2011-11-25 09:44:28 +01001726 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001727 error = FT_THROW( Invalid_File_Format );
Werner Lemberg4086fb72012-03-01 08:55:40 +01001728 goto Exit;
1729
1730 Missing_Encoding:
1731 /* Missing ENCODING field. */
1732 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001733 error = FT_THROW( Missing_Encoding_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001734
1735 Exit:
Werner Lemberg758587d2016-01-12 22:20:06 +01001736 if ( error && ( p->flags & BDF_GLYPH_ ) )
Werner Lembergf4c94d42010-06-19 16:08:31 +02001737 FT_FREE( p->glyph_name );
1738
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001739 return error;
David Turner993a8d02002-05-18 12:03:43 +00001740 }
1741
David Turner993a8d02002-05-18 12:03:43 +00001742
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001743 /* Load the font properties. */
1744 static FT_Error
1745 _bdf_parse_properties( char* line,
1746 unsigned long linelen,
1747 unsigned long lineno,
1748 void* call_data,
1749 void* client_data )
1750 {
1751 unsigned long vlen;
1752 _bdf_line_func_t* next;
1753 _bdf_parse_t* p;
1754 char* name;
1755 char* value;
1756 char nbuf[128];
Werner Lemberge3c93012013-03-14 11:21:17 +01001757 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001758
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001759 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001760
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001761
1762 next = (_bdf_line_func_t *)call_data;
1763 p = (_bdf_parse_t *) client_data;
1764
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001765 /* Check for the end of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001766 if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001767 {
1768 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1769 /* encountered yet, then make sure they are added as properties and */
1770 /* make sure they are set from the font bounding box info. */
1771 /* */
1772 /* This is *always* done regardless of the options, because X11 */
1773 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001774 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001775 {
1776 p->font->font_ascent = p->font->bbx.ascent;
1777 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001778 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
1779 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001780 if ( error )
1781 goto Exit;
1782
1783 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
David Turner993a8d02002-05-18 12:03:43 +00001784 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001785
Werner Lemberg428c2e42003-04-25 05:35:04 +00001786 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001787 {
1788 p->font->font_descent = p->font->bbx.descent;
1789 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001790 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
1791 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001792 if ( error )
1793 goto Exit;
1794
1795 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
David Turner993a8d02002-05-18 12:03:43 +00001796 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001797
Werner Lemberg758587d2016-01-12 22:20:06 +01001798 p->flags &= ~BDF_PROPS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001799 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001800
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001801 goto Exit;
1802 }
David Turner993a8d02002-05-18 12:03:43 +00001803
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001804 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001805 if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001806 goto Exit;
1807
1808 /* Handle COMMENT fields and properties in a special way to preserve */
1809 /* the spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001810 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001811 {
David Turner993a8d02002-05-18 12:03:43 +00001812 name = value = line;
1813 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001814 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001815 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01001816 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001817 if ( error )
1818 goto Exit;
1819 }
1820 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1821 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001822 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001823 if ( error )
1824 goto Exit;
1825 }
1826 else
1827 {
David Turner68df4f72005-03-15 18:18:57 +00001828 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001829 if ( error )
1830 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001831 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001832
David Turner68df4f72005-03-15 18:18:57 +00001833 _bdf_list_shift( &p->list, 1 );
1834 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001835
Werner Lemberge01406b2011-11-25 09:44:28 +01001836 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001837 if ( error )
1838 goto Exit;
1839 }
1840
1841 Exit:
1842 return error;
David Turner993a8d02002-05-18 12:03:43 +00001843 }
1844
David Turner993a8d02002-05-18 12:03:43 +00001845
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001846 /* Load the font header. */
1847 static FT_Error
1848 _bdf_parse_start( char* line,
1849 unsigned long linelen,
1850 unsigned long lineno,
1851 void* call_data,
1852 void* client_data )
1853 {
1854 unsigned long slen;
1855 _bdf_line_func_t* next;
1856 _bdf_parse_t* p;
1857 bdf_font_t* font;
1858 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001859
David Turnerd490e372002-05-28 23:40:37 +00001860 FT_Memory memory = NULL;
Werner Lemberge3c93012013-03-14 11:21:17 +01001861 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001862
1863 FT_UNUSED( lineno ); /* only used in debug mode */
1864
1865
1866 next = (_bdf_line_func_t *)call_data;
1867 p = (_bdf_parse_t *) client_data;
1868
1869 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00001870 memory = p->font->memory;
1871
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001872 /* Check for a comment. This is done to handle those fonts that have */
1873 /* comments before the STARTFONT line for some reason. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001874 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001875 {
1876 if ( p->opts->keep_comments != 0 && p->font != 0 )
1877 {
1878 linelen -= 7;
1879
1880 s = line + 7;
1881 if ( *s != 0 )
1882 {
1883 s++;
1884 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00001885 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001886
1887 error = _bdf_add_comment( p->font, s, linelen );
1888 if ( error )
1889 goto Exit;
1890 /* here font is not defined! */
1891 }
1892
1893 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001894 }
1895
Werner Lemberg758587d2016-01-12 22:20:06 +01001896 if ( !( p->flags & BDF_START_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001897 {
1898 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00001899
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001900 if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001901 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01001902 /* we don't emit an error message since this code gets */
1903 /* explicitly caught one level higher */
Werner Lemberg059bc332013-03-14 10:27:35 +01001904 error = FT_THROW( Missing_Startfont_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001905 goto Exit;
1906 }
David Turner993a8d02002-05-18 12:03:43 +00001907
Werner Lemberg758587d2016-01-12 22:20:06 +01001908 p->flags = BDF_START_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001909 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00001910
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001911 if ( FT_NEW( font ) )
1912 goto Exit;
1913 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00001914
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001915 font->memory = p->memory;
1916 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00001917
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001918 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001919 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001920 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00001921
David Turner993a8d02002-05-18 12:03:43 +00001922
Werner Lemberg7ce6c432015-12-22 05:39:58 +01001923 error = ft_hash_str_init( &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001924 if ( error )
1925 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00001926 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001927 i < _num_bdf_properties; i++, prop++ )
1928 {
Werner Lemberg609546c2015-12-20 07:17:29 +01001929 error = ft_hash_str_insert( prop->name, i,
1930 &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001931 if ( error )
1932 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001933 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001934 }
1935
Werner Lemberg31343562015-12-19 17:02:13 +01001936 if ( FT_ALLOC( p->font->internal, sizeof ( FT_HashRec ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001937 goto Exit;
Werner Lemberg7ce6c432015-12-22 05:39:58 +01001938 error = ft_hash_str_init( (FT_Hash)p->font->internal, memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001939 if ( error )
1940 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00001941 p->font->spacing = p->opts->font_spacing;
Alexei Podtelezhnikovf5fe6e22018-08-13 09:01:53 -04001942 p->font->default_char = ~0UL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001943
1944 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001945 }
1946
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001947 /* Check for the start of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001948 if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001949 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001950 if ( !( p->flags & BDF_FONT_BBX_ ) )
Werner Lembergfb690292010-06-23 10:00:52 +02001951 {
1952 /* Missing the FONTBOUNDINGBOX field. */
1953 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001954 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergfb690292010-06-23 10:00:52 +02001955 goto Exit;
1956 }
1957
David Turner68df4f72005-03-15 18:18:57 +00001958 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001959 if ( error )
1960 goto Exit;
Werner Lembergb6b26f42016-06-09 06:53:48 +02001961
Werner Lembergb66efef2009-03-12 08:07:49 +00001962 /* at this point, `p->font' can't be NULL */
Ben Wagnera512b0f2015-12-14 09:19:52 +01001963 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1] );
Werner Lembergb6b26f42016-06-09 06:53:48 +02001964 /* We need at least 4 bytes per property. */
1965 if ( p->cnt > p->size / 4 )
1966 {
1967 p->font->props_size = 0;
1968
1969 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "STARTPROPERTIES" ));
1970 error = FT_THROW( Invalid_Argument );
1971 goto Exit;
1972 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001973
1974 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
Werner Lemberg9b6b5752012-12-15 01:34:41 +01001975 {
1976 p->font->props_size = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001977 goto Exit;
Werner Lemberg9b6b5752012-12-15 01:34:41 +01001978 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001979
Werner Lemberg758587d2016-01-12 22:20:06 +01001980 p->flags |= BDF_PROPS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001981 *next = _bdf_parse_properties;
1982
1983 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001984 }
1985
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001986 /* Check for the FONTBOUNDINGBOX field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001987 if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001988 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001989 if ( !( p->flags & BDF_SIZE_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001990 {
1991 /* Missing the SIZE field. */
1992 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001993 error = FT_THROW( Missing_Size_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001994 goto Exit;
1995 }
1996
David Turner68df4f72005-03-15 18:18:57 +00001997 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001998 if ( error )
1999 goto Exit;
2000
Ben Wagnera512b0f2015-12-14 09:19:52 +01002001 p->font->bbx.width = _bdf_atous( p->list.field[1] );
2002 p->font->bbx.height = _bdf_atous( p->list.field[2] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002003
Ben Wagnera512b0f2015-12-14 09:19:52 +01002004 p->font->bbx.x_offset = _bdf_atos( p->list.field[3] );
2005 p->font->bbx.y_offset = _bdf_atos( p->list.field[4] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002006
David Turnerd490e372002-05-28 23:40:37 +00002007 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002008 p->font->bbx.y_offset );
2009
2010 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002011
Werner Lemberg758587d2016-01-12 22:20:06 +01002012 p->flags |= BDF_FONT_BBX_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002013
2014 goto Exit;
2015 }
2016
2017 /* The next thing to check for is the FONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002018 if ( _bdf_strncmp( line, "FONT", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002019 {
David Turner68df4f72005-03-15 18:18:57 +00002020 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002021 if ( error )
2022 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002023 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002024
David Turner68df4f72005-03-15 18:18:57 +00002025 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002026
2027 if ( !s )
2028 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002029 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002030 error = FT_THROW( Invalid_File_Format );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002031 goto Exit;
2032 }
2033
Werner Lembergfb690292010-06-23 10:00:52 +02002034 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2035 FT_FREE( p->font->name );
2036
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002037 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2038 goto Exit;
2039 FT_MEM_COPY( p->font->name, s, slen + 1 );
2040
2041 /* If the font name is an XLFD name, set the spacing to the one in */
2042 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002043 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002044 if ( error )
2045 goto Exit;
2046
Werner Lemberg758587d2016-01-12 22:20:06 +01002047 p->flags |= BDF_FONT_NAME_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002048
2049 goto Exit;
2050 }
2051
2052 /* Check for the SIZE field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002053 if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002054 {
Werner Lemberg758587d2016-01-12 22:20:06 +01002055 if ( !( p->flags & BDF_FONT_NAME_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002056 {
2057 /* Missing the FONT field. */
2058 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002059 error = FT_THROW( Missing_Font_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002060 goto Exit;
2061 }
2062
David Turner68df4f72005-03-15 18:18:57 +00002063 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002064 if ( error )
2065 goto Exit;
2066
Ben Wagnera512b0f2015-12-14 09:19:52 +01002067 p->font->point_size = _bdf_atoul( p->list.field[1] );
2068 p->font->resolution_x = _bdf_atoul( p->list.field[2] );
2069 p->font->resolution_y = _bdf_atoul( p->list.field[3] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002070
2071 /* Check for the bits per pixel field. */
2072 if ( p->list.used == 5 )
2073 {
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002074 unsigned short bpp;
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002075
2076
Ben Wagnera512b0f2015-12-14 09:19:52 +01002077 bpp = (unsigned short)_bdf_atos( p->list.field[4] );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002078
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002079 /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
2080 if ( bpp > 4 )
2081 p->font->bpp = 8;
2082 else if ( bpp > 2 )
2083 p->font->bpp = 4;
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002084 else if ( bpp > 1 )
2085 p->font->bpp = 2;
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002086 else
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002087 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002088
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002089 if ( p->font->bpp != bpp )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002090 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002091 }
2092 else
2093 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002094
Werner Lemberg758587d2016-01-12 22:20:06 +01002095 p->flags |= BDF_SIZE_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002096
2097 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002098 }
2099
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002100 /* Check for the CHARS field -- font properties are optional */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002101 if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002102 {
2103 char nbuf[128];
2104
2105
Werner Lemberg758587d2016-01-12 22:20:06 +01002106 if ( !( p->flags & BDF_FONT_BBX_ ) )
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002107 {
2108 /* Missing the FONTBOUNDINGBOX field. */
2109 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002110 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002111 goto Exit;
2112 }
2113
2114 /* Add the two standard X11 properties which are required */
2115 /* for compiling fonts. */
2116 p->font->font_ascent = p->font->bbx.ascent;
2117 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002118 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2119 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002120 if ( error )
2121 goto Exit;
2122 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2123
2124 p->font->font_descent = p->font->bbx.descent;
2125 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002126 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2127 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002128 if ( error )
2129 goto Exit;
2130 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2131
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002132 *next = _bdf_parse_glyphs;
2133
2134 /* A special return value. */
2135 error = -1;
2136 goto Exit;
2137 }
2138
Werner Lemberge01406b2011-11-25 09:44:28 +01002139 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002140 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002141
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002142 Exit:
2143 return error;
2144 }
David Turner993a8d02002-05-18 12:03:43 +00002145
2146
Werner Lemberg9ac90602018-06-03 09:01:17 +02002147 /**************************************************************************
2148 *
2149 * API.
2150 *
2151 */
David Turner993a8d02002-05-18 12:03:43 +00002152
David Turner993a8d02002-05-18 12:03:43 +00002153
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002154 FT_LOCAL_DEF( FT_Error )
2155 bdf_load_font( FT_Stream stream,
2156 FT_Memory extmemory,
2157 bdf_options_t* opts,
2158 bdf_font_t* *font )
2159 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002160 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002161 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002162
Sean McBride7be2a942014-02-08 13:55:38 +01002163 FT_Memory memory = extmemory; /* needed for FT_NEW */
2164 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002165
2166
David Turner68df4f72005-03-15 18:18:57 +00002167 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002168 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002169
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002170 memory = NULL;
2171 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2172 p->minlb = 32767;
Werner Lemberge1ca18d2015-10-17 11:51:27 +02002173 p->size = stream->size;
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002174 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002175
David Turner68df4f72005-03-15 18:18:57 +00002176 _bdf_list_init( &p->list, extmemory );
2177
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002178 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002179 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002180 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002181 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002182
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002183 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002184 {
2185 /* If the font is not proportional, set the font's monowidth */
2186 /* field to the width of the font bounding box. */
David Turner993a8d02002-05-18 12:03:43 +00002187
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002188 if ( p->font->spacing != BDF_PROPORTIONAL )
2189 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002190
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002191 /* If the number of glyphs loaded is not that of the original count, */
2192 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002193 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002194 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002195 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2196 p->font->glyphs_used + p->font->unencoded_used ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002197 }
2198
2199 /* Once the font has been loaded, adjust the overall font metrics if */
2200 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002201 if ( p->opts->correct_metrics != 0 &&
2202 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002203 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002204 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002205 {
2206 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002207 p->font->bbx.width, p->maxrb - p->minlb ));
2208 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
David Turner993a8d02002-05-18 12:03:43 +00002209 }
2210
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002211 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002212 {
2213 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002214 p->font->bbx.x_offset, p->minlb ));
2215 p->font->bbx.x_offset = p->minlb;
David Turner993a8d02002-05-18 12:03:43 +00002216 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002217
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002218 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002219 {
2220 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002221 p->font->bbx.ascent, p->maxas ));
2222 p->font->bbx.ascent = p->maxas;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002223 }
2224
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002225 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002226 {
2227 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002228 p->font->bbx.descent, p->maxds ));
2229 p->font->bbx.descent = p->maxds;
2230 p->font->bbx.y_offset = (short)( -p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002231 }
2232
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002233 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002234 {
2235 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002236 p->font->bbx.height, p->maxas + p->maxds ));
2237 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002238 }
2239
Werner Lemberg758587d2016-01-12 22:20:06 +01002240 if ( p->flags & BDF_SWIDTH_ADJ_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002241 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2242 }
David Turner993a8d02002-05-18 12:03:43 +00002243 }
2244
Werner Lemberg758587d2016-01-12 22:20:06 +01002245 if ( p->flags & BDF_START_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002246 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002247 /* The ENDFONT field was never reached or did not exist. */
Werner Lemberg758587d2016-01-12 22:20:06 +01002248 if ( !( p->flags & BDF_GLYPHS_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002249 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002250 /* Error happened while parsing header. */
2251 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002252 error = FT_THROW( Corrupted_Font_Header );
Bungeman65d89802015-10-15 23:50:16 +02002253 goto Fail;
Werner Lemberge01406b2011-11-25 09:44:28 +01002254 }
2255 else
2256 {
2257 /* Error happened when parsing glyphs. */
2258 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002259 error = FT_THROW( Corrupted_Font_Glyphs );
Bungeman65d89802015-10-15 23:50:16 +02002260 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002261 }
David Turner993a8d02002-05-18 12:03:43 +00002262 }
2263
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002264 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002265 {
2266 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002267 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002268
Werner Lemberg370aea82010-06-08 08:37:11 +02002269 if ( p->font->comments_len > 0 )
2270 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002271 if ( FT_RENEW_ARRAY( p->font->comments,
2272 p->font->comments_len,
2273 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002274 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002275
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002276 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002277 }
David Turner993a8d02002-05-18 12:03:43 +00002278 }
Werner Lemberg5d664b62016-12-17 20:47:42 +01002279 else if ( !error )
Werner Lemberg059bc332013-03-14 10:27:35 +01002280 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002281
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002282 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002283
2284 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002285 if ( p )
2286 {
David Turner68df4f72005-03-15 18:18:57 +00002287 _bdf_list_done( &p->list );
2288
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002289 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002290
Werner Lemberg4a150132015-11-25 07:53:49 +01002291 FT_FREE( p->glyph_name );
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002292 FT_FREE( p );
2293 }
2294
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002295 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002296
2297 Fail:
2298 bdf_free_font( p->font );
2299
2300 memory = extmemory;
2301
2302 FT_FREE( p->font );
2303
2304 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002305 }
David Turner993a8d02002-05-18 12:03:43 +00002306
2307
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002308 FT_LOCAL_DEF( void )
2309 bdf_free_font( bdf_font_t* font )
2310 {
2311 bdf_property_t* prop;
2312 unsigned long i;
2313 bdf_glyph_t* glyphs;
2314 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002315
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002316
2317 if ( font == 0 )
2318 return;
David Turner993a8d02002-05-18 12:03:43 +00002319
2320 memory = font->memory;
2321
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002322 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002323
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002324 /* Free up the internal hash table of property names. */
2325 if ( font->internal )
2326 {
Werner Lemberg7ce6c432015-12-22 05:39:58 +01002327 ft_hash_str_free( (FT_Hash)font->internal, memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002328 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002329 }
2330
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002331 /* Free up the comment info. */
2332 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002333
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002334 /* Free up the properties. */
2335 for ( i = 0; i < font->props_size; i++ )
2336 {
2337 if ( font->props[i].format == BDF_ATOM )
2338 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002339 }
2340
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002341 FT_FREE( font->props );
2342
2343 /* Free up the character info. */
2344 for ( i = 0, glyphs = font->glyphs;
2345 i < font->glyphs_used; i++, glyphs++ )
2346 {
2347 FT_FREE( glyphs->name );
2348 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002349 }
2350
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002351 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2352 i++, glyphs++ )
2353 {
2354 FT_FREE( glyphs->name );
2355 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002356 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002357
2358 FT_FREE( font->glyphs );
2359 FT_FREE( font->unencoded );
2360
David Turner993a8d02002-05-18 12:03:43 +00002361 /* bdf_cleanup */
Werner Lemberg7ce6c432015-12-22 05:39:58 +01002362 ft_hash_str_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002363
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002364 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002365 for ( prop = font->user_props, i = 0;
2366 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002367 {
2368 FT_FREE( prop->name );
2369 if ( prop->format == BDF_ATOM )
2370 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002371 }
David Turner993a8d02002-05-18 12:03:43 +00002372
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002373 FT_FREE( font->user_props );
2374
2375 /* FREE( font ); */ /* XXX Fixme */
2376 }
David Turner993a8d02002-05-18 12:03:43 +00002377
2378
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002379 FT_LOCAL_DEF( bdf_property_t * )
2380 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002381 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002382 {
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002383 size_t* propid;
David Turner993a8d02002-05-18 12:03:43 +00002384
David Turner993a8d02002-05-18 12:03:43 +00002385
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002386 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002387 return 0;
2388
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002389 propid = ft_hash_str_lookup( name, (FT_Hash)font->internal );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002390
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002391 return propid ? ( font->props + *propid ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002392 }
2393
2394
2395/* END */