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