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