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