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