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