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