blob: 1b8d46069f61b175f5b9a40d88d416b3e61ed68d [file] [log] [blame]
David Turner993a8d02002-05-18 12:03:43 +00001/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
Sean McBride7be2a942014-02-08 13:55:38 +01003 * Copyright 2001-2014
Werner Lemberg442bfb82007-02-12 21:44:10 +00004 * Francesco Zappa Nardelli
David Turner993a8d02002-05-18 12:03:43 +00005 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
Werner Lemberg9ac90602018-06-03 09:01:17 +020025 /**************************************************************************
26 *
27 * This file is based on bdf.c,v 1.22 2000/03/16 20:08:50
28 *
29 * taken from Mark Leisher's xmbdfed package
30 *
31 */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000032
David Turner993a8d02002-05-18 12:03:43 +000033
34#include <ft2build.h>
35
Werner Lemberg02d4d592002-05-28 22:38:05 +000036#include FT_FREETYPE_H
David Turner993a8d02002-05-18 12:03:43 +000037#include FT_INTERNAL_DEBUG_H
38#include FT_INTERNAL_STREAM_H
39#include FT_INTERNAL_OBJECTS_H
40
41#include "bdf.h"
David Turner993a8d02002-05-18 12:03:43 +000042#include "bdferror.h"
43
David Turner993a8d02002-05-18 12:03:43 +000044
Werner Lemberg9ac90602018-06-03 09:01:17 +020045 /**************************************************************************
46 *
47 * The macro FT_COMPONENT is used in trace mode. It is an implicit
48 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
49 * messages during execution.
50 */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000051#undef FT_COMPONENT
52#define FT_COMPONENT trace_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"
199#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
200#define ACMSG13 "Glyph %ld extra rows removed.\n"
201#define ACMSG14 "Glyph %ld extra columns removed.\n"
202#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
Werner Lemberg0b1c0c62012-02-25 10:23:04 +0100203#define ACMSG16 "Glyph %ld missing columns padded with zero bits.\n"
Werner Lemberge1ca18d2015-10-17 11:51:27 +0200204#define ACMSG17 "Adjusting number of glyphs to %ld.\n"
Werner Lemberge01406b2011-11-25 09:44:28 +0100205
206 /* Error messages. */
207#define ERRMSG1 "[line %ld] Missing `%s' line.\n"
208#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
209#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
210#define ERRMSG4 "[line %ld] BBX too big.\n"
211#define ERRMSG5 "[line %ld] `%s' value too big.\n"
212#define ERRMSG6 "[line %ld] Input line too long.\n"
213#define ERRMSG7 "[line %ld] Font name too long.\n"
214#define ERRMSG8 "[line %ld] Invalid `%s' value.\n"
215#define ERRMSG9 "[line %ld] Invalid keyword.\n"
216
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +0100217 /* Debug messages. */
218#define DBGMSG1 " [%6ld] %s" /* no \n */
219#define DBGMSG2 " (0x%lX)\n"
220
Werner Lemberge01406b2011-11-25 09:44:28 +0100221
Werner Lemberg9ac90602018-06-03 09:01:17 +0200222 /**************************************************************************
223 *
224 * Utility types and functions.
225 *
226 */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000227
228
229 /* Function type for parsing lines of a BDF font. */
230
231 typedef FT_Error
232 (*_bdf_line_func_t)( char* line,
233 unsigned long linelen,
234 unsigned long lineno,
235 void* call_data,
236 void* client_data );
237
238
239 /* List structure for splitting lines into fields. */
240
241 typedef struct _bdf_list_t_
242 {
243 char** field;
244 unsigned long size;
245 unsigned long used;
David Turner68df4f72005-03-15 18:18:57 +0000246 FT_Memory memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000247
248 } _bdf_list_t;
249
250
251 /* Structure used while loading BDF fonts. */
252
253 typedef struct _bdf_parse_t_
254 {
255 unsigned long flags;
256 unsigned long cnt;
257 unsigned long row;
258
259 short minlb;
260 short maxlb;
261 short maxrb;
262 short maxas;
263 short maxds;
264
265 short rbearing;
266
267 char* glyph_name;
268 long glyph_enc;
269
270 bdf_font_t* font;
271 bdf_options_t* opts;
272
Werner Lemberged54e432011-11-27 16:39:53 +0100273 unsigned long have[34816]; /* must be in sync with `nmod' and `umod' */
274 /* arrays from `bdf_font_t' structure */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000275 _bdf_list_t list;
276
277 FT_Memory memory;
Werner Lemberge1ca18d2015-10-17 11:51:27 +0200278 unsigned long size; /* the stream size */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000279
280 } _bdf_parse_t;
281
282
Werner Lemberga08b2172007-03-28 07:17:17 +0000283#define setsbit( m, cc ) \
284 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
285#define sbitset( m, cc ) \
286 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000287
288
David Turner68df4f72005-03-15 18:18:57 +0000289 static void
290 _bdf_list_init( _bdf_list_t* list,
291 FT_Memory memory )
292 {
Werner Lembergebf55852005-03-16 01:49:54 +0000293 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000294 list->memory = memory;
295 }
296
Werner Lembergebf55852005-03-16 01:49:54 +0000297
David Turner68df4f72005-03-15 18:18:57 +0000298 static void
299 _bdf_list_done( _bdf_list_t* list )
300 {
301 FT_Memory memory = list->memory;
302
Werner Lembergebf55852005-03-16 01:49:54 +0000303
David Turner68df4f72005-03-15 18:18:57 +0000304 if ( memory )
305 {
306 FT_FREE( list->field );
Werner Lembergebf55852005-03-16 01:49:54 +0000307 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000308 }
309 }
310
311
312 static FT_Error
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900313 _bdf_list_ensure( _bdf_list_t* list,
314 unsigned long num_items ) /* same as _bdf_list_t.used */
David Turner68df4f72005-03-15 18:18:57 +0000315 {
Werner Lemberge3c93012013-03-14 11:21:17 +0100316 FT_Error error = FT_Err_Ok;
Werner Lembergebf55852005-03-16 01:49:54 +0000317
David Turner68df4f72005-03-15 18:18:57 +0000318
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900319 if ( num_items > list->size )
David Turner68df4f72005-03-15 18:18:57 +0000320 {
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900321 unsigned long oldsize = list->size; /* same as _bdf_list_t.size */
Werner Lembergcee5d592012-03-01 09:26:03 +0100322 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 5;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900323 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
324 FT_Memory memory = list->memory;
David Turner68df4f72005-03-15 18:18:57 +0000325
Werner Lembergebf55852005-03-16 01:49:54 +0000326
David Turner68df4f72005-03-15 18:18:57 +0000327 if ( oldsize == bigsize )
328 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100329 error = FT_THROW( Out_Of_Memory );
David Turner68df4f72005-03-15 18:18:57 +0000330 goto Exit;
331 }
332 else if ( newsize < oldsize || newsize > bigsize )
333 newsize = bigsize;
334
335 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
336 goto Exit;
337
338 list->size = newsize;
339 }
Werner Lembergebf55852005-03-16 01:49:54 +0000340
David Turner68df4f72005-03-15 18:18:57 +0000341 Exit:
342 return error;
343 }
344
345
346 static void
347 _bdf_list_shift( _bdf_list_t* list,
348 unsigned long n )
349 {
350 unsigned long i, u;
351
352
353 if ( list == 0 || list->used == 0 || n == 0 )
354 return;
355
356 if ( n >= list->used )
357 {
358 list->used = 0;
359 return;
360 }
361
362 for ( u = n, i = 0; u < list->used; i++, u++ )
363 list->field[i] = list->field[u];
364 list->used -= n;
365 }
366
367
Werner Lembergf4c94d42010-06-19 16:08:31 +0200368 /* An empty string for empty fields. */
369
370 static const char empty[1] = { 0 }; /* XXX eliminate this */
371
372
David Turner68df4f72005-03-15 18:18:57 +0000373 static char *
374 _bdf_list_join( _bdf_list_t* list,
375 int c,
376 unsigned long *alen )
377 {
378 unsigned long i, j;
Werner Lembergdc624ca2013-06-04 10:30:48 +0200379 char* dp;
David Turner68df4f72005-03-15 18:18:57 +0000380
381
382 *alen = 0;
383
384 if ( list == 0 || list->used == 0 )
385 return 0;
386
387 dp = list->field[0];
388 for ( i = j = 0; i < list->used; i++ )
389 {
Werner Lembergdc624ca2013-06-04 10:30:48 +0200390 char* fp = list->field[i];
391
392
David Turner68df4f72005-03-15 18:18:57 +0000393 while ( *fp )
394 dp[j++] = *fp++;
395
396 if ( i + 1 < list->used )
397 dp[j++] = (char)c;
398 }
Werner Lembergf4c94d42010-06-19 16:08:31 +0200399 if ( dp != empty )
400 dp[j] = 0;
David Turner68df4f72005-03-15 18:18:57 +0000401
402 *alen = j;
403 return dp;
404 }
405
406
Werner Lemberg03242f52012-02-26 06:52:56 +0100407 /* The code below ensures that we have at least 4 + 1 `field' */
408 /* elements in `list' (which are possibly NULL) so that we */
409 /* don't have to check the number of fields in most cases. */
410
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000411 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000412 _bdf_list_split( _bdf_list_t* list,
413 char* separators,
414 char* line,
415 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000416 {
Werner Lemberg3c374c82015-02-22 09:16:53 +0100417 unsigned long final_empty;
418 int mult;
419 char *sp, *ep, *end;
420 char seps[32];
421 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000422
423
424 /* Initialize the list. */
425 list->used = 0;
Werner Lembergd9c16592012-03-01 15:15:00 +0100426 if ( list->size )
427 {
428 list->field[0] = (char*)empty;
429 list->field[1] = (char*)empty;
430 list->field[2] = (char*)empty;
431 list->field[3] = (char*)empty;
Werner Lemberg649c6732012-03-16 21:12:41 +0100432 list->field[4] = (char*)empty;
Werner Lembergd9c16592012-03-01 15:15:00 +0100433 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000434
435 /* If the line is empty, then simply return. */
436 if ( linelen == 0 || line[0] == 0 )
437 goto Exit;
438
439 /* In the original code, if the `separators' parameter is NULL or */
440 /* empty, the list is split into individual bytes. We don't need */
441 /* this, so an error is signaled. */
442 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000443 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100444 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000445 goto Exit;
446 }
447
448 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000449 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000450
451 /* If the very last character of the separator string is a plus, then */
452 /* set the `mult' flag to indicate that multiple separators should be */
453 /* collapsed into one. */
454 for ( mult = 0, sp = separators; sp && *sp; sp++ )
455 {
456 if ( *sp == '+' && *( sp + 1 ) == 0 )
457 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000458 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000459 setsbit( seps, *sp );
460 }
461
462 /* Break the line up into fields. */
463 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
464 sp < end && *sp; )
465 {
466 /* Collect everything that is not a separator. */
467 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
468 ;
469
470 /* Resize the list if necessary. */
471 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000472 {
Werner Lembergebf55852005-03-16 01:49:54 +0000473 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000474 if ( error )
475 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000476 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000477
478 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000479 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000480
481 sp = ep;
482
483 if ( mult )
484 {
485 /* If multiple separators should be collapsed, do it now by */
486 /* setting all the separator characters to 0. */
487 for ( ; *ep && sbitset( seps, *ep ); ep++ )
488 *ep = 0;
489 }
490 else if ( *ep != 0 )
491 /* Don't collapse multiple separators by making them 0, so just */
492 /* make the one encountered 0. */
493 *ep++ = 0;
494
495 final_empty = ( ep > sp && *ep == 0 );
496 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000497 }
498
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000499 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000500 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000501 {
Werner Lembergebf55852005-03-16 01:49:54 +0000502 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000503 if ( error )
504 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000505 }
506
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000507 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000508 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000509
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000510 list->field[list->used] = 0;
511
512 Exit:
513 return error;
David Turner993a8d02002-05-18 12:03:43 +0000514 }
515
David Turner993a8d02002-05-18 12:03:43 +0000516
David Turner68df4f72005-03-15 18:18:57 +0000517#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000518
Werner Lembergebf55852005-03-16 01:49:54 +0000519
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000520 static FT_Error
521 _bdf_readstream( FT_Stream stream,
522 _bdf_line_func_t callback,
523 void* client_data,
524 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000525 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000526 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000527 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900528 int refill, hold, to_skip;
529 ptrdiff_t bytes, start, end, cursor, avail;
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -0400530 char* buf = NULL;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000531 FT_Memory memory = stream->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100532 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000533
David Turner993a8d02002-05-18 12:03:43 +0000534
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000535 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000536 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100537 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000538 goto Exit;
539 }
David Turner993a8d02002-05-18 12:03:43 +0000540
Werner Lembergebf55852005-03-16 01:49:54 +0000541 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000542 buf_size = 1024;
543
544 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000545 goto Exit;
546
Werner Lembergebf55852005-03-16 01:49:54 +0000547 cb = callback;
548 lineno = 1;
549 buf[0] = 0;
550 start = 0;
Werner Lembergebf55852005-03-16 01:49:54 +0000551 avail = 0;
552 cursor = 0;
553 refill = 1;
554 to_skip = NO_SKIP;
555 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000556
David Turner68df4f72005-03-15 18:18:57 +0000557 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000558 {
David Turner68df4f72005-03-15 18:18:57 +0000559 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000560 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +0200561 bytes = (ptrdiff_t)FT_Stream_TryRead(
562 stream, (FT_Byte*)buf + cursor,
Werner Lemberg3c374c82015-02-22 09:16:53 +0100563 buf_size - (unsigned long)cursor );
David Turner68df4f72005-03-15 18:18:57 +0000564 avail = cursor + bytes;
565 cursor = 0;
566 refill = 0;
567 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000568
David Turner68df4f72005-03-15 18:18:57 +0000569 end = start;
570
Werner Lembergebf55852005-03-16 01:49:54 +0000571 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000572 if ( start < avail && buf[start] == to_skip )
573 {
574 start += 1;
575 to_skip = NO_SKIP;
576 continue;
577 }
578
579 /* try to find the end of the line */
580 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
581 end++;
582
Werner Lembergebf55852005-03-16 01:49:54 +0000583 /* if we hit the end of the buffer, try shifting its content */
584 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000585 if ( end >= avail )
586 {
587 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
588 break; /* ignore it then exit */
589
590 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000591 {
Werner Lembergebf55852005-03-16 01:49:54 +0000592 /* this line is definitely too long; try resizing the input */
593 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000594 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000595
Werner Lembergebf55852005-03-16 01:49:54 +0000596
597 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000598 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100599 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +0100600 error = FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +0000601 goto Exit;
602 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000603
Werner Lembergebf55852005-03-16 01:49:54 +0000604 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000605 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
606 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000607
Werner Lemberg3c374c82015-02-22 09:16:53 +0100608 cursor = (ptrdiff_t)buf_size;
David Turner68df4f72005-03-15 18:18:57 +0000609 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000610 }
611 else
612 {
David Turner68df4f72005-03-15 18:18:57 +0000613 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000614
Werner Lemberg04e547b2013-04-03 07:37:56 +0200615 FT_MEM_MOVE( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000616
David Turner68df4f72005-03-15 18:18:57 +0000617 cursor = bytes;
618 avail -= bytes;
619 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000620 }
David Turner68df4f72005-03-15 18:18:57 +0000621 refill = 1;
622 continue;
David Turner993a8d02002-05-18 12:03:43 +0000623 }
David Turner68df4f72005-03-15 18:18:57 +0000624
625 /* Temporarily NUL-terminate the line. */
626 hold = buf[end];
627 buf[end] = 0;
628
Werner Lemberg0098d552014-12-07 11:03:57 +0100629 /* XXX: Use encoding independent value for 0x1A */
630 if ( buf[start] != '#' && buf[start] != 0x1A && end > start )
David Turner68df4f72005-03-15 18:18:57 +0000631 {
Werner Lemberga9f6f852012-12-17 09:08:09 +0100632 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergebf55852005-03-16 01:49:54 +0000633 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200634 /* Redo if we have encountered CHARS without properties. */
635 if ( error == -1 )
Werner Lemberga9f6f852012-12-17 09:08:09 +0100636 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200637 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000638 if ( error )
639 break;
640 }
641
642 lineno += 1;
643 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000644 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000645
646 if ( hold == '\n' )
647 to_skip = '\r';
648 else if ( hold == '\r' )
649 to_skip = '\n';
650 else
651 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000652 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000653
David Turner68df4f72005-03-15 18:18:57 +0000654 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000655
656 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000657 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000658 return error;
David Turner993a8d02002-05-18 12:03:43 +0000659 }
David Turner993a8d02002-05-18 12:03:43 +0000660
661
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000662 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000663
David Turnerb1b47622002-05-21 21:17:43 +0000664 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000665 {
David Turner993a8d02002-05-18 12:03:43 +0000666 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
667 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
668 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
669 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
Werner Lemberg0098d552014-12-07 11:03:57 +0100671 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 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, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg0098d552014-12-07 11:03:57 +0100674 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000675 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
676 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000677 };
David Turner993a8d02002-05-18 12:03:43 +0000678
David Turnerb1b47622002-05-21 21:17:43 +0000679 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000680 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
David Turner993a8d02002-05-18 12:03:43 +0000682 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
683 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
684 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000685 };
David Turner993a8d02002-05-18 12:03:43 +0000686
David Turnerb1b47622002-05-21 21:17:43 +0000687 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000688 {
Werner Lemberg0098d552014-12-07 11:03:57 +0100689 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
690 0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00,
David Turner993a8d02002-05-18 12:03:43 +0000691 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
692 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000693 };
David Turner993a8d02002-05-18 12:03:43 +0000694
David Turner993a8d02002-05-18 12:03:43 +0000695
Ben Wagnera512b0f2015-12-14 09:19:52 +0100696 /* Routine to convert a decimal ASCII string to an unsigned long integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000697 static unsigned long
Ben Wagnera512b0f2015-12-14 09:19:52 +0100698 _bdf_atoul( char* s )
David Turner993a8d02002-05-18 12:03:43 +0000699 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100700 unsigned long v;
David Turner993a8d02002-05-18 12:03:43 +0000701
702
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000703 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000704 return 0;
705
Ben Wagnera512b0f2015-12-14 09:19:52 +0100706 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200707 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100708 if ( v < ( FT_ULONG_MAX - 9 ) / 10 )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200709 v = v * 10 + a2i[(int)*s];
710 else
711 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100712 v = FT_ULONG_MAX;
Werner Lemberg47a03e92017-06-02 09:06:36 +0200713 break;
714 }
715 }
David Turner993a8d02002-05-18 12:03:43 +0000716
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000717 return v;
718 }
David Turner993a8d02002-05-18 12:03:43 +0000719
David Turner993a8d02002-05-18 12:03:43 +0000720
Ben Wagnera512b0f2015-12-14 09:19:52 +0100721 /* Routine to convert a decimal ASCII string to a signed long integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000722 static long
Ben Wagnera512b0f2015-12-14 09:19:52 +0100723 _bdf_atol( char* s )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000724 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100725 long v, neg;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000726
727
728 if ( s == 0 || *s == 0 )
729 return 0;
730
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000731 /* Check for a minus sign. */
732 neg = 0;
733 if ( *s == '-' )
734 {
735 s++;
736 neg = 1;
737 }
738
Ben Wagnera512b0f2015-12-14 09:19:52 +0100739 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200740 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100741 if ( v < ( FT_LONG_MAX - 9 ) / 10 )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200742 v = v * 10 + a2i[(int)*s];
743 else
744 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100745 v = FT_LONG_MAX;
Werner Lemberg47a03e92017-06-02 09:06:36 +0200746 break;
747 }
748 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000749
750 return ( !neg ) ? v : -v;
751 }
752
753
Ben Wagnera512b0f2015-12-14 09:19:52 +0100754 /* Routine to convert a decimal ASCII string to an unsigned short integer. */
Werner Lembergb13945a2015-02-22 09:15:47 +0100755 static unsigned short
Ben Wagnera512b0f2015-12-14 09:19:52 +0100756 _bdf_atous( char* s )
Werner Lembergb13945a2015-02-22 09:15:47 +0100757 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100758 unsigned short v;
Werner Lembergb13945a2015-02-22 09:15:47 +0100759
760
761 if ( s == 0 || *s == 0 )
762 return 0;
763
Ben Wagnera512b0f2015-12-14 09:19:52 +0100764 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200765 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100766 if ( v < ( FT_USHORT_MAX - 9 ) / 10 )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200767 v = (unsigned short)( v * 10 + a2i[(int)*s] );
768 else
769 {
Werner Lemberg068a7a02017-12-18 20:34:05 +0100770 v = FT_USHORT_MAX;
Werner Lemberg47a03e92017-06-02 09:06:36 +0200771 break;
772 }
773 }
Werner Lembergb13945a2015-02-22 09:15:47 +0100774
775 return v;
776 }
777
778
Ben Wagnera512b0f2015-12-14 09:19:52 +0100779 /* Routine to convert a decimal ASCII string to a signed short integer. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000780 static short
Ben Wagnera512b0f2015-12-14 09:19:52 +0100781 _bdf_atos( char* s )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000782 {
Ben Wagnera512b0f2015-12-14 09:19:52 +0100783 short v, neg;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000784
785
786 if ( s == 0 || *s == 0 )
787 return 0;
788
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000789 /* Check for a minus. */
790 neg = 0;
791 if ( *s == '-' )
792 {
793 s++;
794 neg = 1;
795 }
796
Ben Wagnera512b0f2015-12-14 09:19:52 +0100797 for ( v = 0; sbitset( ddigits, *s ); s++ )
Werner Lemberg47a03e92017-06-02 09:06:36 +0200798 {
799 if ( v < ( SHRT_MAX - 9 ) / 10 )
800 v = (short)( v * 10 + a2i[(int)*s] );
801 else
802 {
803 v = SHRT_MAX;
804 break;
805 }
806 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000807
Werner Lemberg233302a2002-05-22 05:41:06 +0000808 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000809 }
810
811
812 /* Routine to compare two glyphs by encoding so they can be sorted. */
813 static int
814 by_encoding( const void* a,
815 const void* b )
816 {
817 bdf_glyph_t *c1, *c2;
818
819
820 c1 = (bdf_glyph_t *)a;
821 c2 = (bdf_glyph_t *)b;
822
823 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000824 return -1;
David Turner68df4f72005-03-15 18:18:57 +0000825
826 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000827 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000828
David Turner993a8d02002-05-18 12:03:43 +0000829 return 0;
David Turner993a8d02002-05-18 12:03:43 +0000830 }
831
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000832
833 static FT_Error
834 bdf_create_property( char* name,
835 int format,
836 bdf_font_t* font )
837 {
suzuki toshiya704f4d72009-09-13 00:50:14 +0900838 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000839 bdf_property_t* p;
840 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100841 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000842
843
Werner Lemberg96ddc672011-06-29 09:15:54 +0200844 /* First check whether the property has */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000845 /* already been added or not. If it has, then */
846 /* simply ignore it. */
Werner Lemberg609546c2015-12-20 07:17:29 +0100847 if ( ft_hash_str_lookup( name, &(font->proptbl) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000848 goto Exit;
849
David Turner68df4f72005-03-15 18:18:57 +0000850 if ( FT_RENEW_ARRAY( font->user_props,
851 font->nuser_props,
852 font->nuser_props + 1 ) )
853 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000854
855 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +0000856 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000857
suzuki toshiya704f4d72009-09-13 00:50:14 +0900858 n = ft_strlen( name ) + 1;
859 if ( n > FT_ULONG_MAX )
Werner Lemberg059bc332013-03-14 10:27:35 +0100860 return FT_THROW( Invalid_Argument );
David Turner68df4f72005-03-15 18:18:57 +0000861
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000862 if ( FT_NEW_ARRAY( p->name, n ) )
863 goto Exit;
864
865 FT_MEM_COPY( (char *)p->name, name, n );
866
867 p->format = format;
868 p->builtin = 0;
869
870 n = _num_bdf_properties + font->nuser_props;
871
Werner Lemberg609546c2015-12-20 07:17:29 +0100872 error = ft_hash_str_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000873 if ( error )
874 goto Exit;
875
876 font->nuser_props++;
877
878 Exit:
David Turner993a8d02002-05-18 12:03:43 +0000879 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000880 }
David Turner993a8d02002-05-18 12:03:43 +0000881
882
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100883 FT_LOCAL_DEF( bdf_property_t* )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000884 bdf_get_property( char* name,
885 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +0000886 {
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100887 size_t* propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000888
889
890 if ( name == 0 || *name == 0 )
891 return 0;
892
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100893 if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000894 return 0;
895
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100896 if ( *propid >= _num_bdf_properties )
897 return font->user_props + ( *propid - _num_bdf_properties );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000898
Werner Lemberg76e79ec2015-12-20 09:03:15 +0100899 return (bdf_property_t*)_bdf_properties + *propid;
David Turner993a8d02002-05-18 12:03:43 +0000900 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000901
902
Werner Lemberg9ac90602018-06-03 09:01:17 +0200903 /**************************************************************************
904 *
905 * BDF font file parsing flags and functions.
906 *
907 */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000908
909
910 /* Parse flags. */
911
Werner Lemberg758587d2016-01-12 22:20:06 +0100912#define BDF_START_ 0x0001U
913#define BDF_FONT_NAME_ 0x0002U
914#define BDF_SIZE_ 0x0004U
915#define BDF_FONT_BBX_ 0x0008U
916#define BDF_PROPS_ 0x0010U
917#define BDF_GLYPHS_ 0x0020U
918#define BDF_GLYPH_ 0x0040U
919#define BDF_ENCODING_ 0x0080U
920#define BDF_SWIDTH_ 0x0100U
921#define BDF_DWIDTH_ 0x0200U
922#define BDF_BBX_ 0x0400U
923#define BDF_BITMAP_ 0x0800U
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000924
Werner Lemberg758587d2016-01-12 22:20:06 +0100925#define BDF_SWIDTH_ADJ_ 0x1000U
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000926
Werner Lemberg758587d2016-01-12 22:20:06 +0100927#define BDF_GLYPH_BITS_ ( BDF_GLYPH_ | \
928 BDF_ENCODING_ | \
929 BDF_SWIDTH_ | \
930 BDF_DWIDTH_ | \
931 BDF_BBX_ | \
932 BDF_BITMAP_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000933
Werner Lemberg758587d2016-01-12 22:20:06 +0100934#define BDF_GLYPH_WIDTH_CHECK_ 0x40000000UL
935#define BDF_GLYPH_HEIGHT_CHECK_ 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000936
937
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000938 static FT_Error
939 _bdf_add_comment( bdf_font_t* font,
940 char* comment,
941 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +0000942 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000943 char* cp;
944 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100945 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000946
947
David Turner68df4f72005-03-15 18:18:57 +0000948 if ( FT_RENEW_ARRAY( font->comments,
949 font->comments_len,
950 font->comments_len + len + 1 ) )
951 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000952
953 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +0000954
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000955 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +0000956 cp[len] = '\n';
957
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000958 font->comments_len += len + 1;
959
960 Exit:
961 return error;
David Turner993a8d02002-05-18 12:03:43 +0000962 }
963
David Turner993a8d02002-05-18 12:03:43 +0000964
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000965 /* Set the spacing from the font name if it exists, or set it to the */
966 /* default specified in the options. */
967 static FT_Error
968 _bdf_set_default_spacing( bdf_font_t* font,
Werner Lemberge01406b2011-11-25 09:44:28 +0100969 bdf_options_t* opts,
970 unsigned long lineno )
David Turner993a8d02002-05-18 12:03:43 +0000971 {
suzuki toshiya704f4d72009-09-13 00:50:14 +0900972 size_t len;
973 char name[256];
974 _bdf_list_t list;
975 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +0100976 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000977
Dave Arnoldc3782492013-06-05 19:57:55 +0200978 FT_UNUSED( lineno ); /* only used in debug mode */
979
David Turner993a8d02002-05-18 12:03:43 +0000980
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000981 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
982 {
Werner Lemberg059bc332013-03-14 10:27:35 +0100983 error = FT_THROW( Invalid_Argument );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000984 goto Exit;
985 }
David Turner993a8d02002-05-18 12:03:43 +0000986
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000987 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +0000988
David Turner68df4f72005-03-15 18:18:57 +0000989 _bdf_list_init( &list, memory );
990
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000991 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +0000992
suzuki toshiya704f4d72009-09-13 00:50:14 +0900993 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +0000994 /* Limit ourselves to 256 characters in the font name. */
995 if ( len >= 256 )
996 {
Werner Lemberge01406b2011-11-25 09:44:28 +0100997 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +0100998 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +0000999 goto Exit;
1000 }
1001
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001002 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001003
Werner Lembergbadf3172013-06-06 09:16:38 +02001004 error = _bdf_list_split( &list, (char *)"-", name, (unsigned long)len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001005 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001006 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001007
1008 if ( list.used == 15 )
1009 {
1010 switch ( list.field[11][0] )
1011 {
1012 case 'C':
1013 case 'c':
1014 font->spacing = BDF_CHARCELL;
1015 break;
1016 case 'M':
1017 case 'm':
1018 font->spacing = BDF_MONOWIDTH;
1019 break;
1020 case 'P':
1021 case 'p':
1022 font->spacing = BDF_PROPORTIONAL;
1023 break;
David Turner993a8d02002-05-18 12:03:43 +00001024 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001025 }
1026
David Turner68df4f72005-03-15 18:18:57 +00001027 Fail:
1028 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001029
1030 Exit:
1031 return error;
David Turner993a8d02002-05-18 12:03:43 +00001032 }
David Turner993a8d02002-05-18 12:03:43 +00001033
1034
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001035 /* Determine whether the property is an atom or not. If it is, then */
1036 /* clean it up so the double quotes are removed if they exist. */
1037 static int
1038 _bdf_is_atom( char* line,
1039 unsigned long linelen,
1040 char** name,
1041 char** value,
1042 bdf_font_t* font )
1043 {
1044 int hold;
1045 char *sp, *ep;
1046 bdf_property_t* p;
1047
David Turner993a8d02002-05-18 12:03:43 +00001048
1049 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001050
1051 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001052 ep++;
1053
1054 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001055 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001056 {
1057 hold = *ep;
1058 *ep = 0;
1059 }
1060
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001061 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001062
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001063 /* Restore the character that was saved before any return can happen. */
1064 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001065 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001066
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001067 /* If the property exists and is not an atom, just return here. */
1068 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001069 return 0;
1070
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001071 /* The property is an atom. Trim all leading and trailing whitespace */
1072 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001073 sp = ep;
1074 ep = line + linelen;
1075
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001076 /* Trim the leading whitespace if it exists. */
Werner Lemberg320d4972012-02-24 18:06:46 +01001077 if ( *sp )
1078 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001079 while ( *sp &&
1080 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001081 sp++;
1082
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001083 /* Trim the leading double quote if it exists. */
1084 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001085 sp++;
1086 *value = sp;
1087
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001088 /* Trim the trailing whitespace if it exists. */
1089 while ( ep > sp &&
1090 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001091 *--ep = 0;
1092
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001093 /* Trim the trailing double quote if it exists. */
1094 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001095 *--ep = 0;
1096
1097 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001098 }
David Turner993a8d02002-05-18 12:03:43 +00001099
1100
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001101 static FT_Error
Werner Lemberge01406b2011-11-25 09:44:28 +01001102 _bdf_add_property( bdf_font_t* font,
1103 char* name,
1104 char* value,
1105 unsigned long lineno )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001106 {
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001107 size_t* propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001108 bdf_property_t *prop, *fp;
1109 FT_Memory memory = font->memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001110 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001111
Dave Arnoldc3782492013-06-05 19:57:55 +02001112 FT_UNUSED( lineno ); /* only used in debug mode */
1113
David Turner993a8d02002-05-18 12:03:43 +00001114
Werner Lemberg96ddc672011-06-29 09:15:54 +02001115 /* First, check whether the property already exists in the font. */
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001116 if ( ( propid = ft_hash_str_lookup( name,
1117 (FT_Hash)font->internal ) ) != NULL )
David Turner993a8d02002-05-18 12:03:43 +00001118 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001119 /* The property already exists in the font, so simply replace */
1120 /* the value of the property with the current value. */
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001121 fp = font->props + *propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001122
David Turnerb1b47622002-05-21 21:17:43 +00001123 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001124 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001125 case BDF_ATOM:
1126 /* Delete the current atom if it exists. */
1127 FT_FREE( fp->value.atom );
1128
David Turnerc0f9c4a2007-02-12 14:55:03 +00001129 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001130 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001131 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001132 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001133 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001134 break;
1135
1136 case BDF_INTEGER:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001137 fp->value.l = _bdf_atol( value );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001138 break;
1139
1140 case BDF_CARDINAL:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001141 fp->value.ul = _bdf_atoul( value );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001142 break;
David Turnerd490e372002-05-28 23:40:37 +00001143
David Turnerb1b47622002-05-21 21:17:43 +00001144 default:
1145 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001146 }
David Turnerd490e372002-05-28 23:40:37 +00001147
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001148 goto Exit;
1149 }
1150
1151 /* See whether this property type exists yet or not. */
1152 /* If not, create it. */
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001153 propid = ft_hash_str_lookup( name, &(font->proptbl) );
Werner Lemberg4441f7b2016-12-26 17:08:17 +01001154 if ( !propid )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001155 {
1156 error = bdf_create_property( name, BDF_ATOM, font );
1157 if ( error )
1158 goto Exit;
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001159 propid = ft_hash_str_lookup( name, &(font->proptbl) );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001160 }
1161
Werner Lembergb6b26f42016-06-09 06:53:48 +02001162 /* Allocate another property if this is overflowing. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001163 if ( font->props_used == font->props_size )
1164 {
1165 if ( font->props_size == 0 )
1166 {
1167 if ( FT_NEW_ARRAY( font->props, 1 ) )
1168 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001169 }
1170 else
1171 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001172 if ( FT_RENEW_ARRAY( font->props,
1173 font->props_size,
1174 font->props_size + 1 ) )
1175 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001176 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001177
David Turner993a8d02002-05-18 12:03:43 +00001178 fp = font->props + font->props_size;
Werner Lemberg2ecf89b2016-09-28 19:06:21 +02001179 FT_ZERO( fp );
David Turner993a8d02002-05-18 12:03:43 +00001180 font->props_size++;
1181 }
1182
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001183 if ( *propid >= _num_bdf_properties )
1184 prop = font->user_props + ( *propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001185 else
Werner Lemberg76e79ec2015-12-20 09:03:15 +01001186 prop = (bdf_property_t*)_bdf_properties + *propid;
David Turner993a8d02002-05-18 12:03:43 +00001187
1188 fp = font->props + font->props_used;
1189
1190 fp->name = prop->name;
1191 fp->format = prop->format;
1192 fp->builtin = prop->builtin;
1193
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001194 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001195 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001196 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001197 fp->value.atom = 0;
1198 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001199 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001200 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001201 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001202 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001203 break;
David Turner993a8d02002-05-18 12:03:43 +00001204
1205 case BDF_INTEGER:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001206 fp->value.l = _bdf_atol( value );
David Turner993a8d02002-05-18 12:03:43 +00001207 break;
1208
1209 case BDF_CARDINAL:
Ben Wagnera512b0f2015-12-14 09:19:52 +01001210 fp->value.ul = _bdf_atoul( value );
David Turner993a8d02002-05-18 12:03:43 +00001211 break;
David Turner993a8d02002-05-18 12:03:43 +00001212 }
1213
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001214 /* If the property happens to be a comment, then it doesn't need */
1215 /* to be added to the internal hash table. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001216 if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 )
Werner Lemberg370aea82010-06-08 08:37:11 +02001217 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001218 /* Add the property to the font property table. */
Werner Lemberg609546c2015-12-20 07:17:29 +01001219 error = ft_hash_str_insert( fp->name,
1220 font->props_used,
1221 (FT_Hash)font->internal,
1222 memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001223 if ( error )
1224 goto Exit;
1225 }
David Turner993a8d02002-05-18 12:03:43 +00001226
1227 font->props_used++;
1228
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001229 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1230 /* property needs to be located if it exists in the property list, the */
1231 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1232 /* present, and the SPACING property should override the default */
1233 /* spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001234 if ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001235 font->default_char = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001236 else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001237 font->font_ascent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001238 else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001239 font->font_descent = fp->value.l;
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001240 else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001241 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001242 if ( !fp->value.atom )
1243 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001244 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001245 error = FT_THROW( Invalid_File_Format );
Werner Lembergb66efef2009-03-12 08:07:49 +00001246 goto Exit;
1247 }
1248
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001249 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001250 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001251 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001252 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001253 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001254 font->spacing = BDF_CHARCELL;
1255 }
1256
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001257 Exit:
1258 return error;
David Turner993a8d02002-05-18 12:03:43 +00001259 }
1260
David Turner993a8d02002-05-18 12:03:43 +00001261
David Turnerb1b47622002-05-21 21:17:43 +00001262 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001263 {
1264 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1265 };
1266
1267
1268 /* Actually parse the glyph info and bitmaps. */
1269 static FT_Error
1270 _bdf_parse_glyphs( char* line,
1271 unsigned long linelen,
1272 unsigned long lineno,
1273 void* call_data,
1274 void* client_data )
1275 {
1276 int c, mask_index;
1277 char* s;
1278 unsigned char* bp;
1279 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001280
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001281 _bdf_parse_t* p;
1282 bdf_glyph_t* glyph;
1283 bdf_font_t* font;
1284
1285 FT_Memory memory;
Werner Lemberge3c93012013-03-14 11:21:17 +01001286 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001287
Werner Lemberg319c00d2003-04-23 19:48:24 +00001288 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001289 FT_UNUSED( lineno ); /* only used in debug mode */
1290
1291
Werner Lemberg319c00d2003-04-23 19:48:24 +00001292 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001293
1294 font = p->font;
1295 memory = font->memory;
1296
1297 /* Check for a comment. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001298 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001299 {
1300 linelen -= 7;
1301
1302 s = line + 7;
1303 if ( *s != 0 )
1304 {
1305 s++;
1306 linelen--;
1307 }
1308 error = _bdf_add_comment( p->font, s, linelen );
1309 goto Exit;
1310 }
1311
1312 /* The very first thing expected is the number of glyphs. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001313 if ( !( p->flags & BDF_GLYPHS_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001314 {
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001315 if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001316 {
1317 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001318 error = FT_THROW( Missing_Chars_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001319 goto Exit;
1320 }
1321
David Turner68df4f72005-03-15 18:18:57 +00001322 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001323 if ( error )
1324 goto Exit;
Ben Wagnera512b0f2015-12-14 09:19:52 +01001325 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001326
Werner Lemberge1ca18d2015-10-17 11:51:27 +02001327 /* We need at least 20 bytes per glyph. */
1328 if ( p->cnt > p->size / 20 )
1329 {
Werner Lemberg797ca5a2015-10-17 11:57:16 +02001330 p->cnt = font->glyphs_size = p->size / 20;
Werner Lemberge1ca18d2015-10-17 11:51:27 +02001331 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG17, p->cnt ));
1332 }
1333
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001334 /* Make sure the number of glyphs is non-zero. */
1335 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001336 font->glyphs_size = 64;
1337
Werner Lemberga08b2172007-03-28 07:17:17 +00001338 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1339 /* number of code points available in Unicode). */
Werner Lemberge01406b2011-11-25 09:44:28 +01001340 if ( p->cnt >= 0x110000UL )
Werner Lemberga08b2172007-03-28 07:17:17 +00001341 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001342 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001343 error = FT_THROW( Invalid_Argument );
Werner Lemberga08b2172007-03-28 07:17:17 +00001344 goto Exit;
1345 }
1346
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001347 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1348 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001349
Werner Lemberg758587d2016-01-12 22:20:06 +01001350 p->flags |= BDF_GLYPHS_;
David Turner993a8d02002-05-18 12:03:43 +00001351
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001352 goto Exit;
1353 }
1354
1355 /* Check for the ENDFONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001356 if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001357 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001358 if ( p->flags & BDF_GLYPH_BITS_ )
Werner Lembergaf834612014-11-22 13:29:10 +01001359 {
1360 /* Missing ENDCHAR field. */
1361 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1362 error = FT_THROW( Corrupted_Font_Glyphs );
1363 goto Exit;
1364 }
1365
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001366 /* Sort the glyphs by encoding. */
1367 ft_qsort( (char *)font->glyphs,
1368 font->glyphs_used,
1369 sizeof ( bdf_glyph_t ),
1370 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001371
Werner Lemberg758587d2016-01-12 22:20:06 +01001372 p->flags &= ~BDF_START_;
David Turner993a8d02002-05-18 12:03:43 +00001373
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001374 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001375 }
1376
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001377 /* Check for the ENDCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001378 if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001379 {
1380 p->glyph_enc = 0;
Werner Lemberg758587d2016-01-12 22:20:06 +01001381 p->flags &= ~BDF_GLYPH_BITS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001382
1383 goto Exit;
1384 }
1385
Werner Lemberg96ddc672011-06-29 09:15:54 +02001386 /* Check whether a glyph is being scanned but should be */
1387 /* ignored because it is an unencoded glyph. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001388 if ( ( p->flags & BDF_GLYPH_ ) &&
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001389 p->glyph_enc == -1 &&
1390 p->opts->keep_unencoded == 0 )
1391 goto Exit;
1392
1393 /* Check for the STARTCHAR field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001394 if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001395 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001396 if ( p->flags & BDF_GLYPH_BITS_ )
Werner Lembergb1857472015-10-17 14:21:41 +02001397 {
1398 /* Missing ENDCHAR field. */
1399 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
1400 error = FT_THROW( Missing_Startchar_Field );
1401 goto Exit;
1402 }
1403
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001404 /* Set the character name in the parse info first until the */
1405 /* encoding can be checked for an unencoded character. */
1406 FT_FREE( p->glyph_name );
1407
David Turner68df4f72005-03-15 18:18:57 +00001408 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001409 if ( error )
1410 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001411
David Turner68df4f72005-03-15 18:18:57 +00001412 _bdf_list_shift( &p->list, 1 );
1413
1414 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001415
Werner Lembergba03af62007-05-30 13:57:02 +00001416 if ( !s )
1417 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001418 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001419 error = FT_THROW( Invalid_File_Format );
Werner Lembergba03af62007-05-30 13:57:02 +00001420 goto Exit;
1421 }
1422
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001423 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1424 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001425
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001426 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1427
Werner Lemberg758587d2016-01-12 22:20:06 +01001428 p->flags |= BDF_GLYPH_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001429
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001430 FT_TRACE4(( DBGMSG1, lineno, s ));
1431
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001432 goto Exit;
1433 }
1434
1435 /* Check for the ENCODING field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001436 if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001437 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001438 if ( !( p->flags & BDF_GLYPH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001439 {
1440 /* Missing STARTCHAR field. */
1441 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001442 error = FT_THROW( Missing_Startchar_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001443 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001444 }
1445
David Turner68df4f72005-03-15 18:18:57 +00001446 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001447 if ( error )
1448 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001449
Ben Wagnera512b0f2015-12-14 09:19:52 +01001450 p->glyph_enc = _bdf_atol( p->list.field[1] );
David Turner993a8d02002-05-18 12:03:43 +00001451
Werner Lemberg28dd2c42012-02-26 06:18:58 +01001452 /* Normalize negative encoding values. The specification only */
1453 /* allows -1, but we can be more generous here. */
1454 if ( p->glyph_enc < -1 )
1455 p->glyph_enc = -1;
1456
Werner Lemberg03242f52012-02-26 06:52:56 +01001457 /* Check for alternative encoding format. */
1458 if ( p->glyph_enc == -1 && p->list.used > 2 )
Ben Wagnera512b0f2015-12-14 09:19:52 +01001459 p->glyph_enc = _bdf_atol( p->list.field[2] );
Werner Lemberg03242f52012-02-26 06:52:56 +01001460
Werner Lemberg7f2e4f42012-12-15 09:39:41 +01001461 if ( p->glyph_enc < -1 )
1462 p->glyph_enc = -1;
1463
Werner Lemberg6e0d4cd2011-11-27 09:21:03 +01001464 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1465
Werner Lemberged54e432011-11-27 16:39:53 +01001466 /* Check that the encoding is in the Unicode range because */
1467 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lemberg07bdb6e2012-12-15 02:02:23 +01001468 if ( p->glyph_enc > 0 &&
1469 (size_t)p->glyph_enc >= sizeof ( p->have ) /
1470 sizeof ( unsigned long ) * 32 )
David Turner481838e2006-02-23 12:40:14 +00001471 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001472 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001473 error = FT_THROW( Invalid_File_Format );
David Turner481838e2006-02-23 12:40:14 +00001474 goto Exit;
1475 }
1476
Werner Lemberg96ddc672011-06-29 09:15:54 +02001477 /* Check whether this encoding has already been encountered. */
1478 /* If it has then change it to unencoded so it gets added if */
1479 /* indicated. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001480 if ( p->glyph_enc >= 0 )
1481 {
1482 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1483 {
1484 /* Emit a message saying a glyph has been moved to the */
1485 /* unencoded area. */
1486 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1487 p->glyph_enc, p->glyph_name ));
1488 p->glyph_enc = -1;
1489 font->modified = 1;
1490 }
1491 else
1492 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1493 }
1494
1495 if ( p->glyph_enc >= 0 )
1496 {
1497 /* Make sure there are enough glyphs allocated in case the */
1498 /* number of characters happen to be wrong. */
1499 if ( font->glyphs_used == font->glyphs_size )
1500 {
1501 if ( FT_RENEW_ARRAY( font->glyphs,
1502 font->glyphs_size,
1503 font->glyphs_size + 64 ) )
1504 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001505
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001506 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001507 }
1508
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001509 glyph = font->glyphs + font->glyphs_used++;
1510 glyph->name = p->glyph_name;
1511 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001512
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001513 /* Reset the initial glyph info. */
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001514 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001515 }
1516 else
1517 {
Werner Lemberg96ddc672011-06-29 09:15:54 +02001518 /* Unencoded glyph. Check whether it should */
1519 /* be added or not. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001520 if ( p->opts->keep_unencoded != 0 )
1521 {
1522 /* Allocate the next unencoded glyph. */
1523 if ( font->unencoded_used == font->unencoded_size )
1524 {
David Turner68df4f72005-03-15 18:18:57 +00001525 if ( FT_RENEW_ARRAY( font->unencoded ,
1526 font->unencoded_size,
1527 font->unencoded_size + 4 ) )
1528 goto Exit;
1529
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001530 font->unencoded_size += 4;
1531 }
1532
1533 glyph = font->unencoded + font->unencoded_used;
1534 glyph->name = p->glyph_name;
Werner Lemberg3c374c82015-02-22 09:16:53 +01001535 glyph->encoding = (long)font->unencoded_used++;
Werner Lemberg4a150132015-11-25 07:53:49 +01001536
1537 /* Reset the initial glyph info. */
1538 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001539 }
1540 else
Werner Lemberg94cacac2015-11-15 04:45:42 +01001541 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001542 /* Free up the glyph name if the unencoded shouldn't be */
1543 /* kept. */
1544 FT_FREE( p->glyph_name );
Werner Lemberg94cacac2015-11-15 04:45:42 +01001545 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001546
Alexei Podtelezhnikovadb08ef2015-04-11 23:54:19 -04001547 p->glyph_name = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001548 }
1549
1550 /* Clear the flags that might be added when width and height are */
1551 /* checked for consistency. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001552 p->flags &= ~( BDF_GLYPH_WIDTH_CHECK_ | BDF_GLYPH_HEIGHT_CHECK_ );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001553
Werner Lemberg758587d2016-01-12 22:20:06 +01001554 p->flags |= BDF_ENCODING_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001555
1556 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001557 }
1558
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001559 /* Point at the glyph being constructed. */
1560 if ( p->glyph_enc == -1 )
1561 glyph = font->unencoded + ( font->unencoded_used - 1 );
1562 else
1563 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001564
Werner Lemberg96ddc672011-06-29 09:15:54 +02001565 /* Check whether a bitmap is being constructed. */
Werner Lemberg758587d2016-01-12 22:20:06 +01001566 if ( p->flags & BDF_BITMAP_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001567 {
1568 /* If there are more rows than are specified in the glyph metrics, */
1569 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001570 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001571 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001572 if ( !( p->flags & BDF_GLYPH_HEIGHT_CHECK_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001573 {
1574 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001575 p->flags |= BDF_GLYPH_HEIGHT_CHECK_;
David Turner993a8d02002-05-18 12:03:43 +00001576 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001577 }
1578
1579 goto Exit;
1580 }
1581
1582 /* Only collect the number of nibbles indicated by the glyph */
1583 /* metrics. If there are more columns, they are simply ignored. */
1584 nibbles = glyph->bpr << 1;
1585 bp = glyph->bitmap + p->row * glyph->bpr;
1586
David Turnerb698eed2006-02-23 14:50:13 +00001587 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001588 {
1589 c = line[i];
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001590 if ( !sbitset( hdigits, c ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001591 break;
Werner Lemberg233302a2002-05-22 05:41:06 +00001592 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001593 if ( i + 1 < nibbles && ( i & 1 ) )
1594 *++bp = 0;
1595 }
1596
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001597 /* If any line has not enough columns, */
1598 /* indicate they have been padded with zero bits. */
1599 if ( i < nibbles &&
Werner Lemberg758587d2016-01-12 22:20:06 +01001600 !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001601 {
1602 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001603 p->flags |= BDF_GLYPH_WIDTH_CHECK_;
Werner Lemberg0b1c0c62012-02-25 10:23:04 +01001604 font->modified = 1;
1605 }
1606
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001607 /* Remove possible garbage at the right. */
1608 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001609 if ( glyph->bbx.width )
1610 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001611
1612 /* If any line has extra columns, indicate they have been removed. */
Werner Lemberg6ac022d2012-03-01 16:43:20 +01001613 if ( i == nibbles &&
Alexei Podtelezhnikov0c5789f2012-03-22 07:05:40 +01001614 sbitset( hdigits, line[nibbles] ) &&
Werner Lemberg758587d2016-01-12 22:20:06 +01001615 !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001616 {
1617 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
Werner Lemberg758587d2016-01-12 22:20:06 +01001618 p->flags |= BDF_GLYPH_WIDTH_CHECK_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001619 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001620 }
1621
1622 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001623 goto Exit;
1624 }
David Turner993a8d02002-05-18 12:03:43 +00001625
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001626 /* Expect the SWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001627 if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001628 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001629 if ( !( p->flags & BDF_ENCODING_ ) )
Werner Lemberg4086fb72012-03-01 08:55:40 +01001630 goto Missing_Encoding;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001631
David Turner68df4f72005-03-15 18:18:57 +00001632 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001633 if ( error )
1634 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001635
Ben Wagnera512b0f2015-12-14 09:19:52 +01001636 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1] );
Werner Lemberg758587d2016-01-12 22:20:06 +01001637 p->flags |= BDF_SWIDTH_;
David Turner993a8d02002-05-18 12:03:43 +00001638
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001639 goto Exit;
1640 }
David Turner993a8d02002-05-18 12:03:43 +00001641
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001642 /* Expect the DWIDTH (scalable width) field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001643 if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001644 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001645 if ( !( p->flags & BDF_ENCODING_ ) )
Werner Lemberg4086fb72012-03-01 08:55:40 +01001646 goto Missing_Encoding;
1647
David Turner68df4f72005-03-15 18:18:57 +00001648 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001649 if ( error )
1650 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001651
Ben Wagnera512b0f2015-12-14 09:19:52 +01001652 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001653
Werner Lemberg758587d2016-01-12 22:20:06 +01001654 if ( !( p->flags & BDF_SWIDTH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001655 {
1656 /* Missing SWIDTH field. Emit an auto correction message and set */
1657 /* the scalable width from the device width. */
1658 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1659
Werner Lemberg02d4d592002-05-28 22:38:05 +00001660 glyph->swidth = (unsigned short)FT_MulDiv(
1661 glyph->dwidth, 72000L,
1662 (FT_Long)( font->point_size *
1663 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001664 }
1665
Werner Lemberg758587d2016-01-12 22:20:06 +01001666 p->flags |= BDF_DWIDTH_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001667 goto Exit;
1668 }
David Turner993a8d02002-05-18 12:03:43 +00001669
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001670 /* Expect the BBX field next. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001671 if ( _bdf_strncmp( line, "BBX", 3 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001672 {
Werner Lemberg758587d2016-01-12 22:20:06 +01001673 if ( !( p->flags & BDF_ENCODING_ ) )
Werner Lemberg4086fb72012-03-01 08:55:40 +01001674 goto Missing_Encoding;
1675
David Turner68df4f72005-03-15 18:18:57 +00001676 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001677 if ( error )
1678 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001679
Ben Wagnera512b0f2015-12-14 09:19:52 +01001680 glyph->bbx.width = _bdf_atous( p->list.field[1] );
1681 glyph->bbx.height = _bdf_atous( p->list.field[2] );
1682 glyph->bbx.x_offset = _bdf_atos( p->list.field[3] );
1683 glyph->bbx.y_offset = _bdf_atos( p->list.field[4] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001684
1685 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001686 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1687 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001688
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001689 /* Determine the overall font bounding box as the characters are */
1690 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001691 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1692 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001693
David Turnerb1b47622002-05-21 21:17:43 +00001694 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001695
Werner Lembergdfa46192004-03-05 09:26:24 +00001696 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1697 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1698 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001699
Werner Lemberg758587d2016-01-12 22:20:06 +01001700 if ( !( p->flags & BDF_DWIDTH_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001701 {
1702 /* Missing DWIDTH field. Emit an auto correction message and set */
1703 /* the device width to the glyph width. */
1704 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1705 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001706 }
1707
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001708 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1709 /* value if necessary. */
1710 if ( p->opts->correct_metrics != 0 )
1711 {
1712 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001713 unsigned short sw = (unsigned short)FT_MulDiv(
1714 glyph->dwidth, 72000L,
1715 (FT_Long)( font->point_size *
1716 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001717
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001718
1719 if ( sw != glyph->swidth )
1720 {
1721 glyph->swidth = sw;
1722
1723 if ( p->glyph_enc == -1 )
1724 _bdf_set_glyph_modified( font->umod,
1725 font->unencoded_used - 1 );
1726 else
1727 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1728
Werner Lemberg758587d2016-01-12 22:20:06 +01001729 p->flags |= BDF_SWIDTH_ADJ_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001730 font->modified = 1;
1731 }
David Turner993a8d02002-05-18 12:03:43 +00001732 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001733
Werner Lemberg758587d2016-01-12 22:20:06 +01001734 p->flags |= BDF_BBX_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001735 goto Exit;
1736 }
David Turner993a8d02002-05-18 12:03:43 +00001737
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001738 /* And finally, gather up the bitmap. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001739 if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001740 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001741 unsigned long bitmap_size;
1742
1743
Werner Lemberg758587d2016-01-12 22:20:06 +01001744 if ( !( p->flags & BDF_BBX_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001745 {
1746 /* Missing BBX field. */
1747 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001748 error = FT_THROW( Missing_Bbx_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001749 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001750 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001751
1752 /* Allocate enough space for the bitmap. */
Werner Lemberge01406b2011-11-25 09:44:28 +01001753 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001754
1755 bitmap_size = glyph->bpr * glyph->bbx.height;
Werner Lembergc4cad302012-03-08 20:11:37 +01001756 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
Werner Lemberg26170df2006-03-26 07:19:07 +00001757 {
1758 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001759 error = FT_THROW( Bbx_Too_Big );
Werner Lemberg26170df2006-03-26 07:19:07 +00001760 goto Exit;
1761 }
1762 else
1763 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001764
1765 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1766 goto Exit;
1767
1768 p->row = 0;
Werner Lemberg758587d2016-01-12 22:20:06 +01001769 p->flags |= BDF_BITMAP_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001770
1771 goto Exit;
1772 }
1773
Werner Lemberge01406b2011-11-25 09:44:28 +01001774 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001775 error = FT_THROW( Invalid_File_Format );
Werner Lemberg4086fb72012-03-01 08:55:40 +01001776 goto Exit;
1777
1778 Missing_Encoding:
1779 /* Missing ENCODING field. */
1780 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01001781 error = FT_THROW( Missing_Encoding_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001782
1783 Exit:
Werner Lemberg758587d2016-01-12 22:20:06 +01001784 if ( error && ( p->flags & BDF_GLYPH_ ) )
Werner Lembergf4c94d42010-06-19 16:08:31 +02001785 FT_FREE( p->glyph_name );
1786
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001787 return error;
David Turner993a8d02002-05-18 12:03:43 +00001788 }
1789
David Turner993a8d02002-05-18 12:03:43 +00001790
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001791 /* Load the font properties. */
1792 static FT_Error
1793 _bdf_parse_properties( char* line,
1794 unsigned long linelen,
1795 unsigned long lineno,
1796 void* call_data,
1797 void* client_data )
1798 {
1799 unsigned long vlen;
1800 _bdf_line_func_t* next;
1801 _bdf_parse_t* p;
1802 char* name;
1803 char* value;
1804 char nbuf[128];
Werner Lemberge3c93012013-03-14 11:21:17 +01001805 FT_Error error = FT_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001806
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001807 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001808
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001809
1810 next = (_bdf_line_func_t *)call_data;
1811 p = (_bdf_parse_t *) client_data;
1812
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001813 /* Check for the end of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001814 if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001815 {
1816 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1817 /* encountered yet, then make sure they are added as properties and */
1818 /* make sure they are set from the font bounding box info. */
1819 /* */
1820 /* This is *always* done regardless of the options, because X11 */
1821 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001822 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001823 {
1824 p->font->font_ascent = p->font->bbx.ascent;
1825 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001826 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
1827 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001828 if ( error )
1829 goto Exit;
1830
1831 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1832 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001833 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001834
Werner Lemberg428c2e42003-04-25 05:35:04 +00001835 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001836 {
1837 p->font->font_descent = p->font->bbx.descent;
1838 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01001839 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
1840 nbuf, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001841 if ( error )
1842 goto Exit;
1843
1844 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1845 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001846 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001847
Werner Lemberg758587d2016-01-12 22:20:06 +01001848 p->flags &= ~BDF_PROPS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001849 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001850
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001851 goto Exit;
1852 }
David Turner993a8d02002-05-18 12:03:43 +00001853
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001854 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001855 if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001856 goto Exit;
1857
1858 /* Handle COMMENT fields and properties in a special way to preserve */
1859 /* the spacing. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001860 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001861 {
David Turner993a8d02002-05-18 12:03:43 +00001862 name = value = line;
1863 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001864 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001865 *value++ = 0;
Werner Lemberge01406b2011-11-25 09:44:28 +01001866 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001867 if ( error )
1868 goto Exit;
1869 }
1870 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1871 {
Werner Lemberge01406b2011-11-25 09:44:28 +01001872 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001873 if ( error )
1874 goto Exit;
1875 }
1876 else
1877 {
David Turner68df4f72005-03-15 18:18:57 +00001878 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001879 if ( error )
1880 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001881 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001882
David Turner68df4f72005-03-15 18:18:57 +00001883 _bdf_list_shift( &p->list, 1 );
1884 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001885
Werner Lemberge01406b2011-11-25 09:44:28 +01001886 error = _bdf_add_property( p->font, name, value, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001887 if ( error )
1888 goto Exit;
1889 }
1890
1891 Exit:
1892 return error;
David Turner993a8d02002-05-18 12:03:43 +00001893 }
1894
David Turner993a8d02002-05-18 12:03:43 +00001895
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001896 /* Load the font header. */
1897 static FT_Error
1898 _bdf_parse_start( char* line,
1899 unsigned long linelen,
1900 unsigned long lineno,
1901 void* call_data,
1902 void* client_data )
1903 {
1904 unsigned long slen;
1905 _bdf_line_func_t* next;
1906 _bdf_parse_t* p;
1907 bdf_font_t* font;
1908 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001909
David Turnerd490e372002-05-28 23:40:37 +00001910 FT_Memory memory = NULL;
Werner Lemberge3c93012013-03-14 11:21:17 +01001911 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001912
1913 FT_UNUSED( lineno ); /* only used in debug mode */
1914
1915
1916 next = (_bdf_line_func_t *)call_data;
1917 p = (_bdf_parse_t *) client_data;
1918
1919 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00001920 memory = p->font->memory;
1921
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001922 /* Check for a comment. This is done to handle those fonts that have */
1923 /* comments before the STARTFONT line for some reason. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001924 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001925 {
1926 if ( p->opts->keep_comments != 0 && p->font != 0 )
1927 {
1928 linelen -= 7;
1929
1930 s = line + 7;
1931 if ( *s != 0 )
1932 {
1933 s++;
1934 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00001935 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001936
1937 error = _bdf_add_comment( p->font, s, linelen );
1938 if ( error )
1939 goto Exit;
1940 /* here font is not defined! */
1941 }
1942
1943 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001944 }
1945
Werner Lemberg758587d2016-01-12 22:20:06 +01001946 if ( !( p->flags & BDF_START_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001947 {
1948 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00001949
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001950 if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001951 {
Werner Lemberg96fcf872011-12-08 11:22:07 +01001952 /* we don't emit an error message since this code gets */
1953 /* explicitly caught one level higher */
Werner Lemberg059bc332013-03-14 10:27:35 +01001954 error = FT_THROW( Missing_Startfont_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001955 goto Exit;
1956 }
David Turner993a8d02002-05-18 12:03:43 +00001957
Werner Lemberg758587d2016-01-12 22:20:06 +01001958 p->flags = BDF_START_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001959 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00001960
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001961 if ( FT_NEW( font ) )
1962 goto Exit;
1963 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00001964
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001965 font->memory = p->memory;
1966 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00001967
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001968 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001969 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001970 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00001971
David Turner993a8d02002-05-18 12:03:43 +00001972
Werner Lemberg7ce6c432015-12-22 05:39:58 +01001973 error = ft_hash_str_init( &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001974 if ( error )
1975 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00001976 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001977 i < _num_bdf_properties; i++, prop++ )
1978 {
Werner Lemberg609546c2015-12-20 07:17:29 +01001979 error = ft_hash_str_insert( prop->name, i,
1980 &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001981 if ( error )
1982 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001983 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001984 }
1985
Werner Lemberg31343562015-12-19 17:02:13 +01001986 if ( FT_ALLOC( p->font->internal, sizeof ( FT_HashRec ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001987 goto Exit;
Werner Lemberg7ce6c432015-12-22 05:39:58 +01001988 error = ft_hash_str_init( (FT_Hash)p->font->internal, memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001989 if ( error )
1990 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00001991 p->font->spacing = p->opts->font_spacing;
1992 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001993
1994 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001995 }
1996
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001997 /* Check for the start of the properties. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01001998 if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001999 {
Werner Lemberg758587d2016-01-12 22:20:06 +01002000 if ( !( p->flags & BDF_FONT_BBX_ ) )
Werner Lembergfb690292010-06-23 10:00:52 +02002001 {
2002 /* Missing the FONTBOUNDINGBOX field. */
2003 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002004 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergfb690292010-06-23 10:00:52 +02002005 goto Exit;
2006 }
2007
David Turner68df4f72005-03-15 18:18:57 +00002008 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002009 if ( error )
2010 goto Exit;
Werner Lembergb6b26f42016-06-09 06:53:48 +02002011
Werner Lembergb66efef2009-03-12 08:07:49 +00002012 /* at this point, `p->font' can't be NULL */
Ben Wagnera512b0f2015-12-14 09:19:52 +01002013 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1] );
Werner Lembergb6b26f42016-06-09 06:53:48 +02002014 /* We need at least 4 bytes per property. */
2015 if ( p->cnt > p->size / 4 )
2016 {
2017 p->font->props_size = 0;
2018
2019 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "STARTPROPERTIES" ));
2020 error = FT_THROW( Invalid_Argument );
2021 goto Exit;
2022 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002023
2024 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
Werner Lemberg9b6b5752012-12-15 01:34:41 +01002025 {
2026 p->font->props_size = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002027 goto Exit;
Werner Lemberg9b6b5752012-12-15 01:34:41 +01002028 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002029
Werner Lemberg758587d2016-01-12 22:20:06 +01002030 p->flags |= BDF_PROPS_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002031 *next = _bdf_parse_properties;
2032
2033 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002034 }
2035
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002036 /* Check for the FONTBOUNDINGBOX field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002037 if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002038 {
Werner Lemberg758587d2016-01-12 22:20:06 +01002039 if ( !( p->flags & BDF_SIZE_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002040 {
2041 /* Missing the SIZE field. */
2042 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002043 error = FT_THROW( Missing_Size_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002044 goto Exit;
2045 }
2046
David Turner68df4f72005-03-15 18:18:57 +00002047 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002048 if ( error )
2049 goto Exit;
2050
Ben Wagnera512b0f2015-12-14 09:19:52 +01002051 p->font->bbx.width = _bdf_atous( p->list.field[1] );
2052 p->font->bbx.height = _bdf_atous( p->list.field[2] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002053
Ben Wagnera512b0f2015-12-14 09:19:52 +01002054 p->font->bbx.x_offset = _bdf_atos( p->list.field[3] );
2055 p->font->bbx.y_offset = _bdf_atos( p->list.field[4] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002056
David Turnerd490e372002-05-28 23:40:37 +00002057 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002058 p->font->bbx.y_offset );
2059
2060 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002061
Werner Lemberg758587d2016-01-12 22:20:06 +01002062 p->flags |= BDF_FONT_BBX_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002063
2064 goto Exit;
2065 }
2066
2067 /* The next thing to check for is the FONT field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002068 if ( _bdf_strncmp( line, "FONT", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002069 {
David Turner68df4f72005-03-15 18:18:57 +00002070 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002071 if ( error )
2072 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002073 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002074
David Turner68df4f72005-03-15 18:18:57 +00002075 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002076
2077 if ( !s )
2078 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002079 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002080 error = FT_THROW( Invalid_File_Format );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002081 goto Exit;
2082 }
2083
Werner Lembergfb690292010-06-23 10:00:52 +02002084 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2085 FT_FREE( p->font->name );
2086
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002087 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2088 goto Exit;
2089 FT_MEM_COPY( p->font->name, s, slen + 1 );
2090
2091 /* If the font name is an XLFD name, set the spacing to the one in */
2092 /* the font name. If there is no spacing fall back on the default. */
Werner Lemberge01406b2011-11-25 09:44:28 +01002093 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002094 if ( error )
2095 goto Exit;
2096
Werner Lemberg758587d2016-01-12 22:20:06 +01002097 p->flags |= BDF_FONT_NAME_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002098
2099 goto Exit;
2100 }
2101
2102 /* Check for the SIZE field. */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002103 if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002104 {
Werner Lemberg758587d2016-01-12 22:20:06 +01002105 if ( !( p->flags & BDF_FONT_NAME_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002106 {
2107 /* Missing the FONT field. */
2108 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002109 error = FT_THROW( Missing_Font_Field );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002110 goto Exit;
2111 }
2112
David Turner68df4f72005-03-15 18:18:57 +00002113 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002114 if ( error )
2115 goto Exit;
2116
Ben Wagnera512b0f2015-12-14 09:19:52 +01002117 p->font->point_size = _bdf_atoul( p->list.field[1] );
2118 p->font->resolution_x = _bdf_atoul( p->list.field[2] );
2119 p->font->resolution_y = _bdf_atoul( p->list.field[3] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002120
2121 /* Check for the bits per pixel field. */
2122 if ( p->list.used == 5 )
2123 {
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002124 unsigned short bpp;
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002125
2126
Ben Wagnera512b0f2015-12-14 09:19:52 +01002127 bpp = (unsigned short)_bdf_atos( p->list.field[4] );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002128
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002129 /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
2130 if ( bpp > 4 )
2131 p->font->bpp = 8;
2132 else if ( bpp > 2 )
2133 p->font->bpp = 4;
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002134 else if ( bpp > 1 )
2135 p->font->bpp = 2;
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002136 else
Alexei Podtelezhnikov41bfbad2015-06-24 23:57:19 -04002137 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002138
Alexei Podtelezhnikov4308b7b2015-06-24 23:31:17 -04002139 if ( p->font->bpp != bpp )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002140 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002141 }
2142 else
2143 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002144
Werner Lemberg758587d2016-01-12 22:20:06 +01002145 p->flags |= BDF_SIZE_;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002146
2147 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002148 }
2149
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002150 /* Check for the CHARS field -- font properties are optional */
Werner Lemberg2c4832d2014-11-07 07:42:33 +01002151 if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002152 {
2153 char nbuf[128];
2154
2155
Werner Lemberg758587d2016-01-12 22:20:06 +01002156 if ( !( p->flags & BDF_FONT_BBX_ ) )
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002157 {
2158 /* Missing the FONTBOUNDINGBOX field. */
2159 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002160 error = FT_THROW( Missing_Fontboundingbox_Field );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002161 goto Exit;
2162 }
2163
2164 /* Add the two standard X11 properties which are required */
2165 /* for compiling fonts. */
2166 p->font->font_ascent = p->font->bbx.ascent;
2167 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002168 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2169 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002170 if ( error )
2171 goto Exit;
2172 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2173
2174 p->font->font_descent = p->font->bbx.descent;
2175 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
Werner Lemberge01406b2011-11-25 09:44:28 +01002176 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2177 nbuf, lineno );
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002178 if ( error )
2179 goto Exit;
2180 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2181
2182 p->font->modified = 1;
2183
2184 *next = _bdf_parse_glyphs;
2185
2186 /* A special return value. */
2187 error = -1;
2188 goto Exit;
2189 }
2190
Werner Lemberge01406b2011-11-25 09:44:28 +01002191 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002192 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002193
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002194 Exit:
2195 return error;
2196 }
David Turner993a8d02002-05-18 12:03:43 +00002197
2198
Werner Lemberg9ac90602018-06-03 09:01:17 +02002199 /**************************************************************************
2200 *
2201 * API.
2202 *
2203 */
David Turner993a8d02002-05-18 12:03:43 +00002204
David Turner993a8d02002-05-18 12:03:43 +00002205
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002206 FT_LOCAL_DEF( FT_Error )
2207 bdf_load_font( FT_Stream stream,
2208 FT_Memory extmemory,
2209 bdf_options_t* opts,
2210 bdf_font_t* *font )
2211 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002212 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002213 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002214
Sean McBride7be2a942014-02-08 13:55:38 +01002215 FT_Memory memory = extmemory; /* needed for FT_NEW */
2216 FT_Error error = FT_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002217
2218
David Turner68df4f72005-03-15 18:18:57 +00002219 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002220 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002221
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002222 memory = NULL;
2223 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2224 p->minlb = 32767;
Werner Lemberge1ca18d2015-10-17 11:51:27 +02002225 p->size = stream->size;
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002226 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002227
David Turner68df4f72005-03-15 18:18:57 +00002228 _bdf_list_init( &p->list, extmemory );
2229
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002230 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002231 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002232 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002233 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002234
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002235 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002236 {
2237 /* If the font is not proportional, set the font's monowidth */
2238 /* field to the width of the font bounding box. */
David Turner993a8d02002-05-18 12:03:43 +00002239
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002240 if ( p->font->spacing != BDF_PROPORTIONAL )
2241 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002242
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002243 /* If the number of glyphs loaded is not that of the original count, */
2244 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002245 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002246 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002247 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2248 p->font->glyphs_used + p->font->unencoded_used ));
2249 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002250 }
2251
2252 /* Once the font has been loaded, adjust the overall font metrics if */
2253 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002254 if ( p->opts->correct_metrics != 0 &&
2255 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002256 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002257 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002258 {
2259 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002260 p->font->bbx.width, p->maxrb - p->minlb ));
2261 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2262 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002263 }
2264
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002265 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002266 {
2267 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002268 p->font->bbx.x_offset, p->minlb ));
2269 p->font->bbx.x_offset = p->minlb;
2270 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002271 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002272
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002273 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002274 {
2275 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002276 p->font->bbx.ascent, p->maxas ));
2277 p->font->bbx.ascent = p->maxas;
2278 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002279 }
2280
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002281 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002282 {
2283 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002284 p->font->bbx.descent, p->maxds ));
2285 p->font->bbx.descent = p->maxds;
2286 p->font->bbx.y_offset = (short)( -p->maxds );
2287 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002288 }
2289
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002290 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002291 {
2292 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002293 p->font->bbx.height, p->maxas + p->maxds ));
2294 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002295 }
2296
Werner Lemberg758587d2016-01-12 22:20:06 +01002297 if ( p->flags & BDF_SWIDTH_ADJ_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002298 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2299 }
David Turner993a8d02002-05-18 12:03:43 +00002300 }
2301
Werner Lemberg758587d2016-01-12 22:20:06 +01002302 if ( p->flags & BDF_START_ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002303 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002304 /* The ENDFONT field was never reached or did not exist. */
Werner Lemberg758587d2016-01-12 22:20:06 +01002305 if ( !( p->flags & BDF_GLYPHS_ ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002306 {
Werner Lemberge01406b2011-11-25 09:44:28 +01002307 /* Error happened while parsing header. */
2308 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002309 error = FT_THROW( Corrupted_Font_Header );
Bungeman65d89802015-10-15 23:50:16 +02002310 goto Fail;
Werner Lemberge01406b2011-11-25 09:44:28 +01002311 }
2312 else
2313 {
2314 /* Error happened when parsing glyphs. */
2315 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
Werner Lemberg059bc332013-03-14 10:27:35 +01002316 error = FT_THROW( Corrupted_Font_Glyphs );
Bungeman65d89802015-10-15 23:50:16 +02002317 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002318 }
David Turner993a8d02002-05-18 12:03:43 +00002319 }
2320
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002321 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002322 {
2323 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002324 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002325
Werner Lemberg370aea82010-06-08 08:37:11 +02002326 if ( p->font->comments_len > 0 )
2327 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002328 if ( FT_RENEW_ARRAY( p->font->comments,
2329 p->font->comments_len,
2330 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002331 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002332
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002333 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002334 }
David Turner993a8d02002-05-18 12:03:43 +00002335 }
Werner Lemberg5d664b62016-12-17 20:47:42 +01002336 else if ( !error )
Werner Lemberg059bc332013-03-14 10:27:35 +01002337 error = FT_THROW( Invalid_File_Format );
David Turner993a8d02002-05-18 12:03:43 +00002338
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002339 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002340
2341 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002342 if ( p )
2343 {
David Turner68df4f72005-03-15 18:18:57 +00002344 _bdf_list_done( &p->list );
2345
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002346 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002347
Werner Lemberg4a150132015-11-25 07:53:49 +01002348 FT_FREE( p->glyph_name );
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002349 FT_FREE( p );
2350 }
2351
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002352 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002353
2354 Fail:
2355 bdf_free_font( p->font );
2356
2357 memory = extmemory;
2358
2359 FT_FREE( p->font );
2360
2361 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002362 }
David Turner993a8d02002-05-18 12:03:43 +00002363
2364
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002365 FT_LOCAL_DEF( void )
2366 bdf_free_font( bdf_font_t* font )
2367 {
2368 bdf_property_t* prop;
2369 unsigned long i;
2370 bdf_glyph_t* glyphs;
2371 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002372
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002373
2374 if ( font == 0 )
2375 return;
David Turner993a8d02002-05-18 12:03:43 +00002376
2377 memory = font->memory;
2378
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002379 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002380
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002381 /* Free up the internal hash table of property names. */
2382 if ( font->internal )
2383 {
Werner Lemberg7ce6c432015-12-22 05:39:58 +01002384 ft_hash_str_free( (FT_Hash)font->internal, memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002385 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002386 }
2387
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002388 /* Free up the comment info. */
2389 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002390
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002391 /* Free up the properties. */
2392 for ( i = 0; i < font->props_size; i++ )
2393 {
2394 if ( font->props[i].format == BDF_ATOM )
2395 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002396 }
2397
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002398 FT_FREE( font->props );
2399
2400 /* Free up the character info. */
2401 for ( i = 0, glyphs = font->glyphs;
2402 i < font->glyphs_used; i++, glyphs++ )
2403 {
2404 FT_FREE( glyphs->name );
2405 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002406 }
2407
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002408 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2409 i++, glyphs++ )
2410 {
2411 FT_FREE( glyphs->name );
2412 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002413 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002414
2415 FT_FREE( font->glyphs );
2416 FT_FREE( font->unencoded );
2417
2418 /* Free up the overflow storage if it was used. */
2419 for ( i = 0, glyphs = font->overflow.glyphs;
2420 i < font->overflow.glyphs_used; i++, glyphs++ )
2421 {
2422 FT_FREE( glyphs->name );
2423 FT_FREE( glyphs->bitmap );
2424 }
2425
2426 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002427
2428 /* bdf_cleanup */
Werner Lemberg7ce6c432015-12-22 05:39:58 +01002429 ft_hash_str_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002430
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002431 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002432 for ( prop = font->user_props, i = 0;
2433 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002434 {
2435 FT_FREE( prop->name );
2436 if ( prop->format == BDF_ATOM )
2437 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002438 }
David Turner993a8d02002-05-18 12:03:43 +00002439
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002440 FT_FREE( font->user_props );
2441
2442 /* FREE( font ); */ /* XXX Fixme */
2443 }
David Turner993a8d02002-05-18 12:03:43 +00002444
2445
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002446 FT_LOCAL_DEF( bdf_property_t * )
2447 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002448 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002449 {
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002450 size_t* propid;
David Turner993a8d02002-05-18 12:03:43 +00002451
David Turner993a8d02002-05-18 12:03:43 +00002452
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002453 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002454 return 0;
2455
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002456 propid = ft_hash_str_lookup( name, (FT_Hash)font->internal );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002457
Werner Lemberg76e79ec2015-12-20 09:03:15 +01002458 return propid ? ( font->props + *propid ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002459 }
2460
2461
2462/* END */