Home | History | Annotate | Download | only in bdf
      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
    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
    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
    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
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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* )
    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
    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
    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
   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
   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
   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     /* Point at the glyph being constructed. */
   1560     if ( p->glyph_enc == -1 )
   1561       glyph = font->unencoded + ( font->unencoded_used - 1 );
   1562     else
   1563       glyph = font->glyphs + ( font->glyphs_used - 1 );
   1564 
   1565     /* Check whether a bitmap is being constructed. */
   1566     if ( p->flags & BDF_BITMAP_ )
   1567     {
   1568       /* If there are more rows than are specified in the glyph metrics, */
   1569       /* ignore the remaining lines.                                     */
   1570       if ( p->row >= (unsigned long)glyph->bbx.height )
   1571       {
   1572         if ( !( p->flags & BDF_GLYPH_HEIGHT_CHECK_ ) )
   1573         {
   1574           FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
   1575           p->flags |= BDF_GLYPH_HEIGHT_CHECK_;
   1576           font->modified = 1;
   1577         }
   1578 
   1579         goto Exit;
   1580       }
   1581 
   1582       /* Only collect the number of nibbles indicated by the glyph     */
   1583       /* metrics.  If there are more columns, they are simply ignored. */
   1584       nibbles = glyph->bpr << 1;
   1585       bp      = glyph->bitmap + p->row * glyph->bpr;
   1586 
   1587       for ( i = 0; i < nibbles; i++ )
   1588       {
   1589         c = line[i];
   1590         if ( !sbitset( hdigits, c ) )
   1591           break;
   1592         *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
   1593         if ( i + 1 < nibbles && ( i & 1 ) )
   1594           *++bp = 0;
   1595       }
   1596 
   1597       /* If any line has not enough columns,            */
   1598       /* indicate they have been padded with zero bits. */
   1599       if ( i < nibbles                            &&
   1600            !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
   1601       {
   1602         FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
   1603         p->flags       |= BDF_GLYPH_WIDTH_CHECK_;
   1604         font->modified  = 1;
   1605       }
   1606 
   1607       /* Remove possible garbage at the right. */
   1608       mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
   1609       if ( glyph->bbx.width )
   1610         *bp &= nibble_mask[mask_index];
   1611 
   1612       /* If any line has extra columns, indicate they have been removed. */
   1613       if ( i == nibbles                           &&
   1614            sbitset( hdigits, line[nibbles] )      &&
   1615            !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
   1616       {
   1617         FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
   1618         p->flags       |= BDF_GLYPH_WIDTH_CHECK_;
   1619         font->modified  = 1;
   1620       }
   1621 
   1622       p->row++;
   1623       goto Exit;
   1624     }
   1625 
   1626     /* Expect the SWIDTH (scalable width) field next. */
   1627     if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 )
   1628     {
   1629       if ( !( p->flags & BDF_ENCODING_ ) )
   1630         goto Missing_Encoding;
   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       if ( !( p->flags & BDF_ENCODING_ ) )
   1646         goto Missing_Encoding;
   1647 
   1648       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
   1649       if ( error )
   1650         goto Exit;
   1651 
   1652       glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1] );
   1653 
   1654       if ( !( p->flags & BDF_SWIDTH_ ) )
   1655       {
   1656         /* Missing SWIDTH field.  Emit an auto correction message and set */
   1657         /* the scalable width from the device width.                      */
   1658         FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
   1659 
   1660         glyph->swidth = (unsigned short)FT_MulDiv(
   1661                           glyph->dwidth, 72000L,
   1662                           (FT_Long)( font->point_size *
   1663                                      font->resolution_x ) );
   1664       }
   1665 
   1666       p->flags |= BDF_DWIDTH_;
   1667       goto Exit;
   1668     }
   1669 
   1670     /* Expect the BBX field next. */
   1671     if ( _bdf_strncmp( line, "BBX", 3 ) == 0 )
   1672     {
   1673       if ( !( p->flags & BDF_ENCODING_ ) )
   1674         goto Missing_Encoding;
   1675 
   1676       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
   1677       if ( error )
   1678         goto Exit;
   1679 
   1680       glyph->bbx.width    = _bdf_atous( p->list.field[1] );
   1681       glyph->bbx.height   = _bdf_atous( p->list.field[2] );
   1682       glyph->bbx.x_offset = _bdf_atos( p->list.field[3] );
   1683       glyph->bbx.y_offset = _bdf_atos( p->list.field[4] );
   1684 
   1685       /* Generate the ascent and descent of the character. */
   1686       glyph->bbx.ascent  = (short)( glyph->bbx.height + glyph->bbx.y_offset );
   1687       glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
   1688 
   1689       /* Determine the overall font bounding box as the characters are */
   1690       /* loaded so corrections can be done later if indicated.         */
   1691       p->maxas    = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
   1692       p->maxds    = (short)FT_MAX( glyph->bbx.descent, p->maxds );
   1693 
   1694       p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
   1695 
   1696       p->maxrb    = (short)FT_MAX( p->rbearing, p->maxrb );
   1697       p->minlb    = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
   1698       p->maxlb    = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
   1699 
   1700       if ( !( p->flags & BDF_DWIDTH_ ) )
   1701       {
   1702         /* Missing DWIDTH field.  Emit an auto correction message and set */
   1703         /* the device width to the glyph width.                           */
   1704         FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
   1705         glyph->dwidth = glyph->bbx.width;
   1706       }
   1707 
   1708       /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
   1709       /* value if necessary.                                            */
   1710       if ( p->opts->correct_metrics != 0 )
   1711       {
   1712         /* Determine the point size of the glyph. */
   1713         unsigned short  sw = (unsigned short)FT_MulDiv(
   1714                                glyph->dwidth, 72000L,
   1715                                (FT_Long)( font->point_size *
   1716                                           font->resolution_x ) );
   1717 
   1718 
   1719         if ( sw != glyph->swidth )
   1720         {
   1721           glyph->swidth = sw;
   1722 
   1723           if ( p->glyph_enc == -1 )
   1724             _bdf_set_glyph_modified( font->umod,
   1725                                      font->unencoded_used - 1 );
   1726           else
   1727             _bdf_set_glyph_modified( font->nmod, glyph->encoding );
   1728 
   1729           p->flags       |= BDF_SWIDTH_ADJ_;
   1730           font->modified  = 1;
   1731         }
   1732       }
   1733 
   1734       p->flags |= BDF_BBX_;
   1735       goto Exit;
   1736     }
   1737 
   1738     /* And finally, gather up the bitmap. */
   1739     if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 )
   1740     {
   1741       unsigned long  bitmap_size;
   1742 
   1743 
   1744       if ( !( p->flags & BDF_BBX_ ) )
   1745       {
   1746         /* Missing BBX field. */
   1747         FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
   1748         error = FT_THROW( Missing_Bbx_Field );
   1749         goto Exit;
   1750       }
   1751 
   1752       /* Allocate enough space for the bitmap. */
   1753       glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
   1754 
   1755       bitmap_size = glyph->bpr * glyph->bbx.height;
   1756       if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
   1757       {
   1758         FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
   1759         error = FT_THROW( Bbx_Too_Big );
   1760         goto Exit;
   1761       }
   1762       else
   1763         glyph->bytes = (unsigned short)bitmap_size;
   1764 
   1765       if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
   1766         goto Exit;
   1767 
   1768       p->row    = 0;
   1769       p->flags |= BDF_BITMAP_;
   1770 
   1771       goto Exit;
   1772     }
   1773 
   1774     FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
   1775     error = FT_THROW( Invalid_File_Format );
   1776     goto Exit;
   1777 
   1778   Missing_Encoding:
   1779     /* Missing ENCODING field. */
   1780     FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
   1781     error = FT_THROW( Missing_Encoding_Field );
   1782 
   1783   Exit:
   1784     if ( error && ( p->flags & BDF_GLYPH_ ) )
   1785       FT_FREE( p->glyph_name );
   1786 
   1787     return error;
   1788   }
   1789 
   1790 
   1791   /* Load the font properties. */
   1792   static FT_Error
   1793   _bdf_parse_properties( char*          line,
   1794                          unsigned long  linelen,
   1795                          unsigned long  lineno,
   1796                          void*          call_data,
   1797                          void*          client_data )
   1798   {
   1799     unsigned long      vlen;
   1800     _bdf_line_func_t*  next;
   1801     _bdf_parse_t*      p;
   1802     char*              name;
   1803     char*              value;
   1804     char               nbuf[128];
   1805     FT_Error           error = FT_Err_Ok;
   1806 
   1807     FT_UNUSED( lineno );
   1808 
   1809 
   1810     next = (_bdf_line_func_t *)call_data;
   1811     p    = (_bdf_parse_t *)    client_data;
   1812 
   1813     /* Check for the end of the properties. */
   1814     if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
   1815     {
   1816       /* If the FONT_ASCENT or FONT_DESCENT properties have not been      */
   1817       /* encountered yet, then make sure they are added as properties and */
   1818       /* make sure they are set from the font bounding box info.          */
   1819       /*                                                                  */
   1820       /* This is *always* done regardless of the options, because X11     */
   1821       /* requires these two fields to compile fonts.                      */
   1822       if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
   1823       {
   1824         p->font->font_ascent = p->font->bbx.ascent;
   1825         ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
   1826         error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
   1827                                    nbuf, lineno );
   1828         if ( error )
   1829           goto Exit;
   1830 
   1831         FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
   1832         p->font->modified = 1;
   1833       }
   1834 
   1835       if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
   1836       {
   1837         p->font->font_descent = p->font->bbx.descent;
   1838         ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
   1839         error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
   1840                                    nbuf, lineno );
   1841         if ( error )
   1842           goto Exit;
   1843 
   1844         FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
   1845         p->font->modified = 1;
   1846       }
   1847 
   1848       p->flags &= ~BDF_PROPS_;
   1849       *next     = _bdf_parse_glyphs;
   1850 
   1851       goto Exit;
   1852     }
   1853 
   1854     /* Ignore the _XFREE86_GLYPH_RANGES properties. */
   1855     if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
   1856       goto Exit;
   1857 
   1858     /* Handle COMMENT fields and properties in a special way to preserve */
   1859     /* the spacing.                                                      */
   1860     if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
   1861     {
   1862       name = value = line;
   1863       value += 7;
   1864       if ( *value )
   1865         *value++ = 0;
   1866       error = _bdf_add_property( p->font, name, value, lineno );
   1867       if ( error )
   1868         goto Exit;
   1869     }
   1870     else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
   1871     {
   1872       error = _bdf_add_property( p->font, name, value, lineno );
   1873       if ( error )
   1874         goto Exit;
   1875     }
   1876     else
   1877     {
   1878       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
   1879       if ( error )
   1880         goto Exit;
   1881       name = p->list.field[0];
   1882 
   1883       _bdf_list_shift( &p->list, 1 );
   1884       value = _bdf_list_join( &p->list, ' ', &vlen );
   1885 
   1886       error = _bdf_add_property( p->font, name, value, lineno );
   1887       if ( error )
   1888         goto Exit;
   1889     }
   1890 
   1891   Exit:
   1892     return error;
   1893   }
   1894 
   1895 
   1896   /* Load the font header. */
   1897   static FT_Error
   1898   _bdf_parse_start( char*          line,
   1899                     unsigned long  linelen,
   1900                     unsigned long  lineno,
   1901                     void*          call_data,
   1902                     void*          client_data )
   1903   {
   1904     unsigned long      slen;
   1905     _bdf_line_func_t*  next;
   1906     _bdf_parse_t*      p;
   1907     bdf_font_t*        font;
   1908     char               *s;
   1909 
   1910     FT_Memory          memory = NULL;
   1911     FT_Error           error  = FT_Err_Ok;
   1912 
   1913     FT_UNUSED( lineno );            /* only used in debug mode */
   1914 
   1915 
   1916     next = (_bdf_line_func_t *)call_data;
   1917     p    = (_bdf_parse_t *)    client_data;
   1918 
   1919     if ( p->font )
   1920       memory = p->font->memory;
   1921 
   1922     /* Check for a comment.  This is done to handle those fonts that have */
   1923     /* comments before the STARTFONT line for some reason.                */
   1924     if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
   1925     {
   1926       if ( p->opts->keep_comments != 0 && p->font != 0 )
   1927       {
   1928         linelen -= 7;
   1929 
   1930         s = line + 7;
   1931         if ( *s != 0 )
   1932         {
   1933           s++;
   1934           linelen--;
   1935         }
   1936 
   1937         error = _bdf_add_comment( p->font, s, linelen );
   1938         if ( error )
   1939           goto Exit;
   1940         /* here font is not defined! */
   1941       }
   1942 
   1943       goto Exit;
   1944     }
   1945 
   1946     if ( !( p->flags & BDF_START_ ) )
   1947     {
   1948       memory = p->memory;
   1949 
   1950       if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 )
   1951       {
   1952         /* we don't emit an error message since this code gets */
   1953         /* explicitly caught one level higher                  */
   1954         error = FT_THROW( Missing_Startfont_Field );
   1955         goto Exit;
   1956       }
   1957 
   1958       p->flags = BDF_START_;
   1959       font = p->font = 0;
   1960 
   1961       if ( FT_NEW( font ) )
   1962         goto Exit;
   1963       p->font = font;
   1964 
   1965       font->memory = p->memory;
   1966       p->memory    = 0;
   1967 
   1968       { /* setup */
   1969         size_t           i;
   1970         bdf_property_t*  prop;
   1971 
   1972 
   1973         error = ft_hash_str_init( &(font->proptbl), memory );
   1974         if ( error )
   1975           goto Exit;
   1976         for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
   1977               i < _num_bdf_properties; i++, prop++ )
   1978         {
   1979           error = ft_hash_str_insert( prop->name, i,
   1980                                       &(font->proptbl), memory );
   1981           if ( error )
   1982             goto Exit;
   1983         }
   1984       }
   1985 
   1986       if ( FT_ALLOC( p->font->internal, sizeof ( FT_HashRec ) ) )
   1987         goto Exit;
   1988       error = ft_hash_str_init( (FT_Hash)p->font->internal, memory );
   1989       if ( error )
   1990         goto Exit;
   1991       p->font->spacing      = p->opts->font_spacing;
   1992       p->font->default_char = -1;
   1993 
   1994       goto Exit;
   1995     }
   1996 
   1997     /* Check for the start of the properties. */
   1998     if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 )
   1999     {
   2000       if ( !( p->flags & BDF_FONT_BBX_ ) )
   2001       {
   2002         /* Missing the FONTBOUNDINGBOX field. */
   2003         FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
   2004         error = FT_THROW( Missing_Fontboundingbox_Field );
   2005         goto Exit;
   2006       }
   2007 
   2008       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
   2009       if ( error )
   2010         goto Exit;
   2011 
   2012       /* at this point, `p->font' can't be NULL */
   2013       p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1] );
   2014       /* We need at least 4 bytes per property. */
   2015       if ( p->cnt > p->size / 4 )
   2016       {
   2017         p->font->props_size = 0;
   2018 
   2019         FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "STARTPROPERTIES" ));
   2020         error = FT_THROW( Invalid_Argument );
   2021         goto Exit;
   2022       }
   2023 
   2024       if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
   2025       {
   2026         p->font->props_size = 0;
   2027         goto Exit;
   2028       }
   2029 
   2030       p->flags |= BDF_PROPS_;
   2031       *next     = _bdf_parse_properties;
   2032 
   2033       goto Exit;
   2034     }
   2035 
   2036     /* Check for the FONTBOUNDINGBOX field. */
   2037     if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
   2038     {
   2039       if ( !( p->flags & BDF_SIZE_ ) )
   2040       {
   2041         /* Missing the SIZE field. */
   2042         FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
   2043         error = FT_THROW( Missing_Size_Field );
   2044         goto Exit;
   2045       }
   2046 
   2047       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
   2048       if ( error )
   2049         goto Exit;
   2050 
   2051       p->font->bbx.width  = _bdf_atous( p->list.field[1] );
   2052       p->font->bbx.height = _bdf_atous( p->list.field[2] );
   2053 
   2054       p->font->bbx.x_offset = _bdf_atos( p->list.field[3] );
   2055       p->font->bbx.y_offset = _bdf_atos( p->list.field[4] );
   2056 
   2057       p->font->bbx.ascent  = (short)( p->font->bbx.height +
   2058                                       p->font->bbx.y_offset );
   2059 
   2060       p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
   2061 
   2062       p->flags |= BDF_FONT_BBX_;
   2063 
   2064       goto Exit;
   2065     }
   2066 
   2067     /* The next thing to check for is the FONT field. */
   2068     if ( _bdf_strncmp( line, "FONT", 4 ) == 0 )
   2069     {
   2070       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
   2071       if ( error )
   2072         goto Exit;
   2073       _bdf_list_shift( &p->list, 1 );
   2074 
   2075       s = _bdf_list_join( &p->list, ' ', &slen );
   2076 
   2077       if ( !s )
   2078       {
   2079         FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
   2080         error = FT_THROW( Invalid_File_Format );
   2081         goto Exit;
   2082       }
   2083 
   2084       /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
   2085       FT_FREE( p->font->name );
   2086 
   2087       if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
   2088         goto Exit;
   2089       FT_MEM_COPY( p->font->name, s, slen + 1 );
   2090 
   2091       /* If the font name is an XLFD name, set the spacing to the one in  */
   2092       /* the font name.  If there is no spacing fall back on the default. */
   2093       error = _bdf_set_default_spacing( p->font, p->opts, lineno );
   2094       if ( error )
   2095         goto Exit;
   2096 
   2097       p->flags |= BDF_FONT_NAME_;
   2098 
   2099       goto Exit;
   2100     }
   2101 
   2102     /* Check for the SIZE field. */
   2103     if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 )
   2104     {
   2105       if ( !( p->flags & BDF_FONT_NAME_ ) )
   2106       {
   2107         /* Missing the FONT field. */
   2108         FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
   2109         error = FT_THROW( Missing_Font_Field );
   2110         goto Exit;
   2111       }
   2112 
   2113       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
   2114       if ( error )
   2115         goto Exit;
   2116 
   2117       p->font->point_size   = _bdf_atoul( p->list.field[1] );
   2118       p->font->resolution_x = _bdf_atoul( p->list.field[2] );
   2119       p->font->resolution_y = _bdf_atoul( p->list.field[3] );
   2120 
   2121       /* Check for the bits per pixel field. */
   2122       if ( p->list.used == 5 )
   2123       {
   2124         unsigned short bpp;
   2125 
   2126 
   2127         bpp = (unsigned short)_bdf_atos( p->list.field[4] );
   2128 
   2129         /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
   2130         if ( bpp > 4 )
   2131           p->font->bpp = 8;
   2132         else if ( bpp > 2 )
   2133           p->font->bpp = 4;
   2134         else if ( bpp > 1 )
   2135           p->font->bpp = 2;
   2136         else
   2137           p->font->bpp = 1;
   2138 
   2139         if ( p->font->bpp != bpp )
   2140           FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
   2141       }
   2142       else
   2143         p->font->bpp = 1;
   2144 
   2145       p->flags |= BDF_SIZE_;
   2146 
   2147       goto Exit;
   2148     }
   2149 
   2150     /* Check for the CHARS field -- font properties are optional */
   2151     if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
   2152     {
   2153       char  nbuf[128];
   2154 
   2155 
   2156       if ( !( p->flags & BDF_FONT_BBX_ ) )
   2157       {
   2158         /* Missing the FONTBOUNDINGBOX field. */
   2159         FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
   2160         error = FT_THROW( Missing_Fontboundingbox_Field );
   2161         goto Exit;
   2162       }
   2163 
   2164       /* Add the two standard X11 properties which are required */
   2165       /* for compiling fonts.                                   */
   2166       p->font->font_ascent = p->font->bbx.ascent;
   2167       ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
   2168       error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
   2169                                  nbuf, lineno );
   2170       if ( error )
   2171         goto Exit;
   2172       FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
   2173 
   2174       p->font->font_descent = p->font->bbx.descent;
   2175       ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
   2176       error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
   2177                                  nbuf, lineno );
   2178       if ( error )
   2179         goto Exit;
   2180       FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
   2181 
   2182       p->font->modified = 1;
   2183 
   2184       *next = _bdf_parse_glyphs;
   2185 
   2186       /* A special return value. */
   2187       error = -1;
   2188       goto Exit;
   2189     }
   2190 
   2191     FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
   2192     error = FT_THROW( Invalid_File_Format );
   2193 
   2194   Exit:
   2195     return error;
   2196   }
   2197 
   2198 
   2199   /*************************************************************************/
   2200   /*                                                                       */
   2201   /* API.                                                                  */
   2202   /*                                                                       */
   2203   /*************************************************************************/
   2204 
   2205 
   2206   FT_LOCAL_DEF( FT_Error )
   2207   bdf_load_font( FT_Stream       stream,
   2208                  FT_Memory       extmemory,
   2209                  bdf_options_t*  opts,
   2210                  bdf_font_t*    *font )
   2211   {
   2212     unsigned long  lineno = 0; /* make compiler happy */
   2213     _bdf_parse_t   *p     = NULL;
   2214 
   2215     FT_Memory  memory = extmemory; /* needed for FT_NEW */
   2216     FT_Error   error  = FT_Err_Ok;
   2217 
   2218 
   2219     if ( FT_NEW( p ) )
   2220       goto Exit;
   2221 
   2222     memory    = NULL;
   2223     p->opts   = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
   2224     p->minlb  = 32767;
   2225     p->size   = stream->size;
   2226     p->memory = extmemory;  /* only during font creation */
   2227 
   2228     _bdf_list_init( &p->list, extmemory );
   2229 
   2230     error = _bdf_readstream( stream, _bdf_parse_start,
   2231                              (void *)p, &lineno );
   2232     if ( error )
   2233       goto Fail;
   2234 
   2235     if ( p->font != 0 )
   2236     {
   2237       /* If the font is not proportional, set the font's monowidth */
   2238       /* field to the width of the font bounding box.              */
   2239 
   2240       if ( p->font->spacing != BDF_PROPORTIONAL )
   2241         p->font->monowidth = p->font->bbx.width;
   2242 
   2243       /* If the number of glyphs loaded is not that of the original count, */
   2244       /* indicate the difference.                                          */
   2245       if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
   2246       {
   2247         FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
   2248                     p->font->glyphs_used + p->font->unencoded_used ));
   2249         p->font->modified = 1;
   2250       }
   2251 
   2252       /* Once the font has been loaded, adjust the overall font metrics if */
   2253       /* necessary.                                                        */
   2254       if ( p->opts->correct_metrics != 0 &&
   2255            ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
   2256       {
   2257         if ( p->maxrb - p->minlb != p->font->bbx.width )
   2258         {
   2259           FT_TRACE2(( "bdf_load_font: " ACMSG3,
   2260                       p->font->bbx.width, p->maxrb - p->minlb ));
   2261           p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
   2262           p->font->modified  = 1;
   2263         }
   2264 
   2265         if ( p->font->bbx.x_offset != p->minlb )
   2266         {
   2267           FT_TRACE2(( "bdf_load_font: " ACMSG4,
   2268                       p->font->bbx.x_offset, p->minlb ));
   2269           p->font->bbx.x_offset = p->minlb;
   2270           p->font->modified     = 1;
   2271         }
   2272 
   2273         if ( p->font->bbx.ascent != p->maxas )
   2274         {
   2275           FT_TRACE2(( "bdf_load_font: " ACMSG5,
   2276                       p->font->bbx.ascent, p->maxas ));
   2277           p->font->bbx.ascent = p->maxas;
   2278           p->font->modified   = 1;
   2279         }
   2280 
   2281         if ( p->font->bbx.descent != p->maxds )
   2282         {
   2283           FT_TRACE2(( "bdf_load_font: " ACMSG6,
   2284                       p->font->bbx.descent, p->maxds ));
   2285           p->font->bbx.descent  = p->maxds;
   2286           p->font->bbx.y_offset = (short)( -p->maxds );
   2287           p->font->modified     = 1;
   2288         }
   2289 
   2290         if ( p->maxas + p->maxds != p->font->bbx.height )
   2291         {
   2292           FT_TRACE2(( "bdf_load_font: " ACMSG7,
   2293                       p->font->bbx.height, p->maxas + p->maxds ));
   2294           p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
   2295         }
   2296 
   2297         if ( p->flags & BDF_SWIDTH_ADJ_ )
   2298           FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
   2299       }
   2300     }
   2301 
   2302     if ( p->flags & BDF_START_ )
   2303     {
   2304       /* The ENDFONT field was never reached or did not exist. */
   2305       if ( !( p->flags & BDF_GLYPHS_ ) )
   2306       {
   2307         /* Error happened while parsing header. */
   2308         FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
   2309         error = FT_THROW( Corrupted_Font_Header );
   2310         goto Fail;
   2311       }
   2312       else
   2313       {
   2314         /* Error happened when parsing glyphs. */
   2315         FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
   2316         error = FT_THROW( Corrupted_Font_Glyphs );
   2317         goto Fail;
   2318       }
   2319     }
   2320 
   2321     if ( p->font != 0 )
   2322     {
   2323       /* Make sure the comments are NULL terminated if they exist. */
   2324       memory = p->font->memory;
   2325 
   2326       if ( p->font->comments_len > 0 )
   2327       {
   2328         if ( FT_RENEW_ARRAY( p->font->comments,
   2329                              p->font->comments_len,
   2330                              p->font->comments_len + 1 ) )
   2331           goto Fail;
   2332 
   2333         p->font->comments[p->font->comments_len] = 0;
   2334       }
   2335     }
   2336     else if ( !error )
   2337       error = FT_THROW( Invalid_File_Format );
   2338 
   2339     *font = p->font;
   2340 
   2341   Exit:
   2342     if ( p )
   2343     {
   2344       _bdf_list_done( &p->list );
   2345 
   2346       memory = extmemory;
   2347 
   2348       FT_FREE( p->glyph_name );
   2349       FT_FREE( p );
   2350     }
   2351 
   2352     return error;
   2353 
   2354   Fail:
   2355     bdf_free_font( p->font );
   2356 
   2357     memory = extmemory;
   2358 
   2359     FT_FREE( p->font );
   2360 
   2361     goto Exit;
   2362   }
   2363 
   2364 
   2365   FT_LOCAL_DEF( void )
   2366   bdf_free_font( bdf_font_t*  font )
   2367   {
   2368     bdf_property_t*  prop;
   2369     unsigned long    i;
   2370     bdf_glyph_t*     glyphs;
   2371     FT_Memory        memory;
   2372 
   2373 
   2374     if ( font == 0 )
   2375       return;
   2376 
   2377     memory = font->memory;
   2378 
   2379     FT_FREE( font->name );
   2380 
   2381     /* Free up the internal hash table of property names. */
   2382     if ( font->internal )
   2383     {
   2384       ft_hash_str_free( (FT_Hash)font->internal, memory );
   2385       FT_FREE( font->internal );
   2386     }
   2387 
   2388     /* Free up the comment info. */
   2389     FT_FREE( font->comments );
   2390 
   2391     /* Free up the properties. */
   2392     for ( i = 0; i < font->props_size; i++ )
   2393     {
   2394       if ( font->props[i].format == BDF_ATOM )
   2395         FT_FREE( font->props[i].value.atom );
   2396     }
   2397 
   2398     FT_FREE( font->props );
   2399 
   2400     /* Free up the character info. */
   2401     for ( i = 0, glyphs = font->glyphs;
   2402           i < font->glyphs_used; i++, glyphs++ )
   2403     {
   2404       FT_FREE( glyphs->name );
   2405       FT_FREE( glyphs->bitmap );
   2406     }
   2407 
   2408     for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
   2409           i++, glyphs++ )
   2410     {
   2411       FT_FREE( glyphs->name );
   2412       FT_FREE( glyphs->bitmap );
   2413     }
   2414 
   2415     FT_FREE( font->glyphs );
   2416     FT_FREE( font->unencoded );
   2417 
   2418     /* Free up the overflow storage if it was used. */
   2419     for ( i = 0, glyphs = font->overflow.glyphs;
   2420           i < font->overflow.glyphs_used; i++, glyphs++ )
   2421     {
   2422       FT_FREE( glyphs->name );
   2423       FT_FREE( glyphs->bitmap );
   2424     }
   2425 
   2426     FT_FREE( font->overflow.glyphs );
   2427 
   2428     /* bdf_cleanup */
   2429     ft_hash_str_free( &(font->proptbl), memory );
   2430 
   2431     /* Free up the user defined properties. */
   2432     for ( prop = font->user_props, i = 0;
   2433           i < font->nuser_props; i++, prop++ )
   2434     {
   2435       FT_FREE( prop->name );
   2436       if ( prop->format == BDF_ATOM )
   2437         FT_FREE( prop->value.atom );
   2438     }
   2439 
   2440     FT_FREE( font->user_props );
   2441 
   2442     /* FREE( font ); */ /* XXX Fixme */
   2443   }
   2444 
   2445 
   2446   FT_LOCAL_DEF( bdf_property_t * )
   2447   bdf_get_font_property( bdf_font_t*  font,
   2448                          const char*  name )
   2449   {
   2450     size_t*  propid;
   2451 
   2452 
   2453     if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
   2454       return 0;
   2455 
   2456     propid = ft_hash_str_lookup( name, (FT_Hash)font->internal );
   2457 
   2458     return propid ? ( font->props + *propid ) : 0;
   2459   }
   2460 
   2461 
   2462 /* END */
   2463