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