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