sdk-world v2026.11.05
PS2 SDK - world tier (copyleft-allowed, non-essential packages)
Loading...
Searching...
No Matches
bdflib.c
1/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
3 * Copyright 2001-2014
4 * Francesco Zappa Nardelli
5 *
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
25 /**************************************************************************
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 */
32
33
34
35#include <freetype/freetype.h>
39
40#include "bdf.h"
41#include "bdferror.h"
42
43
44 /**************************************************************************
45 *
46 * The macro FT_COMPONENT is used in trace mode. It is an implicit
47 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
48 * messages during execution.
49 */
50#undef FT_COMPONENT
51#define FT_COMPONENT bdflib
52
53
54 /**************************************************************************
55 *
56 * Builtin BDF font properties.
57 *
58 */
59
60 /* List of most properties that might appear in a font. Doesn't include */
61 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
62
63 static const bdf_property_t bdf_properties_[] =
64 {
65 { "ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
66 { "AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
67 { "AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
68 { "AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
69 { "CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
70 { "CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
71 { "CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
72 { "CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
73 { "COPYRIGHT", BDF_ATOM, 1, { 0 } },
74 { "DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
75 { "DESTINATION", BDF_CARDINAL, 1, { 0 } },
76 { "DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
77 { "END_SPACE", BDF_INTEGER, 1, { 0 } },
78 { "FACE_NAME", BDF_ATOM, 1, { 0 } },
79 { "FAMILY_NAME", BDF_ATOM, 1, { 0 } },
80 { "FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
81 { "FONT", BDF_ATOM, 1, { 0 } },
82 { "FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
83 { "FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
84 { "FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
85 { "FOUNDRY", BDF_ATOM, 1, { 0 } },
86 { "FULL_NAME", BDF_ATOM, 1, { 0 } },
87 { "ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
88 { "MAX_SPACE", BDF_INTEGER, 1, { 0 } },
89 { "MIN_SPACE", BDF_INTEGER, 1, { 0 } },
90 { "NORM_SPACE", BDF_INTEGER, 1, { 0 } },
91 { "NOTICE", BDF_ATOM, 1, { 0 } },
92 { "PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
93 { "POINT_SIZE", BDF_INTEGER, 1, { 0 } },
94 { "QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
95 { "RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
96 { "RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
97 { "RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
98 { "RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
99 { "RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
100 { "RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
101 { "RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
102 { "RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
103 { "RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
104 { "RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
105 { "RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
106 { "RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
107 { "RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
108 { "RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
109 { "RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
110 { "RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
111 { "RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
112 { "RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
113 { "RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
114 { "RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
115 { "RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
116 { "RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
117 { "RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
118 { "RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
119 { "RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
120 { "RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
121 { "RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
122 { "RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
123 { "RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
124 { "RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
125 { "RESOLUTION", BDF_INTEGER, 1, { 0 } },
126 { "RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
127 { "RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
128 { "SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
129 { "SLANT", BDF_ATOM, 1, { 0 } },
130 { "SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
131 { "SPACING", BDF_ATOM, 1, { 0 } },
132 { "STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
133 { "STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
134 { "SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
135 { "SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
136 { "SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
137 { "SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
138 { "SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
139 { "SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
140 { "UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
141 { "UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
142 { "WEIGHT", BDF_CARDINAL, 1, { 0 } },
143 { "WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
144 { "X_HEIGHT", BDF_INTEGER, 1, { 0 } },
145 { "_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
146 { "_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
147 };
148
149 static const unsigned long
150 num_bdf_properties_ = sizeof ( bdf_properties_ ) /
151 sizeof ( bdf_properties_[0] );
152
153 /* Auto correction messages. */
154#define ACMSG1 "FONT_ASCENT property missing. " \
155 "Added `FONT_ASCENT %hd'.\n"
156#define ACMSG2 "FONT_DESCENT property missing. " \
157 "Added `FONT_DESCENT %hd'.\n"
158#define ACMSG3 "Font width != actual width. Old: %d New: %d.\n"
159#define ACMSG4 "Font left bearing != actual left bearing. " \
160 "Old: %hd New: %hd.\n"
161#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
162#define ACMSG6 "Font descent != actual descent. Old: %d New: %d.\n"
163#define ACMSG7 "Font height != actual height. Old: %d New: %d.\n"
164#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
165#define ACMSG9 "SWIDTH field missing at line %lu. Set automatically.\n"
166#define ACMSG10 "DWIDTH field missing at line %lu. Set to glyph width.\n"
167#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
168#define ACMSG13 "Glyph %lu extra rows removed.\n"
169#define ACMSG14 "Glyph %lu extra columns removed.\n"
170#define ACMSG15 "Incorrect glyph count: %lu indicated but %lu found.\n"
171#define ACMSG16 "Glyph %lu missing columns padded with zero bits.\n"
172#define ACMSG17 "Adjusting number of glyphs to %lu.\n"
173
174 /* Error messages. */
175#define ERRMSG1 "[line %lu] Missing `%s' line.\n"
176#define ERRMSG2 "[line %lu] Font header corrupted or missing fields.\n"
177#define ERRMSG3 "[line %lu] Font glyphs corrupted or missing fields.\n"
178#define ERRMSG4 "[line %lu] BBX too big.\n"
179#define ERRMSG5 "[line %lu] `%s' value too big.\n"
180#define ERRMSG6 "[line %lu] Input line too long.\n"
181#define ERRMSG7 "[line %lu] Font name too long.\n"
182#define ERRMSG8 "[line %lu] Invalid `%s' value.\n"
183#define ERRMSG9 "[line %lu] Invalid keyword.\n"
184
185 /* Debug messages. */
186#define DBGMSG1 " [%6lu] %s" /* no \n */
187#define DBGMSG2 " (0x%lX)\n"
188
189
190 /**************************************************************************
191 *
192 * Utility types and functions.
193 *
194 */
195
196
197 /* Structure used while loading BDF fonts. */
198
199 typedef struct bdf_parse_t__
200 {
201 unsigned long flags;
202 unsigned long cnt;
203 unsigned long row;
204
205 short minlb;
206 short maxlb;
207 short maxrb;
208 short maxas;
209 short maxds;
210
211 short rbearing;
212
213 char* glyph_name;
214 long glyph_enc;
215
216 bdf_glyph_t* glyph;
217 bdf_font_t* font;
218
219 FT_Memory memory;
220 unsigned long size; /* the stream size */
221
222 } bdf_parse_t_;
223
224
225 /* Function type for parsing lines of a BDF font. */
226
227 typedef FT_Error
228 (*bdf_line_func_t_)( char* line,
229 unsigned long linelen,
230 unsigned long lineno,
231 bdf_parse_t_* p,
232 void* next );
233
234
235#define setsbit( m, cc ) \
236 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
237#define sbitset( m, cc ) \
238 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
239
240
241 static char*
242 bdf_strtok_( char* line,
243 int delim )
244 {
245 while ( *line && *line != delim )
246 line++;
247
248 if ( *line )
249 *line++ = '\0';
250
251 while ( *line && *line == delim )
252 line++;
253
254 return line;
255 }
256
257
258 /* XXX: make this work with EBCDIC also */
259
260 static const unsigned char a2i[128] =
261 {
262 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
263 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
264 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
265 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
266 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
267 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
268 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
269 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
270 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
271 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
272 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
273 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
274 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
275 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
276 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
277 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
278 };
279
280 static const unsigned char ddigits[32] =
281 {
282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 };
287
288
289 /* Routine to convert a decimal ASCII string to an unsigned long integer. */
290 static unsigned long
291 bdf_atoul_( const char* s )
292 {
293 unsigned long v;
294
295
296 for ( v = 0; sbitset( ddigits, *s ); s++ )
297 {
298 if ( v < ( FT_ULONG_MAX - 9 ) / 10 )
299 v = v * 10 + a2i[(int)*s];
300 else
301 {
302 v = FT_ULONG_MAX;
303 break;
304 }
305 }
306
307 return v;
308 }
309
310
311 /* Routine to convert a decimal ASCII string to a signed long integer. */
312 static long
313 bdf_atol_( const char* s )
314 {
315 long v, neg;
316
317
318 /* Check for a minus sign. */
319 if ( *s == '-' )
320 {
321 s++;
322 neg = -1;
323 }
324 else
325 neg = 1;
326
327 for ( v = 0; sbitset( ddigits, *s ); s++ )
328 {
329 if ( v < ( FT_LONG_MAX - 9 ) / 10 )
330 v = v * 10 + a2i[(int)*s];
331 else
332 {
333 v = FT_LONG_MAX;
334 break;
335 }
336 }
337
338 return neg * v;
339 }
340
341
342 /* Routine to convert a decimal ASCII string to an unsigned short integer. */
343 static unsigned short
344 bdf_atous_( const char* s )
345 {
346 unsigned short v;
347
348
349 for ( v = 0; sbitset( ddigits, *s ); s++ )
350 {
351 if ( v < ( FT_USHORT_MAX - 9 ) / 10 )
352 v = (unsigned short)( v * 10 + a2i[(int)*s] );
353 else
354 {
355 v = FT_USHORT_MAX;
356 break;
357 }
358 }
359
360 return v;
361 }
362
363
364 /* Routine to convert a decimal ASCII string to a signed short integer. */
365 static short
366 bdf_atos_( const char* s )
367 {
368 short v, neg;
369
370
371 /* Check for a minus. */
372 if ( *s == '-' )
373 {
374 s++;
375 neg = -1;
376 }
377 else
378 neg = 1;
379
380 for ( v = 0; sbitset( ddigits, *s ); s++ )
381 {
382 if ( v < ( SHRT_MAX - 9 ) / 10 )
383 v = (short)( v * 10 + a2i[(int)*s] );
384 else
385 {
386 v = SHRT_MAX;
387 break;
388 }
389 }
390
391 return neg * v;
392 }
393
394
395 /* Routine to compare two glyphs by encoding so they can be sorted. */
396 FT_COMPARE_DEF( int )
397 by_encoding( const void* a,
398 const void* b )
399 {
400 bdf_glyph_t *c1, *c2;
401
402
403 c1 = (bdf_glyph_t *)a;
404 c2 = (bdf_glyph_t *)b;
405
406 if ( c1->encoding < c2->encoding )
407 return -1;
408
409 if ( c1->encoding > c2->encoding )
410 return 1;
411
412 return 0;
413 }
414
415
416 static FT_Error
417 bdf_create_property( const char* name,
418 int format,
419 bdf_font_t* font )
420 {
421 size_t n;
422 bdf_property_t* p;
423 FT_Memory memory = font->memory;
424 FT_Error error = FT_Err_Ok;
425
426
427 /* First check whether the property has */
428 /* already been added or not. If it has, then */
429 /* simply ignore it. */
430 if ( ft_hash_str_lookup( name, &(font->proptbl) ) )
431 goto Exit;
432
433 if ( FT_QRENEW_ARRAY( font->user_props,
434 font->nuser_props,
435 font->nuser_props + 1 ) )
436 goto Exit;
437
438 p = font->user_props + font->nuser_props;
439
440 if ( FT_STRDUP( p->name, name ) )
441 goto Exit;
442
443 p->format = format;
444 p->builtin = 0;
445 p->value.atom = NULL; /* nothing is ever stored here */
446
447 n = num_bdf_properties_ + font->nuser_props;
448
449 error = ft_hash_str_insert( p->name, n, &(font->proptbl), memory );
450 if ( error )
451 goto Exit;
452
453 font->nuser_props++;
454
455 Exit:
456 return error;
457 }
458
459
460 static bdf_property_t*
461 bdf_get_property( const char* name,
462 bdf_font_t* font )
463 {
464 size_t* propid;
465
466
467 if ( name == NULL || *name == 0 )
468 return NULL;
469
470 if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL )
471 return NULL;
472
473 if ( *propid >= num_bdf_properties_ )
474 return font->user_props + ( *propid - num_bdf_properties_ );
475
476 return (bdf_property_t*)bdf_properties_ + *propid;
477 }
478
479
480 /**************************************************************************
481 *
482 * BDF font file parsing flags and functions.
483 *
484 */
485
486
487 /* Parse flags. */
488
489#define BDF_START_ 0x0001U
490#define BDF_FONT_NAME_ 0x0002U
491#define BDF_SIZE_ 0x0004U
492#define BDF_FONT_BBX_ 0x0008U
493#define BDF_PROPS_ 0x0010U
494#define BDF_GLYPHS_ 0x0020U
495#define BDF_GLYPH_ 0x0040U
496#define BDF_ENCODING_ 0x0080U
497#define BDF_SWIDTH_ 0x0100U
498#define BDF_DWIDTH_ 0x0200U
499#define BDF_BBX_ 0x0400U
500#define BDF_BITMAP_ 0x0800U
501
502#define BDF_GLYPH_BITS_ ( BDF_GLYPH_ | \
503 BDF_ENCODING_ | \
504 BDF_SWIDTH_ | \
505 BDF_DWIDTH_ | \
506 BDF_BBX_ | \
507 BDF_BITMAP_ )
508
509
510 static FT_Error
511 bdf_add_comment_( bdf_font_t* font,
512 const char* comment,
513 unsigned long len )
514 {
515 char* cp;
516 FT_Memory memory = font->memory;
517 FT_Error error = FT_Err_Ok;
518
519
520 /* Skip keyword COMMENT. */
521 comment += 7;
522 len -= 7;
523
524 if ( len == 0 )
525 goto Exit;
526
527 if ( FT_QRENEW_ARRAY( font->comments,
528 font->comments_len,
529 font->comments_len + len + 1 ) )
530 goto Exit;
531
532 cp = font->comments + font->comments_len;
533
534 FT_MEM_COPY( cp, comment, len );
535 cp[len] = '\0';
536
537 font->comments_len += len + 1;
538
539 Exit:
540 return error;
541 }
542
543
544 /* Determine whether the property is an atom or not. If it is, then */
545 /* clean it up so the double quotes are removed if they exist. */
546 static int
547 bdf_is_atom_( char* line,
548 unsigned long linelen,
549 char** name,
550 char** value,
551 bdf_font_t* font )
552 {
553 int hold;
554 char *sp, *ep;
555 bdf_property_t* p;
556
557
558 sp = ep = line;
559
560 while ( *ep && *ep != ' ' )
561 ep++;
562
563 hold = *ep;
564 *ep = '\0';
565
566 p = bdf_get_property( sp, font );
567
568 /* If the property exists and is not an atom, just return here. */
569 if ( p && p->format != BDF_ATOM )
570 {
571 *ep = (char)hold; /* Undo NUL-termination. */
572 return 0;
573 }
574
575 *name = sp;
576
577 /* The property is an atom. Trim all leading and trailing whitespace */
578 /* and double quotes for the atom value. */
579 sp = ep;
580 ep = line + linelen;
581
582 /* Trim the leading whitespace if it exists. */
583 if ( sp < ep )
584 do
585 sp++;
586 while ( *sp == ' ' );
587
588 /* Trim the leading double quote if it exists. */
589 if ( *sp == '"' )
590 sp++;
591
592 *value = sp;
593
594 /* Trim the trailing whitespace if it exists. */
595 if ( sp < ep )
596 do
597 *ep-- = '\0';
598 while ( *ep == ' ' );
599
600 /* Trim the trailing double quote if it exists. */
601 if ( *ep == '"' )
602 *ep = '\0';
603
604 return 1;
605 }
606
607
608 static FT_Error
609 bdf_add_property_( bdf_font_t* font,
610 const char* name,
611 char* value,
612 unsigned long lineno )
613 {
614 size_t* propid;
615 bdf_property_t *prop, *fp;
616 FT_Memory memory = font->memory;
617 FT_Error error = FT_Err_Ok;
618
619 FT_UNUSED( lineno ); /* only used in debug mode */
620
621
622 /* First, check whether the property already exists in the font. */
623 if ( ( propid = ft_hash_str_lookup( name, font->internal ) ) != NULL )
624 {
625 /* The property already exists in the font, so simply replace */
626 /* the value of the property with the current value. */
627 fp = font->props + *propid;
628
629 switch ( fp->format )
630 {
631 case BDF_ATOM:
632 /* Delete the current atom if it exists. */
633 FT_FREE( fp->value.atom );
634
635 if ( value && value[0] != 0 )
636 {
637 if ( FT_STRDUP( fp->value.atom, value ) )
638 goto Exit;
639 }
640 break;
641
642 case BDF_INTEGER:
643 fp->value.l = bdf_atol_( value );
644 break;
645
646 case BDF_CARDINAL:
647 fp->value.ul = bdf_atoul_( value );
648 break;
649
650 default:
651 ;
652 }
653
654 goto Exit;
655 }
656
657 /* See whether this property type exists yet or not. */
658 /* If not, create it. */
659 propid = ft_hash_str_lookup( name, &(font->proptbl) );
660 if ( !propid )
661 {
662 error = bdf_create_property( name, BDF_ATOM, font );
663 if ( error )
664 goto Exit;
665 propid = ft_hash_str_lookup( name, &(font->proptbl) );
666 }
667
668 /* Allocate another property if this is overflowing. */
669 if ( font->props_used == font->props_size )
670 {
671 if ( FT_QRENEW_ARRAY( font->props,
672 font->props_size,
673 font->props_size + 1 ) )
674 goto Exit;
675
676 font->props_size++;
677 }
678
679 if ( *propid >= num_bdf_properties_ )
680 prop = font->user_props + ( *propid - num_bdf_properties_ );
681 else
682 prop = (bdf_property_t*)bdf_properties_ + *propid;
683
684 fp = font->props + font->props_used;
685
686 fp->name = prop->name;
687 fp->format = prop->format;
688 fp->builtin = prop->builtin;
689
690 switch ( prop->format )
691 {
692 case BDF_ATOM:
693 fp->value.atom = NULL;
694 if ( value && value[0] )
695 {
696 if ( FT_STRDUP( fp->value.atom, value ) )
697 goto Exit;
698 }
699 break;
700
701 case BDF_INTEGER:
702 fp->value.l = bdf_atol_( value );
703 break;
704
705 case BDF_CARDINAL:
706 fp->value.ul = bdf_atoul_( value );
707 break;
708 }
709
710 /* Add the property to the font property table. */
711 error = ft_hash_str_insert( fp->name,
712 font->props_used,
713 font->internal,
714 memory );
715 if ( error )
716 goto Exit;
717
718 font->props_used++;
719
720 Exit:
721 return error;
722 }
723
724
725 static FT_Error
726 bdf_parse_end_( char* line,
727 unsigned long linelen,
728 unsigned long lineno,
729 bdf_parse_t_* p,
730 void* next )
731 {
732 /* a no-op; we ignore everything after `ENDFONT' */
733
734 FT_UNUSED( line );
735 FT_UNUSED( linelen );
736 FT_UNUSED( lineno );
737 FT_UNUSED( p );
738 FT_UNUSED( next );
739
740 return FT_Err_Ok;
741 }
742
743
744 /* Line function prototypes. */
745 static FT_Error
746 bdf_parse_start_( char* line,
747 unsigned long linelen,
748 unsigned long lineno,
749 bdf_parse_t_* p,
750 void* next );
751
752
753 static FT_Error
754 bdf_parse_glyphs_( char* line,
755 unsigned long linelen,
756 unsigned long lineno,
757 bdf_parse_t_* p,
758 void* next );
759
760
761 /* Aggressively parse the glyph bitmaps. */
762 static FT_Error
763 bdf_parse_bitmap_( char* line,
764 unsigned long linelen,
765 unsigned long lineno,
766 bdf_parse_t_* p,
767 void* next )
768 {
769 bdf_glyph_t* glyph = p->glyph;
770 unsigned char* bp;
771 unsigned long i, nibbles;
772 int x;
773
774 FT_UNUSED( lineno ); /* only used in debug mode */
775
776
777 nibbles = glyph->bpr << 1;
778 bp = glyph->bitmap + p->row * glyph->bpr;
779
780 if ( nibbles > linelen )
781 {
782 FT_TRACE2(( "bdf_parse_bitmap_: " ACMSG16, glyph->encoding ));
783 nibbles = linelen;
784 }
785
786 for ( i = 0; i < nibbles; i++ )
787 {
788 /* char to hex without checks */
789 x = line[i];
790 x += 9 * ( x & 0x40 ) >> 6; /* for [A-Fa-f] */
791 x &= 0x0F;
792
793 if ( i & 1 )
794 *bp++ |= x;
795 else
796 *bp = (unsigned char)( x << 4 );
797 }
798
799 p->row++;
800
801 /* When done, go back to parsing glyphs */
802 if ( p->row >= (unsigned long)glyph->bbx.height )
803 *(bdf_line_func_t_*)next = bdf_parse_glyphs_;
804
805 return FT_Err_Ok;
806 }
807
808
809 /* Actually parse the glyph info. */
810 static FT_Error
811 bdf_parse_glyphs_( char* line,
812 unsigned long linelen,
813 unsigned long lineno,
814 bdf_parse_t_* p,
815 void* next )
816 {
817 bdf_font_t* font = p->font;
818 bdf_glyph_t* glyph;
819 FT_Memory memory = font->memory;
820 FT_Error error = FT_Err_Ok;
821
822 FT_UNUSED( lineno ); /* only used in debug mode */
823
824
825 /* Check for a comment. */
826 if ( ft_strncmp( line, "COMMENT", 7 ) == 0 )
827 {
828 if ( p->flags & BDF_KEEP_COMMENTS )
829 error = bdf_add_comment_( font, line, linelen );
830
831 goto Exit;
832 }
833
834 /* Check for the ENDFONT field. */
835 if ( ft_strncmp( line, "ENDFONT", 7 ) == 0 )
836 {
837 if ( p->flags & BDF_GLYPH_BITS_ )
838 {
839 /* Missing ENDCHAR field. */
840 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" ));
841 error = FT_THROW( Corrupted_Font_Glyphs );
842 goto Exit;
843 }
844
845 /* Sort the glyphs by encoding. */
846 ft_qsort( (char *)font->glyphs,
847 font->glyphs_used,
848 sizeof ( bdf_glyph_t ),
849 by_encoding );
850
851 p->flags &= ~BDF_START_;
852
853 *(bdf_line_func_t_*)next = bdf_parse_end_;
854
855 goto Exit;
856 }
857
858 /* Check for the ENDCHAR field. */
859 if ( ft_strncmp( line, "ENDCHAR", 7 ) == 0 )
860 {
861 /* Free unused glyph_name */
862 FT_FREE( p->glyph_name );
863
864 p->glyph_enc = 0;
865 p->flags &= ~BDF_GLYPH_BITS_;
866
867 goto Exit;
868 }
869
870 /* Check whether a glyph is being scanned but should be */
871 /* ignored because it is an unencoded glyph. */
872 if ( p->flags & BDF_GLYPH_ &&
873 p->glyph_enc == -1 &&
874 !( p->flags & BDF_KEEP_UNENCODED ) )
875 goto Exit;
876
877 /* Check for the STARTCHAR field. */
878 if ( ft_strncmp( line, "STARTCHAR ", 10 ) == 0 )
879 {
880 if ( p->flags & BDF_GLYPH_BITS_ )
881 {
882 /* Missing ENDCHAR field. */
883 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" ));
884 error = FT_THROW( Missing_Startchar_Field );
885 goto Exit;
886 }
887
888 line = bdf_strtok_( line, ' ' );
889
890 if ( FT_STRDUP( p->glyph_name, line ) )
891 goto Exit;
892
893 p->flags |= BDF_GLYPH_;
894
895 FT_TRACE4(( DBGMSG1, lineno, line ));
896
897 goto Exit;
898 }
899
900 /* Check for the ENCODING field. */
901 if ( ft_strncmp( line, "ENCODING ", 9 ) == 0 )
902 {
903 if ( !( p->flags & BDF_GLYPH_ ) )
904 {
905 /* Missing STARTCHAR field. */
906 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "STARTCHAR" ));
907 error = FT_THROW( Missing_Startchar_Field );
908 goto Exit;
909 }
910
911 line = bdf_strtok_( line, ' ' );
912
913 p->glyph_enc = bdf_atol_( line );
914
915 /* Normalize negative encoding values. The specification only */
916 /* allows -1, but we can be more generous here. */
917 if ( p->glyph_enc < -1 )
918 p->glyph_enc = -1;
919
920 /* Check for alternative encoding format. */
921 line = bdf_strtok_( line, ' ' );
922
923 if ( p->glyph_enc == -1 && *line )
924 p->glyph_enc = bdf_atol_( line );
925
926 if ( p->glyph_enc < -1 || p->glyph_enc >= 0x110000L )
927 p->glyph_enc = -1;
928
929 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
930
931 if ( p->glyph_enc >= 0 )
932 {
933 /* Make sure there are enough glyphs allocated in case the */
934 /* number of characters happen to be wrong. */
935 if ( font->glyphs_used == font->glyphs_size )
936 {
937 if ( FT_RENEW_ARRAY( font->glyphs,
938 font->glyphs_size,
939 font->glyphs_size + 64 ) )
940 goto Exit;
941
942 font->glyphs_size += 64;
943 }
944
945 glyph = font->glyphs + font->glyphs_used++;
946 glyph->name = p->glyph_name;
947 glyph->encoding = (unsigned long)p->glyph_enc;
948 }
949 else if ( p->flags & BDF_KEEP_UNENCODED )
950 {
951 /* Allocate the next unencoded glyph. */
952 if ( font->unencoded_used == font->unencoded_size )
953 {
954 if ( FT_RENEW_ARRAY( font->unencoded ,
955 font->unencoded_size,
956 font->unencoded_size + 4 ) )
957 goto Exit;
958
959 font->unencoded_size += 4;
960 }
961
962 glyph = font->unencoded + font->unencoded_used;
963 glyph->name = p->glyph_name;
964 glyph->encoding = font->unencoded_used++;
965 }
966 else
967 {
968 /* Free up the glyph name if the unencoded shouldn't be */
969 /* kept. */
970 FT_FREE( p->glyph_name );
971 glyph = NULL;
972 }
973
974 p->glyph_name = NULL;
975 p->glyph = glyph;
976 p->flags |= BDF_ENCODING_;
977
978 goto Exit;
979 }
980
981 if ( !( p->flags & BDF_ENCODING_ ) )
982 goto Missing_Encoding;
983
984 /* Point at the glyph being constructed. */
985 glyph = p->glyph;
986
987 /* Expect the SWIDTH (scalable width) field next. */
988 if ( ft_strncmp( line, "SWIDTH ", 7 ) == 0 )
989 {
990 line = bdf_strtok_( line, ' ' );
991 glyph->swidth = bdf_atous_( line );
992
993 p->flags |= BDF_SWIDTH_;
994 goto Exit;
995 }
996
997 /* Expect the DWIDTH (device width) field next. */
998 if ( ft_strncmp( line, "DWIDTH ", 7 ) == 0 )
999 {
1000 line = bdf_strtok_( line, ' ' );
1001 glyph->dwidth = bdf_atous_( line );
1002
1003 if ( !( p->flags & BDF_SWIDTH_ ) )
1004 {
1005 /* Missing SWIDTH field. Emit an auto correction message and set */
1006 /* the scalable width from the device width. */
1007 FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG9, lineno ));
1008
1009 glyph->swidth = (unsigned short)FT_MulDiv(
1010 glyph->dwidth, 72000L,
1011 (FT_Long)( font->point_size *
1012 font->resolution_x ) );
1013 }
1014
1015 p->flags |= BDF_DWIDTH_;
1016 goto Exit;
1017 }
1018
1019 /* Do not leak the bitmap or reset its size */
1020 if ( p->flags & BDF_BITMAP_ )
1021 goto Exit;
1022
1023 /* Expect the BBX field next. */
1024 if ( ft_strncmp( line, "BBX ", 4 ) == 0 )
1025 {
1026 line = bdf_strtok_( line, ' ' );
1027 glyph->bbx.width = bdf_atous_( line );
1028 line = bdf_strtok_( line, ' ' );
1029 glyph->bbx.height = bdf_atous_( line );
1030 line = bdf_strtok_( line, ' ' );
1031 glyph->bbx.x_offset = bdf_atos_( line );
1032 line = bdf_strtok_( line, ' ' );
1033 glyph->bbx.y_offset = bdf_atos_( line );
1034
1035 /* Generate the ascent and descent of the character. */
1036 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1037 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
1038
1039 /* Determine the overall font bounding box as the characters are */
1040 /* loaded so corrections can be done later if indicated. */
1041 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1042 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
1043
1044 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
1045
1046 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1047 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1048 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
1049
1050 if ( !( p->flags & BDF_DWIDTH_ ) )
1051 {
1052 /* Missing DWIDTH field. Emit an auto correction message and set */
1053 /* the device width to the glyph width. */
1054 FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG10, lineno ));
1055 glyph->dwidth = glyph->bbx.width;
1056 }
1057
1058 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1059 /* value if necessary. */
1060 if ( p->flags & BDF_CORRECT_METRICS )
1061 {
1062 /* Determine the point size of the glyph. */
1063 unsigned short sw = (unsigned short)FT_MulDiv(
1064 glyph->dwidth, 72000L,
1065 (FT_Long)( font->point_size *
1066 font->resolution_x ) );
1067
1068
1069 if ( sw != glyph->swidth )
1070 {
1071 glyph->swidth = sw;
1072
1073 FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG8 ));
1074 }
1075 }
1076
1077 p->flags |= BDF_BBX_;
1078 goto Exit;
1079 }
1080
1081 /* And finally, gather up the bitmap. */
1082 if ( ft_strncmp( line, "BITMAP", 6 ) == 0 )
1083 {
1084 unsigned long bitmap_size;
1085
1086
1087 if ( !( p->flags & BDF_BBX_ ) )
1088 {
1089 /* Missing BBX field. */
1090 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "BBX" ));
1091 error = FT_THROW( Missing_Bbx_Field );
1092 goto Exit;
1093 }
1094
1095 /* Allocate enough space for the bitmap. */
1096 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
1097
1098 bitmap_size = glyph->bpr * glyph->bbx.height;
1099 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
1100 {
1101 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG4, lineno ));
1102 error = FT_THROW( Bbx_Too_Big );
1103 goto Exit;
1104 }
1105 else
1106 glyph->bytes = (unsigned short)bitmap_size;
1107
1108 if ( !bitmap_size || FT_ALLOC( glyph->bitmap, glyph->bytes ) )
1109 goto Exit;
1110
1111 p->row = 0;
1112 p->flags |= BDF_BITMAP_;
1113 *(bdf_line_func_t_*)next = bdf_parse_bitmap_;
1114
1115 goto Exit;
1116 }
1117
1118 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG9, lineno ));
1119 error = FT_THROW( Invalid_File_Format );
1120 goto Exit;
1121
1122 Missing_Encoding:
1123 /* Missing ENCODING field. */
1124 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENCODING" ));
1125 error = FT_THROW( Missing_Encoding_Field );
1126
1127 Exit:
1128 if ( error && ( p->flags & BDF_GLYPH_ ) )
1129 FT_FREE( p->glyph_name );
1130
1131 return error;
1132 }
1133
1134
1135 /* Load the font properties. */
1136 static FT_Error
1137 bdf_parse_properties_( char* line,
1138 unsigned long linelen,
1139 unsigned long lineno,
1140 bdf_parse_t_* p,
1141 void* next )
1142 {
1143 bdf_font_t* font = p->font;
1144 FT_Error error = FT_Err_Ok;
1145 char* name;
1146 char* value;
1147
1148 FT_UNUSED( lineno );
1149
1150
1151 /* Check for a comment. */
1152 if ( ft_strncmp( line, "COMMENT", 7 ) == 0 )
1153 {
1154 if ( p->flags & BDF_KEEP_COMMENTS )
1155 error = bdf_add_comment_( font, line, linelen );
1156
1157 goto Exit;
1158 }
1159
1160 /* Check for the end of the properties. */
1161 if ( ft_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
1162 {
1163 *(bdf_line_func_t_*)next = bdf_parse_start_;
1164
1165 goto Exit;
1166 }
1167
1168 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1169 if ( ft_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1170 goto Exit;
1171
1172 if ( bdf_is_atom_( line, linelen, &name, &value, p->font ) )
1173 {
1174 error = bdf_add_property_( font, name, value, lineno );
1175 if ( error )
1176 goto Exit;
1177 }
1178 else
1179 {
1180 value = bdf_strtok_( line, ' ' );
1181
1182 error = bdf_add_property_( font, line, value, lineno );
1183 if ( error )
1184 goto Exit;
1185 }
1186
1187 Exit:
1188 return error;
1189 }
1190
1191
1192 /* Load the font header. */
1193 static FT_Error
1194 bdf_parse_start_( char* line,
1195 unsigned long linelen,
1196 unsigned long lineno,
1197 bdf_parse_t_* p,
1198 void* next )
1199 {
1200 bdf_font_t* font;
1201 FT_Memory memory = p->memory;
1202 FT_Error error = FT_Err_Ok;
1203
1204 FT_UNUSED( lineno ); /* only used in debug mode */
1205
1206
1207 /* The first line must be STARTFONT. */
1208 /* Otherwise, reject the font immediately. */
1209 if ( !( p->flags & BDF_START_ ) )
1210 {
1211 if ( ft_strncmp( line, "STARTFONT", 9 ) != 0 )
1212 {
1213 error = FT_THROW( Missing_Startfont_Field );
1214 goto Exit;
1215 }
1216
1217 p->flags |= BDF_START_;
1218
1219 if ( FT_NEW( p->font ) )
1220 goto Exit;
1221
1222 p->font->memory = memory;
1223
1224 goto Exit;
1225 }
1226
1227 /* Point at the font being constructed. */
1228 font = p->font;
1229
1230 /* Check for a comment. */
1231 if ( ft_strncmp( line, "COMMENT", 7 ) == 0 )
1232 {
1233 if ( p->flags & BDF_KEEP_COMMENTS )
1234 error = bdf_add_comment_( font, line, linelen );
1235
1236 goto Exit;
1237 }
1238
1239 /* Check for the start of the properties. */
1240 if ( !( p->flags & BDF_PROPS_ ) &&
1241 ft_strncmp( line, "STARTPROPERTIES ", 16 ) == 0 )
1242 {
1243 line = bdf_strtok_( line, ' ' );
1244 font->props_size = bdf_atoul_( line );
1245
1246 if ( font->props_size < 2 )
1247 font->props_size = 2;
1248
1249 /* We need at least 4 bytes per property. */
1250 if ( font->props_size > p->size / 4 )
1251 {
1252 font->props_size = 0;
1253
1254 FT_ERROR(( "bdf_parse_start_: " ERRMSG5, lineno, "STARTPROPERTIES" ));
1255 error = FT_THROW( Invalid_Argument );
1256 goto Exit;
1257 }
1258
1259 if ( FT_NEW_ARRAY( font->props, font->props_size ) )
1260 {
1261 font->props_size = 0;
1262 goto Exit;
1263 }
1264
1265 if ( FT_QNEW( font->internal ) )
1266 goto Exit;
1267 error = ft_hash_str_init( font->internal, memory );
1268 if ( error )
1269 goto Exit;
1270
1271 /* preset common properties */
1272 {
1273 bdf_property_t* prop = (bdf_property_t*)bdf_properties_;
1274 FT_Hash proptbl = &font->proptbl;
1275 size_t i;
1276
1277
1278 error = ft_hash_str_init( proptbl, memory );
1279 if ( error )
1280 goto Exit;
1281 for ( i = 0; i < num_bdf_properties_; i++, prop++ )
1282 {
1283 error = ft_hash_str_insert( prop->name, i, proptbl, memory );
1284 if ( error )
1285 goto Exit;
1286 }
1287 }
1288
1289 p->flags |= BDF_PROPS_;
1290
1291 *(bdf_line_func_t_*)next = bdf_parse_properties_;
1292
1293 goto Exit;
1294 }
1295
1296 /* Check for the FONTBOUNDINGBOX field. */
1297 if ( ft_strncmp( line, "FONTBOUNDINGBOX ", 16 ) == 0 )
1298 {
1299 line = bdf_strtok_( line, ' ' );
1300 font->bbx.width = bdf_atous_( line );
1301 line = bdf_strtok_( line, ' ' );
1302 font->bbx.height = bdf_atous_( line );
1303 line = bdf_strtok_( line, ' ' );
1304 font->bbx.x_offset = bdf_atos_( line );
1305 line = bdf_strtok_( line, ' ' );
1306 font->bbx.y_offset = bdf_atos_( line );
1307
1308 font->bbx.ascent = (short)( font->bbx.height +
1309 font->bbx.y_offset );
1310
1311 font->bbx.descent = (short)( -font->bbx.y_offset );
1312
1313 p->flags |= BDF_FONT_BBX_;
1314
1315 goto Exit;
1316 }
1317
1318 /* The next thing to check for is the FONT field. */
1319 if ( ft_strncmp( line, "FONT ", 5 ) == 0 )
1320 {
1321 int i;
1322
1323
1324 line = bdf_strtok_( line, ' ' );
1325
1326 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
1327 FT_FREE( font->name );
1328
1329 if ( FT_STRDUP( font->name, line ) )
1330 goto Exit;
1331
1332 /* If the font name is an XLFD name, set the spacing to the one in */
1333 /* the font name after the 11th dash. */
1334 for ( i = 0; i < 11; i++ )
1335 {
1336 while ( *line && *line != '-' )
1337 line++;
1338 if ( *line )
1339 line++;
1340 }
1341
1342 switch ( *line )
1343 {
1344 case 'C':
1345 case 'c':
1346 font->spacing = BDF_CHARCELL;
1347 break;
1348 case 'M':
1349 case 'm':
1350 font->spacing = BDF_MONOWIDTH;
1351 break;
1352 case 'P':
1353 case 'p':
1354 default:
1355 font->spacing = BDF_PROPORTIONAL;
1356 break;
1357 }
1358
1359 p->flags |= BDF_FONT_NAME_;
1360
1361 goto Exit;
1362 }
1363
1364 /* Check for the SIZE field. */
1365 if ( ft_strncmp( line, "SIZE ", 5 ) == 0 )
1366 {
1367 line = bdf_strtok_( line, ' ' );
1368 font->point_size = bdf_atoul_( line );
1369 line = bdf_strtok_( line, ' ' );
1370 font->resolution_x = bdf_atoul_( line );
1371 line = bdf_strtok_( line, ' ' );
1372 font->resolution_y = bdf_atoul_( line );
1373
1374 /* Check for the bits per pixel field. */
1375 line = bdf_strtok_( line, ' ' );
1376 if ( *line )
1377 {
1378 unsigned short bpp;
1379
1380
1381 bpp = bdf_atous_( line );
1382
1383 /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
1384 if ( bpp > 4 )
1385 font->bpp = 8;
1386 else if ( bpp > 2 )
1387 font->bpp = 4;
1388 else if ( bpp > 1 )
1389 font->bpp = 2;
1390 else
1391 font->bpp = 1;
1392
1393 if ( font->bpp != bpp )
1394 FT_TRACE2(( "bdf_parse_start_: " ACMSG11, font->bpp ));
1395 }
1396 else
1397 font->bpp = 1;
1398
1399 p->flags |= BDF_SIZE_;
1400
1401 goto Exit;
1402 }
1403
1404 /* Check for the CHARS field */
1405 if ( ft_strncmp( line, "CHARS ", 6 ) == 0 )
1406 {
1407 /* Check the header for completeness before parsing glyphs. */
1408 if ( !( p->flags & BDF_FONT_NAME_ ) )
1409 {
1410 /* Missing the FONT field. */
1411 FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONT" ));
1412 error = FT_THROW( Missing_Font_Field );
1413 goto Exit;
1414 }
1415 if ( !( p->flags & BDF_SIZE_ ) )
1416 {
1417 /* Missing the SIZE field. */
1418 FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "SIZE" ));
1419 error = FT_THROW( Missing_Size_Field );
1420 goto Exit;
1421 }
1422 if ( !( p->flags & BDF_FONT_BBX_ ) )
1423 {
1424 /* Missing the FONTBOUNDINGBOX field. */
1425 FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
1426 error = FT_THROW( Missing_Fontboundingbox_Field );
1427 goto Exit;
1428 }
1429
1430 line = bdf_strtok_( line, ' ' );
1431 p->cnt = font->glyphs_size = bdf_atoul_( line );
1432
1433 /* We need at least 20 bytes per glyph. */
1434 if ( p->cnt > p->size / 20 )
1435 {
1436 p->cnt = font->glyphs_size = p->size / 20;
1437 FT_TRACE2(( "bdf_parse_start_: " ACMSG17, p->cnt ));
1438 }
1439
1440 /* Make sure the number of glyphs is non-zero. */
1441 if ( p->cnt == 0 )
1442 font->glyphs_size = 64;
1443
1444 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1445 /* number of code points available in Unicode). */
1446 if ( p->cnt >= 0x110000UL )
1447 {
1448 FT_ERROR(( "bdf_parse_start_: " ERRMSG5, lineno, "CHARS" ));
1449 error = FT_THROW( Invalid_Argument );
1450 goto Exit;
1451 }
1452
1453 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1454 goto Exit;
1455
1456 p->flags |= BDF_GLYPHS_;
1457
1458 *(bdf_line_func_t_*)next = bdf_parse_glyphs_;
1459
1460 goto Exit;
1461 }
1462
1463 FT_ERROR(( "bdf_parse_start_: " ERRMSG9, lineno ));
1464 error = FT_THROW( Invalid_File_Format );
1465
1466 Exit:
1467 return error;
1468 }
1469
1470
1471 static FT_Error
1472 bdf_readstream_( FT_Stream stream,
1473 bdf_parse_t_* p,
1474 unsigned long* lno )
1475 {
1476 bdf_line_func_t_ cb = bdf_parse_start_;
1477 unsigned long lineno, buf_size;
1478 unsigned long bytes, start, end, cursor, avail;
1479 char* buf = NULL;
1480 FT_Memory memory = stream->memory;
1481 FT_Error error = FT_Err_Ok;
1482
1483
1484 /* initial size and allocation of the input buffer */
1485 buf_size = 1024;
1486
1487 if ( FT_QALLOC( buf, buf_size ) )
1488 goto Exit;
1489
1490 lineno = 1;
1491 start = 0;
1492 cursor = 0;
1493
1494 Refill:
1495 bytes = FT_Stream_TryRead( stream,
1496 (FT_Byte*)buf + cursor, buf_size - cursor );
1497 avail = cursor + bytes;
1498
1499 while ( bytes )
1500 {
1501 /* try to find the start of the line */
1502 while ( start < avail && buf[start] < ' ' )
1503 start++;
1504
1505 /* try to find the end of the line */
1506 end = start + 1;
1507 while ( end < avail && buf[end] >= ' ' )
1508 end++;
1509
1510 /* if we hit the end of the buffer, try shifting its content */
1511 /* or even resizing it */
1512 if ( end >= avail )
1513 {
1514 if ( start == 0 )
1515 {
1516 /* this line is definitely too long; try resizing the input */
1517 /* buffer a bit to handle it. */
1518 FT_ULong new_size;
1519
1520
1521 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
1522 {
1523 FT_ERROR(( "bdf_readstream_: " ERRMSG6, lineno ));
1524 error = FT_THROW( Invalid_File_Format );
1525
1526 goto Exit;
1527 }
1528
1529 new_size = buf_size * 4;
1530 if ( FT_QREALLOC( buf, buf_size, new_size ) )
1531 goto Exit;
1532
1533 cursor = avail;
1534 buf_size = new_size;
1535 }
1536 else
1537 {
1538 cursor = avail - start;
1539
1540 FT_MEM_MOVE( buf, buf + start, cursor );
1541
1542 start = 0;
1543 }
1544 goto Refill;
1545 }
1546
1547 /* NUL-terminate the line. */
1548 buf[end] = 0;
1549
1550 if ( buf[start] != '#' )
1551 {
1552 error = (*cb)( buf + start, end - start, lineno, p, (void*)&cb );
1553 if ( error )
1554 break;
1555 }
1556
1557 lineno += 1;
1558 start = end + 1;
1559 }
1560
1561 *lno = lineno;
1562
1563 Exit:
1564 FT_FREE( buf );
1565 return error;
1566 }
1567
1568
1569 /**************************************************************************
1570 *
1571 * API.
1572 *
1573 */
1574
1575
1576 FT_LOCAL_DEF( FT_Error )
1577 bdf_load_font( FT_Stream stream,
1578 FT_Memory memory,
1579 unsigned long flags,
1580 bdf_font_t* *font )
1581 {
1582 unsigned long lineno = 0; /* make compiler happy */
1583 bdf_parse_t_ *p = NULL;
1584
1585 FT_Error error = FT_Err_Ok;
1586
1587
1588 if ( FT_NEW( p ) )
1589 goto Exit;
1590
1591 p->flags = flags; /* comments, metrics, unencoded */
1592 p->minlb = 32767;
1593 p->size = stream->size;
1594 p->memory = memory; /* only during font creation */
1595
1596 error = bdf_readstream_( stream, p, &lineno );
1597 if ( error )
1598 goto Fail;
1599
1600 if ( p->font )
1601 {
1602 /* If the number of glyphs loaded is not that of the original count, */
1603 /* indicate the difference. */
1604 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
1605 {
1606 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
1607 p->font->glyphs_used + p->font->unencoded_used ));
1608 }
1609
1610 /* Once the font has been loaded, adjust the overall font metrics if */
1611 /* necessary. */
1612 if ( p->flags & BDF_CORRECT_METRICS &&
1613 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
1614 {
1615 if ( p->maxrb - p->minlb != p->font->bbx.width )
1616 {
1617 FT_TRACE2(( "bdf_load_font: " ACMSG3,
1618 p->font->bbx.width, p->maxrb - p->minlb ));
1619 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
1620 }
1621
1622 if ( p->font->bbx.x_offset != p->minlb )
1623 {
1624 FT_TRACE2(( "bdf_load_font: " ACMSG4,
1625 p->font->bbx.x_offset, p->minlb ));
1626 p->font->bbx.x_offset = p->minlb;
1627 }
1628
1629 if ( p->font->bbx.ascent != p->maxas )
1630 {
1631 FT_TRACE2(( "bdf_load_font: " ACMSG5,
1632 p->font->bbx.ascent, p->maxas ));
1633 p->font->bbx.ascent = p->maxas;
1634 }
1635
1636 if ( p->font->bbx.descent != p->maxds )
1637 {
1638 FT_TRACE2(( "bdf_load_font: " ACMSG6,
1639 p->font->bbx.descent, p->maxds ));
1640 p->font->bbx.descent = p->maxds;
1641 p->font->bbx.y_offset = (short)( -p->maxds );
1642 }
1643
1644 if ( p->maxas + p->maxds != p->font->bbx.height )
1645 {
1646 FT_TRACE2(( "bdf_load_font: " ACMSG7,
1647 p->font->bbx.height, p->maxas + p->maxds ));
1648 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
1649 }
1650 }
1651 }
1652
1653 if ( p->flags & BDF_START_ )
1654 {
1655 /* The ENDFONT field was never reached or did not exist. */
1656 if ( !( p->flags & BDF_GLYPHS_ ) )
1657 {
1658 /* Error happened while parsing header. */
1659 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
1660 error = FT_THROW( Corrupted_Font_Header );
1661 goto Fail;
1662 }
1663 else
1664 {
1665 /* Error happened when parsing glyphs. */
1666 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
1667 error = FT_THROW( Corrupted_Font_Glyphs );
1668 goto Fail;
1669 }
1670 }
1671
1672 if ( !p->font && !error )
1673 error = FT_THROW( Invalid_File_Format );
1674
1675 *font = p->font;
1676
1677 Exit:
1678 if ( p )
1679 {
1680 FT_FREE( p->glyph_name );
1681 FT_FREE( p );
1682 }
1683
1684 return error;
1685
1686 Fail:
1687 bdf_free_font( p->font );
1688
1689 FT_FREE( p->font );
1690
1691 goto Exit;
1692 }
1693
1694
1695 FT_LOCAL_DEF( void )
1696 bdf_free_font( bdf_font_t* font )
1697 {
1698 bdf_property_t* prop;
1699 unsigned long i;
1700 bdf_glyph_t* glyphs;
1701 FT_Memory memory;
1702
1703
1704 if ( font == NULL )
1705 return;
1706
1707 memory = font->memory;
1708
1709 FT_FREE( font->name );
1710
1711 /* Free up the internal hash table of property names. */
1712 if ( font->internal )
1713 {
1714 ft_hash_str_free( font->internal, memory );
1715 FT_FREE( font->internal );
1716 }
1717
1718 /* Free up the comment info. */
1719 FT_FREE( font->comments );
1720
1721 /* Free up the properties. */
1722 for ( i = 0; i < font->props_size; i++ )
1723 {
1724 if ( font->props[i].format == BDF_ATOM )
1725 FT_FREE( font->props[i].value.atom );
1726 }
1727
1728 FT_FREE( font->props );
1729
1730 /* Free up the character info. */
1731 for ( i = 0, glyphs = font->glyphs;
1732 i < font->glyphs_used; i++, glyphs++ )
1733 {
1734 FT_FREE( glyphs->name );
1735 FT_FREE( glyphs->bitmap );
1736 }
1737
1738 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
1739 i++, glyphs++ )
1740 {
1741 FT_FREE( glyphs->name );
1742 FT_FREE( glyphs->bitmap );
1743 }
1744
1745 FT_FREE( font->glyphs );
1746 FT_FREE( font->unencoded );
1747
1748 /* bdf_cleanup */
1749 ft_hash_str_free( &(font->proptbl), memory );
1750
1751 /* Free up the user defined properties. */
1752 for ( prop = font->user_props, i = 0;
1753 i < font->nuser_props; i++, prop++ )
1754 FT_FREE( prop->name );
1755
1756 FT_FREE( font->user_props );
1757
1758 /* FREE( font ); */ /* XXX Fixme */
1759 }
1760
1761
1762 FT_LOCAL_DEF( bdf_property_t * )
1763 bdf_get_font_property( bdf_font_t* font,
1764 const char* name )
1765 {
1766 size_t* propid;
1767
1768
1769 if ( font == NULL || font->props_size == 0 || name == NULL || *name == 0 )
1770 return 0;
1771
1772 propid = ft_hash_str_lookup( name, font->internal );
1773
1774 return propid ? ( font->props + *propid ) : NULL;
1775 }
1776
1777
1778/* END */