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