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