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