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