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