[FREETYPE]
[reactos.git] / reactos / lib / 3rdparty / freetype / src / bdf / bdflib.c
1 /*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
3 * Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010
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 /*************************************************************************/
173 /* */
174 /* Hash table utilities for the properties. */
175 /* */
176 /*************************************************************************/
177
178 /* XXX: Replace this with FreeType's hash functions */
179
180
181 #define INITIAL_HT_SIZE 241
182
183 typedef void
184 (*hash_free_func)( hashnode node );
185
186 static hashnode*
187 hash_bucket( const char* key,
188 hashtable* ht )
189 {
190 const char* kp = key;
191 unsigned long res = 0;
192 hashnode* bp = ht->table, *ndp;
193
194
195 /* Mocklisp hash function. */
196 while ( *kp )
197 res = ( res << 5 ) - res + *kp++;
198
199 ndp = bp + ( res % ht->size );
200 while ( *ndp )
201 {
202 kp = (*ndp)->key;
203 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
204 break;
205 ndp--;
206 if ( ndp < bp )
207 ndp = bp + ( ht->size - 1 );
208 }
209
210 return ndp;
211 }
212
213
214 static FT_Error
215 hash_rehash( hashtable* ht,
216 FT_Memory memory )
217 {
218 hashnode* obp = ht->table, *bp, *nbp;
219 int i, sz = ht->size;
220 FT_Error error = BDF_Err_Ok;
221
222
223 ht->size <<= 1;
224 ht->limit = ht->size / 3;
225
226 if ( FT_NEW_ARRAY( ht->table, ht->size ) )
227 goto Exit;
228
229 for ( i = 0, bp = obp; i < sz; i++, bp++ )
230 {
231 if ( *bp )
232 {
233 nbp = hash_bucket( (*bp)->key, ht );
234 *nbp = *bp;
235 }
236 }
237 FT_FREE( obp );
238
239 Exit:
240 return error;
241 }
242
243
244 static FT_Error
245 hash_init( hashtable* ht,
246 FT_Memory memory )
247 {
248 int sz = INITIAL_HT_SIZE;
249 FT_Error error = BDF_Err_Ok;
250
251
252 ht->size = sz;
253 ht->limit = sz / 3;
254 ht->used = 0;
255
256 if ( FT_NEW_ARRAY( ht->table, sz ) )
257 goto Exit;
258
259 Exit:
260 return error;
261 }
262
263
264 static void
265 hash_free( hashtable* ht,
266 FT_Memory memory )
267 {
268 if ( ht != 0 )
269 {
270 int i, sz = ht->size;
271 hashnode* bp = ht->table;
272
273
274 for ( i = 0; i < sz; i++, bp++ )
275 FT_FREE( *bp );
276
277 FT_FREE( ht->table );
278 }
279 }
280
281
282 static FT_Error
283 hash_insert( char* key,
284 size_t data,
285 hashtable* ht,
286 FT_Memory memory )
287 {
288 hashnode nn, *bp = hash_bucket( key, ht );
289 FT_Error error = BDF_Err_Ok;
290
291
292 nn = *bp;
293 if ( !nn )
294 {
295 if ( FT_NEW( nn ) )
296 goto Exit;
297 *bp = nn;
298
299 nn->key = key;
300 nn->data = data;
301
302 if ( ht->used >= ht->limit )
303 {
304 error = hash_rehash( ht, memory );
305 if ( error )
306 goto Exit;
307 }
308 ht->used++;
309 }
310 else
311 nn->data = data;
312
313 Exit:
314 return error;
315 }
316
317
318 static hashnode
319 hash_lookup( const char* key,
320 hashtable* ht )
321 {
322 hashnode *np = hash_bucket( key, ht );
323
324
325 return *np;
326 }
327
328
329 /*************************************************************************/
330 /* */
331 /* Utility types and functions. */
332 /* */
333 /*************************************************************************/
334
335
336 /* Function type for parsing lines of a BDF font. */
337
338 typedef FT_Error
339 (*_bdf_line_func_t)( char* line,
340 unsigned long linelen,
341 unsigned long lineno,
342 void* call_data,
343 void* client_data );
344
345
346 /* List structure for splitting lines into fields. */
347
348 typedef struct _bdf_list_t_
349 {
350 char** field;
351 unsigned long size;
352 unsigned long used;
353 FT_Memory memory;
354
355 } _bdf_list_t;
356
357
358 /* Structure used while loading BDF fonts. */
359
360 typedef struct _bdf_parse_t_
361 {
362 unsigned long flags;
363 unsigned long cnt;
364 unsigned long row;
365
366 short minlb;
367 short maxlb;
368 short maxrb;
369 short maxas;
370 short maxds;
371
372 short rbearing;
373
374 char* glyph_name;
375 long glyph_enc;
376
377 bdf_font_t* font;
378 bdf_options_t* opts;
379
380 unsigned long have[2048];
381 _bdf_list_t list;
382
383 FT_Memory memory;
384
385 } _bdf_parse_t;
386
387
388 #define setsbit( m, cc ) \
389 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
390 #define sbitset( m, cc ) \
391 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
392
393
394 static void
395 _bdf_list_init( _bdf_list_t* list,
396 FT_Memory memory )
397 {
398 FT_ZERO( list );
399 list->memory = memory;
400 }
401
402
403 static void
404 _bdf_list_done( _bdf_list_t* list )
405 {
406 FT_Memory memory = list->memory;
407
408
409 if ( memory )
410 {
411 FT_FREE( list->field );
412 FT_ZERO( list );
413 }
414 }
415
416
417 static FT_Error
418 _bdf_list_ensure( _bdf_list_t* list,
419 unsigned long num_items ) /* same as _bdf_list_t.used */
420 {
421 FT_Error error = BDF_Err_Ok;
422
423
424 if ( num_items > list->size )
425 {
426 unsigned long oldsize = list->size; /* same as _bdf_list_t.size */
427 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 4;
428 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
429 FT_Memory memory = list->memory;
430
431
432 if ( oldsize == bigsize )
433 {
434 error = BDF_Err_Out_Of_Memory;
435 goto Exit;
436 }
437 else if ( newsize < oldsize || newsize > bigsize )
438 newsize = bigsize;
439
440 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
441 goto Exit;
442
443 list->size = newsize;
444 }
445
446 Exit:
447 return error;
448 }
449
450
451 static void
452 _bdf_list_shift( _bdf_list_t* list,
453 unsigned long n )
454 {
455 unsigned long i, u;
456
457
458 if ( list == 0 || list->used == 0 || n == 0 )
459 return;
460
461 if ( n >= list->used )
462 {
463 list->used = 0;
464 return;
465 }
466
467 for ( u = n, i = 0; u < list->used; i++, u++ )
468 list->field[i] = list->field[u];
469 list->used -= n;
470 }
471
472
473 /* An empty string for empty fields. */
474
475 static const char empty[1] = { 0 }; /* XXX eliminate this */
476
477
478 static char *
479 _bdf_list_join( _bdf_list_t* list,
480 int c,
481 unsigned long *alen )
482 {
483 unsigned long i, j;
484 char *fp, *dp;
485
486
487 *alen = 0;
488
489 if ( list == 0 || list->used == 0 )
490 return 0;
491
492 dp = list->field[0];
493 for ( i = j = 0; i < list->used; i++ )
494 {
495 fp = list->field[i];
496 while ( *fp )
497 dp[j++] = *fp++;
498
499 if ( i + 1 < list->used )
500 dp[j++] = (char)c;
501 }
502 if ( dp != empty )
503 dp[j] = 0;
504
505 *alen = j;
506 return dp;
507 }
508
509
510 static FT_Error
511 _bdf_list_split( _bdf_list_t* list,
512 char* separators,
513 char* line,
514 unsigned long linelen )
515 {
516 int mult, final_empty;
517 char *sp, *ep, *end;
518 char seps[32];
519 FT_Error error = BDF_Err_Ok;
520
521
522 /* Initialize the list. */
523 list->used = 0;
524
525 /* If the line is empty, then simply return. */
526 if ( linelen == 0 || line[0] == 0 )
527 goto Exit;
528
529 /* In the original code, if the `separators' parameter is NULL or */
530 /* empty, the list is split into individual bytes. We don't need */
531 /* this, so an error is signaled. */
532 if ( separators == 0 || *separators == 0 )
533 {
534 error = BDF_Err_Invalid_Argument;
535 goto Exit;
536 }
537
538 /* Prepare the separator bitmap. */
539 FT_MEM_ZERO( seps, 32 );
540
541 /* If the very last character of the separator string is a plus, then */
542 /* set the `mult' flag to indicate that multiple separators should be */
543 /* collapsed into one. */
544 for ( mult = 0, sp = separators; sp && *sp; sp++ )
545 {
546 if ( *sp == '+' && *( sp + 1 ) == 0 )
547 mult = 1;
548 else
549 setsbit( seps, *sp );
550 }
551
552 /* Break the line up into fields. */
553 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
554 sp < end && *sp; )
555 {
556 /* Collect everything that is not a separator. */
557 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
558 ;
559
560 /* Resize the list if necessary. */
561 if ( list->used == list->size )
562 {
563 error = _bdf_list_ensure( list, list->used + 1 );
564 if ( error )
565 goto Exit;
566 }
567
568 /* Assign the field appropriately. */
569 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
570
571 sp = ep;
572
573 if ( mult )
574 {
575 /* If multiple separators should be collapsed, do it now by */
576 /* setting all the separator characters to 0. */
577 for ( ; *ep && sbitset( seps, *ep ); ep++ )
578 *ep = 0;
579 }
580 else if ( *ep != 0 )
581 /* Don't collapse multiple separators by making them 0, so just */
582 /* make the one encountered 0. */
583 *ep++ = 0;
584
585 final_empty = ( ep > sp && *ep == 0 );
586 sp = ep;
587 }
588
589 /* Finally, NULL-terminate the list. */
590 if ( list->used + final_empty >= list->size )
591 {
592 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
593 if ( error )
594 goto Exit;
595 }
596
597 if ( final_empty )
598 list->field[list->used++] = (char*)empty;
599
600 list->field[list->used] = 0;
601
602 Exit:
603 return error;
604 }
605
606
607 #define NO_SKIP 256 /* this value cannot be stored in a 'char' */
608
609
610 static FT_Error
611 _bdf_readstream( FT_Stream stream,
612 _bdf_line_func_t callback,
613 void* client_data,
614 unsigned long *lno )
615 {
616 _bdf_line_func_t cb;
617 unsigned long lineno, buf_size;
618 int refill, hold, to_skip;
619 ptrdiff_t bytes, start, end, cursor, avail;
620 char* buf = 0;
621 FT_Memory memory = stream->memory;
622 FT_Error error = BDF_Err_Ok;
623
624
625 if ( callback == 0 )
626 {
627 error = BDF_Err_Invalid_Argument;
628 goto Exit;
629 }
630
631 /* initial size and allocation of the input buffer */
632 buf_size = 1024;
633
634 if ( FT_NEW_ARRAY( buf, buf_size ) )
635 goto Exit;
636
637 cb = callback;
638 lineno = 1;
639 buf[0] = 0;
640 start = 0;
641 end = 0;
642 avail = 0;
643 cursor = 0;
644 refill = 1;
645 to_skip = NO_SKIP;
646 bytes = 0; /* make compiler happy */
647
648 for (;;)
649 {
650 if ( refill )
651 {
652 bytes = (ptrdiff_t)FT_Stream_TryRead(
653 stream, (FT_Byte*)buf + cursor,
654 (FT_ULong)( buf_size - cursor ) );
655 avail = cursor + bytes;
656 cursor = 0;
657 refill = 0;
658 }
659
660 end = start;
661
662 /* should we skip an optional character like \n or \r? */
663 if ( start < avail && buf[start] == to_skip )
664 {
665 start += 1;
666 to_skip = NO_SKIP;
667 continue;
668 }
669
670 /* try to find the end of the line */
671 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
672 end++;
673
674 /* if we hit the end of the buffer, try shifting its content */
675 /* or even resizing it */
676 if ( end >= avail )
677 {
678 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
679 break; /* ignore it then exit */
680
681 if ( start == 0 )
682 {
683 /* this line is definitely too long; try resizing the input */
684 /* buffer a bit to handle it. */
685 FT_ULong new_size;
686
687
688 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
689 {
690 error = BDF_Err_Invalid_Argument;
691 goto Exit;
692 }
693
694 new_size = buf_size * 2;
695 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
696 goto Exit;
697
698 cursor = buf_size;
699 buf_size = new_size;
700 }
701 else
702 {
703 bytes = avail - start;
704
705 FT_MEM_COPY( buf, buf + start, bytes );
706
707 cursor = bytes;
708 avail -= bytes;
709 start = 0;
710 }
711 refill = 1;
712 continue;
713 }
714
715 /* Temporarily NUL-terminate the line. */
716 hold = buf[end];
717 buf[end] = 0;
718
719 /* XXX: Use encoding independent value for 0x1a */
720 if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
721 {
722 error = (*cb)( buf + start, end - start, lineno,
723 (void*)&cb, client_data );
724 /* Redo if we have encountered CHARS without properties. */
725 if ( error == -1 )
726 error = (*cb)( buf + start, end - start, lineno,
727 (void*)&cb, client_data );
728 if ( error )
729 break;
730 }
731
732 lineno += 1;
733 buf[end] = (char)hold;
734 start = end + 1;
735
736 if ( hold == '\n' )
737 to_skip = '\r';
738 else if ( hold == '\r' )
739 to_skip = '\n';
740 else
741 to_skip = NO_SKIP;
742 }
743
744 *lno = lineno;
745
746 Exit:
747 FT_FREE( buf );
748 return error;
749 }
750
751
752 /* XXX: make this work with EBCDIC also */
753
754 static const unsigned char a2i[128] =
755 {
756 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
758 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
759 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
760 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
761 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
762 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
764 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
767 };
768
769 static const unsigned char odigits[32] =
770 {
771 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
774 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
775 };
776
777 static const unsigned char ddigits[32] =
778 {
779 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
780 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
782 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
783 };
784
785 static const unsigned char hdigits[32] =
786 {
787 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
788 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
789 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
790 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
791 };
792
793
794 #define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
795
796
797 /* Routine to convert an ASCII string into an unsigned long integer. */
798 static unsigned long
799 _bdf_atoul( char* s,
800 char** end,
801 int base )
802 {
803 unsigned long v;
804 const unsigned char* dmap;
805
806
807 if ( s == 0 || *s == 0 )
808 return 0;
809
810 /* Make sure the radix is something recognizable. Default to 10. */
811 switch ( base )
812 {
813 case 8:
814 dmap = odigits;
815 break;
816 case 16:
817 dmap = hdigits;
818 break;
819 default:
820 base = 10;
821 dmap = ddigits;
822 break;
823 }
824
825 /* Check for the special hex prefix. */
826 if ( *s == '0' &&
827 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
828 {
829 base = 16;
830 dmap = hdigits;
831 s += 2;
832 }
833
834 for ( v = 0; isdigok( dmap, *s ); s++ )
835 v = v * base + a2i[(int)*s];
836
837 if ( end != 0 )
838 *end = s;
839
840 return v;
841 }
842
843
844 /* Routine to convert an ASCII string into an signed long integer. */
845 static long
846 _bdf_atol( char* s,
847 char** end,
848 int base )
849 {
850 long v, neg;
851 const unsigned char* dmap;
852
853
854 if ( s == 0 || *s == 0 )
855 return 0;
856
857 /* Make sure the radix is something recognizable. Default to 10. */
858 switch ( base )
859 {
860 case 8:
861 dmap = odigits;
862 break;
863 case 16:
864 dmap = hdigits;
865 break;
866 default:
867 base = 10;
868 dmap = ddigits;
869 break;
870 }
871
872 /* Check for a minus sign. */
873 neg = 0;
874 if ( *s == '-' )
875 {
876 s++;
877 neg = 1;
878 }
879
880 /* Check for the special hex prefix. */
881 if ( *s == '0' &&
882 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
883 {
884 base = 16;
885 dmap = hdigits;
886 s += 2;
887 }
888
889 for ( v = 0; isdigok( dmap, *s ); s++ )
890 v = v * base + a2i[(int)*s];
891
892 if ( end != 0 )
893 *end = s;
894
895 return ( !neg ) ? v : -v;
896 }
897
898
899 /* Routine to convert an ASCII string into an signed short integer. */
900 static short
901 _bdf_atos( char* s,
902 char** end,
903 int base )
904 {
905 short v, neg;
906 const unsigned char* dmap;
907
908
909 if ( s == 0 || *s == 0 )
910 return 0;
911
912 /* Make sure the radix is something recognizable. Default to 10. */
913 switch ( base )
914 {
915 case 8:
916 dmap = odigits;
917 break;
918 case 16:
919 dmap = hdigits;
920 break;
921 default:
922 base = 10;
923 dmap = ddigits;
924 break;
925 }
926
927 /* Check for a minus. */
928 neg = 0;
929 if ( *s == '-' )
930 {
931 s++;
932 neg = 1;
933 }
934
935 /* Check for the special hex prefix. */
936 if ( *s == '0' &&
937 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
938 {
939 base = 16;
940 dmap = hdigits;
941 s += 2;
942 }
943
944 for ( v = 0; isdigok( dmap, *s ); s++ )
945 v = (short)( v * base + a2i[(int)*s] );
946
947 if ( end != 0 )
948 *end = s;
949
950 return (short)( ( !neg ) ? v : -v );
951 }
952
953
954 /* Routine to compare two glyphs by encoding so they can be sorted. */
955 static int
956 by_encoding( const void* a,
957 const void* b )
958 {
959 bdf_glyph_t *c1, *c2;
960
961
962 c1 = (bdf_glyph_t *)a;
963 c2 = (bdf_glyph_t *)b;
964
965 if ( c1->encoding < c2->encoding )
966 return -1;
967
968 if ( c1->encoding > c2->encoding )
969 return 1;
970
971 return 0;
972 }
973
974
975 static FT_Error
976 bdf_create_property( char* name,
977 int format,
978 bdf_font_t* font )
979 {
980 size_t n;
981 bdf_property_t* p;
982 FT_Memory memory = font->memory;
983 FT_Error error = BDF_Err_Ok;
984
985
986 /* First check to see if the property has */
987 /* already been added or not. If it has, then */
988 /* simply ignore it. */
989 if ( hash_lookup( name, &(font->proptbl) ) )
990 goto Exit;
991
992 if ( FT_RENEW_ARRAY( font->user_props,
993 font->nuser_props,
994 font->nuser_props + 1 ) )
995 goto Exit;
996
997 p = font->user_props + font->nuser_props;
998 FT_ZERO( p );
999
1000 n = ft_strlen( name ) + 1;
1001 if ( n > FT_ULONG_MAX )
1002 return BDF_Err_Invalid_Argument;
1003
1004 if ( FT_NEW_ARRAY( p->name, n ) )
1005 goto Exit;
1006
1007 FT_MEM_COPY( (char *)p->name, name, n );
1008
1009 p->format = format;
1010 p->builtin = 0;
1011
1012 n = _num_bdf_properties + font->nuser_props;
1013
1014 error = hash_insert( p->name, n, &(font->proptbl), memory );
1015 if ( error )
1016 goto Exit;
1017
1018 font->nuser_props++;
1019
1020 Exit:
1021 return error;
1022 }
1023
1024
1025 FT_LOCAL_DEF( bdf_property_t * )
1026 bdf_get_property( char* name,
1027 bdf_font_t* font )
1028 {
1029 hashnode hn;
1030 size_t propid;
1031
1032
1033 if ( name == 0 || *name == 0 )
1034 return 0;
1035
1036 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1037 return 0;
1038
1039 propid = hn->data;
1040 if ( propid >= _num_bdf_properties )
1041 return font->user_props + ( propid - _num_bdf_properties );
1042
1043 return (bdf_property_t*)_bdf_properties + propid;
1044 }
1045
1046
1047 /*************************************************************************/
1048 /* */
1049 /* BDF font file parsing flags and functions. */
1050 /* */
1051 /*************************************************************************/
1052
1053
1054 /* Parse flags. */
1055
1056 #define _BDF_START 0x0001
1057 #define _BDF_FONT_NAME 0x0002
1058 #define _BDF_SIZE 0x0004
1059 #define _BDF_FONT_BBX 0x0008
1060 #define _BDF_PROPS 0x0010
1061 #define _BDF_GLYPHS 0x0020
1062 #define _BDF_GLYPH 0x0040
1063 #define _BDF_ENCODING 0x0080
1064 #define _BDF_SWIDTH 0x0100
1065 #define _BDF_DWIDTH 0x0200
1066 #define _BDF_BBX 0x0400
1067 #define _BDF_BITMAP 0x0800
1068
1069 #define _BDF_SWIDTH_ADJ 0x1000
1070
1071 #define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1072 _BDF_ENCODING | \
1073 _BDF_SWIDTH | \
1074 _BDF_DWIDTH | \
1075 _BDF_BBX | \
1076 _BDF_BITMAP )
1077
1078 #define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1079 #define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
1080
1081
1082 /* Auto correction messages. */
1083 #define ACMSG1 "FONT_ASCENT property missing. " \
1084 "Added \"FONT_ASCENT %hd\".\n"
1085 #define ACMSG2 "FONT_DESCENT property missing. " \
1086 "Added \"FONT_DESCENT %hd\".\n"
1087 #define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
1088 #define ACMSG4 "Font left bearing != actual left bearing. " \
1089 "Old: %hd New: %hd.\n"
1090 #define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
1091 #define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
1092 #define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
1093 #define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
1094 #define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
1095 #define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
1096 #define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
1097 #define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
1098 #define ACMSG13 "Glyph %ld extra rows removed.\n"
1099 #define ACMSG14 "Glyph %ld extra columns removed.\n"
1100 #define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
1101
1102 /* Error messages. */
1103 #define ERRMSG1 "[line %ld] Missing \"%s\" line.\n"
1104 #define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
1105 #define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
1106 #define ERRMSG4 "[line %ld] BBX too big.\n"
1107
1108
1109 static FT_Error
1110 _bdf_add_comment( bdf_font_t* font,
1111 char* comment,
1112 unsigned long len )
1113 {
1114 char* cp;
1115 FT_Memory memory = font->memory;
1116 FT_Error error = BDF_Err_Ok;
1117
1118
1119 if ( FT_RENEW_ARRAY( font->comments,
1120 font->comments_len,
1121 font->comments_len + len + 1 ) )
1122 goto Exit;
1123
1124 cp = font->comments + font->comments_len;
1125
1126 FT_MEM_COPY( cp, comment, len );
1127 cp[len] = '\n';
1128
1129 font->comments_len += len + 1;
1130
1131 Exit:
1132 return error;
1133 }
1134
1135
1136 /* Set the spacing from the font name if it exists, or set it to the */
1137 /* default specified in the options. */
1138 static FT_Error
1139 _bdf_set_default_spacing( bdf_font_t* font,
1140 bdf_options_t* opts )
1141 {
1142 size_t len;
1143 char name[256];
1144 _bdf_list_t list;
1145 FT_Memory memory;
1146 FT_Error error = BDF_Err_Ok;
1147
1148
1149 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1150 {
1151 error = BDF_Err_Invalid_Argument;
1152 goto Exit;
1153 }
1154
1155 memory = font->memory;
1156
1157 _bdf_list_init( &list, memory );
1158
1159 font->spacing = opts->font_spacing;
1160
1161 len = ft_strlen( font->name ) + 1;
1162 /* Limit ourselves to 256 characters in the font name. */
1163 if ( len >= 256 )
1164 {
1165 error = BDF_Err_Invalid_Argument;
1166 goto Exit;
1167 }
1168
1169 FT_MEM_COPY( name, font->name, len );
1170
1171 error = _bdf_list_split( &list, (char *)"-", name, len );
1172 if ( error )
1173 goto Fail;
1174
1175 if ( list.used == 15 )
1176 {
1177 switch ( list.field[11][0] )
1178 {
1179 case 'C':
1180 case 'c':
1181 font->spacing = BDF_CHARCELL;
1182 break;
1183 case 'M':
1184 case 'm':
1185 font->spacing = BDF_MONOWIDTH;
1186 break;
1187 case 'P':
1188 case 'p':
1189 font->spacing = BDF_PROPORTIONAL;
1190 break;
1191 }
1192 }
1193
1194 Fail:
1195 _bdf_list_done( &list );
1196
1197 Exit:
1198 return error;
1199 }
1200
1201
1202 /* Determine whether the property is an atom or not. If it is, then */
1203 /* clean it up so the double quotes are removed if they exist. */
1204 static int
1205 _bdf_is_atom( char* line,
1206 unsigned long linelen,
1207 char** name,
1208 char** value,
1209 bdf_font_t* font )
1210 {
1211 int hold;
1212 char *sp, *ep;
1213 bdf_property_t* p;
1214
1215
1216 *name = sp = ep = line;
1217
1218 while ( *ep && *ep != ' ' && *ep != '\t' )
1219 ep++;
1220
1221 hold = -1;
1222 if ( *ep )
1223 {
1224 hold = *ep;
1225 *ep = 0;
1226 }
1227
1228 p = bdf_get_property( sp, font );
1229
1230 /* Restore the character that was saved before any return can happen. */
1231 if ( hold != -1 )
1232 *ep = (char)hold;
1233
1234 /* If the property exists and is not an atom, just return here. */
1235 if ( p && p->format != BDF_ATOM )
1236 return 0;
1237
1238 /* The property is an atom. Trim all leading and trailing whitespace */
1239 /* and double quotes for the atom value. */
1240 sp = ep;
1241 ep = line + linelen;
1242
1243 /* Trim the leading whitespace if it exists. */
1244 *sp++ = 0;
1245 while ( *sp &&
1246 ( *sp == ' ' || *sp == '\t' ) )
1247 sp++;
1248
1249 /* Trim the leading double quote if it exists. */
1250 if ( *sp == '"' )
1251 sp++;
1252 *value = sp;
1253
1254 /* Trim the trailing whitespace if it exists. */
1255 while ( ep > sp &&
1256 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
1257 *--ep = 0;
1258
1259 /* Trim the trailing double quote if it exists. */
1260 if ( ep > sp && *( ep - 1 ) == '"' )
1261 *--ep = 0;
1262
1263 return 1;
1264 }
1265
1266
1267 static FT_Error
1268 _bdf_add_property( bdf_font_t* font,
1269 char* name,
1270 char* value )
1271 {
1272 size_t propid;
1273 hashnode hn;
1274 bdf_property_t *prop, *fp;
1275 FT_Memory memory = font->memory;
1276 FT_Error error = BDF_Err_Ok;
1277
1278
1279 /* First, check to see if the property already exists in the font. */
1280 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
1281 {
1282 /* The property already exists in the font, so simply replace */
1283 /* the value of the property with the current value. */
1284 fp = font->props + hn->data;
1285
1286 switch ( fp->format )
1287 {
1288 case BDF_ATOM:
1289 /* Delete the current atom if it exists. */
1290 FT_FREE( fp->value.atom );
1291
1292 if ( value && value[0] != 0 )
1293 {
1294 if ( FT_STRDUP( fp->value.atom, value ) )
1295 goto Exit;
1296 }
1297 break;
1298
1299 case BDF_INTEGER:
1300 fp->value.l = _bdf_atol( value, 0, 10 );
1301 break;
1302
1303 case BDF_CARDINAL:
1304 fp->value.ul = _bdf_atoul( value, 0, 10 );
1305 break;
1306
1307 default:
1308 ;
1309 }
1310
1311 goto Exit;
1312 }
1313
1314 /* See whether this property type exists yet or not. */
1315 /* If not, create it. */
1316 hn = hash_lookup( name, &(font->proptbl) );
1317 if ( hn == 0 )
1318 {
1319 error = bdf_create_property( name, BDF_ATOM, font );
1320 if ( error )
1321 goto Exit;
1322 hn = hash_lookup( name, &(font->proptbl) );
1323 }
1324
1325 /* Allocate another property if this is overflow. */
1326 if ( font->props_used == font->props_size )
1327 {
1328 if ( font->props_size == 0 )
1329 {
1330 if ( FT_NEW_ARRAY( font->props, 1 ) )
1331 goto Exit;
1332 }
1333 else
1334 {
1335 if ( FT_RENEW_ARRAY( font->props,
1336 font->props_size,
1337 font->props_size + 1 ) )
1338 goto Exit;
1339 }
1340
1341 fp = font->props + font->props_size;
1342 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
1343 font->props_size++;
1344 }
1345
1346 propid = hn->data;
1347 if ( propid >= _num_bdf_properties )
1348 prop = font->user_props + ( propid - _num_bdf_properties );
1349 else
1350 prop = (bdf_property_t*)_bdf_properties + propid;
1351
1352 fp = font->props + font->props_used;
1353
1354 fp->name = prop->name;
1355 fp->format = prop->format;
1356 fp->builtin = prop->builtin;
1357
1358 switch ( prop->format )
1359 {
1360 case BDF_ATOM:
1361 fp->value.atom = 0;
1362 if ( value != 0 && value[0] )
1363 {
1364 if ( FT_STRDUP( fp->value.atom, value ) )
1365 goto Exit;
1366 }
1367 break;
1368
1369 case BDF_INTEGER:
1370 fp->value.l = _bdf_atol( value, 0, 10 );
1371 break;
1372
1373 case BDF_CARDINAL:
1374 fp->value.ul = _bdf_atoul( value, 0, 10 );
1375 break;
1376 }
1377
1378 /* If the property happens to be a comment, then it doesn't need */
1379 /* to be added to the internal hash table. */
1380 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 )
1381 {
1382 /* Add the property to the font property table. */
1383 error = hash_insert( fp->name,
1384 font->props_used,
1385 (hashtable *)font->internal,
1386 memory );
1387 if ( error )
1388 goto Exit;
1389 }
1390
1391 font->props_used++;
1392
1393 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1394 /* property needs to be located if it exists in the property list, the */
1395 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1396 /* present, and the SPACING property should override the default */
1397 /* spacing. */
1398 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
1399 font->default_char = fp->value.l;
1400 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
1401 font->font_ascent = fp->value.l;
1402 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
1403 font->font_descent = fp->value.l;
1404 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
1405 {
1406 if ( !fp->value.atom )
1407 {
1408 error = BDF_Err_Invalid_File_Format;
1409 goto Exit;
1410 }
1411
1412 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
1413 font->spacing = BDF_PROPORTIONAL;
1414 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
1415 font->spacing = BDF_MONOWIDTH;
1416 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
1417 font->spacing = BDF_CHARCELL;
1418 }
1419
1420 Exit:
1421 return error;
1422 }
1423
1424
1425 static const unsigned char nibble_mask[8] =
1426 {
1427 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1428 };
1429
1430
1431 /* Actually parse the glyph info and bitmaps. */
1432 static FT_Error
1433 _bdf_parse_glyphs( char* line,
1434 unsigned long linelen,
1435 unsigned long lineno,
1436 void* call_data,
1437 void* client_data )
1438 {
1439 int c, mask_index;
1440 char* s;
1441 unsigned char* bp;
1442 unsigned long i, slen, nibbles;
1443
1444 _bdf_parse_t* p;
1445 bdf_glyph_t* glyph;
1446 bdf_font_t* font;
1447
1448 FT_Memory memory;
1449 FT_Error error = BDF_Err_Ok;
1450
1451 FT_UNUSED( call_data );
1452 FT_UNUSED( lineno ); /* only used in debug mode */
1453
1454
1455 p = (_bdf_parse_t *)client_data;
1456
1457 font = p->font;
1458 memory = font->memory;
1459
1460 /* Check for a comment. */
1461 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1462 {
1463 linelen -= 7;
1464
1465 s = line + 7;
1466 if ( *s != 0 )
1467 {
1468 s++;
1469 linelen--;
1470 }
1471 error = _bdf_add_comment( p->font, s, linelen );
1472 goto Exit;
1473 }
1474
1475 /* The very first thing expected is the number of glyphs. */
1476 if ( !( p->flags & _BDF_GLYPHS ) )
1477 {
1478 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1479 {
1480 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1481 error = BDF_Err_Missing_Chars_Field;
1482 goto Exit;
1483 }
1484
1485 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1486 if ( error )
1487 goto Exit;
1488 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1489
1490 /* Make sure the number of glyphs is non-zero. */
1491 if ( p->cnt == 0 )
1492 font->glyphs_size = 64;
1493
1494 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1495 /* number of code points available in Unicode). */
1496 if ( p->cnt >= 1114112UL )
1497 {
1498 error = BDF_Err_Invalid_Argument;
1499 goto Exit;
1500 }
1501
1502 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1503 goto Exit;
1504
1505 p->flags |= _BDF_GLYPHS;
1506
1507 goto Exit;
1508 }
1509
1510 /* Check for the ENDFONT field. */
1511 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1512 {
1513 /* Sort the glyphs by encoding. */
1514 ft_qsort( (char *)font->glyphs,
1515 font->glyphs_used,
1516 sizeof ( bdf_glyph_t ),
1517 by_encoding );
1518
1519 p->flags &= ~_BDF_START;
1520
1521 goto Exit;
1522 }
1523
1524 /* Check for the ENDCHAR field. */
1525 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1526 {
1527 p->glyph_enc = 0;
1528 p->flags &= ~_BDF_GLYPH_BITS;
1529
1530 goto Exit;
1531 }
1532
1533 /* Check to see whether a glyph is being scanned but should be */
1534 /* ignored because it is an unencoded glyph. */
1535 if ( ( p->flags & _BDF_GLYPH ) &&
1536 p->glyph_enc == -1 &&
1537 p->opts->keep_unencoded == 0 )
1538 goto Exit;
1539
1540 /* Check for the STARTCHAR field. */
1541 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1542 {
1543 /* Set the character name in the parse info first until the */
1544 /* encoding can be checked for an unencoded character. */
1545 FT_FREE( p->glyph_name );
1546
1547 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1548 if ( error )
1549 goto Exit;
1550
1551 _bdf_list_shift( &p->list, 1 );
1552
1553 s = _bdf_list_join( &p->list, ' ', &slen );
1554
1555 if ( !s )
1556 {
1557 error = BDF_Err_Invalid_File_Format;
1558 goto Exit;
1559 }
1560
1561 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1562 goto Exit;
1563
1564 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1565
1566 p->flags |= _BDF_GLYPH;
1567
1568 goto Exit;
1569 }
1570
1571 /* Check for the ENCODING field. */
1572 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1573 {
1574 if ( !( p->flags & _BDF_GLYPH ) )
1575 {
1576 /* Missing STARTCHAR field. */
1577 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1578 error = BDF_Err_Missing_Startchar_Field;
1579 goto Exit;
1580 }
1581
1582 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1583 if ( error )
1584 goto Exit;
1585
1586 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
1587
1588 /* Check that the encoding is in the range [0,65536] because */
1589 /* otherwise p->have (a bitmap with static size) overflows. */
1590 if ( (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
1591 {
1592 error = BDF_Err_Invalid_File_Format;
1593 goto Exit;
1594 }
1595
1596 /* Check to see whether this encoding has already been encountered. */
1597 /* If it has then change it to unencoded so it gets added if */
1598 /* indicated. */
1599 if ( p->glyph_enc >= 0 )
1600 {
1601 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1602 {
1603 /* Emit a message saying a glyph has been moved to the */
1604 /* unencoded area. */
1605 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1606 p->glyph_enc, p->glyph_name ));
1607 p->glyph_enc = -1;
1608 font->modified = 1;
1609 }
1610 else
1611 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1612 }
1613
1614 if ( p->glyph_enc >= 0 )
1615 {
1616 /* Make sure there are enough glyphs allocated in case the */
1617 /* number of characters happen to be wrong. */
1618 if ( font->glyphs_used == font->glyphs_size )
1619 {
1620 if ( FT_RENEW_ARRAY( font->glyphs,
1621 font->glyphs_size,
1622 font->glyphs_size + 64 ) )
1623 goto Exit;
1624
1625 font->glyphs_size += 64;
1626 }
1627
1628 glyph = font->glyphs + font->glyphs_used++;
1629 glyph->name = p->glyph_name;
1630 glyph->encoding = p->glyph_enc;
1631
1632 /* Reset the initial glyph info. */
1633 p->glyph_name = 0;
1634 }
1635 else
1636 {
1637 /* Unencoded glyph. Check to see whether it should */
1638 /* be added or not. */
1639 if ( p->opts->keep_unencoded != 0 )
1640 {
1641 /* Allocate the next unencoded glyph. */
1642 if ( font->unencoded_used == font->unencoded_size )
1643 {
1644 if ( FT_RENEW_ARRAY( font->unencoded ,
1645 font->unencoded_size,
1646 font->unencoded_size + 4 ) )
1647 goto Exit;
1648
1649 font->unencoded_size += 4;
1650 }
1651
1652 glyph = font->unencoded + font->unencoded_used;
1653 glyph->name = p->glyph_name;
1654 glyph->encoding = font->unencoded_used++;
1655 }
1656 else
1657 /* Free up the glyph name if the unencoded shouldn't be */
1658 /* kept. */
1659 FT_FREE( p->glyph_name );
1660
1661 p->glyph_name = 0;
1662 }
1663
1664 /* Clear the flags that might be added when width and height are */
1665 /* checked for consistency. */
1666 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1667
1668 p->flags |= _BDF_ENCODING;
1669
1670 goto Exit;
1671 }
1672
1673 /* Point at the glyph being constructed. */
1674 if ( p->glyph_enc == -1 )
1675 glyph = font->unencoded + ( font->unencoded_used - 1 );
1676 else
1677 glyph = font->glyphs + ( font->glyphs_used - 1 );
1678
1679 /* Check to see whether a bitmap is being constructed. */
1680 if ( p->flags & _BDF_BITMAP )
1681 {
1682 /* If there are more rows than are specified in the glyph metrics, */
1683 /* ignore the remaining lines. */
1684 if ( p->row >= (unsigned long)glyph->bbx.height )
1685 {
1686 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1687 {
1688 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1689 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
1690 font->modified = 1;
1691 }
1692
1693 goto Exit;
1694 }
1695
1696 /* Only collect the number of nibbles indicated by the glyph */
1697 /* metrics. If there are more columns, they are simply ignored. */
1698 nibbles = glyph->bpr << 1;
1699 bp = glyph->bitmap + p->row * glyph->bpr;
1700
1701 for ( i = 0; i < nibbles; i++ )
1702 {
1703 c = line[i];
1704 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
1705 if ( i + 1 < nibbles && ( i & 1 ) )
1706 *++bp = 0;
1707 }
1708
1709 /* Remove possible garbage at the right. */
1710 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
1711 if ( glyph->bbx.width )
1712 *bp &= nibble_mask[mask_index];
1713
1714 /* If any line has extra columns, indicate they have been removed. */
1715 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1716 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1717 {
1718 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1719 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1720 font->modified = 1;
1721 }
1722
1723 p->row++;
1724 goto Exit;
1725 }
1726
1727 /* Expect the SWIDTH (scalable width) field next. */
1728 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1729 {
1730 if ( !( p->flags & _BDF_ENCODING ) )
1731 {
1732 /* Missing ENCODING field. */
1733 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1734 error = BDF_Err_Missing_Encoding_Field;
1735 goto Exit;
1736 }
1737
1738 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1739 if ( error )
1740 goto Exit;
1741
1742 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
1743 p->flags |= _BDF_SWIDTH;
1744
1745 goto Exit;
1746 }
1747
1748 /* Expect the DWIDTH (scalable width) field next. */
1749 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1750 {
1751 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1752 if ( error )
1753 goto Exit;
1754
1755 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
1756
1757 if ( !( p->flags & _BDF_SWIDTH ) )
1758 {
1759 /* Missing SWIDTH field. Emit an auto correction message and set */
1760 /* the scalable width from the device width. */
1761 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1762
1763 glyph->swidth = (unsigned short)FT_MulDiv(
1764 glyph->dwidth, 72000L,
1765 (FT_Long)( font->point_size *
1766 font->resolution_x ) );
1767 }
1768
1769 p->flags |= _BDF_DWIDTH;
1770 goto Exit;
1771 }
1772
1773 /* Expect the BBX field next. */
1774 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1775 {
1776 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1777 if ( error )
1778 goto Exit;
1779
1780 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1781 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1782 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1783 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1784
1785 /* Generate the ascent and descent of the character. */
1786 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1787 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
1788
1789 /* Determine the overall font bounding box as the characters are */
1790 /* loaded so corrections can be done later if indicated. */
1791 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1792 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
1793
1794 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
1795
1796 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1797 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1798 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
1799
1800 if ( !( p->flags & _BDF_DWIDTH ) )
1801 {
1802 /* Missing DWIDTH field. Emit an auto correction message and set */
1803 /* the device width to the glyph width. */
1804 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1805 glyph->dwidth = glyph->bbx.width;
1806 }
1807
1808 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1809 /* value if necessary. */
1810 if ( p->opts->correct_metrics != 0 )
1811 {
1812 /* Determine the point size of the glyph. */
1813 unsigned short sw = (unsigned short)FT_MulDiv(
1814 glyph->dwidth, 72000L,
1815 (FT_Long)( font->point_size *
1816 font->resolution_x ) );
1817
1818
1819 if ( sw != glyph->swidth )
1820 {
1821 glyph->swidth = sw;
1822
1823 if ( p->glyph_enc == -1 )
1824 _bdf_set_glyph_modified( font->umod,
1825 font->unencoded_used - 1 );
1826 else
1827 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1828
1829 p->flags |= _BDF_SWIDTH_ADJ;
1830 font->modified = 1;
1831 }
1832 }
1833
1834 p->flags |= _BDF_BBX;
1835 goto Exit;
1836 }
1837
1838 /* And finally, gather up the bitmap. */
1839 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1840 {
1841 unsigned long bitmap_size;
1842
1843
1844 if ( !( p->flags & _BDF_BBX ) )
1845 {
1846 /* Missing BBX field. */
1847 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1848 error = BDF_Err_Missing_Bbx_Field;
1849 goto Exit;
1850 }
1851
1852 /* Allocate enough space for the bitmap. */
1853 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
1854
1855 bitmap_size = glyph->bpr * glyph->bbx.height;
1856 if ( bitmap_size > 0xFFFFU )
1857 {
1858 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1859 error = BDF_Err_Bbx_Too_Big;
1860 goto Exit;
1861 }
1862 else
1863 glyph->bytes = (unsigned short)bitmap_size;
1864
1865 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1866 goto Exit;
1867
1868 p->row = 0;
1869 p->flags |= _BDF_BITMAP;
1870
1871 goto Exit;
1872 }
1873
1874 error = BDF_Err_Invalid_File_Format;
1875
1876 Exit:
1877 if ( error && ( p->flags & _BDF_GLYPH ) )
1878 FT_FREE( p->glyph_name );
1879
1880 return error;
1881 }
1882
1883
1884 /* Load the font properties. */
1885 static FT_Error
1886 _bdf_parse_properties( char* line,
1887 unsigned long linelen,
1888 unsigned long lineno,
1889 void* call_data,
1890 void* client_data )
1891 {
1892 unsigned long vlen;
1893 _bdf_line_func_t* next;
1894 _bdf_parse_t* p;
1895 char* name;
1896 char* value;
1897 char nbuf[128];
1898 FT_Error error = BDF_Err_Ok;
1899
1900 FT_UNUSED( lineno );
1901
1902
1903 next = (_bdf_line_func_t *)call_data;
1904 p = (_bdf_parse_t *) client_data;
1905
1906 /* Check for the end of the properties. */
1907 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1908 {
1909 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1910 /* encountered yet, then make sure they are added as properties and */
1911 /* make sure they are set from the font bounding box info. */
1912 /* */
1913 /* This is *always* done regardless of the options, because X11 */
1914 /* requires these two fields to compile fonts. */
1915 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
1916 {
1917 p->font->font_ascent = p->font->bbx.ascent;
1918 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1919 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
1920 if ( error )
1921 goto Exit;
1922
1923 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1924 p->font->modified = 1;
1925 }
1926
1927 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
1928 {
1929 p->font->font_descent = p->font->bbx.descent;
1930 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1931 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
1932 if ( error )
1933 goto Exit;
1934
1935 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1936 p->font->modified = 1;
1937 }
1938
1939 p->flags &= ~_BDF_PROPS;
1940 *next = _bdf_parse_glyphs;
1941
1942 goto Exit;
1943 }
1944
1945 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1946 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1947 goto Exit;
1948
1949 /* Handle COMMENT fields and properties in a special way to preserve */
1950 /* the spacing. */
1951 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1952 {
1953 name = value = line;
1954 value += 7;
1955 if ( *value )
1956 *value++ = 0;
1957 error = _bdf_add_property( p->font, name, value );
1958 if ( error )
1959 goto Exit;
1960 }
1961 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1962 {
1963 error = _bdf_add_property( p->font, name, value );
1964 if ( error )
1965 goto Exit;
1966 }
1967 else
1968 {
1969 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1970 if ( error )
1971 goto Exit;
1972 name = p->list.field[0];
1973
1974 _bdf_list_shift( &p->list, 1 );
1975 value = _bdf_list_join( &p->list, ' ', &vlen );
1976
1977 error = _bdf_add_property( p->font, name, value );
1978 if ( error )
1979 goto Exit;
1980 }
1981
1982 Exit:
1983 return error;
1984 }
1985
1986
1987 /* Load the font header. */
1988 static FT_Error
1989 _bdf_parse_start( char* line,
1990 unsigned long linelen,
1991 unsigned long lineno,
1992 void* call_data,
1993 void* client_data )
1994 {
1995 unsigned long slen;
1996 _bdf_line_func_t* next;
1997 _bdf_parse_t* p;
1998 bdf_font_t* font;
1999 char *s;
2000
2001 FT_Memory memory = NULL;
2002 FT_Error error = BDF_Err_Ok;
2003
2004 FT_UNUSED( lineno ); /* only used in debug mode */
2005
2006
2007 next = (_bdf_line_func_t *)call_data;
2008 p = (_bdf_parse_t *) client_data;
2009
2010 if ( p->font )
2011 memory = p->font->memory;
2012
2013 /* Check for a comment. This is done to handle those fonts that have */
2014 /* comments before the STARTFONT line for some reason. */
2015 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2016 {
2017 if ( p->opts->keep_comments != 0 && p->font != 0 )
2018 {
2019 linelen -= 7;
2020
2021 s = line + 7;
2022 if ( *s != 0 )
2023 {
2024 s++;
2025 linelen--;
2026 }
2027
2028 error = _bdf_add_comment( p->font, s, linelen );
2029 if ( error )
2030 goto Exit;
2031 /* here font is not defined! */
2032 }
2033
2034 goto Exit;
2035 }
2036
2037 if ( !( p->flags & _BDF_START ) )
2038 {
2039 memory = p->memory;
2040
2041 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2042 {
2043 /* No STARTFONT field is a good indication of a problem. */
2044 error = BDF_Err_Missing_Startfont_Field;
2045 goto Exit;
2046 }
2047
2048 p->flags = _BDF_START;
2049 font = p->font = 0;
2050
2051 if ( FT_NEW( font ) )
2052 goto Exit;
2053 p->font = font;
2054
2055 font->memory = p->memory;
2056 p->memory = 0;
2057
2058 { /* setup */
2059 size_t i;
2060 bdf_property_t* prop;
2061
2062
2063 error = hash_init( &(font->proptbl), memory );
2064 if ( error )
2065 goto Exit;
2066 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
2067 i < _num_bdf_properties; i++, prop++ )
2068 {
2069 error = hash_insert( prop->name, i,
2070 &(font->proptbl), memory );
2071 if ( error )
2072 goto Exit;
2073 }
2074 }
2075
2076 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2077 goto Exit;
2078 error = hash_init( (hashtable *)p->font->internal,memory );
2079 if ( error )
2080 goto Exit;
2081 p->font->spacing = p->opts->font_spacing;
2082 p->font->default_char = -1;
2083
2084 goto Exit;
2085 }
2086
2087 /* Check for the start of the properties. */
2088 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2089 {
2090 if ( !( p->flags & _BDF_FONT_BBX ) )
2091 {
2092 /* Missing the FONTBOUNDINGBOX field. */
2093 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2094 error = BDF_Err_Missing_Fontboundingbox_Field;
2095 goto Exit;
2096 }
2097
2098 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2099 if ( error )
2100 goto Exit;
2101 /* at this point, `p->font' can't be NULL */
2102 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2103
2104 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2105 goto Exit;
2106
2107 p->flags |= _BDF_PROPS;
2108 *next = _bdf_parse_properties;
2109
2110 goto Exit;
2111 }
2112
2113 /* Check for the FONTBOUNDINGBOX field. */
2114 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2115 {
2116 if ( !( p->flags & _BDF_SIZE ) )
2117 {
2118 /* Missing the SIZE field. */
2119 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2120 error = BDF_Err_Missing_Size_Field;
2121 goto Exit;
2122 }
2123
2124 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2125 if ( error )
2126 goto Exit;
2127
2128 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2129 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2130
2131 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2132 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2133
2134 p->font->bbx.ascent = (short)( p->font->bbx.height +
2135 p->font->bbx.y_offset );
2136
2137 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
2138
2139 p->flags |= _BDF_FONT_BBX;
2140
2141 goto Exit;
2142 }
2143
2144 /* The next thing to check for is the FONT field. */
2145 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2146 {
2147 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2148 if ( error )
2149 goto Exit;
2150 _bdf_list_shift( &p->list, 1 );
2151
2152 s = _bdf_list_join( &p->list, ' ', &slen );
2153
2154 if ( !s )
2155 {
2156 error = BDF_Err_Invalid_File_Format;
2157 goto Exit;
2158 }
2159
2160 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2161 FT_FREE( p->font->name );
2162
2163 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2164 goto Exit;
2165 FT_MEM_COPY( p->font->name, s, slen + 1 );
2166
2167 /* If the font name is an XLFD name, set the spacing to the one in */
2168 /* the font name. If there is no spacing fall back on the default. */
2169 error = _bdf_set_default_spacing( p->font, p->opts );
2170 if ( error )
2171 goto Exit;
2172
2173 p->flags |= _BDF_FONT_NAME;
2174
2175 goto Exit;
2176 }
2177
2178 /* Check for the SIZE field. */
2179 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2180 {
2181 if ( !( p->flags & _BDF_FONT_NAME ) )
2182 {
2183 /* Missing the FONT field. */
2184 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2185 error = BDF_Err_Missing_Font_Field;
2186 goto Exit;
2187 }
2188
2189 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2190 if ( error )
2191 goto Exit;
2192
2193 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2194 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2195 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2196
2197 /* Check for the bits per pixel field. */
2198 if ( p->list.used == 5 )
2199 {
2200 unsigned short bitcount, i, shift;
2201
2202
2203 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2204
2205 /* Only values 1, 2, 4, 8 are allowed. */
2206 shift = p->font->bpp;
2207 bitcount = 0;
2208 for ( i = 0; shift > 0; i++ )
2209 {
2210 if ( shift & 1 )
2211 bitcount = i;
2212 shift >>= 1;
2213 }
2214
2215 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
2216
2217 if ( p->font->bpp > shift || p->font->bpp != shift )
2218 {
2219 /* select next higher value */
2220 p->font->bpp = (unsigned short)( shift << 1 );
2221 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
2222 }
2223 }
2224 else
2225 p->font->bpp = 1;
2226
2227 p->flags |= _BDF_SIZE;
2228
2229 goto Exit;
2230 }
2231
2232 /* Check for the CHARS field -- font properties are optional */
2233 if ( ft_memcmp( line, "CHARS", 5 ) == 0 )
2234 {
2235 char nbuf[128];
2236
2237
2238 if ( !( p->flags & _BDF_FONT_BBX ) )
2239 {
2240 /* Missing the FONTBOUNDINGBOX field. */
2241 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2242 error = BDF_Err_Missing_Fontboundingbox_Field;
2243 goto Exit;
2244 }
2245
2246 /* Add the two standard X11 properties which are required */
2247 /* for compiling fonts. */
2248 p->font->font_ascent = p->font->bbx.ascent;
2249 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
2250 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
2251 if ( error )
2252 goto Exit;
2253 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2254
2255 p->font->font_descent = p->font->bbx.descent;
2256 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
2257 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
2258 if ( error )
2259 goto Exit;
2260 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2261
2262 p->font->modified = 1;
2263
2264 *next = _bdf_parse_glyphs;
2265
2266 /* A special return value. */
2267 error = -1;
2268 goto Exit;
2269 }
2270
2271 error = BDF_Err_Invalid_File_Format;
2272
2273 Exit:
2274 return error;
2275 }
2276
2277
2278 /*************************************************************************/
2279 /* */
2280 /* API. */
2281 /* */
2282 /*************************************************************************/
2283
2284
2285 FT_LOCAL_DEF( FT_Error )
2286 bdf_load_font( FT_Stream stream,
2287 FT_Memory extmemory,
2288 bdf_options_t* opts,
2289 bdf_font_t* *font )
2290 {
2291 unsigned long lineno = 0; /* make compiler happy */
2292 _bdf_parse_t *p = NULL;
2293
2294 FT_Memory memory = extmemory;
2295 FT_Error error = BDF_Err_Ok;
2296
2297
2298 if ( FT_NEW( p ) )
2299 goto Exit;
2300
2301 memory = NULL;
2302 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2303 p->minlb = 32767;
2304 p->memory = extmemory; /* only during font creation */
2305
2306 _bdf_list_init( &p->list, extmemory );
2307
2308 error = _bdf_readstream( stream, _bdf_parse_start,
2309 (void *)p, &lineno );
2310 if ( error )
2311 goto Fail;
2312
2313 if ( p->font != 0 )
2314 {
2315 /* If the font is not proportional, set the font's monowidth */
2316 /* field to the width of the font bounding box. */
2317 memory = p->font->memory;
2318
2319 if ( p->font->spacing != BDF_PROPORTIONAL )
2320 p->font->monowidth = p->font->bbx.width;
2321
2322 /* If the number of glyphs loaded is not that of the original count, */
2323 /* indicate the difference. */
2324 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
2325 {
2326 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2327 p->font->glyphs_used + p->font->unencoded_used ));
2328 p->font->modified = 1;
2329 }
2330
2331 /* Once the font has been loaded, adjust the overall font metrics if */
2332 /* necessary. */
2333 if ( p->opts->correct_metrics != 0 &&
2334 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
2335 {
2336 if ( p->maxrb - p->minlb != p->font->bbx.width )
2337 {
2338 FT_TRACE2(( "bdf_load_font: " ACMSG3,
2339 p->font->bbx.width, p->maxrb - p->minlb ));
2340 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2341 p->font->modified = 1;
2342 }
2343
2344 if ( p->font->bbx.x_offset != p->minlb )
2345 {
2346 FT_TRACE2(( "bdf_load_font: " ACMSG4,
2347 p->font->bbx.x_offset, p->minlb ));
2348 p->font->bbx.x_offset = p->minlb;
2349 p->font->modified = 1;
2350 }
2351
2352 if ( p->font->bbx.ascent != p->maxas )
2353 {
2354 FT_TRACE2(( "bdf_load_font: " ACMSG5,
2355 p->font->bbx.ascent, p->maxas ));
2356 p->font->bbx.ascent = p->maxas;
2357 p->font->modified = 1;
2358 }
2359
2360 if ( p->font->bbx.descent != p->maxds )
2361 {
2362 FT_TRACE2(( "bdf_load_font: " ACMSG6,
2363 p->font->bbx.descent, p->maxds ));
2364 p->font->bbx.descent = p->maxds;
2365 p->font->bbx.y_offset = (short)( -p->maxds );
2366 p->font->modified = 1;
2367 }
2368
2369 if ( p->maxas + p->maxds != p->font->bbx.height )
2370 {
2371 FT_TRACE2(( "bdf_load_font: " ACMSG7,
2372 p->font->bbx.height, p->maxas + p->maxds ));
2373 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
2374 }
2375
2376 if ( p->flags & _BDF_SWIDTH_ADJ )
2377 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2378 }
2379 }
2380
2381 if ( p->flags & _BDF_START )
2382 {
2383 {
2384 /* The ENDFONT field was never reached or did not exist. */
2385 if ( !( p->flags & _BDF_GLYPHS ) )
2386 {
2387 /* Error happened while parsing header. */
2388 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2389 error = BDF_Err_Corrupted_Font_Header;
2390 goto Exit;
2391 }
2392 else
2393 {
2394 /* Error happened when parsing glyphs. */
2395 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2396 error = BDF_Err_Corrupted_Font_Glyphs;
2397 goto Exit;
2398 }
2399 }
2400 }
2401
2402 if ( p->font != 0 )
2403 {
2404 /* Make sure the comments are NULL terminated if they exist. */
2405 memory = p->font->memory;
2406
2407 if ( p->font->comments_len > 0 )
2408 {
2409 if ( FT_RENEW_ARRAY( p->font->comments,
2410 p->font->comments_len,
2411 p->font->comments_len + 1 ) )
2412 goto Fail;
2413
2414 p->font->comments[p->font->comments_len] = 0;
2415 }
2416 }
2417 else if ( error == BDF_Err_Ok )
2418 error = BDF_Err_Invalid_File_Format;
2419
2420 *font = p->font;
2421
2422 Exit:
2423 if ( p )
2424 {
2425 _bdf_list_done( &p->list );
2426
2427 memory = extmemory;
2428
2429 FT_FREE( p );
2430 }
2431
2432 return error;
2433
2434 Fail:
2435 bdf_free_font( p->font );
2436
2437 memory = extmemory;
2438
2439 FT_FREE( p->font );
2440
2441 goto Exit;
2442 }
2443
2444
2445 FT_LOCAL_DEF( void )
2446 bdf_free_font( bdf_font_t* font )
2447 {
2448 bdf_property_t* prop;
2449 unsigned long i;
2450 bdf_glyph_t* glyphs;
2451 FT_Memory memory;
2452
2453
2454 if ( font == 0 )
2455 return;
2456
2457 memory = font->memory;
2458
2459 FT_FREE( font->name );
2460
2461 /* Free up the internal hash table of property names. */
2462 if ( font->internal )
2463 {
2464 hash_free( (hashtable *)font->internal, memory );
2465 FT_FREE( font->internal );
2466 }
2467
2468 /* Free up the comment info. */
2469 FT_FREE( font->comments );
2470
2471 /* Free up the properties. */
2472 for ( i = 0; i < font->props_size; i++ )
2473 {
2474 if ( font->props[i].format == BDF_ATOM )
2475 FT_FREE( font->props[i].value.atom );
2476 }
2477
2478 FT_FREE( font->props );
2479
2480 /* Free up the character info. */
2481 for ( i = 0, glyphs = font->glyphs;
2482 i < font->glyphs_used; i++, glyphs++ )
2483 {
2484 FT_FREE( glyphs->name );
2485 FT_FREE( glyphs->bitmap );
2486 }
2487
2488 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2489 i++, glyphs++ )
2490 {
2491 FT_FREE( glyphs->name );
2492 FT_FREE( glyphs->bitmap );
2493 }
2494
2495 FT_FREE( font->glyphs );
2496 FT_FREE( font->unencoded );
2497
2498 /* Free up the overflow storage if it was used. */
2499 for ( i = 0, glyphs = font->overflow.glyphs;
2500 i < font->overflow.glyphs_used; i++, glyphs++ )
2501 {
2502 FT_FREE( glyphs->name );
2503 FT_FREE( glyphs->bitmap );
2504 }
2505
2506 FT_FREE( font->overflow.glyphs );
2507
2508 /* bdf_cleanup */
2509 hash_free( &(font->proptbl), memory );
2510
2511 /* Free up the user defined properties. */
2512 for ( prop = font->user_props, i = 0;
2513 i < font->nuser_props; i++, prop++ )
2514 {
2515 FT_FREE( prop->name );
2516 if ( prop->format == BDF_ATOM )
2517 FT_FREE( prop->value.atom );
2518 }
2519
2520 FT_FREE( font->user_props );
2521
2522 /* FREE( font ); */ /* XXX Fixme */
2523 }
2524
2525
2526 FT_LOCAL_DEF( bdf_property_t * )
2527 bdf_get_font_property( bdf_font_t* font,
2528 const char* name )
2529 {
2530 hashnode hn;
2531
2532
2533 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
2534 return 0;
2535
2536 hn = hash_lookup( name, (hashtable *)font->internal );
2537
2538 return hn ? ( font->props + hn->data ) : 0;
2539 }
2540
2541
2542 /* END */