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>
36#include <freetype/internal/ftdebug.h>
37#include <freetype/internal/ftstream.h>
38#include <freetype/internal/ftobjs.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#define BUFSIZE 128
55
56
57 /**************************************************************************
58 *
59 * Default BDF font options.
60 *
61 */
62
63
64 static const bdf_options_t bdf_opts_ =
65 {
66 1, /* Correct metrics. */
67 1, /* Preserve unencoded glyphs. */
68 0, /* Preserve comments. */
69 BDF_PROPORTIONAL /* Default spacing. */
70 };
71
72
73 /**************************************************************************
74 *
75 * Builtin BDF font properties.
76 *
77 */
78
79 /* List of most properties that might appear in a font. Doesn't include */
80 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
81
82 static const bdf_property_t bdf_properties_[] =
83 {
84 { "ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
85 { "AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
86 { "AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
87 { "AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
88 { "CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
89 { "CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
90 { "CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
91 { "CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
92 { "COMMENT", BDF_ATOM, 1, { 0 } },
93 { "COPYRIGHT", BDF_ATOM, 1, { 0 } },
94 { "DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
95 { "DESTINATION", BDF_CARDINAL, 1, { 0 } },
96 { "DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
97 { "END_SPACE", BDF_INTEGER, 1, { 0 } },
98 { "FACE_NAME", BDF_ATOM, 1, { 0 } },
99 { "FAMILY_NAME", BDF_ATOM, 1, { 0 } },
100 { "FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
101 { "FONT", BDF_ATOM, 1, { 0 } },
102 { "FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
103 { "FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
104 { "FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
105 { "FOUNDRY", BDF_ATOM, 1, { 0 } },
106 { "FULL_NAME", BDF_ATOM, 1, { 0 } },
107 { "ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
108 { "MAX_SPACE", BDF_INTEGER, 1, { 0 } },
109 { "MIN_SPACE", BDF_INTEGER, 1, { 0 } },
110 { "NORM_SPACE", BDF_INTEGER, 1, { 0 } },
111 { "NOTICE", BDF_ATOM, 1, { 0 } },
112 { "PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
113 { "POINT_SIZE", BDF_INTEGER, 1, { 0 } },
114 { "QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
115 { "RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
116 { "RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
117 { "RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
118 { "RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
119 { "RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
120 { "RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
121 { "RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
122 { "RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
123 { "RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
124 { "RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
125 { "RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
126 { "RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
127 { "RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
128 { "RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
129 { "RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
130 { "RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
131 { "RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
132 { "RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
133 { "RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
134 { "RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
135 { "RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
136 { "RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
137 { "RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
138 { "RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
139 { "RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
140 { "RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
141 { "RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
142 { "RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
143 { "RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
144 { "RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
145 { "RESOLUTION", BDF_INTEGER, 1, { 0 } },
146 { "RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
147 { "RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
148 { "SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
149 { "SLANT", BDF_ATOM, 1, { 0 } },
150 { "SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
151 { "SPACING", BDF_ATOM, 1, { 0 } },
152 { "STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
153 { "STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
154 { "SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
155 { "SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
156 { "SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
157 { "SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
158 { "SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
159 { "SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
160 { "UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
161 { "UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
162 { "WEIGHT", BDF_CARDINAL, 1, { 0 } },
163 { "WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
164 { "X_HEIGHT", BDF_INTEGER, 1, { 0 } },
165 { "_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
166 { "_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
167 };
168
169 static const unsigned long
170 num_bdf_properties_ = sizeof ( bdf_properties_ ) /
171 sizeof ( bdf_properties_[0] );
172
173
174 /* An auxiliary macro to parse properties, to be used in conditionals. */
175 /* It behaves like `strncmp' but also tests the following character */
176 /* whether it is a whitespace or null. */
177 /* `property' is a constant string of length `n' to compare with. */
178#define _bdf_strncmp( name, property, n ) \
179 ( ft_strncmp( name, property, n ) || \
180 !( name[n] == ' ' || \
181 name[n] == '\0' || \
182 name[n] == '\n' || \
183 name[n] == '\r' || \
184 name[n] == '\t' ) )
185
186 /* Auto correction messages. */
187#define ACMSG1 "FONT_ASCENT property missing. " \
188 "Added `FONT_ASCENT %hd'.\n"
189#define ACMSG2 "FONT_DESCENT property missing. " \
190 "Added `FONT_DESCENT %hd'.\n"
191#define ACMSG3 "Font width != actual width. Old: %d New: %d.\n"
192#define ACMSG4 "Font left bearing != actual left bearing. " \
193 "Old: %hd New: %hd.\n"
194#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
195#define ACMSG6 "Font descent != actual descent. Old: %d New: %d.\n"
196#define ACMSG7 "Font height != actual height. Old: %d New: %d.\n"
197#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
198#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
199#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
200#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
201#define ACMSG13 "Glyph %lu extra rows removed.\n"
202#define ACMSG14 "Glyph %lu extra columns removed.\n"
203#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
204#define ACMSG16 "Glyph %lu missing columns padded with zero bits.\n"
205#define ACMSG17 "Adjusting number of glyphs to %ld.\n"
206
207 /* Error messages. */
208#define ERRMSG1 "[line %ld] Missing `%s' line.\n"
209#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
210#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
211#define ERRMSG4 "[line %ld] BBX too big.\n"
212#define ERRMSG5 "[line %ld] `%s' value too big.\n"
213#define ERRMSG6 "[line %ld] Input line too long.\n"
214#define ERRMSG7 "[line %ld] Font name too long.\n"
215#define ERRMSG8 "[line %ld] Invalid `%s' value.\n"
216#define ERRMSG9 "[line %ld] Invalid keyword.\n"
217
218 /* Debug messages. */
219#define DBGMSG1 " [%6ld] %s" /* no \n */
220#define DBGMSG2 " (0x%lX)\n"
221
222
223 /**************************************************************************
224 *
225 * Utility types and functions.
226 *
227 */
228
229
230 /* Function type for parsing lines of a BDF font. */
231
232 typedef FT_Error
233 (*bdf_line_func_t_)( char* line,
234 unsigned long linelen,
235 unsigned long lineno,
236 void* call_data,
237 void* client_data );
238
239
240 /* List structure for splitting lines into fields. */
241
242 typedef struct bdf_list_t__
243 {
244 char** field;
245 unsigned long size;
246 unsigned long used;
247 FT_Memory memory;
248
249 } bdf_list_t_;
250
251
252 /* Structure used while loading BDF fonts. */
253
254 typedef struct bdf_parse_t__
255 {
256 unsigned long flags;
257 unsigned long cnt;
258 unsigned long row;
259
260 short minlb;
261 short maxlb;
262 short maxrb;
263 short maxas;
264 short maxds;
265
266 short rbearing;
267
268 char* glyph_name;
269 long glyph_enc;
270
271 bdf_font_t* font;
272 bdf_options_t* opts;
273
274 bdf_list_t_ list;
275
276 FT_Memory memory;
277 unsigned long size; /* the stream size */
278
279 } bdf_parse_t_;
280
281
282#define setsbit( m, cc ) \
283 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
284#define sbitset( m, cc ) \
285 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
286
287
288 static void
289 bdf_list_init_( bdf_list_t_* list,
290 FT_Memory memory )
291 {
292 FT_ZERO( list );
293 list->memory = memory;
294 }
295
296
297 static void
298 bdf_list_done_( bdf_list_t_* list )
299 {
300 FT_Memory memory = list->memory;
301
302
303 if ( memory )
304 {
305 FT_FREE( list->field );
306 FT_ZERO( list );
307 }
308 }
309
310
311 static FT_Error
312 bdf_list_ensure_( bdf_list_t_* list,
313 unsigned long num_items ) /* same as bdf_list_t_.used */
314 {
315 FT_Error error = FT_Err_Ok;
316
317
318 if ( num_items > list->size )
319 {
320 unsigned long oldsize = list->size; /* same as bdf_list_t_.size */
321 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 5;
322 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
323 FT_Memory memory = list->memory;
324
325
326 if ( oldsize == bigsize )
327 {
328 error = FT_THROW( Out_Of_Memory );
329 goto Exit;
330 }
331 else if ( newsize < oldsize || newsize > bigsize )
332 newsize = bigsize;
333
334 if ( FT_QRENEW_ARRAY( list->field, oldsize, newsize ) )
335 goto Exit;
336
337 list->size = newsize;
338 }
339
340 Exit:
341 return error;
342 }
343
344
345 static void
346 bdf_list_shift_( bdf_list_t_* list,
347 unsigned long n )
348 {
349 unsigned long i, u;
350
351
352 if ( list == NULL || list->used == 0 || n == 0 )
353 return;
354
355 if ( n >= list->used )
356 {
357 list->used = 0;
358 return;
359 }
360
361 for ( u = n, i = 0; u < list->used; i++, u++ )
362 list->field[i] = list->field[u];
363 list->used -= n;
364 }
365
366
367 /* An empty string for empty fields. */
368
369 static const char empty[] = ""; /* XXX eliminate this */
370
371
372 static char *
373 bdf_list_join_( bdf_list_t_* list,
374 int c,
375 unsigned long *alen )
376 {
377 unsigned long i, j;
378 char* dp;
379
380
381 *alen = 0;
382
383 if ( list == NULL || list->used == 0 )
384 return NULL;
385
386 dp = list->field[0];
387 for ( i = j = 0; i < list->used; i++ )
388 {
389 char* fp = list->field[i];
390
391
392 while ( *fp )
393 dp[j++] = *fp++;
394
395 if ( i + 1 < list->used )
396 dp[j++] = (char)c;
397 }
398 if ( dp != empty )
399 dp[j] = 0;
400
401 *alen = j;
402 return dp;
403 }
404
405
406 /* The code below ensures that we have at least 4 + 1 `field' */
407 /* elements in `list' (which are possibly NULL) so that we */
408 /* don't have to check the number of fields in most cases. */
409
410 static FT_Error
411 bdf_list_split_( bdf_list_t_* list,
412 const char* separators,
413 char* line,
414 unsigned long linelen )
415 {
416 unsigned long final_empty;
417 int mult;
418 const char *sp, *end;
419 char *ep;
420 char seps[32];
421 FT_Error error = FT_Err_Ok;
422
423
424 /* Initialize the list. */
425 list->used = 0;
426 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;
432 list->field[4] = (char*)empty;
433 }
434
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 == NULL || *separators == 0 )
443 {
444 error = FT_THROW( Invalid_Argument );
445 goto Exit;
446 }
447
448 /* Prepare the separator bitmap. */
449 FT_MEM_ZERO( seps, 32 );
450
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;
458 else
459 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 )
472 {
473 error = bdf_list_ensure_( list, list->used + 1 );
474 if ( error )
475 goto Exit;
476 }
477
478 /* Assign the field appropriately. */
479 list->field[list->used++] = ( ep > sp ) ? (char*)sp : (char*)empty;
480
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;
497 }
498
499 /* Finally, NULL-terminate the list. */
500 if ( list->used + final_empty >= list->size )
501 {
502 error = bdf_list_ensure_( list, list->used + final_empty + 1 );
503 if ( error )
504 goto Exit;
505 }
506
507 if ( final_empty )
508 list->field[list->used++] = (char*)empty;
509
510 list->field[list->used] = NULL;
511
512 Exit:
513 return error;
514 }
515
516
517#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
518
519
520 static FT_Error
521 bdf_readstream_( FT_Stream stream,
522 bdf_line_func_t_ callback,
523 void* client_data,
524 unsigned long *lno )
525 {
526 bdf_line_func_t_ cb;
527 unsigned long lineno, buf_size;
528 int refill, hold, to_skip;
529 ptrdiff_t bytes, start, end, cursor, avail;
530 char* buf = NULL;
531 FT_Memory memory = stream->memory;
532 FT_Error error = FT_Err_Ok;
533
534
535 if ( callback == NULL )
536 {
537 error = FT_THROW( Invalid_Argument );
538 goto Exit;
539 }
540
541 /* initial size and allocation of the input buffer */
542 buf_size = 1024;
543
544 if ( FT_QALLOC( buf, buf_size ) )
545 goto Exit;
546
547 cb = callback;
548 lineno = 1;
549 buf[0] = 0;
550 start = 0;
551 avail = 0;
552 cursor = 0;
553 refill = 1;
554 to_skip = NO_SKIP;
555 bytes = 0; /* make compiler happy */
556
557 for (;;)
558 {
559 if ( refill )
560 {
561 bytes = (ptrdiff_t)FT_Stream_TryRead(
562 stream, (FT_Byte*)buf + cursor,
563 buf_size - (unsigned long)cursor );
564 avail = cursor + bytes;
565 cursor = 0;
566 refill = 0;
567 }
568
569 end = start;
570
571 /* should we skip an optional character like \n or \r? */
572 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
583 /* if we hit the end of the buffer, try shifting its content */
584 /* or even resizing it */
585 if ( end >= avail )
586 {
587 if ( bytes == 0 )
588 {
589 /* last line in file doesn't end in \r or \n; */
590 /* ignore it then exit */
591 if ( lineno == 1 )
592 error = FT_THROW( Missing_Startfont_Field );
593 break;
594 }
595
596 if ( start == 0 )
597 {
598 /* this line is definitely too long; try resizing the input */
599 /* buffer a bit to handle it. */
600 FT_ULong new_size;
601
602
603 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
604 {
605 if ( lineno == 1 )
606 error = FT_THROW( Missing_Startfont_Field );
607 else
608 {
609 FT_ERROR(( "bdf_readstream_: " ERRMSG6, lineno ));
610 error = FT_THROW( Invalid_Argument );
611 }
612 goto Exit;
613 }
614
615 new_size = buf_size * 2;
616 if ( FT_QREALLOC( buf, buf_size, new_size ) )
617 goto Exit;
618
619 cursor = avail;
620 buf_size = new_size;
621 }
622 else
623 {
624 bytes = avail - start;
625
626 FT_MEM_MOVE( buf, buf + start, bytes );
627
628 cursor = bytes;
629 start = 0;
630 }
631 refill = 1;
632 continue;
633 }
634
635 /* Temporarily NUL-terminate the line. */
636 hold = buf[end];
637 buf[end] = 0;
638
639 /* XXX: Use encoding independent value for 0x1A */
640 if ( buf[start] != '#' && buf[start] != 0x1A && end > start )
641 {
642 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
643 (void*)&cb, client_data );
644 /* Redo if we have encountered CHARS without properties. */
645 if ( error == -1 )
646 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
647 (void*)&cb, client_data );
648 if ( error )
649 break;
650 }
651
652 lineno += 1;
653 buf[end] = (char)hold;
654 start = end + 1;
655
656 if ( hold == '\n' )
657 to_skip = '\r';
658 else if ( hold == '\r' )
659 to_skip = '\n';
660 else
661 to_skip = NO_SKIP;
662 }
663
664 *lno = lineno;
665
666 Exit:
667 FT_FREE( buf );
668 return error;
669 }
670
671
672 /* XXX: make this work with EBCDIC also */
673
674 static const unsigned char a2i[128] =
675 {
676 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
677 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
678 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
680 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
681 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
682 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
683 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
684 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
685 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
686 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
687 };
688
689 static const unsigned char ddigits[32] =
690 {
691 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
692 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
693 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
694 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
695 };
696
697 static const unsigned char hdigits[32] =
698 {
699 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
700 0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00,
701 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
702 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
703 };
704
705
706 /* Routine to convert a decimal ASCII string to an unsigned long integer. */
707 static unsigned long
708 bdf_atoul_( const char* s )
709 {
710 unsigned long v;
711
712
713 if ( s == NULL || *s == 0 )
714 return 0;
715
716 for ( v = 0; sbitset( ddigits, *s ); s++ )
717 {
718 if ( v < ( FT_ULONG_MAX - 9 ) / 10 )
719 v = v * 10 + a2i[(int)*s];
720 else
721 {
722 v = FT_ULONG_MAX;
723 break;
724 }
725 }
726
727 return v;
728 }
729
730
731 /* Routine to convert a decimal ASCII string to a signed long integer. */
732 static long
733 bdf_atol_( const char* s )
734 {
735 long v, neg;
736
737
738 if ( s == NULL || *s == 0 )
739 return 0;
740
741 /* Check for a minus sign. */
742 neg = 0;
743 if ( *s == '-' )
744 {
745 s++;
746 neg = 1;
747 }
748
749 for ( v = 0; sbitset( ddigits, *s ); s++ )
750 {
751 if ( v < ( FT_LONG_MAX - 9 ) / 10 )
752 v = v * 10 + a2i[(int)*s];
753 else
754 {
755 v = FT_LONG_MAX;
756 break;
757 }
758 }
759
760 return ( !neg ) ? v : -v;
761 }
762
763
764 /* Routine to convert a decimal ASCII string to an unsigned short integer. */
765 static unsigned short
766 bdf_atous_( const char* s )
767 {
768 unsigned short v;
769
770
771 if ( s == NULL || *s == 0 )
772 return 0;
773
774 for ( v = 0; sbitset( ddigits, *s ); s++ )
775 {
776 if ( v < ( FT_USHORT_MAX - 9 ) / 10 )
777 v = (unsigned short)( v * 10 + a2i[(int)*s] );
778 else
779 {
780 v = FT_USHORT_MAX;
781 break;
782 }
783 }
784
785 return v;
786 }
787
788
789 /* Routine to convert a decimal ASCII string to a signed short integer. */
790 static short
791 bdf_atos_( const char* s )
792 {
793 short v, neg;
794
795
796 if ( s == NULL || *s == 0 )
797 return 0;
798
799 /* Check for a minus. */
800 neg = 0;
801 if ( *s == '-' )
802 {
803 s++;
804 neg = 1;
805 }
806
807 for ( v = 0; sbitset( ddigits, *s ); s++ )
808 {
809 if ( v < ( SHRT_MAX - 9 ) / 10 )
810 v = (short)( v * 10 + a2i[(int)*s] );
811 else
812 {
813 v = SHRT_MAX;
814 break;
815 }
816 }
817
818 return (short)( ( !neg ) ? v : -v );
819 }
820
821
822 /* Routine to compare two glyphs by encoding so they can be sorted. */
823 FT_COMPARE_DEF( int )
824 by_encoding( const void* a,
825 const void* b )
826 {
827 bdf_glyph_t *c1, *c2;
828
829
830 c1 = (bdf_glyph_t *)a;
831 c2 = (bdf_glyph_t *)b;
832
833 if ( c1->encoding < c2->encoding )
834 return -1;
835
836 if ( c1->encoding > c2->encoding )
837 return 1;
838
839 return 0;
840 }
841
842
843 static FT_Error
844 bdf_create_property( const char* name,
845 int format,
846 bdf_font_t* font )
847 {
848 size_t n;
849 bdf_property_t* p;
850 FT_Memory memory = font->memory;
851 FT_Error error = FT_Err_Ok;
852
853
854 /* First check whether the property has */
855 /* already been added or not. If it has, then */
856 /* simply ignore it. */
857 if ( ft_hash_str_lookup( name, &(font->proptbl) ) )
858 goto Exit;
859
860 if ( FT_QRENEW_ARRAY( font->user_props,
861 font->nuser_props,
862 font->nuser_props + 1 ) )
863 goto Exit;
864
865 p = font->user_props + font->nuser_props;
866
867 n = ft_strlen( name ) + 1;
868 if ( n > FT_LONG_MAX )
869 return FT_THROW( Invalid_Argument );
870
871 if ( FT_QALLOC( p->name, n ) )
872 goto Exit;
873
874 FT_MEM_COPY( (char *)p->name, name, n );
875
876 p->format = format;
877 p->builtin = 0;
878 p->value.atom = NULL; /* nothing is ever stored here */
879
880 n = num_bdf_properties_ + font->nuser_props;
881
882 error = ft_hash_str_insert( p->name, n, &(font->proptbl), memory );
883 if ( error )
884 goto Exit;
885
886 font->nuser_props++;
887
888 Exit:
889 return error;
890 }
891
892
893 static bdf_property_t*
894 bdf_get_property( const char* name,
895 bdf_font_t* font )
896 {
897 size_t* propid;
898
899
900 if ( name == NULL || *name == 0 )
901 return NULL;
902
903 if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL )
904 return NULL;
905
906 if ( *propid >= num_bdf_properties_ )
907 return font->user_props + ( *propid - num_bdf_properties_ );
908
909 return (bdf_property_t*)bdf_properties_ + *propid;
910 }
911
912
913 /**************************************************************************
914 *
915 * BDF font file parsing flags and functions.
916 *
917 */
918
919
920 /* Parse flags. */
921
922#define BDF_START_ 0x0001U
923#define BDF_FONT_NAME_ 0x0002U
924#define BDF_SIZE_ 0x0004U
925#define BDF_FONT_BBX_ 0x0008U
926#define BDF_PROPS_ 0x0010U
927#define BDF_GLYPHS_ 0x0020U
928#define BDF_GLYPH_ 0x0040U
929#define BDF_ENCODING_ 0x0080U
930#define BDF_SWIDTH_ 0x0100U
931#define BDF_DWIDTH_ 0x0200U
932#define BDF_BBX_ 0x0400U
933#define BDF_BITMAP_ 0x0800U
934
935#define BDF_SWIDTH_ADJ_ 0x1000U
936
937#define BDF_GLYPH_BITS_ ( BDF_GLYPH_ | \
938 BDF_ENCODING_ | \
939 BDF_SWIDTH_ | \
940 BDF_DWIDTH_ | \
941 BDF_BBX_ | \
942 BDF_BITMAP_ )
943
944#define BDF_GLYPH_WIDTH_CHECK_ 0x40000000UL
945#define BDF_GLYPH_HEIGHT_CHECK_ 0x80000000UL
946
947
948 static FT_Error
949 bdf_add_comment_( bdf_font_t* font,
950 const char* comment,
951 unsigned long len )
952 {
953 char* cp;
954 FT_Memory memory = font->memory;
955 FT_Error error = FT_Err_Ok;
956
957
958 if ( FT_QRENEW_ARRAY( font->comments,
959 font->comments_len,
960 font->comments_len + len + 1 ) )
961 goto Exit;
962
963 cp = font->comments + font->comments_len;
964
965 FT_MEM_COPY( cp, comment, len );
966 cp[len] = '\0';
967
968 font->comments_len += len + 1;
969
970 Exit:
971 return error;
972 }
973
974
975 /* Set the spacing from the font name if it exists, or set it to the */
976 /* default specified in the options. */
977 static FT_Error
978 bdf_set_default_spacing_( bdf_font_t* font,
979 bdf_options_t* opts,
980 unsigned long lineno )
981 {
982 size_t len;
983 char name[256];
984 bdf_list_t_ list;
985 FT_Memory memory;
986 FT_Error error = FT_Err_Ok;
987
988 FT_UNUSED( lineno ); /* only used in debug mode */
989
990
991 if ( font == NULL || font->name == NULL || font->name[0] == 0 )
992 {
993 error = FT_THROW( Invalid_Argument );
994 goto Exit;
995 }
996
997 memory = font->memory;
998
999 bdf_list_init_( &list, memory );
1000
1001 font->spacing = opts->font_spacing;
1002
1003 len = ft_strlen( font->name ) + 1;
1004 /* Limit ourselves to 256 characters in the font name. */
1005 if ( len >= 256 )
1006 {
1007 FT_ERROR(( "bdf_set_default_spacing_: " ERRMSG7, lineno ));
1008 error = FT_THROW( Invalid_Argument );
1009 goto Exit;
1010 }
1011
1012 FT_MEM_COPY( name, font->name, len );
1013
1014 error = bdf_list_split_( &list, "-", name, (unsigned long)len );
1015 if ( error )
1016 goto Fail;
1017
1018 if ( list.used == 15 )
1019 {
1020 switch ( list.field[11][0] )
1021 {
1022 case 'C':
1023 case 'c':
1024 font->spacing = BDF_CHARCELL;
1025 break;
1026 case 'M':
1027 case 'm':
1028 font->spacing = BDF_MONOWIDTH;
1029 break;
1030 case 'P':
1031 case 'p':
1032 font->spacing = BDF_PROPORTIONAL;
1033 break;
1034 }
1035 }
1036
1037 Fail:
1038 bdf_list_done_( &list );
1039
1040 Exit:
1041 return error;
1042 }
1043
1044
1045 /* Determine whether the property is an atom or not. If it is, then */
1046 /* clean it up so the double quotes are removed if they exist. */
1047 static int
1048 bdf_is_atom_( char* line,
1049 unsigned long linelen,
1050 char** name,
1051 char** value,
1052 bdf_font_t* font )
1053 {
1054 int hold;
1055 char *sp, *ep;
1056 bdf_property_t* p;
1057
1058
1059 sp = ep = line;
1060
1061 while ( *ep && *ep != ' ' && *ep != '\t' )
1062 ep++;
1063
1064 hold = *ep;
1065 *ep = '\0';
1066
1067 p = bdf_get_property( sp, font );
1068
1069 /* If the property exists and is not an atom, just return here. */
1070 if ( p && p->format != BDF_ATOM )
1071 {
1072 *ep = (char)hold; /* Undo NUL-termination. */
1073 return 0;
1074 }
1075
1076 *name = sp;
1077
1078 /* The property is an atom. Trim all leading and trailing whitespace */
1079 /* and double quotes for the atom value. */
1080 sp = ep;
1081 ep = line + linelen;
1082
1083 /* Trim the leading whitespace if it exists. */
1084 if ( sp < ep )
1085 do
1086 sp++;
1087 while ( *sp == ' ' || *sp == '\t' );
1088
1089 /* Trim the leading double quote if it exists. */
1090 if ( *sp == '"' )
1091 sp++;
1092
1093 *value = sp;
1094
1095 /* Trim the trailing whitespace if it exists. */
1096 if ( sp < ep )
1097 do
1098 *ep-- = '\0';
1099 while ( *ep == ' ' || *ep == '\t' );
1100
1101 /* Trim the trailing double quote if it exists. */
1102 if ( *ep == '"' )
1103 *ep = '\0';
1104
1105 return 1;
1106 }
1107
1108
1109 static FT_Error
1110 bdf_add_property_( bdf_font_t* font,
1111 const char* name,
1112 char* value,
1113 unsigned long lineno )
1114 {
1115 size_t* propid;
1116 bdf_property_t *prop, *fp;
1117 FT_Memory memory = font->memory;
1118 FT_Error error = FT_Err_Ok;
1119
1120 FT_UNUSED( lineno ); /* only used in debug mode */
1121
1122
1123 /* First, check whether the property already exists in the font. */
1124 if ( ( propid = ft_hash_str_lookup( name,
1125 (FT_Hash)font->internal ) ) != NULL )
1126 {
1127 /* The property already exists in the font, so simply replace */
1128 /* the value of the property with the current value. */
1129 fp = font->props + *propid;
1130
1131 switch ( fp->format )
1132 {
1133 case BDF_ATOM:
1134 /* Delete the current atom if it exists. */
1135 FT_FREE( fp->value.atom );
1136
1137 if ( value && value[0] != 0 )
1138 {
1139 if ( FT_STRDUP( fp->value.atom, value ) )
1140 goto Exit;
1141 }
1142 break;
1143
1144 case BDF_INTEGER:
1145 fp->value.l = bdf_atol_( value );
1146 break;
1147
1148 case BDF_CARDINAL:
1149 fp->value.ul = bdf_atoul_( value );
1150 break;
1151
1152 default:
1153 ;
1154 }
1155
1156 goto Exit;
1157 }
1158
1159 /* See whether this property type exists yet or not. */
1160 /* If not, create it. */
1161 propid = ft_hash_str_lookup( name, &(font->proptbl) );
1162 if ( !propid )
1163 {
1164 error = bdf_create_property( name, BDF_ATOM, font );
1165 if ( error )
1166 goto Exit;
1167 propid = ft_hash_str_lookup( name, &(font->proptbl) );
1168 }
1169
1170 /* Allocate another property if this is overflowing. */
1171 if ( font->props_used == font->props_size )
1172 {
1173 if ( FT_QRENEW_ARRAY( font->props,
1174 font->props_size,
1175 font->props_size + 1 ) )
1176 goto Exit;
1177
1178 font->props_size++;
1179 }
1180
1181 if ( *propid >= num_bdf_properties_ )
1182 prop = font->user_props + ( *propid - num_bdf_properties_ );
1183 else
1184 prop = (bdf_property_t*)bdf_properties_ + *propid;
1185
1186 fp = font->props + font->props_used;
1187
1188 fp->name = prop->name;
1189 fp->format = prop->format;
1190 fp->builtin = prop->builtin;
1191
1192 switch ( prop->format )
1193 {
1194 case BDF_ATOM:
1195 fp->value.atom = NULL;
1196 if ( value && value[0] )
1197 {
1198 if ( FT_STRDUP( fp->value.atom, value ) )
1199 goto Exit;
1200 }
1201 break;
1202
1203 case BDF_INTEGER:
1204 fp->value.l = bdf_atol_( value );
1205 break;
1206
1207 case BDF_CARDINAL:
1208 fp->value.ul = bdf_atoul_( value );
1209 break;
1210 }
1211
1212 /* If the property happens to be a comment, then it doesn't need */
1213 /* to be added to the internal hash table. */
1214 if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 )
1215 {
1216 /* Add the property to the font property table. */
1217 error = ft_hash_str_insert( fp->name,
1218 font->props_used,
1219 (FT_Hash)font->internal,
1220 memory );
1221 if ( error )
1222 goto Exit;
1223 }
1224
1225 font->props_used++;
1226
1227 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1228 /* property needs to be located if it exists in the property list, the */
1229 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1230 /* present, and the SPACING property should override the default */
1231 /* spacing. */
1232 if ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 )
1233 font->default_char = fp->value.ul;
1234 else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 )
1235 font->font_ascent = fp->value.l;
1236 else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 )
1237 font->font_descent = fp->value.l;
1238 else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 )
1239 {
1240 if ( !fp->value.atom )
1241 {
1242 FT_ERROR(( "bdf_add_property_: " ERRMSG8, lineno, "SPACING" ));
1243 error = FT_THROW( Invalid_File_Format );
1244 goto Exit;
1245 }
1246
1247 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
1248 font->spacing = BDF_PROPORTIONAL;
1249 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
1250 font->spacing = BDF_MONOWIDTH;
1251 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
1252 font->spacing = BDF_CHARCELL;
1253 }
1254
1255 Exit:
1256 return error;
1257 }
1258
1259
1260 static const unsigned char nibble_mask[8] =
1261 {
1262 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1263 };
1264
1265
1266 static FT_Error
1267 bdf_parse_end_( char* line,
1268 unsigned long linelen,
1269 unsigned long lineno,
1270 void* call_data,
1271 void* client_data )
1272 {
1273 /* a no-op; we ignore everything after `ENDFONT' */
1274
1275 FT_UNUSED( line );
1276 FT_UNUSED( linelen );
1277 FT_UNUSED( lineno );
1278 FT_UNUSED( call_data );
1279 FT_UNUSED( client_data );
1280
1281 return FT_Err_Ok;
1282 }
1283
1284
1285 /* Actually parse the glyph info and bitmaps. */
1286 static FT_Error
1287 bdf_parse_glyphs_( char* line,
1288 unsigned long linelen,
1289 unsigned long lineno,
1290 void* call_data,
1291 void* client_data )
1292 {
1293 int c, mask_index;
1294 char* s;
1295 unsigned char* bp;
1296 unsigned long i, slen, nibbles;
1297
1298 bdf_line_func_t_* next;
1299 bdf_parse_t_* p;
1300 bdf_glyph_t* glyph;
1301 bdf_font_t* font;
1302
1303 FT_Memory memory;
1304 FT_Error error = FT_Err_Ok;
1305
1306 FT_UNUSED( lineno ); /* only used in debug mode */
1307
1308
1309 next = (bdf_line_func_t_ *)call_data;
1310 p = (bdf_parse_t_ *) client_data;
1311
1312 font = p->font;
1313 memory = font->memory;
1314
1315 /* Check for a comment. */
1316 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
1317 {
1318 if ( p->opts->keep_comments )
1319 {
1320 linelen -= 7;
1321
1322 s = line + 7;
1323 if ( *s != 0 )
1324 {
1325 s++;
1326 linelen--;
1327 }
1328 error = bdf_add_comment_( p->font, s, linelen );
1329 }
1330 goto Exit;
1331 }
1332
1333 /* The very first thing expected is the number of glyphs. */
1334 if ( !( p->flags & BDF_GLYPHS_ ) )
1335 {
1336 if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 )
1337 {
1338 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "CHARS" ));
1339 error = FT_THROW( Missing_Chars_Field );
1340 goto Exit;
1341 }
1342
1343 error = bdf_list_split_( &p->list, " +", line, linelen );
1344 if ( error )
1345 goto Exit;
1346 p->cnt = font->glyphs_size = bdf_atoul_( p->list.field[1] );
1347
1348 /* We need at least 20 bytes per glyph. */
1349 if ( p->cnt > p->size / 20 )
1350 {
1351 p->cnt = font->glyphs_size = p->size / 20;
1352 FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG17, p->cnt ));
1353 }
1354
1355 /* Make sure the number of glyphs is non-zero. */
1356 if ( p->cnt == 0 )
1357 font->glyphs_size = 64;
1358
1359 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1360 /* number of code points available in Unicode). */
1361 if ( p->cnt >= 0x110000UL )
1362 {
1363 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG5, lineno, "CHARS" ));
1364 error = FT_THROW( Invalid_Argument );
1365 goto Exit;
1366 }
1367
1368 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1369 goto Exit;
1370
1371 p->flags |= BDF_GLYPHS_;
1372
1373 goto Exit;
1374 }
1375
1376 /* Check for the ENDFONT field. */
1377 if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 )
1378 {
1379 if ( p->flags & BDF_GLYPH_BITS_ )
1380 {
1381 /* Missing ENDCHAR field. */
1382 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" ));
1383 error = FT_THROW( Corrupted_Font_Glyphs );
1384 goto Exit;
1385 }
1386
1387 /* Sort the glyphs by encoding. */
1388 ft_qsort( (char *)font->glyphs,
1389 font->glyphs_used,
1390 sizeof ( bdf_glyph_t ),
1391 by_encoding );
1392
1393 p->flags &= ~BDF_START_;
1394 *next = bdf_parse_end_;
1395
1396 goto Exit;
1397 }
1398
1399 /* Check for the ENDCHAR field. */
1400 if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 )
1401 {
1402 p->glyph_enc = 0;
1403 p->flags &= ~BDF_GLYPH_BITS_;
1404
1405 goto Exit;
1406 }
1407
1408 /* Check whether a glyph is being scanned but should be */
1409 /* ignored because it is an unencoded glyph. */
1410 if ( ( p->flags & BDF_GLYPH_ ) &&
1411 p->glyph_enc == -1 &&
1412 p->opts->keep_unencoded == 0 )
1413 goto Exit;
1414
1415 /* Check for the STARTCHAR field. */
1416 if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 )
1417 {
1418 if ( p->flags & BDF_GLYPH_BITS_ )
1419 {
1420 /* Missing ENDCHAR field. */
1421 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" ));
1422 error = FT_THROW( Missing_Startchar_Field );
1423 goto Exit;
1424 }
1425
1426 /* Set the character name in the parse info first until the */
1427 /* encoding can be checked for an unencoded character. */
1428 FT_FREE( p->glyph_name );
1429
1430 error = bdf_list_split_( &p->list, " +", line, linelen );
1431 if ( error )
1432 goto Exit;
1433
1434 bdf_list_shift_( &p->list, 1 );
1435
1436 s = bdf_list_join_( &p->list, ' ', &slen );
1437
1438 if ( !s )
1439 {
1440 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG8, lineno, "STARTCHAR" ));
1441 error = FT_THROW( Invalid_File_Format );
1442 goto Exit;
1443 }
1444
1445 if ( FT_QALLOC( p->glyph_name, slen + 1 ) )
1446 goto Exit;
1447
1448 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1449
1450 p->flags |= BDF_GLYPH_;
1451
1452 FT_TRACE4(( DBGMSG1, lineno, s ));
1453
1454 goto Exit;
1455 }
1456
1457 /* Check for the ENCODING field. */
1458 if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 )
1459 {
1460 if ( !( p->flags & BDF_GLYPH_ ) )
1461 {
1462 /* Missing STARTCHAR field. */
1463 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "STARTCHAR" ));
1464 error = FT_THROW( Missing_Startchar_Field );
1465 goto Exit;
1466 }
1467
1468 error = bdf_list_split_( &p->list, " +", line, linelen );
1469 if ( error )
1470 goto Exit;
1471
1472 p->glyph_enc = bdf_atol_( p->list.field[1] );
1473
1474 /* Normalize negative encoding values. The specification only */
1475 /* allows -1, but we can be more generous here. */
1476 if ( p->glyph_enc < -1 )
1477 p->glyph_enc = -1;
1478
1479 /* Check for alternative encoding format. */
1480 if ( p->glyph_enc == -1 && p->list.used > 2 )
1481 p->glyph_enc = bdf_atol_( p->list.field[2] );
1482
1483 if ( p->glyph_enc < -1 || p->glyph_enc >= 0x110000L )
1484 p->glyph_enc = -1;
1485
1486 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1487
1488 if ( p->glyph_enc >= 0 )
1489 {
1490 /* Make sure there are enough glyphs allocated in case the */
1491 /* number of characters happen to be wrong. */
1492 if ( font->glyphs_used == font->glyphs_size )
1493 {
1494 if ( FT_RENEW_ARRAY( font->glyphs,
1495 font->glyphs_size,
1496 font->glyphs_size + 64 ) )
1497 goto Exit;
1498
1499 font->glyphs_size += 64;
1500 }
1501
1502 glyph = font->glyphs + font->glyphs_used++;
1503 glyph->name = p->glyph_name;
1504 glyph->encoding = (unsigned long)p->glyph_enc;
1505
1506 /* Reset the initial glyph info. */
1507 p->glyph_name = NULL;
1508 }
1509 else
1510 {
1511 /* Unencoded glyph. Check whether it should */
1512 /* be added or not. */
1513 if ( p->opts->keep_unencoded )
1514 {
1515 /* Allocate the next unencoded glyph. */
1516 if ( font->unencoded_used == font->unencoded_size )
1517 {
1518 if ( FT_RENEW_ARRAY( font->unencoded ,
1519 font->unencoded_size,
1520 font->unencoded_size + 4 ) )
1521 goto Exit;
1522
1523 font->unencoded_size += 4;
1524 }
1525
1526 glyph = font->unencoded + font->unencoded_used;
1527 glyph->name = p->glyph_name;
1528 glyph->encoding = font->unencoded_used++;
1529
1530 /* Reset the initial glyph info. */
1531 p->glyph_name = NULL;
1532 }
1533 else
1534 {
1535 /* Free up the glyph name if the unencoded shouldn't be */
1536 /* kept. */
1537 FT_FREE( p->glyph_name );
1538 }
1539 }
1540
1541 /* Clear the flags that might be added when width and height are */
1542 /* checked for consistency. */
1543 p->flags &= ~( BDF_GLYPH_WIDTH_CHECK_ | BDF_GLYPH_HEIGHT_CHECK_ );
1544
1545 p->flags |= BDF_ENCODING_;
1546
1547 goto Exit;
1548 }
1549
1550 if ( !( p->flags & BDF_ENCODING_ ) )
1551 goto Missing_Encoding;
1552
1553 /* Point at the glyph being constructed. */
1554 if ( p->glyph_enc == -1 )
1555 glyph = font->unencoded + ( font->unencoded_used - 1 );
1556 else
1557 glyph = font->glyphs + ( font->glyphs_used - 1 );
1558
1559 /* Check whether a bitmap is being constructed. */
1560 if ( p->flags & BDF_BITMAP_ )
1561 {
1562 /* If there are more rows than are specified in the glyph metrics, */
1563 /* ignore the remaining lines. */
1564 if ( p->row >= (unsigned long)glyph->bbx.height )
1565 {
1566 if ( !( p->flags & BDF_GLYPH_HEIGHT_CHECK_ ) )
1567 {
1568 FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG13, glyph->encoding ));
1569 p->flags |= BDF_GLYPH_HEIGHT_CHECK_;
1570 }
1571
1572 goto Exit;
1573 }
1574
1575 /* Only collect the number of nibbles indicated by the glyph */
1576 /* metrics. If there are more columns, they are simply ignored. */
1577 nibbles = glyph->bpr << 1;
1578 bp = glyph->bitmap + p->row * glyph->bpr;
1579
1580 for ( i = 0; i < nibbles; i++ )
1581 {
1582 c = line[i];
1583 if ( !sbitset( hdigits, c ) )
1584 break;
1585 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
1586 if ( i + 1 < nibbles && ( i & 1 ) )
1587 *++bp = 0;
1588 }
1589
1590 /* If any line has not enough columns, */
1591 /* indicate they have been padded with zero bits. */
1592 if ( i < nibbles &&
1593 !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
1594 {
1595 FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG16, glyph->encoding ));
1596 p->flags |= BDF_GLYPH_WIDTH_CHECK_;
1597 }
1598
1599 /* Remove possible garbage at the right. */
1600 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
1601 if ( glyph->bbx.width )
1602 *bp &= nibble_mask[mask_index];
1603
1604 /* If any line has extra columns, indicate they have been removed. */
1605 if ( i == nibbles &&
1606 sbitset( hdigits, line[nibbles] ) &&
1607 !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
1608 {
1609 FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG14, glyph->encoding ));
1610 p->flags |= BDF_GLYPH_WIDTH_CHECK_;
1611 }
1612
1613 p->row++;
1614 goto Exit;
1615 }
1616
1617 /* Expect the SWIDTH (scalable width) field next. */
1618 if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 )
1619 {
1620 error = bdf_list_split_( &p->list, " +", line, linelen );
1621 if ( error )
1622 goto Exit;
1623
1624 glyph->swidth = bdf_atous_( p->list.field[1] );
1625 p->flags |= BDF_SWIDTH_;
1626
1627 goto Exit;
1628 }
1629
1630 /* Expect the DWIDTH (device width) field next. */
1631 if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 )
1632 {
1633 error = bdf_list_split_( &p->list, " +", line, linelen );
1634 if ( error )
1635 goto Exit;
1636
1637 glyph->dwidth = bdf_atous_( p->list.field[1] );
1638
1639 if ( !( p->flags & BDF_SWIDTH_ ) )
1640 {
1641 /* Missing SWIDTH field. Emit an auto correction message and set */
1642 /* the scalable width from the device width. */
1643 FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG9, lineno ));
1644
1645 glyph->swidth = (unsigned short)FT_MulDiv(
1646 glyph->dwidth, 72000L,
1647 (FT_Long)( font->point_size *
1648 font->resolution_x ) );
1649 }
1650
1651 p->flags |= BDF_DWIDTH_;
1652 goto Exit;
1653 }
1654
1655 /* Expect the BBX field next. */
1656 if ( _bdf_strncmp( line, "BBX", 3 ) == 0 )
1657 {
1658 error = bdf_list_split_( &p->list, " +", line, linelen );
1659 if ( error )
1660 goto Exit;
1661
1662 glyph->bbx.width = bdf_atous_( p->list.field[1] );
1663 glyph->bbx.height = bdf_atous_( p->list.field[2] );
1664 glyph->bbx.x_offset = bdf_atos_( p->list.field[3] );
1665 glyph->bbx.y_offset = bdf_atos_( p->list.field[4] );
1666
1667 /* Generate the ascent and descent of the character. */
1668 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1669 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
1670
1671 /* Determine the overall font bounding box as the characters are */
1672 /* loaded so corrections can be done later if indicated. */
1673 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1674 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
1675
1676 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
1677
1678 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1679 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1680 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
1681
1682 if ( !( p->flags & BDF_DWIDTH_ ) )
1683 {
1684 /* Missing DWIDTH field. Emit an auto correction message and set */
1685 /* the device width to the glyph width. */
1686 FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG10, lineno ));
1687 glyph->dwidth = glyph->bbx.width;
1688 }
1689
1690 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1691 /* value if necessary. */
1692 if ( p->opts->correct_metrics )
1693 {
1694 /* Determine the point size of the glyph. */
1695 unsigned short sw = (unsigned short)FT_MulDiv(
1696 glyph->dwidth, 72000L,
1697 (FT_Long)( font->point_size *
1698 font->resolution_x ) );
1699
1700
1701 if ( sw != glyph->swidth )
1702 {
1703 glyph->swidth = sw;
1704
1705 p->flags |= BDF_SWIDTH_ADJ_;
1706 }
1707 }
1708
1709 p->flags |= BDF_BBX_;
1710 goto Exit;
1711 }
1712
1713 /* And finally, gather up the bitmap. */
1714 if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 )
1715 {
1716 unsigned long bitmap_size;
1717
1718
1719 if ( !( p->flags & BDF_BBX_ ) )
1720 {
1721 /* Missing BBX field. */
1722 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "BBX" ));
1723 error = FT_THROW( Missing_Bbx_Field );
1724 goto Exit;
1725 }
1726
1727 /* Allocate enough space for the bitmap. */
1728 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
1729
1730 bitmap_size = glyph->bpr * glyph->bbx.height;
1731 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
1732 {
1733 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG4, lineno ));
1734 error = FT_THROW( Bbx_Too_Big );
1735 goto Exit;
1736 }
1737 else
1738 glyph->bytes = (unsigned short)bitmap_size;
1739
1740 if ( FT_ALLOC( glyph->bitmap, glyph->bytes ) )
1741 goto Exit;
1742
1743 p->row = 0;
1744 p->flags |= BDF_BITMAP_;
1745
1746 goto Exit;
1747 }
1748
1749 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG9, lineno ));
1750 error = FT_THROW( Invalid_File_Format );
1751 goto Exit;
1752
1753 Missing_Encoding:
1754 /* Missing ENCODING field. */
1755 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENCODING" ));
1756 error = FT_THROW( Missing_Encoding_Field );
1757
1758 Exit:
1759 if ( error && ( p->flags & BDF_GLYPH_ ) )
1760 FT_FREE( p->glyph_name );
1761
1762 return error;
1763 }
1764
1765
1766 /* Load the font properties. */
1767 static FT_Error
1768 bdf_parse_properties_( char* line,
1769 unsigned long linelen,
1770 unsigned long lineno,
1771 void* call_data,
1772 void* client_data )
1773 {
1774 unsigned long vlen;
1775 bdf_line_func_t_* next;
1776 bdf_parse_t_* p;
1777 char* name;
1778 char* value;
1779 char nbuf[BUFSIZE];
1780 FT_Error error = FT_Err_Ok;
1781
1782 FT_UNUSED( lineno );
1783
1784
1785 next = (bdf_line_func_t_ *)call_data;
1786 p = (bdf_parse_t_ *) client_data;
1787
1788 /* Check for the end of the properties. */
1789 if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
1790 {
1791 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1792 /* encountered yet, then make sure they are added as properties and */
1793 /* make sure they are set from the font bounding box info. */
1794 /* */
1795 /* This is *always* done regardless of the options, because X11 */
1796 /* requires these two fields to compile fonts. */
1797 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
1798 {
1799 p->font->font_ascent = p->font->bbx.ascent;
1800 ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.ascent );
1801 error = bdf_add_property_( p->font, "FONT_ASCENT",
1802 nbuf, lineno );
1803 if ( error )
1804 goto Exit;
1805
1806 FT_TRACE2(( "bdf_parse_properties_: " ACMSG1, p->font->bbx.ascent ));
1807 }
1808
1809 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
1810 {
1811 p->font->font_descent = p->font->bbx.descent;
1812 ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.descent );
1813 error = bdf_add_property_( p->font, "FONT_DESCENT",
1814 nbuf, lineno );
1815 if ( error )
1816 goto Exit;
1817
1818 FT_TRACE2(( "bdf_parse_properties_: " ACMSG2, p->font->bbx.descent ));
1819 }
1820
1821 p->flags &= ~BDF_PROPS_;
1822 *next = bdf_parse_glyphs_;
1823
1824 goto Exit;
1825 }
1826
1827 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1828 if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1829 goto Exit;
1830
1831 /* Handle COMMENT fields and properties in a special way to preserve */
1832 /* the spacing. */
1833 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
1834 {
1835 name = value = line;
1836 value += 7;
1837 if ( *value )
1838 *value++ = 0;
1839 error = bdf_add_property_( p->font, name, value, lineno );
1840 if ( error )
1841 goto Exit;
1842 }
1843 else if ( bdf_is_atom_( line, linelen, &name, &value, p->font ) )
1844 {
1845 error = bdf_add_property_( p->font, name, value, lineno );
1846 if ( error )
1847 goto Exit;
1848 }
1849 else
1850 {
1851 error = bdf_list_split_( &p->list, " +", line, linelen );
1852 if ( error )
1853 goto Exit;
1854 name = p->list.field[0];
1855
1856 bdf_list_shift_( &p->list, 1 );
1857 value = bdf_list_join_( &p->list, ' ', &vlen );
1858
1859 error = bdf_add_property_( p->font, name, value, lineno );
1860 if ( error )
1861 goto Exit;
1862 }
1863
1864 Exit:
1865 return error;
1866 }
1867
1868
1869 /* Load the font header. */
1870 static FT_Error
1871 bdf_parse_start_( char* line,
1872 unsigned long linelen,
1873 unsigned long lineno,
1874 void* call_data,
1875 void* client_data )
1876 {
1877 unsigned long slen;
1878 bdf_line_func_t_* next;
1879 bdf_parse_t_* p;
1880 bdf_font_t* font;
1881 char *s;
1882
1883 FT_Memory memory = NULL;
1884 FT_Error error = FT_Err_Ok;
1885
1886 FT_UNUSED( lineno ); /* only used in debug mode */
1887
1888
1889 next = (bdf_line_func_t_ *)call_data;
1890 p = (bdf_parse_t_ *) client_data;
1891
1892 if ( p->font )
1893 memory = p->font->memory;
1894
1895 /* Check for a comment. This is done to handle those fonts that have */
1896 /* comments before the STARTFONT line for some reason. */
1897 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
1898 {
1899 if ( p->opts->keep_comments && p->font )
1900 {
1901 linelen -= 7;
1902
1903 s = line + 7;
1904 if ( *s != 0 )
1905 {
1906 s++;
1907 linelen--;
1908 }
1909 error = bdf_add_comment_( p->font, s, linelen );
1910 }
1911 goto Exit;
1912 }
1913
1914 if ( !( p->flags & BDF_START_ ) )
1915 {
1916 memory = p->memory;
1917
1918 if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 )
1919 {
1920 /* we don't emit an error message since this code gets */
1921 /* explicitly caught one level higher */
1922 error = FT_THROW( Missing_Startfont_Field );
1923 goto Exit;
1924 }
1925
1926 p->flags = BDF_START_;
1927 font = p->font = NULL;
1928
1929 if ( FT_NEW( font ) )
1930 goto Exit;
1931 p->font = font;
1932
1933 font->memory = p->memory;
1934
1935 { /* setup */
1936 size_t i;
1937 bdf_property_t* prop;
1938
1939
1940 error = ft_hash_str_init( &(font->proptbl), memory );
1941 if ( error )
1942 goto Exit;
1943 for ( i = 0, prop = (bdf_property_t*)bdf_properties_;
1944 i < num_bdf_properties_; i++, prop++ )
1945 {
1946 error = ft_hash_str_insert( prop->name, i,
1947 &(font->proptbl), memory );
1948 if ( error )
1949 goto Exit;
1950 }
1951 }
1952
1953 if ( FT_QALLOC( p->font->internal, sizeof ( FT_HashRec ) ) )
1954 goto Exit;
1955 error = ft_hash_str_init( (FT_Hash)p->font->internal, memory );
1956 if ( error )
1957 goto Exit;
1958 p->font->spacing = p->opts->font_spacing;
1959 p->font->default_char = ~0UL;
1960
1961 goto Exit;
1962 }
1963
1964 /* Check for the start of the properties. */
1965 if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 )
1966 {
1967 if ( !( p->flags & BDF_FONT_BBX_ ) )
1968 {
1969 /* Missing the FONTBOUNDINGBOX field. */
1970 FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
1971 error = FT_THROW( Missing_Fontboundingbox_Field );
1972 goto Exit;
1973 }
1974
1975 error = bdf_list_split_( &p->list, " +", line, linelen );
1976 if ( error )
1977 goto Exit;
1978
1979 /* at this point, `p->font' can't be NULL */
1980 p->cnt = p->font->props_size = bdf_atoul_( p->list.field[1] );
1981 /* We need at least 4 bytes per property. */
1982 if ( p->cnt > p->size / 4 )
1983 {
1984 p->font->props_size = 0;
1985
1986 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG5, lineno, "STARTPROPERTIES" ));
1987 error = FT_THROW( Invalid_Argument );
1988 goto Exit;
1989 }
1990
1991 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
1992 {
1993 p->font->props_size = 0;
1994 goto Exit;
1995 }
1996
1997 p->flags |= BDF_PROPS_;
1998 *next = bdf_parse_properties_;
1999
2000 goto Exit;
2001 }
2002
2003 /* Check for the FONTBOUNDINGBOX field. */
2004 if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2005 {
2006 if ( !( p->flags & BDF_SIZE_ ) )
2007 {
2008 /* Missing the SIZE field. */
2009 FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "SIZE" ));
2010 error = FT_THROW( Missing_Size_Field );
2011 goto Exit;
2012 }
2013
2014 error = bdf_list_split_( &p->list, " +", line, linelen );
2015 if ( error )
2016 goto Exit;
2017
2018 p->font->bbx.width = bdf_atous_( p->list.field[1] );
2019 p->font->bbx.height = bdf_atous_( p->list.field[2] );
2020
2021 p->font->bbx.x_offset = bdf_atos_( p->list.field[3] );
2022 p->font->bbx.y_offset = bdf_atos_( p->list.field[4] );
2023
2024 p->font->bbx.ascent = (short)( p->font->bbx.height +
2025 p->font->bbx.y_offset );
2026
2027 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
2028
2029 p->flags |= BDF_FONT_BBX_;
2030
2031 goto Exit;
2032 }
2033
2034 /* The next thing to check for is the FONT field. */
2035 if ( _bdf_strncmp( line, "FONT", 4 ) == 0 )
2036 {
2037 error = bdf_list_split_( &p->list, " +", line, linelen );
2038 if ( error )
2039 goto Exit;
2040 bdf_list_shift_( &p->list, 1 );
2041
2042 s = bdf_list_join_( &p->list, ' ', &slen );
2043
2044 if ( !s )
2045 {
2046 FT_ERROR(( "bdf_parse_start_: " ERRMSG8, lineno, "FONT" ));
2047 error = FT_THROW( Invalid_File_Format );
2048 goto Exit;
2049 }
2050
2051 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2052 FT_FREE( p->font->name );
2053
2054 if ( FT_QALLOC( p->font->name, slen + 1 ) )
2055 goto Exit;
2056 FT_MEM_COPY( p->font->name, s, slen + 1 );
2057
2058 /* If the font name is an XLFD name, set the spacing to the one in */
2059 /* the font name. If there is no spacing fall back on the default. */
2060 error = bdf_set_default_spacing_( p->font, p->opts, lineno );
2061 if ( error )
2062 goto Exit;
2063
2064 p->flags |= BDF_FONT_NAME_;
2065
2066 goto Exit;
2067 }
2068
2069 /* Check for the SIZE field. */
2070 if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 )
2071 {
2072 if ( !( p->flags & BDF_FONT_NAME_ ) )
2073 {
2074 /* Missing the FONT field. */
2075 FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONT" ));
2076 error = FT_THROW( Missing_Font_Field );
2077 goto Exit;
2078 }
2079
2080 error = bdf_list_split_( &p->list, " +", line, linelen );
2081 if ( error )
2082 goto Exit;
2083
2084 p->font->point_size = bdf_atoul_( p->list.field[1] );
2085 p->font->resolution_x = bdf_atoul_( p->list.field[2] );
2086 p->font->resolution_y = bdf_atoul_( p->list.field[3] );
2087
2088 /* Check for the bits per pixel field. */
2089 if ( p->list.used == 5 )
2090 {
2091 unsigned short bpp;
2092
2093
2094 bpp = bdf_atous_( p->list.field[4] );
2095
2096 /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
2097 if ( bpp > 4 )
2098 p->font->bpp = 8;
2099 else if ( bpp > 2 )
2100 p->font->bpp = 4;
2101 else if ( bpp > 1 )
2102 p->font->bpp = 2;
2103 else
2104 p->font->bpp = 1;
2105
2106 if ( p->font->bpp != bpp )
2107 FT_TRACE2(( "bdf_parse_start_: " ACMSG11, p->font->bpp ));
2108 }
2109 else
2110 p->font->bpp = 1;
2111
2112 p->flags |= BDF_SIZE_;
2113
2114 goto Exit;
2115 }
2116
2117 /* Check for the CHARS field -- font properties are optional */
2118 if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
2119 {
2120 char nbuf[BUFSIZE];
2121
2122
2123 if ( !( p->flags & BDF_FONT_BBX_ ) )
2124 {
2125 /* Missing the FONTBOUNDINGBOX field. */
2126 FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2127 error = FT_THROW( Missing_Fontboundingbox_Field );
2128 goto Exit;
2129 }
2130
2131 /* Add the two standard X11 properties which are required */
2132 /* for compiling fonts. */
2133 p->font->font_ascent = p->font->bbx.ascent;
2134 ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.ascent );
2135 error = bdf_add_property_( p->font, "FONT_ASCENT",
2136 nbuf, lineno );
2137 if ( error )
2138 goto Exit;
2139 FT_TRACE2(( "bdf_parse_properties_: " ACMSG1, p->font->bbx.ascent ));
2140
2141 p->font->font_descent = p->font->bbx.descent;
2142 ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.descent );
2143 error = bdf_add_property_( p->font, "FONT_DESCENT",
2144 nbuf, lineno );
2145 if ( error )
2146 goto Exit;
2147 FT_TRACE2(( "bdf_parse_properties_: " ACMSG2, p->font->bbx.descent ));
2148
2149 *next = bdf_parse_glyphs_;
2150
2151 /* A special return value. */
2152 error = -1;
2153 goto Exit;
2154 }
2155
2156 FT_ERROR(( "bdf_parse_start_: " ERRMSG9, lineno ));
2157 error = FT_THROW( Invalid_File_Format );
2158
2159 Exit:
2160 return error;
2161 }
2162
2163
2164 /**************************************************************************
2165 *
2166 * API.
2167 *
2168 */
2169
2170
2171 FT_LOCAL_DEF( FT_Error )
2172 bdf_load_font( FT_Stream stream,
2173 FT_Memory memory,
2174 bdf_options_t* opts,
2175 bdf_font_t* *font )
2176 {
2177 unsigned long lineno = 0; /* make compiler happy */
2178 bdf_parse_t_ *p = NULL;
2179
2180 FT_Error error = FT_Err_Ok;
2181
2182
2183 if ( FT_NEW( p ) )
2184 goto Exit;
2185
2186 p->opts = (bdf_options_t*)( opts ? opts : &bdf_opts_ );
2187 p->minlb = 32767;
2188 p->size = stream->size;
2189 p->memory = memory; /* only during font creation */
2190
2191 bdf_list_init_( &p->list, memory );
2192
2193 error = bdf_readstream_( stream, bdf_parse_start_,
2194 (void *)p, &lineno );
2195 if ( error )
2196 goto Fail;
2197
2198 if ( p->font )
2199 {
2200 /* If the font is not proportional, set the font's monowidth */
2201 /* field to the width of the font bounding box. */
2202
2203 if ( p->font->spacing != BDF_PROPORTIONAL )
2204 p->font->monowidth = p->font->bbx.width;
2205
2206 /* If the number of glyphs loaded is not that of the original count, */
2207 /* indicate the difference. */
2208 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
2209 {
2210 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2211 p->font->glyphs_used + p->font->unencoded_used ));
2212 }
2213
2214 /* Once the font has been loaded, adjust the overall font metrics if */
2215 /* necessary. */
2216 if ( p->opts->correct_metrics != 0 &&
2217 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
2218 {
2219 if ( p->maxrb - p->minlb != p->font->bbx.width )
2220 {
2221 FT_TRACE2(( "bdf_load_font: " ACMSG3,
2222 p->font->bbx.width, p->maxrb - p->minlb ));
2223 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2224 }
2225
2226 if ( p->font->bbx.x_offset != p->minlb )
2227 {
2228 FT_TRACE2(( "bdf_load_font: " ACMSG4,
2229 p->font->bbx.x_offset, p->minlb ));
2230 p->font->bbx.x_offset = p->minlb;
2231 }
2232
2233 if ( p->font->bbx.ascent != p->maxas )
2234 {
2235 FT_TRACE2(( "bdf_load_font: " ACMSG5,
2236 p->font->bbx.ascent, p->maxas ));
2237 p->font->bbx.ascent = p->maxas;
2238 }
2239
2240 if ( p->font->bbx.descent != p->maxds )
2241 {
2242 FT_TRACE2(( "bdf_load_font: " ACMSG6,
2243 p->font->bbx.descent, p->maxds ));
2244 p->font->bbx.descent = p->maxds;
2245 p->font->bbx.y_offset = (short)( -p->maxds );
2246 }
2247
2248 if ( p->maxas + p->maxds != p->font->bbx.height )
2249 {
2250 FT_TRACE2(( "bdf_load_font: " ACMSG7,
2251 p->font->bbx.height, p->maxas + p->maxds ));
2252 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
2253 }
2254
2255 if ( p->flags & BDF_SWIDTH_ADJ_ )
2256 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2257 }
2258 }
2259
2260 if ( p->flags & BDF_START_ )
2261 {
2262 /* The ENDFONT field was never reached or did not exist. */
2263 if ( !( p->flags & BDF_GLYPHS_ ) )
2264 {
2265 /* Error happened while parsing header. */
2266 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2267 error = FT_THROW( Corrupted_Font_Header );
2268 goto Fail;
2269 }
2270 else
2271 {
2272 /* Error happened when parsing glyphs. */
2273 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2274 error = FT_THROW( Corrupted_Font_Glyphs );
2275 goto Fail;
2276 }
2277 }
2278
2279 if ( !p->font && !error )
2280 error = FT_THROW( Invalid_File_Format );
2281
2282 *font = p->font;
2283
2284 Exit:
2285 if ( p )
2286 {
2287 bdf_list_done_( &p->list );
2288
2289 FT_FREE( p->glyph_name );
2290 FT_FREE( p );
2291 }
2292
2293 return error;
2294
2295 Fail:
2296 bdf_free_font( p->font );
2297
2298 FT_FREE( p->font );
2299
2300 goto Exit;
2301 }
2302
2303
2304 FT_LOCAL_DEF( void )
2305 bdf_free_font( bdf_font_t* font )
2306 {
2307 bdf_property_t* prop;
2308 unsigned long i;
2309 bdf_glyph_t* glyphs;
2310 FT_Memory memory;
2311
2312
2313 if ( font == NULL )
2314 return;
2315
2316 memory = font->memory;
2317
2318 FT_FREE( font->name );
2319
2320 /* Free up the internal hash table of property names. */
2321 if ( font->internal )
2322 {
2323 ft_hash_str_free( (FT_Hash)font->internal, memory );
2324 FT_FREE( font->internal );
2325 }
2326
2327 /* Free up the comment info. */
2328 FT_FREE( font->comments );
2329
2330 /* Free up the properties. */
2331 for ( i = 0; i < font->props_size; i++ )
2332 {
2333 if ( font->props[i].format == BDF_ATOM )
2334 FT_FREE( font->props[i].value.atom );
2335 }
2336
2337 FT_FREE( font->props );
2338
2339 /* Free up the character info. */
2340 for ( i = 0, glyphs = font->glyphs;
2341 i < font->glyphs_used; i++, glyphs++ )
2342 {
2343 FT_FREE( glyphs->name );
2344 FT_FREE( glyphs->bitmap );
2345 }
2346
2347 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2348 i++, glyphs++ )
2349 {
2350 FT_FREE( glyphs->name );
2351 FT_FREE( glyphs->bitmap );
2352 }
2353
2354 FT_FREE( font->glyphs );
2355 FT_FREE( font->unencoded );
2356
2357 /* bdf_cleanup */
2358 ft_hash_str_free( &(font->proptbl), memory );
2359
2360 /* Free up the user defined properties. */
2361 for ( prop = font->user_props, i = 0;
2362 i < font->nuser_props; i++, prop++ )
2363 FT_FREE( prop->name );
2364
2365 FT_FREE( font->user_props );
2366
2367 /* FREE( font ); */ /* XXX Fixme */
2368 }
2369
2370
2371 FT_LOCAL_DEF( bdf_property_t * )
2372 bdf_get_font_property( bdf_font_t* font,
2373 const char* name )
2374 {
2375 size_t* propid;
2376
2377
2378 if ( font == NULL || font->props_size == 0 || name == NULL || *name == 0 )
2379 return 0;
2380
2381 propid = ft_hash_str_lookup( name, (FT_Hash)font->internal );
2382
2383 return propid ? ( font->props + *propid ) : 0;
2384 }
2385
2386
2387/* END */
2388