• 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   = avail;
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           start  = 0;
627         }
628         refill = 1;
629         continue;
630       }
631 
632       /* Temporarily NUL-terminate the line. */
633       hold     = buf[end];
634       buf[end] = 0;
635 
636       /* XXX: Use encoding independent value for 0x1A */
637       if ( buf[start] != '#' && buf[start] != 0x1A && end > start )
638       {
639         error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
640                        (void*)&cb, client_data );
641         /* Redo if we have encountered CHARS without properties. */
642         if ( error == -1 )
643           error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
644                          (void*)&cb, client_data );
645         if ( error )
646           break;
647       }
648 
649       lineno  += 1;
650       buf[end] = (char)hold;
651       start    = end + 1;
652 
653       if ( hold == '\n' )
654         to_skip = '\r';
655       else if ( hold == '\r' )
656         to_skip = '\n';
657       else
658         to_skip = NO_SKIP;
659     }
660 
661     *lno = lineno;
662 
663   Exit:
664     FT_FREE( buf );
665     return error;
666   }
667 
668 
669   /* XXX: make this work with EBCDIC also */
670 
671   static const unsigned char  a2i[128] =
672   {
673     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
678     0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
679     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
680     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
681     0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
682     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
683     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
684   };
685 
686   static const unsigned char  ddigits[32] =
687   {
688     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
689     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
690     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
691     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
692   };
693 
694   static const unsigned char  hdigits[32] =
695   {
696     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
697     0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00,
698     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
699     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
700   };
701 
702 
703   /* Routine to convert a decimal ASCII string to an unsigned long integer. */
704   static unsigned long
bdf_atoul_(const char * s)705   bdf_atoul_( const char*  s )
706   {
707     unsigned long  v;
708 
709 
710     if ( s == NULL || *s == 0 )
711       return 0;
712 
713     for ( v = 0; sbitset( ddigits, *s ); s++ )
714     {
715       if ( v < ( FT_ULONG_MAX - 9 ) / 10 )
716         v = v * 10 + a2i[(int)*s];
717       else
718       {
719         v = FT_ULONG_MAX;
720         break;
721       }
722     }
723 
724     return v;
725   }
726 
727 
728   /* Routine to convert a decimal ASCII string to a signed long integer. */
729   static long
bdf_atol_(const char * s)730   bdf_atol_( const char*  s )
731   {
732     long  v, neg;
733 
734 
735     if ( s == NULL || *s == 0 )
736       return 0;
737 
738     /* Check for a minus sign. */
739     neg = 0;
740     if ( *s == '-' )
741     {
742       s++;
743       neg = 1;
744     }
745 
746     for ( v = 0; sbitset( ddigits, *s ); s++ )
747     {
748       if ( v < ( FT_LONG_MAX - 9 ) / 10 )
749         v = v * 10 + a2i[(int)*s];
750       else
751       {
752         v = FT_LONG_MAX;
753         break;
754       }
755     }
756 
757     return ( !neg ) ? v : -v;
758   }
759 
760 
761   /* Routine to convert a decimal ASCII string to an unsigned short integer. */
762   static unsigned short
bdf_atous_(const char * s)763   bdf_atous_( const char*  s )
764   {
765     unsigned short  v;
766 
767 
768     if ( s == NULL || *s == 0 )
769       return 0;
770 
771     for ( v = 0; sbitset( ddigits, *s ); s++ )
772     {
773       if ( v < ( FT_USHORT_MAX - 9 ) / 10 )
774         v = (unsigned short)( v * 10 + a2i[(int)*s] );
775       else
776       {
777         v = FT_USHORT_MAX;
778         break;
779       }
780     }
781 
782     return v;
783   }
784 
785 
786   /* Routine to convert a decimal ASCII string to a signed short integer. */
787   static short
bdf_atos_(const char * s)788   bdf_atos_( const char*  s )
789   {
790     short  v, neg;
791 
792 
793     if ( s == NULL || *s == 0 )
794       return 0;
795 
796     /* Check for a minus. */
797     neg = 0;
798     if ( *s == '-' )
799     {
800       s++;
801       neg = 1;
802     }
803 
804     for ( v = 0; sbitset( ddigits, *s ); s++ )
805     {
806       if ( v < ( SHRT_MAX - 9 ) / 10 )
807         v = (short)( v * 10 + a2i[(int)*s] );
808       else
809       {
810         v = SHRT_MAX;
811         break;
812       }
813     }
814 
815     return (short)( ( !neg ) ? v : -v );
816   }
817 
818 
819   /* Routine to compare two glyphs by encoding so they can be sorted. */
820   FT_COMPARE_DEF( int )
by_encoding(const void * a,const void * b)821   by_encoding( const void*  a,
822                const void*  b )
823   {
824     bdf_glyph_t  *c1, *c2;
825 
826 
827     c1 = (bdf_glyph_t *)a;
828     c2 = (bdf_glyph_t *)b;
829 
830     if ( c1->encoding < c2->encoding )
831       return -1;
832 
833     if ( c1->encoding > c2->encoding )
834       return 1;
835 
836     return 0;
837   }
838 
839 
840   static FT_Error
bdf_create_property(const char * name,int format,bdf_font_t * font)841   bdf_create_property( const char*  name,
842                        int          format,
843                        bdf_font_t*  font )
844   {
845     size_t           n;
846     bdf_property_t*  p;
847     FT_Memory        memory = font->memory;
848     FT_Error         error  = FT_Err_Ok;
849 
850 
851     /* First check whether the property has        */
852     /* already been added or not.  If it has, then */
853     /* simply ignore it.                           */
854     if ( ft_hash_str_lookup( name, &(font->proptbl) ) )
855       goto Exit;
856 
857     if ( FT_QRENEW_ARRAY( font->user_props,
858                           font->nuser_props,
859                           font->nuser_props + 1 ) )
860       goto Exit;
861 
862     p = font->user_props + font->nuser_props;
863 
864     n = ft_strlen( name ) + 1;
865     if ( n > FT_LONG_MAX )
866       return FT_THROW( Invalid_Argument );
867 
868     if ( FT_QALLOC( p->name, n ) )
869       goto Exit;
870 
871     FT_MEM_COPY( (char *)p->name, name, n );
872 
873     p->format     = format;
874     p->builtin    = 0;
875     p->value.atom = NULL;  /* nothing is ever stored here */
876 
877     n = num_bdf_properties_ + font->nuser_props;
878 
879     error = ft_hash_str_insert( p->name, n, &(font->proptbl), memory );
880     if ( error )
881       goto Exit;
882 
883     font->nuser_props++;
884 
885   Exit:
886     return error;
887   }
888 
889 
890   FT_LOCAL_DEF( bdf_property_t* )
bdf_get_property(char * name,bdf_font_t * font)891   bdf_get_property( char*        name,
892                     bdf_font_t*  font )
893   {
894     size_t*  propid;
895 
896 
897     if ( name == NULL || *name == 0 )
898       return 0;
899 
900     if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL )
901       return 0;
902 
903     if ( *propid >= num_bdf_properties_ )
904       return font->user_props + ( *propid - num_bdf_properties_ );
905 
906     return (bdf_property_t*)bdf_properties_ + *propid;
907   }
908 
909 
910   /**************************************************************************
911    *
912    * BDF font file parsing flags and functions.
913    *
914    */
915 
916 
917   /* Parse flags. */
918 
919 #define BDF_START_      0x0001U
920 #define BDF_FONT_NAME_  0x0002U
921 #define BDF_SIZE_       0x0004U
922 #define BDF_FONT_BBX_   0x0008U
923 #define BDF_PROPS_      0x0010U
924 #define BDF_GLYPHS_     0x0020U
925 #define BDF_GLYPH_      0x0040U
926 #define BDF_ENCODING_   0x0080U
927 #define BDF_SWIDTH_     0x0100U
928 #define BDF_DWIDTH_     0x0200U
929 #define BDF_BBX_        0x0400U
930 #define BDF_BITMAP_     0x0800U
931 
932 #define BDF_SWIDTH_ADJ_  0x1000U
933 
934 #define BDF_GLYPH_BITS_ ( BDF_GLYPH_    | \
935                           BDF_ENCODING_ | \
936                           BDF_SWIDTH_   | \
937                           BDF_DWIDTH_   | \
938                           BDF_BBX_      | \
939                           BDF_BITMAP_   )
940 
941 #define BDF_GLYPH_WIDTH_CHECK_   0x40000000UL
942 #define BDF_GLYPH_HEIGHT_CHECK_  0x80000000UL
943 
944 
945   static FT_Error
bdf_add_comment_(bdf_font_t * font,char * comment,unsigned long len)946   bdf_add_comment_( bdf_font_t*    font,
947                     char*          comment,
948                     unsigned long  len )
949   {
950     char*      cp;
951     FT_Memory  memory = font->memory;
952     FT_Error   error  = FT_Err_Ok;
953 
954 
955     if ( FT_QRENEW_ARRAY( font->comments,
956                           font->comments_len,
957                           font->comments_len + len + 1 ) )
958       goto Exit;
959 
960     cp = font->comments + font->comments_len;
961 
962     FT_MEM_COPY( cp, comment, len );
963     cp[len] = '\0';
964 
965     font->comments_len += len + 1;
966 
967   Exit:
968     return error;
969   }
970 
971 
972   /* Set the spacing from the font name if it exists, or set it to the */
973   /* default specified in the options.                                 */
974   static FT_Error
bdf_set_default_spacing_(bdf_font_t * font,bdf_options_t * opts,unsigned long lineno)975   bdf_set_default_spacing_( bdf_font_t*     font,
976                             bdf_options_t*  opts,
977                             unsigned long   lineno )
978   {
979     size_t       len;
980     char         name[256];
981     bdf_list_t_  list;
982     FT_Memory    memory;
983     FT_Error     error = FT_Err_Ok;
984 
985     FT_UNUSED( lineno );        /* only used in debug mode */
986 
987 
988     if ( font == NULL || font->name == NULL || font->name[0] == 0 )
989     {
990       error = FT_THROW( Invalid_Argument );
991       goto Exit;
992     }
993 
994     memory = font->memory;
995 
996     bdf_list_init_( &list, memory );
997 
998     font->spacing = opts->font_spacing;
999 
1000     len = ft_strlen( font->name ) + 1;
1001     /* Limit ourselves to 256 characters in the font name. */
1002     if ( len >= 256 )
1003     {
1004       FT_ERROR(( "bdf_set_default_spacing_: " ERRMSG7, lineno ));
1005       error = FT_THROW( Invalid_Argument );
1006       goto Exit;
1007     }
1008 
1009     FT_MEM_COPY( name, font->name, len );
1010 
1011     error = bdf_list_split_( &list, "-", name, (unsigned long)len );
1012     if ( error )
1013       goto Fail;
1014 
1015     if ( list.used == 15 )
1016     {
1017       switch ( list.field[11][0] )
1018       {
1019       case 'C':
1020       case 'c':
1021         font->spacing = BDF_CHARCELL;
1022         break;
1023       case 'M':
1024       case 'm':
1025         font->spacing = BDF_MONOWIDTH;
1026         break;
1027       case 'P':
1028       case 'p':
1029         font->spacing = BDF_PROPORTIONAL;
1030         break;
1031       }
1032     }
1033 
1034   Fail:
1035     bdf_list_done_( &list );
1036 
1037   Exit:
1038     return error;
1039   }
1040 
1041 
1042   /* Determine whether the property is an atom or not.  If it is, then */
1043   /* clean it up so the double quotes are removed if they exist.       */
1044   static int
bdf_is_atom_(char * line,unsigned long linelen,char ** name,char ** value,bdf_font_t * font)1045   bdf_is_atom_( char*          line,
1046                 unsigned long  linelen,
1047                 char**         name,
1048                 char**         value,
1049                 bdf_font_t*    font )
1050   {
1051     int              hold;
1052     char             *sp, *ep;
1053     bdf_property_t*  p;
1054 
1055 
1056     *name = sp = ep = line;
1057 
1058     while ( *ep && *ep != ' ' && *ep != '\t' )
1059       ep++;
1060 
1061     hold = -1;
1062     if ( *ep )
1063     {
1064       hold = *ep;
1065       *ep  = 0;
1066     }
1067 
1068     p = bdf_get_property( sp, font );
1069 
1070     /* Restore the character that was saved before any return can happen. */
1071     if ( hold != -1 )
1072       *ep = (char)hold;
1073 
1074     /* If the property exists and is not an atom, just return here. */
1075     if ( p && p->format != BDF_ATOM )
1076       return 0;
1077 
1078     /* The property is an atom.  Trim all leading and trailing whitespace */
1079     /* and double quotes for the atom value.                              */
1080     sp = ep;
1081     ep = line + linelen;
1082 
1083     /* Trim the leading whitespace if it exists. */
1084     if ( *sp )
1085       *sp++ = 0;
1086     while ( *sp                           &&
1087             ( *sp == ' ' || *sp == '\t' ) )
1088       sp++;
1089 
1090     /* Trim the leading double quote if it exists. */
1091     if ( *sp == '"' )
1092       sp++;
1093     *value = sp;
1094 
1095     /* Trim the trailing whitespace if it exists. */
1096     while ( ep > sp                                       &&
1097             ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
1098       *--ep = 0;
1099 
1100     /* Trim the trailing double quote if it exists. */
1101     if ( ep > sp && *( ep - 1 ) == '"' )
1102       *--ep = 0;
1103 
1104     return 1;
1105   }
1106 
1107 
1108   static FT_Error
bdf_add_property_(bdf_font_t * font,const char * name,char * value,unsigned long lineno)1109   bdf_add_property_( bdf_font_t*    font,
1110                      const char*    name,
1111                      char*          value,
1112                      unsigned long  lineno )
1113   {
1114     size_t*         propid;
1115     bdf_property_t  *prop, *fp;
1116     FT_Memory       memory = font->memory;
1117     FT_Error        error  = FT_Err_Ok;
1118 
1119     FT_UNUSED( lineno );        /* only used in debug mode */
1120 
1121 
1122     /* First, check whether the property already exists in the font. */
1123     if ( ( propid = ft_hash_str_lookup( name,
1124                                         (FT_Hash)font->internal ) ) != NULL )
1125     {
1126       /* The property already exists in the font, so simply replace */
1127       /* the value of the property with the current value.          */
1128       fp = font->props + *propid;
1129 
1130       switch ( fp->format )
1131       {
1132       case BDF_ATOM:
1133         /* Delete the current atom if it exists. */
1134         FT_FREE( fp->value.atom );
1135 
1136         if ( value && value[0] != 0 )
1137         {
1138           if ( FT_STRDUP( fp->value.atom, value ) )
1139             goto Exit;
1140         }
1141         break;
1142 
1143       case BDF_INTEGER:
1144         fp->value.l = bdf_atol_( value );
1145         break;
1146 
1147       case BDF_CARDINAL:
1148         fp->value.ul = bdf_atoul_( value );
1149         break;
1150 
1151       default:
1152         ;
1153       }
1154 
1155       goto Exit;
1156     }
1157 
1158     /* See whether this property type exists yet or not. */
1159     /* If not, create it.                                */
1160     propid = ft_hash_str_lookup( name, &(font->proptbl) );
1161     if ( !propid )
1162     {
1163       error = bdf_create_property( name, BDF_ATOM, font );
1164       if ( error )
1165         goto Exit;
1166       propid = ft_hash_str_lookup( name, &(font->proptbl) );
1167     }
1168 
1169     /* Allocate another property if this is overflowing. */
1170     if ( font->props_used == font->props_size )
1171     {
1172       if ( FT_QRENEW_ARRAY( font->props,
1173                             font->props_size,
1174                             font->props_size + 1 ) )
1175         goto Exit;
1176 
1177       font->props_size++;
1178     }
1179 
1180     if ( *propid >= num_bdf_properties_ )
1181       prop = font->user_props + ( *propid - num_bdf_properties_ );
1182     else
1183       prop = (bdf_property_t*)bdf_properties_ + *propid;
1184 
1185     fp = font->props + font->props_used;
1186 
1187     fp->name    = prop->name;
1188     fp->format  = prop->format;
1189     fp->builtin = prop->builtin;
1190 
1191     switch ( prop->format )
1192     {
1193     case BDF_ATOM:
1194       fp->value.atom = NULL;
1195       if ( value && value[0] )
1196       {
1197         if ( FT_STRDUP( fp->value.atom, value ) )
1198           goto Exit;
1199       }
1200       break;
1201 
1202     case BDF_INTEGER:
1203       fp->value.l = bdf_atol_( value );
1204       break;
1205 
1206     case BDF_CARDINAL:
1207       fp->value.ul = bdf_atoul_( value );
1208       break;
1209     }
1210 
1211     /* If the property happens to be a comment, then it doesn't need */
1212     /* to be added to the internal hash table.                       */
1213     if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 )
1214     {
1215       /* Add the property to the font property table. */
1216       error = ft_hash_str_insert( fp->name,
1217                                   font->props_used,
1218                                   (FT_Hash)font->internal,
1219                                   memory );
1220       if ( error )
1221         goto Exit;
1222     }
1223 
1224     font->props_used++;
1225 
1226     /* Some special cases need to be handled here.  The DEFAULT_CHAR       */
1227     /* property needs to be located if it exists in the property list, the */
1228     /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are        */
1229     /* present, and the SPACING property should override the default       */
1230     /* spacing.                                                            */
1231     if ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 )
1232       font->default_char = fp->value.ul;
1233     else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 )
1234       font->font_ascent = fp->value.l;
1235     else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 )
1236       font->font_descent = fp->value.l;
1237     else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 )
1238     {
1239       if ( !fp->value.atom )
1240       {
1241         FT_ERROR(( "bdf_add_property_: " ERRMSG8, lineno, "SPACING" ));
1242         error = FT_THROW( Invalid_File_Format );
1243         goto Exit;
1244       }
1245 
1246       if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
1247         font->spacing = BDF_PROPORTIONAL;
1248       else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
1249         font->spacing = BDF_MONOWIDTH;
1250       else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
1251         font->spacing = BDF_CHARCELL;
1252     }
1253 
1254   Exit:
1255     return error;
1256   }
1257 
1258 
1259   static const unsigned char nibble_mask[8] =
1260   {
1261     0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1262   };
1263 
1264 
1265   static FT_Error
bdf_parse_end_(char * line,unsigned long linelen,unsigned long lineno,void * call_data,void * client_data)1266   bdf_parse_end_( char*          line,
1267                   unsigned long  linelen,
1268                   unsigned long  lineno,
1269                   void*          call_data,
1270                   void*          client_data )
1271   {
1272     /* a no-op; we ignore everything after `ENDFONT' */
1273 
1274     FT_UNUSED( line );
1275     FT_UNUSED( linelen );
1276     FT_UNUSED( lineno );
1277     FT_UNUSED( call_data );
1278     FT_UNUSED( client_data );
1279 
1280     return FT_Err_Ok;
1281   }
1282 
1283 
1284   /* Actually parse the glyph info and bitmaps. */
1285   static FT_Error
bdf_parse_glyphs_(char * line,unsigned long linelen,unsigned long lineno,void * call_data,void * client_data)1286   bdf_parse_glyphs_( char*          line,
1287                      unsigned long  linelen,
1288                      unsigned long  lineno,
1289                      void*          call_data,
1290                      void*          client_data )
1291   {
1292     int                c, mask_index;
1293     char*              s;
1294     unsigned char*     bp;
1295     unsigned long      i, slen, nibbles;
1296 
1297     bdf_line_func_t_*  next;
1298     bdf_parse_t_*      p;
1299     bdf_glyph_t*       glyph;
1300     bdf_font_t*        font;
1301 
1302     FT_Memory          memory;
1303     FT_Error           error = FT_Err_Ok;
1304 
1305     FT_UNUSED( lineno );        /* only used in debug mode */
1306 
1307 
1308     next = (bdf_line_func_t_ *)call_data;
1309     p    = (bdf_parse_t_ *)    client_data;
1310 
1311     font   = p->font;
1312     memory = font->memory;
1313 
1314     /* Check for a comment. */
1315     if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
1316     {
1317       if ( p->opts->keep_comments )
1318       {
1319         linelen -= 7;
1320 
1321         s = line + 7;
1322         if ( *s != 0 )
1323         {
1324           s++;
1325           linelen--;
1326         }
1327         error = bdf_add_comment_( p->font, s, linelen );
1328       }
1329       goto Exit;
1330     }
1331 
1332     /* The very first thing expected is the number of glyphs. */
1333     if ( !( p->flags & BDF_GLYPHS_ ) )
1334     {
1335       if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 )
1336       {
1337         FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "CHARS" ));
1338         error = FT_THROW( Missing_Chars_Field );
1339         goto Exit;
1340       }
1341 
1342       error = bdf_list_split_( &p->list, " +", line, linelen );
1343       if ( error )
1344         goto Exit;
1345       p->cnt = font->glyphs_size = bdf_atoul_( p->list.field[1] );
1346 
1347       /* We need at least 20 bytes per glyph. */
1348       if ( p->cnt > p->size / 20 )
1349       {
1350         p->cnt = font->glyphs_size = p->size / 20;
1351         FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG17, p->cnt ));
1352       }
1353 
1354       /* Make sure the number of glyphs is non-zero. */
1355       if ( p->cnt == 0 )
1356         font->glyphs_size = 64;
1357 
1358       /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1359       /* number of code points available in Unicode).                 */
1360       if ( p->cnt >= 0x110000UL )
1361       {
1362         FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG5, lineno, "CHARS" ));
1363         error = FT_THROW( Invalid_Argument );
1364         goto Exit;
1365       }
1366 
1367       if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1368         goto Exit;
1369 
1370       p->flags |= BDF_GLYPHS_;
1371 
1372       goto Exit;
1373     }
1374 
1375     /* Check for the ENDFONT field. */
1376     if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 )
1377     {
1378       if ( p->flags & BDF_GLYPH_BITS_ )
1379       {
1380         /* Missing ENDCHAR field. */
1381         FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" ));
1382         error = FT_THROW( Corrupted_Font_Glyphs );
1383         goto Exit;
1384       }
1385 
1386       /* Sort the glyphs by encoding. */
1387       ft_qsort( (char *)font->glyphs,
1388                 font->glyphs_used,
1389                 sizeof ( bdf_glyph_t ),
1390                 by_encoding );
1391 
1392       p->flags &= ~BDF_START_;
1393       *next     = bdf_parse_end_;
1394 
1395       goto Exit;
1396     }
1397 
1398     /* Check for the ENDCHAR field. */
1399     if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 )
1400     {
1401       p->glyph_enc = 0;
1402       p->flags    &= ~BDF_GLYPH_BITS_;
1403 
1404       goto Exit;
1405     }
1406 
1407     /* Check whether a glyph is being scanned but should be */
1408     /* ignored because it is an unencoded glyph.            */
1409     if ( ( p->flags & BDF_GLYPH_ )     &&
1410          p->glyph_enc            == -1 &&
1411          p->opts->keep_unencoded == 0  )
1412       goto Exit;
1413 
1414     /* Check for the STARTCHAR field. */
1415     if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 )
1416     {
1417       if ( p->flags & BDF_GLYPH_BITS_ )
1418       {
1419         /* Missing ENDCHAR field. */
1420         FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" ));
1421         error = FT_THROW( Missing_Startchar_Field );
1422         goto Exit;
1423       }
1424 
1425       /* Set the character name in the parse info first until the */
1426       /* encoding can be checked for an unencoded character.      */
1427       FT_FREE( p->glyph_name );
1428 
1429       error = bdf_list_split_( &p->list, " +", line, linelen );
1430       if ( error )
1431         goto Exit;
1432 
1433       bdf_list_shift_( &p->list, 1 );
1434 
1435       s = bdf_list_join_( &p->list, ' ', &slen );
1436 
1437       if ( !s )
1438       {
1439         FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG8, lineno, "STARTCHAR" ));
1440         error = FT_THROW( Invalid_File_Format );
1441         goto Exit;
1442       }
1443 
1444       if ( FT_QALLOC( p->glyph_name, slen + 1 ) )
1445         goto Exit;
1446 
1447       FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1448 
1449       p->flags |= BDF_GLYPH_;
1450 
1451       FT_TRACE4(( DBGMSG1, lineno, s ));
1452 
1453       goto Exit;
1454     }
1455 
1456     /* Check for the ENCODING field. */
1457     if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 )
1458     {
1459       if ( !( p->flags & BDF_GLYPH_ ) )
1460       {
1461         /* Missing STARTCHAR field. */
1462         FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "STARTCHAR" ));
1463         error = FT_THROW( Missing_Startchar_Field );
1464         goto Exit;
1465       }
1466 
1467       error = bdf_list_split_( &p->list, " +", line, linelen );
1468       if ( error )
1469         goto Exit;
1470 
1471       p->glyph_enc = bdf_atol_( p->list.field[1] );
1472 
1473       /* Normalize negative encoding values.  The specification only */
1474       /* allows -1, but we can be more generous here.                */
1475       if ( p->glyph_enc < -1 )
1476         p->glyph_enc = -1;
1477 
1478       /* Check for alternative encoding format. */
1479       if ( p->glyph_enc == -1 && p->list.used > 2 )
1480         p->glyph_enc = bdf_atol_( p->list.field[2] );
1481 
1482       if ( p->glyph_enc < -1 || p->glyph_enc >= 0x110000L )
1483         p->glyph_enc = -1;
1484 
1485       FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1486 
1487       if ( p->glyph_enc >= 0 )
1488       {
1489         /* Make sure there are enough glyphs allocated in case the */
1490         /* number of characters happen to be wrong.                */
1491         if ( font->glyphs_used == font->glyphs_size )
1492         {
1493           if ( FT_RENEW_ARRAY( font->glyphs,
1494                                font->glyphs_size,
1495                                font->glyphs_size + 64 ) )
1496             goto Exit;
1497 
1498           font->glyphs_size += 64;
1499         }
1500 
1501         glyph           = font->glyphs + font->glyphs_used++;
1502         glyph->name     = p->glyph_name;
1503         glyph->encoding = (unsigned long)p->glyph_enc;
1504 
1505         /* Reset the initial glyph info. */
1506         p->glyph_name = NULL;
1507       }
1508       else
1509       {
1510         /* Unencoded glyph.  Check whether it should */
1511         /* be added or not.                          */
1512         if ( p->opts->keep_unencoded )
1513         {
1514           /* Allocate the next unencoded glyph. */
1515           if ( font->unencoded_used == font->unencoded_size )
1516           {
1517             if ( FT_RENEW_ARRAY( font->unencoded ,
1518                                  font->unencoded_size,
1519                                  font->unencoded_size + 4 ) )
1520               goto Exit;
1521 
1522             font->unencoded_size += 4;
1523           }
1524 
1525           glyph           = font->unencoded + font->unencoded_used;
1526           glyph->name     = p->glyph_name;
1527           glyph->encoding = font->unencoded_used++;
1528 
1529           /* Reset the initial glyph info. */
1530           p->glyph_name = NULL;
1531         }
1532         else
1533         {
1534           /* Free up the glyph name if the unencoded shouldn't be */
1535           /* kept.                                                */
1536           FT_FREE( p->glyph_name );
1537         }
1538       }
1539 
1540       /* Clear the flags that might be added when width and height are */
1541       /* checked for consistency.                                      */
1542       p->flags &= ~( BDF_GLYPH_WIDTH_CHECK_ | BDF_GLYPH_HEIGHT_CHECK_ );
1543 
1544       p->flags |= BDF_ENCODING_;
1545 
1546       goto Exit;
1547     }
1548 
1549     if ( !( p->flags & BDF_ENCODING_ ) )
1550       goto Missing_Encoding;
1551 
1552     /* Point at the glyph being constructed. */
1553     if ( p->glyph_enc == -1 )
1554       glyph = font->unencoded + ( font->unencoded_used - 1 );
1555     else
1556       glyph = font->glyphs + ( font->glyphs_used - 1 );
1557 
1558     /* Check whether a bitmap is being constructed. */
1559     if ( p->flags & BDF_BITMAP_ )
1560     {
1561       /* If there are more rows than are specified in the glyph metrics, */
1562       /* ignore the remaining lines.                                     */
1563       if ( p->row >= (unsigned long)glyph->bbx.height )
1564       {
1565         if ( !( p->flags & BDF_GLYPH_HEIGHT_CHECK_ ) )
1566         {
1567           FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG13, glyph->encoding ));
1568           p->flags |= BDF_GLYPH_HEIGHT_CHECK_;
1569         }
1570 
1571         goto Exit;
1572       }
1573 
1574       /* Only collect the number of nibbles indicated by the glyph     */
1575       /* metrics.  If there are more columns, they are simply ignored. */
1576       nibbles = glyph->bpr << 1;
1577       bp      = glyph->bitmap + p->row * glyph->bpr;
1578 
1579       for ( i = 0; i < nibbles; i++ )
1580       {
1581         c = line[i];
1582         if ( !sbitset( hdigits, c ) )
1583           break;
1584         *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
1585         if ( i + 1 < nibbles && ( i & 1 ) )
1586           *++bp = 0;
1587       }
1588 
1589       /* If any line has not enough columns,            */
1590       /* indicate they have been padded with zero bits. */
1591       if ( i < nibbles                            &&
1592            !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
1593       {
1594         FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG16, glyph->encoding ));
1595         p->flags       |= BDF_GLYPH_WIDTH_CHECK_;
1596       }
1597 
1598       /* Remove possible garbage at the right. */
1599       mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
1600       if ( glyph->bbx.width )
1601         *bp &= nibble_mask[mask_index];
1602 
1603       /* If any line has extra columns, indicate they have been removed. */
1604       if ( i == nibbles                           &&
1605            sbitset( hdigits, line[nibbles] )      &&
1606            !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
1607       {
1608         FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG14, glyph->encoding ));
1609         p->flags       |= BDF_GLYPH_WIDTH_CHECK_;
1610       }
1611 
1612       p->row++;
1613       goto Exit;
1614     }
1615 
1616     /* Expect the SWIDTH (scalable width) field next. */
1617     if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 )
1618     {
1619       error = bdf_list_split_( &p->list, " +", line, linelen );
1620       if ( error )
1621         goto Exit;
1622 
1623       glyph->swidth = bdf_atous_( p->list.field[1] );
1624       p->flags |= BDF_SWIDTH_;
1625 
1626       goto Exit;
1627     }
1628 
1629     /* Expect the DWIDTH (device width) field next. */
1630     if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 )
1631     {
1632       error = bdf_list_split_( &p->list, " +", line, linelen );
1633       if ( error )
1634         goto Exit;
1635 
1636       glyph->dwidth = bdf_atous_( p->list.field[1] );
1637 
1638       if ( !( p->flags & BDF_SWIDTH_ ) )
1639       {
1640         /* Missing SWIDTH field.  Emit an auto correction message and set */
1641         /* the scalable width from the device width.                      */
1642         FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG9, lineno ));
1643 
1644         glyph->swidth = (unsigned short)FT_MulDiv(
1645                           glyph->dwidth, 72000L,
1646                           (FT_Long)( font->point_size *
1647                                      font->resolution_x ) );
1648       }
1649 
1650       p->flags |= BDF_DWIDTH_;
1651       goto Exit;
1652     }
1653 
1654     /* Expect the BBX field next. */
1655     if ( _bdf_strncmp( line, "BBX", 3 ) == 0 )
1656     {
1657       error = bdf_list_split_( &p->list, " +", line, linelen );
1658       if ( error )
1659         goto Exit;
1660 
1661       glyph->bbx.width    = bdf_atous_( p->list.field[1] );
1662       glyph->bbx.height   = bdf_atous_( p->list.field[2] );
1663       glyph->bbx.x_offset = bdf_atos_( p->list.field[3] );
1664       glyph->bbx.y_offset = bdf_atos_( p->list.field[4] );
1665 
1666       /* Generate the ascent and descent of the character. */
1667       glyph->bbx.ascent  = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1668       glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
1669 
1670       /* Determine the overall font bounding box as the characters are */
1671       /* loaded so corrections can be done later if indicated.         */
1672       p->maxas    = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1673       p->maxds    = (short)FT_MAX( glyph->bbx.descent, p->maxds );
1674 
1675       p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
1676 
1677       p->maxrb    = (short)FT_MAX( p->rbearing, p->maxrb );
1678       p->minlb    = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1679       p->maxlb    = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
1680 
1681       if ( !( p->flags & BDF_DWIDTH_ ) )
1682       {
1683         /* Missing DWIDTH field.  Emit an auto correction message and set */
1684         /* the device width to the glyph width.                           */
1685         FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG10, lineno ));
1686         glyph->dwidth = glyph->bbx.width;
1687       }
1688 
1689       /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1690       /* value if necessary.                                            */
1691       if ( p->opts->correct_metrics )
1692       {
1693         /* Determine the point size of the glyph. */
1694         unsigned short  sw = (unsigned short)FT_MulDiv(
1695                                glyph->dwidth, 72000L,
1696                                (FT_Long)( font->point_size *
1697                                           font->resolution_x ) );
1698 
1699 
1700         if ( sw != glyph->swidth )
1701         {
1702           glyph->swidth = sw;
1703 
1704           p->flags       |= BDF_SWIDTH_ADJ_;
1705         }
1706       }
1707 
1708       p->flags |= BDF_BBX_;
1709       goto Exit;
1710     }
1711 
1712     /* And finally, gather up the bitmap. */
1713     if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 )
1714     {
1715       unsigned long  bitmap_size;
1716 
1717 
1718       if ( !( p->flags & BDF_BBX_ ) )
1719       {
1720         /* Missing BBX field. */
1721         FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "BBX" ));
1722         error = FT_THROW( Missing_Bbx_Field );
1723         goto Exit;
1724       }
1725 
1726       /* Allocate enough space for the bitmap. */
1727       glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
1728 
1729       bitmap_size = glyph->bpr * glyph->bbx.height;
1730       if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
1731       {
1732         FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG4, lineno ));
1733         error = FT_THROW( Bbx_Too_Big );
1734         goto Exit;
1735       }
1736       else
1737         glyph->bytes = (unsigned short)bitmap_size;
1738 
1739       if ( FT_ALLOC( glyph->bitmap, glyph->bytes ) )
1740         goto Exit;
1741 
1742       p->row    = 0;
1743       p->flags |= BDF_BITMAP_;
1744 
1745       goto Exit;
1746     }
1747 
1748     FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG9, lineno ));
1749     error = FT_THROW( Invalid_File_Format );
1750     goto Exit;
1751 
1752   Missing_Encoding:
1753     /* Missing ENCODING field. */
1754     FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENCODING" ));
1755     error = FT_THROW( Missing_Encoding_Field );
1756 
1757   Exit:
1758     if ( error && ( p->flags & BDF_GLYPH_ ) )
1759       FT_FREE( p->glyph_name );
1760 
1761     return error;
1762   }
1763 
1764 
1765   /* Load the font properties. */
1766   static FT_Error
bdf_parse_properties_(char * line,unsigned long linelen,unsigned long lineno,void * call_data,void * client_data)1767   bdf_parse_properties_( char*          line,
1768                          unsigned long  linelen,
1769                          unsigned long  lineno,
1770                          void*          call_data,
1771                          void*          client_data )
1772   {
1773     unsigned long      vlen;
1774     bdf_line_func_t_*  next;
1775     bdf_parse_t_*      p;
1776     char*              name;
1777     char*              value;
1778     char               nbuf[128];
1779     FT_Error           error = FT_Err_Ok;
1780 
1781     FT_UNUSED( lineno );
1782 
1783 
1784     next = (bdf_line_func_t_ *)call_data;
1785     p    = (bdf_parse_t_ *)    client_data;
1786 
1787     /* Check for the end of the properties. */
1788     if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
1789     {
1790       /* If the FONT_ASCENT or FONT_DESCENT properties have not been      */
1791       /* encountered yet, then make sure they are added as properties and */
1792       /* make sure they are set from the font bounding box info.          */
1793       /*                                                                  */
1794       /* This is *always* done regardless of the options, because X11     */
1795       /* requires these two fields to compile fonts.                      */
1796       if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
1797       {
1798         p->font->font_ascent = p->font->bbx.ascent;
1799         ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1800         error = bdf_add_property_( p->font, "FONT_ASCENT",
1801                                    nbuf, lineno );
1802         if ( error )
1803           goto Exit;
1804 
1805         FT_TRACE2(( "bdf_parse_properties_: " ACMSG1, p->font->bbx.ascent ));
1806       }
1807 
1808       if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
1809       {
1810         p->font->font_descent = p->font->bbx.descent;
1811         ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1812         error = bdf_add_property_( p->font, "FONT_DESCENT",
1813                                    nbuf, lineno );
1814         if ( error )
1815           goto Exit;
1816 
1817         FT_TRACE2(( "bdf_parse_properties_: " ACMSG2, p->font->bbx.descent ));
1818       }
1819 
1820       p->flags &= ~BDF_PROPS_;
1821       *next     = bdf_parse_glyphs_;
1822 
1823       goto Exit;
1824     }
1825 
1826     /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1827     if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1828       goto Exit;
1829 
1830     /* Handle COMMENT fields and properties in a special way to preserve */
1831     /* the spacing.                                                      */
1832     if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
1833     {
1834       name = value = line;
1835       value += 7;
1836       if ( *value )
1837         *value++ = 0;
1838       error = bdf_add_property_( p->font, name, value, lineno );
1839       if ( error )
1840         goto Exit;
1841     }
1842     else if ( bdf_is_atom_( line, linelen, &name, &value, p->font ) )
1843     {
1844       error = bdf_add_property_( p->font, name, value, lineno );
1845       if ( error )
1846         goto Exit;
1847     }
1848     else
1849     {
1850       error = bdf_list_split_( &p->list, " +", line, linelen );
1851       if ( error )
1852         goto Exit;
1853       name = p->list.field[0];
1854 
1855       bdf_list_shift_( &p->list, 1 );
1856       value = bdf_list_join_( &p->list, ' ', &vlen );
1857 
1858       error = bdf_add_property_( p->font, name, value, lineno );
1859       if ( error )
1860         goto Exit;
1861     }
1862 
1863   Exit:
1864     return error;
1865   }
1866 
1867 
1868   /* Load the font header. */
1869   static FT_Error
bdf_parse_start_(char * line,unsigned long linelen,unsigned long lineno,void * call_data,void * client_data)1870   bdf_parse_start_( char*          line,
1871                     unsigned long  linelen,
1872                     unsigned long  lineno,
1873                     void*          call_data,
1874                     void*          client_data )
1875   {
1876     unsigned long      slen;
1877     bdf_line_func_t_*  next;
1878     bdf_parse_t_*      p;
1879     bdf_font_t*        font;
1880     char               *s;
1881 
1882     FT_Memory          memory = NULL;
1883     FT_Error           error  = FT_Err_Ok;
1884 
1885     FT_UNUSED( lineno );            /* only used in debug mode */
1886 
1887 
1888     next = (bdf_line_func_t_ *)call_data;
1889     p    = (bdf_parse_t_ *)    client_data;
1890 
1891     if ( p->font )
1892       memory = p->font->memory;
1893 
1894     /* Check for a comment.  This is done to handle those fonts that have */
1895     /* comments before the STARTFONT line for some reason.                */
1896     if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
1897     {
1898       if ( p->opts->keep_comments && p->font )
1899       {
1900         linelen -= 7;
1901 
1902         s = line + 7;
1903         if ( *s != 0 )
1904         {
1905           s++;
1906           linelen--;
1907         }
1908         error = bdf_add_comment_( p->font, s, linelen );
1909       }
1910       goto Exit;
1911     }
1912 
1913     if ( !( p->flags & BDF_START_ ) )
1914     {
1915       memory = p->memory;
1916 
1917       if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 )
1918       {
1919         /* we don't emit an error message since this code gets */
1920         /* explicitly caught one level higher                  */
1921         error = FT_THROW( Missing_Startfont_Field );
1922         goto Exit;
1923       }
1924 
1925       p->flags = BDF_START_;
1926       font = p->font = NULL;
1927 
1928       if ( FT_NEW( font ) )
1929         goto Exit;
1930       p->font = font;
1931 
1932       font->memory = p->memory;
1933 
1934       { /* setup */
1935         size_t           i;
1936         bdf_property_t*  prop;
1937 
1938 
1939         error = ft_hash_str_init( &(font->proptbl), memory );
1940         if ( error )
1941           goto Exit;
1942         for ( i = 0, prop = (bdf_property_t*)bdf_properties_;
1943               i < num_bdf_properties_; i++, prop++ )
1944         {
1945           error = ft_hash_str_insert( prop->name, i,
1946                                       &(font->proptbl), memory );
1947           if ( error )
1948             goto Exit;
1949         }
1950       }
1951 
1952       if ( FT_QALLOC( p->font->internal, sizeof ( FT_HashRec ) ) )
1953         goto Exit;
1954       error = ft_hash_str_init( (FT_Hash)p->font->internal, memory );
1955       if ( error )
1956         goto Exit;
1957       p->font->spacing      = p->opts->font_spacing;
1958       p->font->default_char = ~0UL;
1959 
1960       goto Exit;
1961     }
1962 
1963     /* Check for the start of the properties. */
1964     if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 )
1965     {
1966       if ( !( p->flags & BDF_FONT_BBX_ ) )
1967       {
1968         /* Missing the FONTBOUNDINGBOX field. */
1969         FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
1970         error = FT_THROW( Missing_Fontboundingbox_Field );
1971         goto Exit;
1972       }
1973 
1974       error = bdf_list_split_( &p->list, " +", line, linelen );
1975       if ( error )
1976         goto Exit;
1977 
1978       /* at this point, `p->font' can't be NULL */
1979       p->cnt = p->font->props_size = bdf_atoul_( p->list.field[1] );
1980       /* We need at least 4 bytes per property. */
1981       if ( p->cnt > p->size / 4 )
1982       {
1983         p->font->props_size = 0;
1984 
1985         FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG5, lineno, "STARTPROPERTIES" ));
1986         error = FT_THROW( Invalid_Argument );
1987         goto Exit;
1988       }
1989 
1990       if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
1991       {
1992         p->font->props_size = 0;
1993         goto Exit;
1994       }
1995 
1996       p->flags |= BDF_PROPS_;
1997       *next     = bdf_parse_properties_;
1998 
1999       goto Exit;
2000     }
2001 
2002     /* Check for the FONTBOUNDINGBOX field. */
2003     if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2004     {
2005       if ( !( p->flags & BDF_SIZE_ ) )
2006       {
2007         /* Missing the SIZE field. */
2008         FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "SIZE" ));
2009         error = FT_THROW( Missing_Size_Field );
2010         goto Exit;
2011       }
2012 
2013       error = bdf_list_split_( &p->list, " +", line, linelen );
2014       if ( error )
2015         goto Exit;
2016 
2017       p->font->bbx.width  = bdf_atous_( p->list.field[1] );
2018       p->font->bbx.height = bdf_atous_( p->list.field[2] );
2019 
2020       p->font->bbx.x_offset = bdf_atos_( p->list.field[3] );
2021       p->font->bbx.y_offset = bdf_atos_( p->list.field[4] );
2022 
2023       p->font->bbx.ascent  = (short)( p->font->bbx.height +
2024                                       p->font->bbx.y_offset );
2025 
2026       p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
2027 
2028       p->flags |= BDF_FONT_BBX_;
2029 
2030       goto Exit;
2031     }
2032 
2033     /* The next thing to check for is the FONT field. */
2034     if ( _bdf_strncmp( line, "FONT", 4 ) == 0 )
2035     {
2036       error = bdf_list_split_( &p->list, " +", line, linelen );
2037       if ( error )
2038         goto Exit;
2039       bdf_list_shift_( &p->list, 1 );
2040 
2041       s = bdf_list_join_( &p->list, ' ', &slen );
2042 
2043       if ( !s )
2044       {
2045         FT_ERROR(( "bdf_parse_start_: " ERRMSG8, lineno, "FONT" ));
2046         error = FT_THROW( Invalid_File_Format );
2047         goto Exit;
2048       }
2049 
2050       /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2051       FT_FREE( p->font->name );
2052 
2053       if ( FT_QALLOC( p->font->name, slen + 1 ) )
2054         goto Exit;
2055       FT_MEM_COPY( p->font->name, s, slen + 1 );
2056 
2057       /* If the font name is an XLFD name, set the spacing to the one in  */
2058       /* the font name.  If there is no spacing fall back on the default. */
2059       error = bdf_set_default_spacing_( p->font, p->opts, lineno );
2060       if ( error )
2061         goto Exit;
2062 
2063       p->flags |= BDF_FONT_NAME_;
2064 
2065       goto Exit;
2066     }
2067 
2068     /* Check for the SIZE field. */
2069     if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 )
2070     {
2071       if ( !( p->flags & BDF_FONT_NAME_ ) )
2072       {
2073         /* Missing the FONT field. */
2074         FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONT" ));
2075         error = FT_THROW( Missing_Font_Field );
2076         goto Exit;
2077       }
2078 
2079       error = bdf_list_split_( &p->list, " +", line, linelen );
2080       if ( error )
2081         goto Exit;
2082 
2083       p->font->point_size   = bdf_atoul_( p->list.field[1] );
2084       p->font->resolution_x = bdf_atoul_( p->list.field[2] );
2085       p->font->resolution_y = bdf_atoul_( p->list.field[3] );
2086 
2087       /* Check for the bits per pixel field. */
2088       if ( p->list.used == 5 )
2089       {
2090         unsigned short bpp;
2091 
2092 
2093         bpp = bdf_atous_( p->list.field[4] );
2094 
2095         /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
2096         if ( bpp > 4 )
2097           p->font->bpp = 8;
2098         else if ( bpp > 2 )
2099           p->font->bpp = 4;
2100         else if ( bpp > 1 )
2101           p->font->bpp = 2;
2102         else
2103           p->font->bpp = 1;
2104 
2105         if ( p->font->bpp != bpp )
2106           FT_TRACE2(( "bdf_parse_start_: " ACMSG11, p->font->bpp ));
2107       }
2108       else
2109         p->font->bpp = 1;
2110 
2111       p->flags |= BDF_SIZE_;
2112 
2113       goto Exit;
2114     }
2115 
2116     /* Check for the CHARS field -- font properties are optional */
2117     if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
2118     {
2119       char  nbuf[128];
2120 
2121 
2122       if ( !( p->flags & BDF_FONT_BBX_ ) )
2123       {
2124         /* Missing the FONTBOUNDINGBOX field. */
2125         FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2126         error = FT_THROW( Missing_Fontboundingbox_Field );
2127         goto Exit;
2128       }
2129 
2130       /* Add the two standard X11 properties which are required */
2131       /* for compiling fonts.                                   */
2132       p->font->font_ascent = p->font->bbx.ascent;
2133       ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
2134       error = bdf_add_property_( p->font, "FONT_ASCENT",
2135                                  nbuf, lineno );
2136       if ( error )
2137         goto Exit;
2138       FT_TRACE2(( "bdf_parse_properties_: " ACMSG1, p->font->bbx.ascent ));
2139 
2140       p->font->font_descent = p->font->bbx.descent;
2141       ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
2142       error = bdf_add_property_( p->font, "FONT_DESCENT",
2143                                  nbuf, lineno );
2144       if ( error )
2145         goto Exit;
2146       FT_TRACE2(( "bdf_parse_properties_: " ACMSG2, p->font->bbx.descent ));
2147 
2148       *next = bdf_parse_glyphs_;
2149 
2150       /* A special return value. */
2151       error = -1;
2152       goto Exit;
2153     }
2154 
2155     FT_ERROR(( "bdf_parse_start_: " ERRMSG9, lineno ));
2156     error = FT_THROW( Invalid_File_Format );
2157 
2158   Exit:
2159     return error;
2160   }
2161 
2162 
2163   /**************************************************************************
2164    *
2165    * API.
2166    *
2167    */
2168 
2169 
2170   FT_LOCAL_DEF( FT_Error )
bdf_load_font(FT_Stream stream,FT_Memory memory,bdf_options_t * opts,bdf_font_t ** font)2171   bdf_load_font( FT_Stream       stream,
2172                  FT_Memory       memory,
2173                  bdf_options_t*  opts,
2174                  bdf_font_t*    *font )
2175   {
2176     unsigned long  lineno = 0; /* make compiler happy */
2177     bdf_parse_t_   *p     = NULL;
2178 
2179     FT_Error  error = FT_Err_Ok;
2180 
2181 
2182     if ( FT_NEW( p ) )
2183       goto Exit;
2184 
2185     p->opts   = (bdf_options_t*)( opts ? opts : &bdf_opts_ );
2186     p->minlb  = 32767;
2187     p->size   = stream->size;
2188     p->memory = memory;  /* only during font creation */
2189 
2190     bdf_list_init_( &p->list, memory );
2191 
2192     error = bdf_readstream_( stream, bdf_parse_start_,
2193                              (void *)p, &lineno );
2194     if ( error )
2195       goto Fail;
2196 
2197     if ( p->font )
2198     {
2199       /* If the font is not proportional, set the font's monowidth */
2200       /* field to the width of the font bounding box.              */
2201 
2202       if ( p->font->spacing != BDF_PROPORTIONAL )
2203         p->font->monowidth = p->font->bbx.width;
2204 
2205       /* If the number of glyphs loaded is not that of the original count, */
2206       /* indicate the difference.                                          */
2207       if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
2208       {
2209         FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2210                     p->font->glyphs_used + p->font->unencoded_used ));
2211       }
2212 
2213       /* Once the font has been loaded, adjust the overall font metrics if */
2214       /* necessary.                                                        */
2215       if ( p->opts->correct_metrics != 0 &&
2216            ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
2217       {
2218         if ( p->maxrb - p->minlb != p->font->bbx.width )
2219         {
2220           FT_TRACE2(( "bdf_load_font: " ACMSG3,
2221                       p->font->bbx.width, p->maxrb - p->minlb ));
2222           p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2223         }
2224 
2225         if ( p->font->bbx.x_offset != p->minlb )
2226         {
2227           FT_TRACE2(( "bdf_load_font: " ACMSG4,
2228                       p->font->bbx.x_offset, p->minlb ));
2229           p->font->bbx.x_offset = p->minlb;
2230         }
2231 
2232         if ( p->font->bbx.ascent != p->maxas )
2233         {
2234           FT_TRACE2(( "bdf_load_font: " ACMSG5,
2235                       p->font->bbx.ascent, p->maxas ));
2236           p->font->bbx.ascent = p->maxas;
2237         }
2238 
2239         if ( p->font->bbx.descent != p->maxds )
2240         {
2241           FT_TRACE2(( "bdf_load_font: " ACMSG6,
2242                       p->font->bbx.descent, p->maxds ));
2243           p->font->bbx.descent  = p->maxds;
2244           p->font->bbx.y_offset = (short)( -p->maxds );
2245         }
2246 
2247         if ( p->maxas + p->maxds != p->font->bbx.height )
2248         {
2249           FT_TRACE2(( "bdf_load_font: " ACMSG7,
2250                       p->font->bbx.height, p->maxas + p->maxds ));
2251           p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
2252         }
2253 
2254         if ( p->flags & BDF_SWIDTH_ADJ_ )
2255           FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2256       }
2257     }
2258 
2259     if ( p->flags & BDF_START_ )
2260     {
2261       /* The ENDFONT field was never reached or did not exist. */
2262       if ( !( p->flags & BDF_GLYPHS_ ) )
2263       {
2264         /* Error happened while parsing header. */
2265         FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2266         error = FT_THROW( Corrupted_Font_Header );
2267         goto Fail;
2268       }
2269       else
2270       {
2271         /* Error happened when parsing glyphs. */
2272         FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2273         error = FT_THROW( Corrupted_Font_Glyphs );
2274         goto Fail;
2275       }
2276     }
2277 
2278     if ( !p->font && !error )
2279       error = FT_THROW( Invalid_File_Format );
2280 
2281     *font = p->font;
2282 
2283   Exit:
2284     if ( p )
2285     {
2286       bdf_list_done_( &p->list );
2287 
2288       FT_FREE( p->glyph_name );
2289       FT_FREE( p );
2290     }
2291 
2292     return error;
2293 
2294   Fail:
2295     bdf_free_font( p->font );
2296 
2297     FT_FREE( p->font );
2298 
2299     goto Exit;
2300   }
2301 
2302 
2303   FT_LOCAL_DEF( void )
bdf_free_font(bdf_font_t * font)2304   bdf_free_font( bdf_font_t*  font )
2305   {
2306     bdf_property_t*  prop;
2307     unsigned long    i;
2308     bdf_glyph_t*     glyphs;
2309     FT_Memory        memory;
2310 
2311 
2312     if ( font == NULL )
2313       return;
2314 
2315     memory = font->memory;
2316 
2317     FT_FREE( font->name );
2318 
2319     /* Free up the internal hash table of property names. */
2320     if ( font->internal )
2321     {
2322       ft_hash_str_free( (FT_Hash)font->internal, memory );
2323       FT_FREE( font->internal );
2324     }
2325 
2326     /* Free up the comment info. */
2327     FT_FREE( font->comments );
2328 
2329     /* Free up the properties. */
2330     for ( i = 0; i < font->props_size; i++ )
2331     {
2332       if ( font->props[i].format == BDF_ATOM )
2333         FT_FREE( font->props[i].value.atom );
2334     }
2335 
2336     FT_FREE( font->props );
2337 
2338     /* Free up the character info. */
2339     for ( i = 0, glyphs = font->glyphs;
2340           i < font->glyphs_used; i++, glyphs++ )
2341     {
2342       FT_FREE( glyphs->name );
2343       FT_FREE( glyphs->bitmap );
2344     }
2345 
2346     for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2347           i++, glyphs++ )
2348     {
2349       FT_FREE( glyphs->name );
2350       FT_FREE( glyphs->bitmap );
2351     }
2352 
2353     FT_FREE( font->glyphs );
2354     FT_FREE( font->unencoded );
2355 
2356     /* bdf_cleanup */
2357     ft_hash_str_free( &(font->proptbl), memory );
2358 
2359     /* Free up the user defined properties. */
2360     for ( prop = font->user_props, i = 0;
2361           i < font->nuser_props; i++, prop++ )
2362       FT_FREE( prop->name );
2363 
2364     FT_FREE( font->user_props );
2365 
2366     /* FREE( font ); */ /* XXX Fixme */
2367   }
2368 
2369 
2370   FT_LOCAL_DEF( bdf_property_t * )
bdf_get_font_property(bdf_font_t * font,const char * name)2371   bdf_get_font_property( bdf_font_t*  font,
2372                          const char*  name )
2373   {
2374     size_t*  propid;
2375 
2376 
2377     if ( font == NULL || font->props_size == 0 || name == NULL || *name == 0 )
2378       return 0;
2379 
2380     propid = ft_hash_str_lookup( name, (FT_Hash)font->internal );
2381 
2382     return propid ? ( font->props + *propid ) : 0;
2383   }
2384 
2385 
2386 /* END */
2387