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