1 /*
2  * Copyright 2000 Computing Research Labs, New Mexico State University
3  * Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009
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*
hash_bucket(const char * key,hashtable * ht)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
hash_rehash(hashtable * ht,FT_Memory memory)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
hash_init(hashtable * ht,FT_Memory memory)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
hash_free(hashtable * ht,FT_Memory memory)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
hash_insert(char * key,void * data,hashtable * ht,FT_Memory memory)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
hash_lookup(const char * key,hashtable * ht)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
_bdf_list_init(_bdf_list_t * list,FT_Memory memory)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
_bdf_list_done(_bdf_list_t * list)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
_bdf_list_ensure(_bdf_list_t * list,int num_items)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
_bdf_list_shift(_bdf_list_t * list,unsigned long n)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 *
_bdf_list_join(_bdf_list_t * list,int c,unsigned long * alen)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
_bdf_list_split(_bdf_list_t * list,char * separators,char * line,unsigned long linelen)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
_bdf_readstream(FT_Stream stream,_bdf_line_func_t callback,void * client_data,unsigned long * lno)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
_bdf_atoul(char * s,char ** end,int base)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
_bdf_atol(char * s,char ** end,int base)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
_bdf_atos(char * s,char ** end,int base)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
by_encoding(const void * a,const void * b)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
bdf_create_property(char * name,int format,bdf_font_t * font)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 * )
bdf_get_property(char * name,bdf_font_t * font)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
_bdf_add_comment(bdf_font_t * font,char * comment,unsigned long len)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
_bdf_set_default_spacing(bdf_font_t * font,bdf_options_t * opts)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
_bdf_is_atom(char * line,unsigned long linelen,char ** name,char ** value,bdf_font_t * font)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
_bdf_add_property(bdf_font_t * font,char * name,char * value)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 )
1398       {
1399         error = BDF_Err_Invalid_File_Format;
1400         goto Exit;
1401       }
1402 
1403       if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
1404         font->spacing = BDF_PROPORTIONAL;
1405       else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
1406         font->spacing = BDF_MONOWIDTH;
1407       else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
1408         font->spacing = BDF_CHARCELL;
1409     }
1410 
1411   Exit:
1412     return error;
1413   }
1414 
1415 
1416   static const unsigned char nibble_mask[8] =
1417   {
1418     0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1419   };
1420 
1421 
1422   /* Actually parse the glyph info and bitmaps. */
1423   static FT_Error
_bdf_parse_glyphs(char * line,unsigned long linelen,unsigned long lineno,void * call_data,void * client_data)1424   _bdf_parse_glyphs( char*          line,
1425                      unsigned long  linelen,
1426                      unsigned long  lineno,
1427                      void*          call_data,
1428                      void*          client_data )
1429   {
1430     int                c, mask_index;
1431     char*              s;
1432     unsigned char*     bp;
1433     unsigned long      i, slen, nibbles;
1434 
1435     _bdf_parse_t*      p;
1436     bdf_glyph_t*       glyph;
1437     bdf_font_t*        font;
1438 
1439     FT_Memory          memory;
1440     FT_Error           error = BDF_Err_Ok;
1441 
1442     FT_UNUSED( call_data );
1443     FT_UNUSED( lineno );        /* only used in debug mode */
1444 
1445 
1446     p = (_bdf_parse_t *)client_data;
1447 
1448     font   = p->font;
1449     memory = font->memory;
1450 
1451     /* Check for a comment. */
1452     if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1453     {
1454       linelen -= 7;
1455 
1456       s = line + 7;
1457       if ( *s != 0 )
1458       {
1459         s++;
1460         linelen--;
1461       }
1462       error = _bdf_add_comment( p->font, s, linelen );
1463       goto Exit;
1464     }
1465 
1466     /* The very first thing expected is the number of glyphs. */
1467     if ( !( p->flags & _BDF_GLYPHS ) )
1468     {
1469       if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1470       {
1471         FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1472         error = BDF_Err_Missing_Chars_Field;
1473         goto Exit;
1474       }
1475 
1476       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1477       if ( error )
1478         goto Exit;
1479       p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1480 
1481       /* Make sure the number of glyphs is non-zero. */
1482       if ( p->cnt == 0 )
1483         font->glyphs_size = 64;
1484 
1485       /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1486       /* number of code points available in Unicode).                 */
1487       if ( p->cnt >= 1114112UL )
1488       {
1489         error = BDF_Err_Invalid_Argument;
1490         goto Exit;
1491       }
1492 
1493       if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1494         goto Exit;
1495 
1496       p->flags |= _BDF_GLYPHS;
1497 
1498       goto Exit;
1499     }
1500 
1501     /* Check for the ENDFONT field. */
1502     if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1503     {
1504       /* Sort the glyphs by encoding. */
1505       ft_qsort( (char *)font->glyphs,
1506                 font->glyphs_used,
1507                 sizeof ( bdf_glyph_t ),
1508                 by_encoding );
1509 
1510       p->flags &= ~_BDF_START;
1511 
1512       goto Exit;
1513     }
1514 
1515     /* Check for the ENDCHAR field. */
1516     if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1517     {
1518       p->glyph_enc = 0;
1519       p->flags    &= ~_BDF_GLYPH_BITS;
1520 
1521       goto Exit;
1522     }
1523 
1524     /* Check to see whether a glyph is being scanned but should be */
1525     /* ignored because it is an unencoded glyph.                   */
1526     if ( ( p->flags & _BDF_GLYPH )     &&
1527          p->glyph_enc            == -1 &&
1528          p->opts->keep_unencoded == 0  )
1529       goto Exit;
1530 
1531     /* Check for the STARTCHAR field. */
1532     if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1533     {
1534       /* Set the character name in the parse info first until the */
1535       /* encoding can be checked for an unencoded character.      */
1536       FT_FREE( p->glyph_name );
1537 
1538       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1539       if ( error )
1540         goto Exit;
1541 
1542       _bdf_list_shift( &p->list, 1 );
1543 
1544       s = _bdf_list_join( &p->list, ' ', &slen );
1545 
1546       if ( !s )
1547       {
1548         error = BDF_Err_Invalid_File_Format;
1549         goto Exit;
1550       }
1551 
1552       if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1553         goto Exit;
1554 
1555       FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1556 
1557       p->flags |= _BDF_GLYPH;
1558 
1559       goto Exit;
1560     }
1561 
1562     /* Check for the ENCODING field. */
1563     if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1564     {
1565       if ( !( p->flags & _BDF_GLYPH ) )
1566       {
1567         /* Missing STARTCHAR field. */
1568         FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1569         error = BDF_Err_Missing_Startchar_Field;
1570         goto Exit;
1571       }
1572 
1573       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1574       if ( error )
1575         goto Exit;
1576 
1577       p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
1578 
1579       /* Check that the encoding is in the range [0,65536] because        */
1580       /* otherwise p->have (a bitmap with static size) overflows.         */
1581       if ( (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
1582       {
1583         error = BDF_Err_Invalid_File_Format;
1584         goto Exit;
1585       }
1586 
1587       /* Check to see whether this encoding has already been encountered. */
1588       /* If it has then change it to unencoded so it gets added if        */
1589       /* indicated.                                                       */
1590       if ( p->glyph_enc >= 0 )
1591       {
1592         if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1593         {
1594           /* Emit a message saying a glyph has been moved to the */
1595           /* unencoded area.                                     */
1596           FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1597                       p->glyph_enc, p->glyph_name ));
1598           p->glyph_enc = -1;
1599           font->modified = 1;
1600         }
1601         else
1602           _bdf_set_glyph_modified( p->have, p->glyph_enc );
1603       }
1604 
1605       if ( p->glyph_enc >= 0 )
1606       {
1607         /* Make sure there are enough glyphs allocated in case the */
1608         /* number of characters happen to be wrong.                */
1609         if ( font->glyphs_used == font->glyphs_size )
1610         {
1611           if ( FT_RENEW_ARRAY( font->glyphs,
1612                                font->glyphs_size,
1613                                font->glyphs_size + 64 ) )
1614             goto Exit;
1615 
1616           font->glyphs_size += 64;
1617         }
1618 
1619         glyph           = font->glyphs + font->glyphs_used++;
1620         glyph->name     = p->glyph_name;
1621         glyph->encoding = p->glyph_enc;
1622 
1623         /* Reset the initial glyph info. */
1624         p->glyph_name = 0;
1625       }
1626       else
1627       {
1628         /* Unencoded glyph.  Check to see whether it should */
1629         /* be added or not.                                 */
1630         if ( p->opts->keep_unencoded != 0 )
1631         {
1632           /* Allocate the next unencoded glyph. */
1633           if ( font->unencoded_used == font->unencoded_size )
1634           {
1635             if ( FT_RENEW_ARRAY( font->unencoded ,
1636                                  font->unencoded_size,
1637                                  font->unencoded_size + 4 ) )
1638               goto Exit;
1639 
1640             font->unencoded_size += 4;
1641           }
1642 
1643           glyph           = font->unencoded + font->unencoded_used;
1644           glyph->name     = p->glyph_name;
1645           glyph->encoding = font->unencoded_used++;
1646         }
1647         else
1648           /* Free up the glyph name if the unencoded shouldn't be */
1649           /* kept.                                                */
1650           FT_FREE( p->glyph_name );
1651 
1652         p->glyph_name = 0;
1653       }
1654 
1655       /* Clear the flags that might be added when width and height are */
1656       /* checked for consistency.                                      */
1657       p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1658 
1659       p->flags |= _BDF_ENCODING;
1660 
1661       goto Exit;
1662     }
1663 
1664     /* Point at the glyph being constructed. */
1665     if ( p->glyph_enc == -1 )
1666       glyph = font->unencoded + ( font->unencoded_used - 1 );
1667     else
1668       glyph = font->glyphs + ( font->glyphs_used - 1 );
1669 
1670     /* Check to see whether a bitmap is being constructed. */
1671     if ( p->flags & _BDF_BITMAP )
1672     {
1673       /* If there are more rows than are specified in the glyph metrics, */
1674       /* ignore the remaining lines.                                     */
1675       if ( p->row >= (unsigned long)glyph->bbx.height )
1676       {
1677         if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1678         {
1679           FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1680           p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
1681           font->modified = 1;
1682         }
1683 
1684         goto Exit;
1685       }
1686 
1687       /* Only collect the number of nibbles indicated by the glyph     */
1688       /* metrics.  If there are more columns, they are simply ignored. */
1689       nibbles = glyph->bpr << 1;
1690       bp      = glyph->bitmap + p->row * glyph->bpr;
1691 
1692       for ( i = 0; i < nibbles; i++ )
1693       {
1694         c = line[i];
1695         *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
1696         if ( i + 1 < nibbles && ( i & 1 ) )
1697           *++bp = 0;
1698       }
1699 
1700       /* Remove possible garbage at the right. */
1701       mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
1702       if ( glyph->bbx.width )
1703         *bp &= nibble_mask[mask_index];
1704 
1705       /* If any line has extra columns, indicate they have been removed. */
1706       if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1707            !( p->flags & _BDF_GLYPH_WIDTH_CHECK )                   )
1708       {
1709         FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1710         p->flags       |= _BDF_GLYPH_WIDTH_CHECK;
1711         font->modified  = 1;
1712       }
1713 
1714       p->row++;
1715       goto Exit;
1716     }
1717 
1718     /* Expect the SWIDTH (scalable width) field next. */
1719     if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1720     {
1721       if ( !( p->flags & _BDF_ENCODING ) )
1722       {
1723         /* Missing ENCODING field. */
1724         FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1725         error = BDF_Err_Missing_Encoding_Field;
1726         goto Exit;
1727       }
1728 
1729       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1730       if ( error )
1731         goto Exit;
1732 
1733       glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
1734       p->flags |= _BDF_SWIDTH;
1735 
1736       goto Exit;
1737     }
1738 
1739     /* Expect the DWIDTH (scalable width) field next. */
1740     if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1741     {
1742       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1743       if ( error )
1744         goto Exit;
1745 
1746       glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
1747 
1748       if ( !( p->flags & _BDF_SWIDTH ) )
1749       {
1750         /* Missing SWIDTH field.  Emit an auto correction message and set */
1751         /* the scalable width from the device width.                      */
1752         FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1753 
1754         glyph->swidth = (unsigned short)FT_MulDiv(
1755                           glyph->dwidth, 72000L,
1756                           (FT_Long)( font->point_size *
1757                                      font->resolution_x ) );
1758       }
1759 
1760       p->flags |= _BDF_DWIDTH;
1761       goto Exit;
1762     }
1763 
1764     /* Expect the BBX field next. */
1765     if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1766     {
1767       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1768       if ( error )
1769         goto Exit;
1770 
1771       glyph->bbx.width    = _bdf_atos( p->list.field[1], 0, 10 );
1772       glyph->bbx.height   = _bdf_atos( p->list.field[2], 0, 10 );
1773       glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1774       glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1775 
1776       /* Generate the ascent and descent of the character. */
1777       glyph->bbx.ascent  = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1778       glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
1779 
1780       /* Determine the overall font bounding box as the characters are */
1781       /* loaded so corrections can be done later if indicated.         */
1782       p->maxas    = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1783       p->maxds    = (short)FT_MAX( glyph->bbx.descent, p->maxds );
1784 
1785       p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
1786 
1787       p->maxrb    = (short)FT_MAX( p->rbearing, p->maxrb );
1788       p->minlb    = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1789       p->maxlb    = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
1790 
1791       if ( !( p->flags & _BDF_DWIDTH ) )
1792       {
1793         /* Missing DWIDTH field.  Emit an auto correction message and set */
1794         /* the device width to the glyph width.                           */
1795         FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1796         glyph->dwidth = glyph->bbx.width;
1797       }
1798 
1799       /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1800       /* value if necessary.                                            */
1801       if ( p->opts->correct_metrics != 0 )
1802       {
1803         /* Determine the point size of the glyph. */
1804         unsigned short  sw = (unsigned short)FT_MulDiv(
1805                                glyph->dwidth, 72000L,
1806                                (FT_Long)( font->point_size *
1807                                           font->resolution_x ) );
1808 
1809 
1810         if ( sw != glyph->swidth )
1811         {
1812           glyph->swidth = sw;
1813 
1814           if ( p->glyph_enc == -1 )
1815             _bdf_set_glyph_modified( font->umod,
1816                                      font->unencoded_used - 1 );
1817           else
1818             _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1819 
1820           p->flags       |= _BDF_SWIDTH_ADJ;
1821           font->modified  = 1;
1822         }
1823       }
1824 
1825       p->flags |= _BDF_BBX;
1826       goto Exit;
1827     }
1828 
1829     /* And finally, gather up the bitmap. */
1830     if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1831     {
1832       unsigned long  bitmap_size;
1833 
1834 
1835       if ( !( p->flags & _BDF_BBX ) )
1836       {
1837         /* Missing BBX field. */
1838         FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1839         error = BDF_Err_Missing_Bbx_Field;
1840         goto Exit;
1841       }
1842 
1843       /* Allocate enough space for the bitmap. */
1844       glyph->bpr   = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
1845 
1846       bitmap_size = glyph->bpr * glyph->bbx.height;
1847       if ( bitmap_size > 0xFFFFU )
1848       {
1849         FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1850         error = BDF_Err_Bbx_Too_Big;
1851         goto Exit;
1852       }
1853       else
1854         glyph->bytes = (unsigned short)bitmap_size;
1855 
1856       if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1857         goto Exit;
1858 
1859       p->row    = 0;
1860       p->flags |= _BDF_BITMAP;
1861 
1862       goto Exit;
1863     }
1864 
1865     error = BDF_Err_Invalid_File_Format;
1866 
1867   Exit:
1868     return error;
1869   }
1870 
1871 
1872   /* Load the font properties. */
1873   static FT_Error
_bdf_parse_properties(char * line,unsigned long linelen,unsigned long lineno,void * call_data,void * client_data)1874   _bdf_parse_properties( char*          line,
1875                          unsigned long  linelen,
1876                          unsigned long  lineno,
1877                          void*          call_data,
1878                          void*          client_data )
1879   {
1880     unsigned long      vlen;
1881     _bdf_line_func_t*  next;
1882     _bdf_parse_t*      p;
1883     char*              name;
1884     char*              value;
1885     char               nbuf[128];
1886     FT_Error           error = BDF_Err_Ok;
1887 
1888     FT_UNUSED( lineno );
1889 
1890 
1891     next = (_bdf_line_func_t *)call_data;
1892     p    = (_bdf_parse_t *)    client_data;
1893 
1894     /* Check for the end of the properties. */
1895     if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1896     {
1897       /* If the FONT_ASCENT or FONT_DESCENT properties have not been      */
1898       /* encountered yet, then make sure they are added as properties and */
1899       /* make sure they are set from the font bounding box info.          */
1900       /*                                                                  */
1901       /* This is *always* done regardless of the options, because X11     */
1902       /* requires these two fields to compile fonts.                      */
1903       if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
1904       {
1905         p->font->font_ascent = p->font->bbx.ascent;
1906         ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1907         error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
1908         if ( error )
1909           goto Exit;
1910 
1911         FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1912         p->font->modified = 1;
1913       }
1914 
1915       if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
1916       {
1917         p->font->font_descent = p->font->bbx.descent;
1918         ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1919         error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
1920         if ( error )
1921           goto Exit;
1922 
1923         FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1924         p->font->modified = 1;
1925       }
1926 
1927       p->flags &= ~_BDF_PROPS;
1928       *next     = _bdf_parse_glyphs;
1929 
1930       goto Exit;
1931     }
1932 
1933     /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1934     if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1935       goto Exit;
1936 
1937     /* Handle COMMENT fields and properties in a special way to preserve */
1938     /* the spacing.                                                      */
1939     if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1940     {
1941       name = value = line;
1942       value += 7;
1943       if ( *value )
1944         *value++ = 0;
1945       error = _bdf_add_property( p->font, name, value );
1946       if ( error )
1947         goto Exit;
1948     }
1949     else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1950     {
1951       error = _bdf_add_property( p->font, name, value );
1952       if ( error )
1953         goto Exit;
1954     }
1955     else
1956     {
1957       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1958       if ( error )
1959         goto Exit;
1960       name = p->list.field[0];
1961 
1962       _bdf_list_shift( &p->list, 1 );
1963       value = _bdf_list_join( &p->list, ' ', &vlen );
1964 
1965       error = _bdf_add_property( p->font, name, value );
1966       if ( error )
1967         goto Exit;
1968     }
1969 
1970   Exit:
1971     return error;
1972   }
1973 
1974 
1975   /* Load the font header. */
1976   static FT_Error
_bdf_parse_start(char * line,unsigned long linelen,unsigned long lineno,void * call_data,void * client_data)1977   _bdf_parse_start( char*          line,
1978                     unsigned long  linelen,
1979                     unsigned long  lineno,
1980                     void*          call_data,
1981                     void*          client_data )
1982   {
1983     unsigned long      slen;
1984     _bdf_line_func_t*  next;
1985     _bdf_parse_t*      p;
1986     bdf_font_t*        font;
1987     char               *s;
1988 
1989     FT_Memory          memory = NULL;
1990     FT_Error           error  = BDF_Err_Ok;
1991 
1992     FT_UNUSED( lineno );            /* only used in debug mode */
1993 
1994 
1995     next = (_bdf_line_func_t *)call_data;
1996     p    = (_bdf_parse_t *)    client_data;
1997 
1998     if ( p->font )
1999       memory = p->font->memory;
2000 
2001     /* Check for a comment.  This is done to handle those fonts that have */
2002     /* comments before the STARTFONT line for some reason.                */
2003     if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2004     {
2005       if ( p->opts->keep_comments != 0 && p->font != 0 )
2006       {
2007         linelen -= 7;
2008 
2009         s = line + 7;
2010         if ( *s != 0 )
2011         {
2012           s++;
2013           linelen--;
2014         }
2015 
2016         error = _bdf_add_comment( p->font, s, linelen );
2017         if ( error )
2018           goto Exit;
2019         /* here font is not defined! */
2020       }
2021 
2022       goto Exit;
2023     }
2024 
2025     if ( !( p->flags & _BDF_START ) )
2026     {
2027       memory = p->memory;
2028 
2029       if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2030       {
2031         /* No STARTFONT field is a good indication of a problem. */
2032         error = BDF_Err_Missing_Startfont_Field;
2033         goto Exit;
2034       }
2035 
2036       p->flags = _BDF_START;
2037       font = p->font = 0;
2038 
2039       if ( FT_NEW( font ) )
2040         goto Exit;
2041       p->font = font;
2042 
2043       font->memory = p->memory;
2044       p->memory    = 0;
2045 
2046       { /* setup */
2047         unsigned long    i;
2048         bdf_property_t*  prop;
2049 
2050 
2051         error = hash_init( &(font->proptbl), memory );
2052         if ( error )
2053           goto Exit;
2054         for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
2055               i < _num_bdf_properties; i++, prop++ )
2056         {
2057           error = hash_insert( prop->name, (void *)i,
2058                                &(font->proptbl), memory );
2059           if ( error )
2060             goto Exit;
2061         }
2062       }
2063 
2064       if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2065         goto Exit;
2066       error = hash_init( (hashtable *)p->font->internal,memory );
2067       if ( error )
2068         goto Exit;
2069       p->font->spacing      = p->opts->font_spacing;
2070       p->font->default_char = -1;
2071 
2072       goto Exit;
2073     }
2074 
2075     /* Check for the start of the properties. */
2076     if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2077     {
2078       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2079       if ( error )
2080         goto Exit;
2081       /* at this point, `p->font' can't be NULL */
2082       p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2083 
2084       if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2085         goto Exit;
2086 
2087       p->flags |= _BDF_PROPS;
2088       *next     = _bdf_parse_properties;
2089 
2090       goto Exit;
2091     }
2092 
2093     /* Check for the FONTBOUNDINGBOX field. */
2094     if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2095     {
2096       if ( !(p->flags & _BDF_SIZE ) )
2097       {
2098         /* Missing the SIZE field. */
2099         FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2100         error = BDF_Err_Missing_Size_Field;
2101         goto Exit;
2102       }
2103 
2104       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2105       if ( error )
2106         goto Exit;
2107 
2108       p->font->bbx.width  = _bdf_atos( p->list.field[1], 0, 10 );
2109       p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2110 
2111       p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2112       p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2113 
2114       p->font->bbx.ascent  = (short)( p->font->bbx.height +
2115                                       p->font->bbx.y_offset );
2116 
2117       p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
2118 
2119       p->flags |= _BDF_FONT_BBX;
2120 
2121       goto Exit;
2122     }
2123 
2124     /* The next thing to check for is the FONT field. */
2125     if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2126     {
2127       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2128       if ( error )
2129         goto Exit;
2130       _bdf_list_shift( &p->list, 1 );
2131 
2132       s = _bdf_list_join( &p->list, ' ', &slen );
2133 
2134       if ( !s )
2135       {
2136         error = BDF_Err_Invalid_File_Format;
2137         goto Exit;
2138       }
2139 
2140       if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2141         goto Exit;
2142       FT_MEM_COPY( p->font->name, s, slen + 1 );
2143 
2144       /* If the font name is an XLFD name, set the spacing to the one in  */
2145       /* the font name.  If there is no spacing fall back on the default. */
2146       error = _bdf_set_default_spacing( p->font, p->opts );
2147       if ( error )
2148         goto Exit;
2149 
2150       p->flags |= _BDF_FONT_NAME;
2151 
2152       goto Exit;
2153     }
2154 
2155     /* Check for the SIZE field. */
2156     if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2157     {
2158       if ( !( p->flags & _BDF_FONT_NAME ) )
2159       {
2160         /* Missing the FONT field. */
2161         FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2162         error = BDF_Err_Missing_Font_Field;
2163         goto Exit;
2164       }
2165 
2166       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2167       if ( error )
2168         goto Exit;
2169 
2170       p->font->point_size   = _bdf_atoul( p->list.field[1], 0, 10 );
2171       p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2172       p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2173 
2174       /* Check for the bits per pixel field. */
2175       if ( p->list.used == 5 )
2176       {
2177         unsigned short bitcount, i, shift;
2178 
2179 
2180         p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2181 
2182         /* Only values 1, 2, 4, 8 are allowed. */
2183         shift = p->font->bpp;
2184         bitcount = 0;
2185         for ( i = 0; shift > 0; i++ )
2186         {
2187           if ( shift & 1 )
2188             bitcount = i;
2189           shift >>= 1;
2190         }
2191 
2192         shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
2193 
2194         if ( p->font->bpp > shift || p->font->bpp != shift )
2195         {
2196           /* select next higher value */
2197           p->font->bpp = (unsigned short)( shift << 1 );
2198           FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
2199         }
2200       }
2201       else
2202         p->font->bpp = 1;
2203 
2204       p->flags |= _BDF_SIZE;
2205 
2206       goto Exit;
2207     }
2208 
2209     error = BDF_Err_Invalid_File_Format;
2210 
2211   Exit:
2212     return error;
2213   }
2214 
2215 
2216   /*************************************************************************/
2217   /*                                                                       */
2218   /* API.                                                                  */
2219   /*                                                                       */
2220   /*************************************************************************/
2221 
2222 
2223   FT_LOCAL_DEF( FT_Error )
bdf_load_font(FT_Stream stream,FT_Memory extmemory,bdf_options_t * opts,bdf_font_t ** font)2224   bdf_load_font( FT_Stream       stream,
2225                  FT_Memory       extmemory,
2226                  bdf_options_t*  opts,
2227                  bdf_font_t*    *font )
2228   {
2229     unsigned long  lineno = 0; /* make compiler happy */
2230     _bdf_parse_t   *p;
2231 
2232     FT_Memory      memory = extmemory;
2233     FT_Error       error  = BDF_Err_Ok;
2234 
2235 
2236     if ( FT_NEW( p ) )
2237       goto Exit;
2238 
2239     memory    = NULL;
2240     p->opts   = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2241     p->minlb  = 32767;
2242     p->memory = extmemory;  /* only during font creation */
2243 
2244     _bdf_list_init( &p->list, extmemory );
2245 
2246     error = _bdf_readstream( stream, _bdf_parse_start,
2247                              (void *)p, &lineno );
2248     if ( error )
2249       goto Fail;
2250 
2251     if ( p->font != 0 )
2252     {
2253       /* If the font is not proportional, set the font's monowidth */
2254       /* field to the width of the font bounding box.              */
2255       memory = p->font->memory;
2256 
2257       if ( p->font->spacing != BDF_PROPORTIONAL )
2258         p->font->monowidth = p->font->bbx.width;
2259 
2260       /* If the number of glyphs loaded is not that of the original count, */
2261       /* indicate the difference.                                          */
2262       if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
2263       {
2264         FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2265                     p->font->glyphs_used + p->font->unencoded_used ));
2266         p->font->modified = 1;
2267       }
2268 
2269       /* Once the font has been loaded, adjust the overall font metrics if */
2270       /* necessary.                                                        */
2271       if ( p->opts->correct_metrics != 0 &&
2272            ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
2273       {
2274         if ( p->maxrb - p->minlb != p->font->bbx.width )
2275         {
2276           FT_TRACE2(( "bdf_load_font: " ACMSG3,
2277                       p->font->bbx.width, p->maxrb - p->minlb ));
2278           p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2279           p->font->modified  = 1;
2280         }
2281 
2282         if ( p->font->bbx.x_offset != p->minlb )
2283         {
2284           FT_TRACE2(( "bdf_load_font: " ACMSG4,
2285                       p->font->bbx.x_offset, p->minlb ));
2286           p->font->bbx.x_offset = p->minlb;
2287           p->font->modified     = 1;
2288         }
2289 
2290         if ( p->font->bbx.ascent != p->maxas )
2291         {
2292           FT_TRACE2(( "bdf_load_font: " ACMSG5,
2293                       p->font->bbx.ascent, p->maxas ));
2294           p->font->bbx.ascent = p->maxas;
2295           p->font->modified   = 1;
2296         }
2297 
2298         if ( p->font->bbx.descent != p->maxds )
2299         {
2300           FT_TRACE2(( "bdf_load_font: " ACMSG6,
2301                       p->font->bbx.descent, p->maxds ));
2302           p->font->bbx.descent  = p->maxds;
2303           p->font->bbx.y_offset = (short)( -p->maxds );
2304           p->font->modified     = 1;
2305         }
2306 
2307         if ( p->maxas + p->maxds != p->font->bbx.height )
2308         {
2309           FT_TRACE2(( "bdf_load_font: " ACMSG7,
2310                       p->font->bbx.height, p->maxas + p->maxds ));
2311           p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
2312         }
2313 
2314         if ( p->flags & _BDF_SWIDTH_ADJ )
2315           FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2316       }
2317     }
2318 
2319     if ( p->flags & _BDF_START )
2320     {
2321       {
2322         /* The ENDFONT field was never reached or did not exist. */
2323         if ( !( p->flags & _BDF_GLYPHS ) )
2324         {
2325           /* Error happened while parsing header. */
2326           FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2327           error = BDF_Err_Corrupted_Font_Header;
2328           goto Exit;
2329         }
2330         else
2331         {
2332           /* Error happened when parsing glyphs. */
2333           FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2334           error = BDF_Err_Corrupted_Font_Glyphs;
2335           goto Exit;
2336         }
2337       }
2338     }
2339 
2340     if ( p->font != 0 )
2341     {
2342       /* Make sure the comments are NULL terminated if they exist. */
2343       memory = p->font->memory;
2344 
2345       if ( p->font->comments_len > 0 ) {
2346         if ( FT_RENEW_ARRAY( p->font->comments,
2347                              p->font->comments_len,
2348                              p->font->comments_len + 1 ) )
2349           goto Fail;
2350 
2351         p->font->comments[p->font->comments_len] = 0;
2352       }
2353     }
2354     else if ( error == BDF_Err_Ok )
2355       error = BDF_Err_Invalid_File_Format;
2356 
2357     *font = p->font;
2358 
2359   Exit:
2360     if ( p )
2361     {
2362       _bdf_list_done( &p->list );
2363 
2364       memory = extmemory;
2365 
2366       FT_FREE( p );
2367     }
2368 
2369     return error;
2370 
2371   Fail:
2372     bdf_free_font( p->font );
2373 
2374     memory = extmemory;
2375 
2376     FT_FREE( p->font );
2377 
2378     goto Exit;
2379   }
2380 
2381 
2382   FT_LOCAL_DEF( void )
bdf_free_font(bdf_font_t * font)2383   bdf_free_font( bdf_font_t*  font )
2384   {
2385     bdf_property_t*  prop;
2386     unsigned long    i;
2387     bdf_glyph_t*     glyphs;
2388     FT_Memory        memory;
2389 
2390 
2391     if ( font == 0 )
2392       return;
2393 
2394     memory = font->memory;
2395 
2396     FT_FREE( font->name );
2397 
2398     /* Free up the internal hash table of property names. */
2399     if ( font->internal )
2400     {
2401       hash_free( (hashtable *)font->internal, memory );
2402       FT_FREE( font->internal );
2403     }
2404 
2405     /* Free up the comment info. */
2406     FT_FREE( font->comments );
2407 
2408     /* Free up the properties. */
2409     for ( i = 0; i < font->props_size; i++ )
2410     {
2411       if ( font->props[i].format == BDF_ATOM )
2412         FT_FREE( font->props[i].value.atom );
2413     }
2414 
2415     FT_FREE( font->props );
2416 
2417     /* Free up the character info. */
2418     for ( i = 0, glyphs = font->glyphs;
2419           i < font->glyphs_used; i++, glyphs++ )
2420     {
2421       FT_FREE( glyphs->name );
2422       FT_FREE( glyphs->bitmap );
2423     }
2424 
2425     for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2426           i++, glyphs++ )
2427     {
2428       FT_FREE( glyphs->name );
2429       FT_FREE( glyphs->bitmap );
2430     }
2431 
2432     FT_FREE( font->glyphs );
2433     FT_FREE( font->unencoded );
2434 
2435     /* Free up the overflow storage if it was used. */
2436     for ( i = 0, glyphs = font->overflow.glyphs;
2437           i < font->overflow.glyphs_used; i++, glyphs++ )
2438     {
2439       FT_FREE( glyphs->name );
2440       FT_FREE( glyphs->bitmap );
2441     }
2442 
2443     FT_FREE( font->overflow.glyphs );
2444 
2445     /* bdf_cleanup */
2446     hash_free( &(font->proptbl), memory );
2447 
2448     /* Free up the user defined properties. */
2449     for (prop = font->user_props, i = 0;
2450          i < font->nuser_props; i++, prop++ )
2451     {
2452       FT_FREE( prop->name );
2453       if ( prop->format == BDF_ATOM )
2454         FT_FREE( prop->value.atom );
2455     }
2456 
2457     FT_FREE( font->user_props );
2458 
2459     /* FREE( font ); */ /* XXX Fixme */
2460   }
2461 
2462 
2463   FT_LOCAL_DEF( bdf_property_t * )
bdf_get_font_property(bdf_font_t * font,const char * name)2464   bdf_get_font_property( bdf_font_t*  font,
2465                          const char*  name )
2466   {
2467     hashnode  hn;
2468 
2469 
2470     if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
2471       return 0;
2472 
2473     hn = hash_lookup( name, (hashtable *)font->internal );
2474 
2475     return hn ? ( font->props + (unsigned long)hn->data ) : 0;
2476   }
2477 
2478 
2479 /* END */
2480