tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

bdflib.c (49632B)


      1 /*
      2 * Copyright 2000 Computing Research Labs, New Mexico State University
      3 * Copyright 2001-2014
      4 *   Francesco Zappa Nardelli
      5 *
      6 * Permission is hereby granted, free of charge, to any person obtaining a
      7 * copy of this software and associated documentation files (the "Software"),
      8 * to deal in the Software without restriction, including without limitation
      9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10 * and/or sell copies of the Software, and to permit persons to whom the
     11 * Software is furnished to do so, subject to the following conditions:
     12 *
     13 * The above copyright notice and this permission notice shall be included in
     14 * all copies or substantial portions of the Software.
     15 *
     16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
     20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
     21 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
     22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23 */
     24 
     25  /**************************************************************************
     26   *
     27   * This file is based on bdf.c,v 1.22 2000/03/16 20:08:50
     28   *
     29   * taken from Mark Leisher's xmbdfed package
     30   *
     31   */
     32 
     33 
     34 
     35 #include <freetype/freetype.h>
     36 #include <freetype/internal/ftdebug.h>
     37 #include <freetype/internal/ftstream.h>
     38 #include <freetype/internal/ftobjs.h>
     39 
     40 #include "bdf.h"
     41 #include "bdferror.h"
     42 
     43 
     44  /**************************************************************************
     45   *
     46   * The macro FT_COMPONENT is used in trace mode.  It is an implicit
     47   * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
     48   * messages during execution.
     49   */
     50 #undef  FT_COMPONENT
     51 #define FT_COMPONENT  bdflib
     52 
     53 
     54  /**************************************************************************
     55   *
     56   * Builtin BDF font properties.
     57   *
     58   */
     59 
     60  /* List of most properties that might appear in a font.  Doesn't include */
     61  /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts.           */
     62 
     63  static const bdf_property_t  bdf_properties_[] =
     64  {
     65    { "ADD_STYLE_NAME",          BDF_ATOM,     1, { 0 } },
     66    { "AVERAGE_WIDTH",           BDF_INTEGER,  1, { 0 } },
     67    { "AVG_CAPITAL_WIDTH",       BDF_INTEGER,  1, { 0 } },
     68    { "AVG_LOWERCASE_WIDTH",     BDF_INTEGER,  1, { 0 } },
     69    { "CAP_HEIGHT",              BDF_INTEGER,  1, { 0 } },
     70    { "CHARSET_COLLECTIONS",     BDF_ATOM,     1, { 0 } },
     71    { "CHARSET_ENCODING",        BDF_ATOM,     1, { 0 } },
     72    { "CHARSET_REGISTRY",        BDF_ATOM,     1, { 0 } },
     73    { "COPYRIGHT",               BDF_ATOM,     1, { 0 } },
     74    { "DEFAULT_CHAR",            BDF_CARDINAL, 1, { 0 } },
     75    { "DESTINATION",             BDF_CARDINAL, 1, { 0 } },
     76    { "DEVICE_FONT_NAME",        BDF_ATOM,     1, { 0 } },
     77    { "END_SPACE",               BDF_INTEGER,  1, { 0 } },
     78    { "FACE_NAME",               BDF_ATOM,     1, { 0 } },
     79    { "FAMILY_NAME",             BDF_ATOM,     1, { 0 } },
     80    { "FIGURE_WIDTH",            BDF_INTEGER,  1, { 0 } },
     81    { "FONT",                    BDF_ATOM,     1, { 0 } },
     82    { "FONTNAME_REGISTRY",       BDF_ATOM,     1, { 0 } },
     83    { "FONT_ASCENT",             BDF_INTEGER,  1, { 0 } },
     84    { "FONT_DESCENT",            BDF_INTEGER,  1, { 0 } },
     85    { "FOUNDRY",                 BDF_ATOM,     1, { 0 } },
     86    { "FULL_NAME",               BDF_ATOM,     1, { 0 } },
     87    { "ITALIC_ANGLE",            BDF_INTEGER,  1, { 0 } },
     88    { "MAX_SPACE",               BDF_INTEGER,  1, { 0 } },
     89    { "MIN_SPACE",               BDF_INTEGER,  1, { 0 } },
     90    { "NORM_SPACE",              BDF_INTEGER,  1, { 0 } },
     91    { "NOTICE",                  BDF_ATOM,     1, { 0 } },
     92    { "PIXEL_SIZE",              BDF_INTEGER,  1, { 0 } },
     93    { "POINT_SIZE",              BDF_INTEGER,  1, { 0 } },
     94    { "QUAD_WIDTH",              BDF_INTEGER,  1, { 0 } },
     95    { "RAW_ASCENT",              BDF_INTEGER,  1, { 0 } },
     96    { "RAW_AVERAGE_WIDTH",       BDF_INTEGER,  1, { 0 } },
     97    { "RAW_AVG_CAPITAL_WIDTH",   BDF_INTEGER,  1, { 0 } },
     98    { "RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER,  1, { 0 } },
     99    { "RAW_CAP_HEIGHT",          BDF_INTEGER,  1, { 0 } },
    100    { "RAW_DESCENT",             BDF_INTEGER,  1, { 0 } },
    101    { "RAW_END_SPACE",           BDF_INTEGER,  1, { 0 } },
    102    { "RAW_FIGURE_WIDTH",        BDF_INTEGER,  1, { 0 } },
    103    { "RAW_MAX_SPACE",           BDF_INTEGER,  1, { 0 } },
    104    { "RAW_MIN_SPACE",           BDF_INTEGER,  1, { 0 } },
    105    { "RAW_NORM_SPACE",          BDF_INTEGER,  1, { 0 } },
    106    { "RAW_PIXEL_SIZE",          BDF_INTEGER,  1, { 0 } },
    107    { "RAW_POINT_SIZE",          BDF_INTEGER,  1, { 0 } },
    108    { "RAW_PIXELSIZE",           BDF_INTEGER,  1, { 0 } },
    109    { "RAW_POINTSIZE",           BDF_INTEGER,  1, { 0 } },
    110    { "RAW_QUAD_WIDTH",          BDF_INTEGER,  1, { 0 } },
    111    { "RAW_SMALL_CAP_SIZE",      BDF_INTEGER,  1, { 0 } },
    112    { "RAW_STRIKEOUT_ASCENT",    BDF_INTEGER,  1, { 0 } },
    113    { "RAW_STRIKEOUT_DESCENT",   BDF_INTEGER,  1, { 0 } },
    114    { "RAW_SUBSCRIPT_SIZE",      BDF_INTEGER,  1, { 0 } },
    115    { "RAW_SUBSCRIPT_X",         BDF_INTEGER,  1, { 0 } },
    116    { "RAW_SUBSCRIPT_Y",         BDF_INTEGER,  1, { 0 } },
    117    { "RAW_SUPERSCRIPT_SIZE",    BDF_INTEGER,  1, { 0 } },
    118    { "RAW_SUPERSCRIPT_X",       BDF_INTEGER,  1, { 0 } },
    119    { "RAW_SUPERSCRIPT_Y",       BDF_INTEGER,  1, { 0 } },
    120    { "RAW_UNDERLINE_POSITION",  BDF_INTEGER,  1, { 0 } },
    121    { "RAW_UNDERLINE_THICKNESS", BDF_INTEGER,  1, { 0 } },
    122    { "RAW_X_HEIGHT",            BDF_INTEGER,  1, { 0 } },
    123    { "RELATIVE_SETWIDTH",       BDF_CARDINAL, 1, { 0 } },
    124    { "RELATIVE_WEIGHT",         BDF_CARDINAL, 1, { 0 } },
    125    { "RESOLUTION",              BDF_INTEGER,  1, { 0 } },
    126    { "RESOLUTION_X",            BDF_CARDINAL, 1, { 0 } },
    127    { "RESOLUTION_Y",            BDF_CARDINAL, 1, { 0 } },
    128    { "SETWIDTH_NAME",           BDF_ATOM,     1, { 0 } },
    129    { "SLANT",                   BDF_ATOM,     1, { 0 } },
    130    { "SMALL_CAP_SIZE",          BDF_INTEGER,  1, { 0 } },
    131    { "SPACING",                 BDF_ATOM,     1, { 0 } },
    132    { "STRIKEOUT_ASCENT",        BDF_INTEGER,  1, { 0 } },
    133    { "STRIKEOUT_DESCENT",       BDF_INTEGER,  1, { 0 } },
    134    { "SUBSCRIPT_SIZE",          BDF_INTEGER,  1, { 0 } },
    135    { "SUBSCRIPT_X",             BDF_INTEGER,  1, { 0 } },
    136    { "SUBSCRIPT_Y",             BDF_INTEGER,  1, { 0 } },
    137    { "SUPERSCRIPT_SIZE",        BDF_INTEGER,  1, { 0 } },
    138    { "SUPERSCRIPT_X",           BDF_INTEGER,  1, { 0 } },
    139    { "SUPERSCRIPT_Y",           BDF_INTEGER,  1, { 0 } },
    140    { "UNDERLINE_POSITION",      BDF_INTEGER,  1, { 0 } },
    141    { "UNDERLINE_THICKNESS",     BDF_INTEGER,  1, { 0 } },
    142    { "WEIGHT",                  BDF_CARDINAL, 1, { 0 } },
    143    { "WEIGHT_NAME",             BDF_ATOM,     1, { 0 } },
    144    { "X_HEIGHT",                BDF_INTEGER,  1, { 0 } },
    145    { "_MULE_BASELINE_OFFSET",   BDF_INTEGER,  1, { 0 } },
    146    { "_MULE_RELATIVE_COMPOSE",  BDF_INTEGER,  1, { 0 } },
    147  };
    148 
    149  static const unsigned long
    150  num_bdf_properties_ = sizeof ( bdf_properties_ ) /
    151                        sizeof ( bdf_properties_[0] );
    152 
    153  /* Auto correction messages. */
    154 #define ACMSG1   "FONT_ASCENT property missing.  " \
    155                 "Added `FONT_ASCENT %hd'.\n"
    156 #define ACMSG2   "FONT_DESCENT property missing.  " \
    157                 "Added `FONT_DESCENT %hd'.\n"
    158 #define ACMSG3   "Font width != actual width.  Old: %d New: %d.\n"
    159 #define ACMSG4   "Font left bearing != actual left bearing.  " \
    160                 "Old: %hd New: %hd.\n"
    161 #define ACMSG5   "Font ascent != actual ascent.  Old: %hd New: %hd.\n"
    162 #define ACMSG6   "Font descent != actual descent.  Old: %d New: %d.\n"
    163 #define ACMSG7   "Font height != actual height. Old: %d New: %d.\n"
    164 #define ACMSG8   "Glyph scalable width (SWIDTH) adjustments made.\n"
    165 #define ACMSG9   "SWIDTH field missing at line %lu.  Set automatically.\n"
    166 #define ACMSG10  "DWIDTH field missing at line %lu.  Set to glyph width.\n"
    167 #define ACMSG11  "SIZE bits per pixel field adjusted to %hd.\n"
    168 #define ACMSG13  "Glyph %lu extra rows removed.\n"
    169 #define ACMSG14  "Glyph %lu extra columns removed.\n"
    170 #define ACMSG15  "Incorrect glyph count: %lu indicated but %lu found.\n"
    171 #define ACMSG16  "Glyph %lu missing columns padded with zero bits.\n"
    172 #define ACMSG17  "Adjusting number of glyphs to %lu.\n"
    173 
    174  /* Error messages. */
    175 #define ERRMSG1  "[line %lu] Missing `%s' line.\n"
    176 #define ERRMSG2  "[line %lu] Font header corrupted or missing fields.\n"
    177 #define ERRMSG3  "[line %lu] Font glyphs corrupted or missing fields.\n"
    178 #define ERRMSG4  "[line %lu] BBX too big.\n"
    179 #define ERRMSG5  "[line %lu] `%s' value too big.\n"
    180 #define ERRMSG6  "[line %lu] Input line too long.\n"
    181 #define ERRMSG7  "[line %lu] Font name too long.\n"
    182 #define ERRMSG8  "[line %lu] Invalid `%s' value.\n"
    183 #define ERRMSG9  "[line %lu] Invalid keyword.\n"
    184 
    185  /* Debug messages. */
    186 #define DBGMSG1  "  [%6lu] %s" /* no \n */
    187 #define DBGMSG2  " (0x%lX)\n"
    188 
    189 
    190  /**************************************************************************
    191   *
    192   * Utility types and functions.
    193   *
    194   */
    195 
    196 
    197  /* Structure used while loading BDF fonts. */
    198 
    199  typedef struct  bdf_parse_t__
    200  {
    201    unsigned long   flags;
    202    unsigned long   cnt;
    203    unsigned long   row;
    204 
    205    short           minlb;
    206    short           maxlb;
    207    short           maxrb;
    208    short           maxas;
    209    short           maxds;
    210 
    211    short           rbearing;
    212 
    213    char*           glyph_name;
    214    long            glyph_enc;
    215 
    216    bdf_glyph_t*    glyph;
    217    bdf_font_t*     font;
    218 
    219    FT_Memory       memory;
    220    unsigned long   size;        /* the stream size */
    221 
    222  } bdf_parse_t_;
    223 
    224 
    225  /* Function type for parsing lines of a BDF font. */
    226 
    227  typedef FT_Error
    228  (*bdf_line_func_t_)( char*          line,
    229                       unsigned long  linelen,
    230                       unsigned long  lineno,
    231                       bdf_parse_t_*  p,
    232                       void*          next );
    233 
    234 
    235 #define setsbit( m, cc ) \
    236          ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
    237 #define sbitset( m, cc ) \
    238          ( m[(FT_Byte)(cc) >> 3]  & ( 1 << ( (cc) & 7 ) ) )
    239 
    240 
    241  static char*
    242  bdf_strtok_( char*  line,
    243               int    delim )
    244  {
    245    while ( *line && *line != delim )
    246      line++;
    247 
    248    if ( *line )
    249      *line++ = '\0';
    250 
    251    while ( *line && *line == delim )
    252      line++;
    253 
    254    return line;
    255  }
    256 
    257 
    258  /* XXX: make this work with EBCDIC also */
    259 
    260  static const unsigned char  a2i[128] =
    261  {
    262    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    263    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    264    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    265    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    266    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    267    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    268    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    269    0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    270    0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
    271    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    272    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    273    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    274    0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
    275    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    276    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    277    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    278  };
    279 
    280  static const unsigned char  ddigits[32] =
    281  {
    282    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
    283    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    284    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    285    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    286  };
    287 
    288 
    289  /* Routine to convert a decimal ASCII string to an unsigned long integer. */
    290  static unsigned long
    291  bdf_atoul_( const char*  s )
    292  {
    293    unsigned long  v;
    294 
    295 
    296    for ( v = 0; sbitset( ddigits, *s ); s++ )
    297    {
    298      if ( v < ( FT_ULONG_MAX - 9 ) / 10 )
    299        v = v * 10 + a2i[(int)*s];
    300      else
    301      {
    302        v = FT_ULONG_MAX;
    303        break;
    304      }
    305    }
    306 
    307    return v;
    308  }
    309 
    310 
    311  /* Routine to convert a decimal ASCII string to a signed long integer. */
    312  static long
    313  bdf_atol_( const char*  s )
    314  {
    315    long  v, neg;
    316 
    317 
    318    /* Check for a minus sign. */
    319    if ( *s == '-' )
    320    {
    321      s++;
    322      neg = -1;
    323    }
    324    else
    325      neg =  1;
    326 
    327    for ( v = 0; sbitset( ddigits, *s ); s++ )
    328    {
    329      if ( v < ( FT_LONG_MAX - 9 ) / 10 )
    330        v = v * 10 + a2i[(int)*s];
    331      else
    332      {
    333        v = FT_LONG_MAX;
    334        break;
    335      }
    336    }
    337 
    338    return neg * v;
    339  }
    340 
    341 
    342  /* Routine to convert a decimal ASCII string to an unsigned short integer. */
    343  static unsigned short
    344  bdf_atous_( const char*  s )
    345  {
    346    unsigned short  v;
    347 
    348 
    349    for ( v = 0; sbitset( ddigits, *s ); s++ )
    350    {
    351      if ( v < ( FT_USHORT_MAX - 9 ) / 10 )
    352        v = (unsigned short)( v * 10 + a2i[(int)*s] );
    353      else
    354      {
    355        v = FT_USHORT_MAX;
    356        break;
    357      }
    358    }
    359 
    360    return v;
    361  }
    362 
    363 
    364  /* Routine to convert a decimal ASCII string to a signed short integer. */
    365  static short
    366  bdf_atos_( const char*  s )
    367  {
    368    short  v, neg;
    369 
    370 
    371    /* Check for a minus. */
    372    if ( *s == '-' )
    373    {
    374      s++;
    375      neg = -1;
    376    }
    377    else
    378      neg =  1;
    379 
    380    for ( v = 0; sbitset( ddigits, *s ); s++ )
    381    {
    382      if ( v < ( SHRT_MAX - 9 ) / 10 )
    383        v = (short)( v * 10 + a2i[(int)*s] );
    384      else
    385      {
    386        v = SHRT_MAX;
    387        break;
    388      }
    389    }
    390 
    391    return neg * v;
    392  }
    393 
    394 
    395  /* Routine to compare two glyphs by encoding so they can be sorted. */
    396  FT_COMPARE_DEF( int )
    397  by_encoding( const void*  a,
    398               const void*  b )
    399  {
    400    bdf_glyph_t  *c1, *c2;
    401 
    402 
    403    c1 = (bdf_glyph_t *)a;
    404    c2 = (bdf_glyph_t *)b;
    405 
    406    if ( c1->encoding < c2->encoding )
    407      return -1;
    408 
    409    if ( c1->encoding > c2->encoding )
    410      return 1;
    411 
    412    return 0;
    413  }
    414 
    415 
    416  static FT_Error
    417  bdf_create_property( const char*  name,
    418                       int          format,
    419                       bdf_font_t*  font )
    420  {
    421    size_t           n;
    422    bdf_property_t*  p;
    423    FT_Memory        memory = font->memory;
    424    FT_Error         error  = FT_Err_Ok;
    425 
    426 
    427    /* First check whether the property has        */
    428    /* already been added or not.  If it has, then */
    429    /* simply ignore it.                           */
    430    if ( ft_hash_str_lookup( name, &(font->proptbl) ) )
    431      goto Exit;
    432 
    433    if ( FT_QRENEW_ARRAY( font->user_props,
    434                          font->nuser_props,
    435                          font->nuser_props + 1 ) )
    436      goto Exit;
    437 
    438    p = font->user_props + font->nuser_props;
    439 
    440    if ( FT_STRDUP( p->name, name ) )
    441      goto Exit;
    442 
    443    p->format     = format;
    444    p->builtin    = 0;
    445    p->value.atom = NULL;  /* nothing is ever stored here */
    446 
    447    n = num_bdf_properties_ + font->nuser_props;
    448 
    449    error = ft_hash_str_insert( p->name, n, &(font->proptbl), memory );
    450    if ( error )
    451      goto Exit;
    452 
    453    font->nuser_props++;
    454 
    455  Exit:
    456    return error;
    457  }
    458 
    459 
    460  static bdf_property_t*
    461  bdf_get_property( const char*  name,
    462                    bdf_font_t*  font )
    463  {
    464    size_t*  propid;
    465 
    466 
    467    if ( name == NULL || *name == 0 )
    468      return NULL;
    469 
    470    if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL )
    471      return NULL;
    472 
    473    if ( *propid >= num_bdf_properties_ )
    474      return font->user_props + ( *propid - num_bdf_properties_ );
    475 
    476    return (bdf_property_t*)bdf_properties_ + *propid;
    477  }
    478 
    479 
    480  /**************************************************************************
    481   *
    482   * BDF font file parsing flags and functions.
    483   *
    484   */
    485 
    486 
    487  /* Parse flags. */
    488 
    489 #define BDF_START_      0x0001U
    490 #define BDF_FONT_NAME_  0x0002U
    491 #define BDF_SIZE_       0x0004U
    492 #define BDF_FONT_BBX_   0x0008U
    493 #define BDF_PROPS_      0x0010U
    494 #define BDF_GLYPHS_     0x0020U
    495 #define BDF_GLYPH_      0x0040U
    496 #define BDF_ENCODING_   0x0080U
    497 #define BDF_SWIDTH_     0x0100U
    498 #define BDF_DWIDTH_     0x0200U
    499 #define BDF_BBX_        0x0400U
    500 #define BDF_BITMAP_     0x0800U
    501 
    502 #define BDF_GLYPH_BITS_ ( BDF_GLYPH_    | \
    503                          BDF_ENCODING_ | \
    504                          BDF_SWIDTH_   | \
    505                          BDF_DWIDTH_   | \
    506                          BDF_BBX_      | \
    507                          BDF_BITMAP_   )
    508 
    509 
    510  static FT_Error
    511  bdf_add_comment_( bdf_font_t*    font,
    512                    const char*    comment,
    513                    unsigned long  len )
    514  {
    515    char*      cp;
    516    FT_Memory  memory = font->memory;
    517    FT_Error   error  = FT_Err_Ok;
    518 
    519 
    520    /* Skip keyword COMMENT. */
    521    comment += 7;
    522    len     -= 7;
    523 
    524    if ( len == 0 )
    525      goto Exit;
    526 
    527    if ( FT_QRENEW_ARRAY( font->comments,
    528                          font->comments_len,
    529                          font->comments_len + len + 1 ) )
    530      goto Exit;
    531 
    532    cp = font->comments + font->comments_len;
    533 
    534    FT_MEM_COPY( cp, comment, len );
    535    cp[len] = '\0';
    536 
    537    font->comments_len += len + 1;
    538 
    539  Exit:
    540    return error;
    541  }
    542 
    543 
    544  /* Determine whether the property is an atom or not.  If it is, then */
    545  /* clean it up so the double quotes are removed if they exist.       */
    546  static int
    547  bdf_is_atom_( char*          line,
    548                unsigned long  linelen,
    549                char**         name,
    550                char**         value,
    551                bdf_font_t*    font )
    552  {
    553    int              hold;
    554    char             *sp, *ep;
    555    bdf_property_t*  p;
    556 
    557 
    558    sp = ep = line;
    559 
    560    while ( *ep && *ep != ' ' )
    561      ep++;
    562 
    563    hold = *ep;
    564    *ep  = '\0';
    565 
    566    p = bdf_get_property( sp, font );
    567 
    568    /* If the property exists and is not an atom, just return here. */
    569    if ( p && p->format != BDF_ATOM )
    570    {
    571      *ep = (char)hold;  /* Undo NUL-termination. */
    572      return 0;
    573    }
    574 
    575    *name = sp;
    576 
    577    /* The property is an atom.  Trim all leading and trailing whitespace */
    578    /* and double quotes for the atom value.                              */
    579    sp = ep;
    580    ep = line + linelen;
    581 
    582    /* Trim the leading whitespace if it exists. */
    583    if ( sp < ep )
    584      do
    585         sp++;
    586      while ( *sp == ' ' );
    587 
    588    /* Trim the leading double quote if it exists. */
    589    if ( *sp == '"' )
    590      sp++;
    591 
    592    *value = sp;
    593 
    594    /* Trim the trailing whitespace if it exists. */
    595    if ( sp < ep )
    596      do
    597        *ep-- = '\0';
    598      while ( *ep == ' ' );
    599 
    600    /* Trim the trailing double quote if it exists. */
    601    if ( *ep  == '"' )
    602      *ep = '\0';
    603 
    604    return 1;
    605  }
    606 
    607 
    608  static FT_Error
    609  bdf_add_property_( bdf_font_t*    font,
    610                     const char*    name,
    611                     char*          value,
    612                     unsigned long  lineno )
    613  {
    614    size_t*         propid;
    615    bdf_property_t  *prop, *fp;
    616    FT_Memory       memory = font->memory;
    617    FT_Error        error  = FT_Err_Ok;
    618 
    619    FT_UNUSED( lineno );        /* only used in debug mode */
    620 
    621 
    622    /* First, check whether the property already exists in the font. */
    623    if ( ( propid = ft_hash_str_lookup( name, font->internal ) ) != NULL )
    624    {
    625      /* The property already exists in the font, so simply replace */
    626      /* the value of the property with the current value.          */
    627      fp = font->props + *propid;
    628 
    629      switch ( fp->format )
    630      {
    631      case BDF_ATOM:
    632        /* Delete the current atom if it exists. */
    633        FT_FREE( fp->value.atom );
    634 
    635        if ( value && value[0] != 0 )
    636        {
    637          if ( FT_STRDUP( fp->value.atom, value ) )
    638            goto Exit;
    639        }
    640        break;
    641 
    642      case BDF_INTEGER:
    643        fp->value.l = bdf_atol_( value );
    644        break;
    645 
    646      case BDF_CARDINAL:
    647        fp->value.ul = bdf_atoul_( value );
    648        break;
    649 
    650      default:
    651        ;
    652      }
    653 
    654      goto Exit;
    655    }
    656 
    657    /* See whether this property type exists yet or not. */
    658    /* If not, create it.                                */
    659    propid = ft_hash_str_lookup( name, &(font->proptbl) );
    660    if ( !propid )
    661    {
    662      error = bdf_create_property( name, BDF_ATOM, font );
    663      if ( error )
    664        goto Exit;
    665      propid = ft_hash_str_lookup( name, &(font->proptbl) );
    666    }
    667 
    668    /* Allocate another property if this is overflowing. */
    669    if ( font->props_used == font->props_size )
    670    {
    671      if ( FT_QRENEW_ARRAY( font->props,
    672                            font->props_size,
    673                            font->props_size + 1 ) )
    674        goto Exit;
    675 
    676      font->props_size++;
    677    }
    678 
    679    if ( *propid >= num_bdf_properties_ )
    680      prop = font->user_props + ( *propid - num_bdf_properties_ );
    681    else
    682      prop = (bdf_property_t*)bdf_properties_ + *propid;
    683 
    684    fp = font->props + font->props_used;
    685 
    686    fp->name    = prop->name;
    687    fp->format  = prop->format;
    688    fp->builtin = prop->builtin;
    689 
    690    switch ( prop->format )
    691    {
    692    case BDF_ATOM:
    693      fp->value.atom = NULL;
    694      if ( value && value[0] )
    695      {
    696        if ( FT_STRDUP( fp->value.atom, value ) )
    697          goto Exit;
    698      }
    699      break;
    700 
    701    case BDF_INTEGER:
    702      fp->value.l = bdf_atol_( value );
    703      break;
    704 
    705    case BDF_CARDINAL:
    706      fp->value.ul = bdf_atoul_( value );
    707      break;
    708    }
    709 
    710    /* Add the property to the font property table. */
    711    error = ft_hash_str_insert( fp->name,
    712                                font->props_used,
    713                                font->internal,
    714                                memory );
    715    if ( error )
    716      goto Exit;
    717 
    718    font->props_used++;
    719 
    720  Exit:
    721    return error;
    722  }
    723 
    724 
    725  static FT_Error
    726  bdf_parse_end_( char*          line,
    727                  unsigned long  linelen,
    728                  unsigned long  lineno,
    729                  bdf_parse_t_*  p,
    730                  void*          next )
    731  {
    732    /* a no-op; we ignore everything after `ENDFONT' */
    733 
    734    FT_UNUSED( line );
    735    FT_UNUSED( linelen );
    736    FT_UNUSED( lineno );
    737    FT_UNUSED( p );
    738    FT_UNUSED( next );
    739 
    740    return FT_Err_Ok;
    741  }
    742 
    743 
    744  /* Line function prototypes. */
    745  static FT_Error
    746  bdf_parse_start_( char*          line,
    747                    unsigned long  linelen,
    748                    unsigned long  lineno,
    749                    bdf_parse_t_*  p,
    750                    void*          next );
    751 
    752 
    753  static FT_Error
    754  bdf_parse_glyphs_( char*          line,
    755                     unsigned long  linelen,
    756                     unsigned long  lineno,
    757                     bdf_parse_t_*  p,
    758                     void*          next );
    759 
    760 
    761  /* Aggressively parse the glyph bitmaps. */
    762  static FT_Error
    763  bdf_parse_bitmap_( char*          line,
    764                     unsigned long  linelen,
    765                     unsigned long  lineno,
    766                     bdf_parse_t_*  p,
    767                     void*          next )
    768  {
    769    bdf_glyph_t*    glyph = p->glyph;
    770    unsigned char*  bp;
    771    unsigned long   i, nibbles;
    772    int             x;
    773 
    774    FT_UNUSED( lineno );        /* only used in debug mode */
    775 
    776 
    777    nibbles = glyph->bpr << 1;
    778    bp      = glyph->bitmap + p->row * glyph->bpr;
    779 
    780    if ( nibbles > linelen )
    781    {
    782      FT_TRACE2(( "bdf_parse_bitmap_: " ACMSG16, glyph->encoding ));
    783      nibbles = linelen;
    784    }
    785 
    786    for ( i = 0; i < nibbles; i++ )
    787    {
    788      /* char to hex without checks */
    789      x  = line[i];
    790      x += 9 * ( x & 0x40 ) >> 6;  /* for [A-Fa-f] */
    791      x &= 0x0F;
    792 
    793      if ( i & 1 )
    794        *bp++ |= x;
    795      else
    796        *bp = (unsigned char)( x << 4 );
    797    }
    798 
    799    p->row++;
    800 
    801    /* When done, go back to parsing glyphs */
    802    if ( p->row >= (unsigned long)glyph->bbx.height )
    803      *(bdf_line_func_t_*)next = bdf_parse_glyphs_;
    804 
    805    return FT_Err_Ok;
    806  }
    807 
    808 
    809  /* Actually parse the glyph info. */
    810  static FT_Error
    811  bdf_parse_glyphs_( char*          line,
    812                     unsigned long  linelen,
    813                     unsigned long  lineno,
    814                     bdf_parse_t_*  p,
    815                     void*          next )
    816  {
    817    bdf_font_t*   font   = p->font;
    818    bdf_glyph_t*  glyph;
    819    FT_Memory     memory = font->memory;
    820    FT_Error      error  = FT_Err_Ok;
    821 
    822    FT_UNUSED( lineno );        /* only used in debug mode */
    823 
    824 
    825    /* Check for a comment. */
    826    if ( ft_strncmp( line, "COMMENT", 7 ) == 0 )
    827    {
    828      if ( p->flags & BDF_KEEP_COMMENTS )
    829        error = bdf_add_comment_( font, line, linelen );
    830 
    831      goto Exit;
    832    }
    833 
    834    /* Check for the ENDFONT field. */
    835    if ( ft_strncmp( line, "ENDFONT", 7 ) == 0 )
    836    {
    837      if ( p->flags & BDF_GLYPH_BITS_ )
    838      {
    839        /* Missing ENDCHAR field. */
    840        FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" ));
    841        error = FT_THROW( Corrupted_Font_Glyphs );
    842        goto Exit;
    843      }
    844 
    845      /* Sort the glyphs by encoding. */
    846      ft_qsort( (char *)font->glyphs,
    847                font->glyphs_used,
    848                sizeof ( bdf_glyph_t ),
    849                by_encoding );
    850 
    851      p->flags &= ~BDF_START_;
    852 
    853      *(bdf_line_func_t_*)next = bdf_parse_end_;
    854 
    855      goto Exit;
    856    }
    857 
    858    /* Check for the ENDCHAR field. */
    859    if ( ft_strncmp( line, "ENDCHAR", 7 ) == 0 )
    860    {
    861      /* Free unused glyph_name */
    862      FT_FREE( p->glyph_name );
    863 
    864      p->glyph_enc = 0;
    865      p->flags    &= ~BDF_GLYPH_BITS_;
    866 
    867      goto Exit;
    868    }
    869 
    870    /* Check whether a glyph is being scanned but should be */
    871    /* ignored because it is an unencoded glyph.            */
    872    if ( p->flags & BDF_GLYPH_              &&
    873         p->glyph_enc            == -1      &&
    874         !( p->flags & BDF_KEEP_UNENCODED ) )
    875      goto Exit;
    876 
    877    /* Check for the STARTCHAR field. */
    878    if ( ft_strncmp( line, "STARTCHAR ", 10 ) == 0 )
    879    {
    880      if ( p->flags & BDF_GLYPH_BITS_ )
    881      {
    882        /* Missing ENDCHAR field. */
    883        FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" ));
    884        error = FT_THROW( Missing_Startchar_Field );
    885        goto Exit;
    886      }
    887 
    888      line = bdf_strtok_( line, ' ' );
    889 
    890      if ( FT_STRDUP( p->glyph_name, line ) )
    891        goto Exit;
    892 
    893      p->flags |= BDF_GLYPH_;
    894 
    895      FT_TRACE4(( DBGMSG1, lineno, line ));
    896 
    897      goto Exit;
    898    }
    899 
    900    /* Check for the ENCODING field. */
    901    if ( ft_strncmp( line, "ENCODING ", 9 ) == 0 )
    902    {
    903      if ( !( p->flags & BDF_GLYPH_ ) )
    904      {
    905        /* Missing STARTCHAR field. */
    906        FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "STARTCHAR" ));
    907        error = FT_THROW( Missing_Startchar_Field );
    908        goto Exit;
    909      }
    910 
    911      line = bdf_strtok_( line, ' ' );
    912 
    913      p->glyph_enc = bdf_atol_( line );
    914 
    915      /* Normalize negative encoding values.  The specification only */
    916      /* allows -1, but we can be more generous here.                */
    917      if ( p->glyph_enc < -1 )
    918        p->glyph_enc = -1;
    919 
    920      /* Check for alternative encoding format. */
    921      line = bdf_strtok_( line, ' ' );
    922 
    923      if ( p->glyph_enc == -1 && *line )
    924        p->glyph_enc = bdf_atol_( line );
    925 
    926      if ( p->glyph_enc < -1 || p->glyph_enc >= 0x110000L )
    927        p->glyph_enc = -1;
    928 
    929      FT_TRACE4(( DBGMSG2, p->glyph_enc ));
    930 
    931      if ( p->glyph_enc >= 0 )
    932      {
    933        /* Make sure there are enough glyphs allocated in case the */
    934        /* number of characters happen to be wrong.                */
    935        if ( font->glyphs_used == font->glyphs_size )
    936        {
    937          if ( FT_RENEW_ARRAY( font->glyphs,
    938                               font->glyphs_size,
    939                               font->glyphs_size + 64 ) )
    940            goto Exit;
    941 
    942          font->glyphs_size += 64;
    943        }
    944 
    945        glyph           = font->glyphs + font->glyphs_used++;
    946        glyph->name     = p->glyph_name;
    947        glyph->encoding = (unsigned long)p->glyph_enc;
    948      }
    949      else if ( p->flags & BDF_KEEP_UNENCODED )
    950      {
    951        /* Allocate the next unencoded glyph. */
    952        if ( font->unencoded_used == font->unencoded_size )
    953        {
    954          if ( FT_RENEW_ARRAY( font->unencoded ,
    955                               font->unencoded_size,
    956                               font->unencoded_size + 4 ) )
    957            goto Exit;
    958 
    959          font->unencoded_size += 4;
    960        }
    961 
    962        glyph           = font->unencoded + font->unencoded_used;
    963        glyph->name     = p->glyph_name;
    964        glyph->encoding = font->unencoded_used++;
    965      }
    966      else
    967      {
    968        /* Free up the glyph name if the unencoded shouldn't be */
    969        /* kept.                                                */
    970        FT_FREE( p->glyph_name );
    971        glyph = NULL;
    972      }
    973 
    974      p->glyph_name = NULL;
    975      p->glyph      = glyph;
    976      p->flags     |= BDF_ENCODING_;
    977 
    978      goto Exit;
    979    }
    980 
    981    if ( !( p->flags & BDF_ENCODING_ ) )
    982      goto Missing_Encoding;
    983 
    984    /* Point at the glyph being constructed. */
    985    glyph = p->glyph;
    986 
    987    /* Expect the SWIDTH (scalable width) field next. */
    988    if ( ft_strncmp( line, "SWIDTH ", 7 ) == 0 )
    989    {
    990      line          = bdf_strtok_( line, ' ' );
    991      glyph->swidth = bdf_atous_( line );
    992 
    993      p->flags |= BDF_SWIDTH_;
    994      goto Exit;
    995    }
    996 
    997    /* Expect the DWIDTH (device width) field next. */
    998    if ( ft_strncmp( line, "DWIDTH ", 7 ) == 0 )
    999    {
   1000      line          = bdf_strtok_( line, ' ' );
   1001      glyph->dwidth = bdf_atous_( line );
   1002 
   1003      if ( !( p->flags & BDF_SWIDTH_ ) )
   1004      {
   1005        /* Missing SWIDTH field.  Emit an auto correction message and set */
   1006        /* the scalable width from the device width.                      */
   1007        FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG9, lineno ));
   1008 
   1009        glyph->swidth = (unsigned short)FT_MulDiv(
   1010                          glyph->dwidth, 72000L,
   1011                          (FT_Long)( font->point_size *
   1012                                     font->resolution_x ) );
   1013      }
   1014 
   1015      p->flags |= BDF_DWIDTH_;
   1016      goto Exit;
   1017    }
   1018 
   1019    /* Do not leak the bitmap or reset its size */
   1020    if ( p->flags & BDF_BITMAP_ )
   1021      goto Exit;
   1022 
   1023    /* Expect the BBX field next. */
   1024    if ( ft_strncmp( line, "BBX ", 4 ) == 0 )
   1025    {
   1026      line                = bdf_strtok_( line, ' ' );
   1027      glyph->bbx.width    = bdf_atous_( line );
   1028      line                = bdf_strtok_( line, ' ' );
   1029      glyph->bbx.height   = bdf_atous_( line );
   1030      line                = bdf_strtok_( line, ' ' );
   1031      glyph->bbx.x_offset = bdf_atos_( line );
   1032      line                = bdf_strtok_( line, ' ' );
   1033      glyph->bbx.y_offset = bdf_atos_( line );
   1034 
   1035      /* Generate the ascent and descent of the character. */
   1036      glyph->bbx.ascent  = (short)( glyph->bbx.height + glyph->bbx.y_offset );
   1037      glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
   1038 
   1039      /* Determine the overall font bounding box as the characters are */
   1040      /* loaded so corrections can be done later if indicated.         */
   1041      p->maxas    = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
   1042      p->maxds    = (short)FT_MAX( glyph->bbx.descent, p->maxds );
   1043 
   1044      p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
   1045 
   1046      p->maxrb    = (short)FT_MAX( p->rbearing, p->maxrb );
   1047      p->minlb    = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
   1048      p->maxlb    = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
   1049 
   1050      if ( !( p->flags & BDF_DWIDTH_ ) )
   1051      {
   1052        /* Missing DWIDTH field.  Emit an auto correction message and set */
   1053        /* the device width to the glyph width.                           */
   1054        FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG10, lineno ));
   1055        glyph->dwidth = glyph->bbx.width;
   1056      }
   1057 
   1058      /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
   1059      /* value if necessary.                                            */
   1060      if ( p->flags & BDF_CORRECT_METRICS )
   1061      {
   1062        /* Determine the point size of the glyph. */
   1063        unsigned short  sw = (unsigned short)FT_MulDiv(
   1064                               glyph->dwidth, 72000L,
   1065                               (FT_Long)( font->point_size *
   1066                                          font->resolution_x ) );
   1067 
   1068 
   1069        if ( sw != glyph->swidth )
   1070        {
   1071          glyph->swidth = sw;
   1072 
   1073          FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG8 ));
   1074        }
   1075      }
   1076 
   1077      p->flags |= BDF_BBX_;
   1078      goto Exit;
   1079    }
   1080 
   1081    /* And finally, gather up the bitmap. */
   1082    if ( ft_strncmp( line, "BITMAP", 6 ) == 0 )
   1083    {
   1084      unsigned long  bitmap_size;
   1085 
   1086 
   1087      if ( !( p->flags & BDF_BBX_ ) )
   1088      {
   1089        /* Missing BBX field. */
   1090        FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "BBX" ));
   1091        error = FT_THROW( Missing_Bbx_Field );
   1092        goto Exit;
   1093      }
   1094 
   1095      /* Allocate enough space for the bitmap. */
   1096      glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
   1097 
   1098      bitmap_size = glyph->bpr * glyph->bbx.height;
   1099      if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
   1100      {
   1101        FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG4, lineno ));
   1102        error = FT_THROW( Bbx_Too_Big );
   1103        goto Exit;
   1104      }
   1105      else
   1106        glyph->bytes = (unsigned short)bitmap_size;
   1107 
   1108      if ( !bitmap_size || FT_ALLOC( glyph->bitmap, glyph->bytes ) )
   1109        goto Exit;
   1110 
   1111      p->row    = 0;
   1112      p->flags |= BDF_BITMAP_;
   1113      *(bdf_line_func_t_*)next = bdf_parse_bitmap_;
   1114 
   1115      goto Exit;
   1116    }
   1117 
   1118    FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG9, lineno ));
   1119    error = FT_THROW( Invalid_File_Format );
   1120    goto Exit;
   1121 
   1122  Missing_Encoding:
   1123    /* Missing ENCODING field. */
   1124    FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENCODING" ));
   1125    error = FT_THROW( Missing_Encoding_Field );
   1126 
   1127  Exit:
   1128    if ( error && ( p->flags & BDF_GLYPH_ ) )
   1129      FT_FREE( p->glyph_name );
   1130 
   1131    return error;
   1132  }
   1133 
   1134 
   1135  /* Load the font properties. */
   1136  static FT_Error
   1137  bdf_parse_properties_( char*          line,
   1138                         unsigned long  linelen,
   1139                         unsigned long  lineno,
   1140                         bdf_parse_t_*  p,
   1141                         void*          next )
   1142  {
   1143    bdf_font_t*  font  = p->font;
   1144    FT_Error     error = FT_Err_Ok;
   1145    char*        name;
   1146    char*        value;
   1147 
   1148    FT_UNUSED( lineno );
   1149 
   1150 
   1151    /* Check for a comment. */
   1152    if ( ft_strncmp( line, "COMMENT", 7 ) == 0 )
   1153    {
   1154      if ( p->flags & BDF_KEEP_COMMENTS )
   1155        error = bdf_add_comment_( font, line, linelen );
   1156 
   1157      goto Exit;
   1158    }
   1159 
   1160    /* Check for the end of the properties. */
   1161    if ( ft_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
   1162    {
   1163      *(bdf_line_func_t_*)next = bdf_parse_start_;
   1164 
   1165      goto Exit;
   1166    }
   1167 
   1168    /* Ignore the _XFREE86_GLYPH_RANGES properties. */
   1169    if ( ft_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
   1170      goto Exit;
   1171 
   1172    if ( bdf_is_atom_( line, linelen, &name, &value, p->font ) )
   1173    {
   1174      error = bdf_add_property_( font, name, value, lineno );
   1175      if ( error )
   1176        goto Exit;
   1177    }
   1178    else
   1179    {
   1180      value = bdf_strtok_( line, ' ' );
   1181 
   1182      error = bdf_add_property_( font, line, value, lineno );
   1183      if ( error )
   1184        goto Exit;
   1185    }
   1186 
   1187  Exit:
   1188    return error;
   1189  }
   1190 
   1191 
   1192  /* Load the font header. */
   1193  static FT_Error
   1194  bdf_parse_start_( char*          line,
   1195                    unsigned long  linelen,
   1196                    unsigned long  lineno,
   1197                    bdf_parse_t_*  p,
   1198                    void*          next )
   1199  {
   1200    bdf_font_t*  font;
   1201    FT_Memory    memory = p->memory;
   1202    FT_Error     error  = FT_Err_Ok;
   1203 
   1204    FT_UNUSED( lineno );            /* only used in debug mode */
   1205 
   1206 
   1207    /* The first line must be STARTFONT.       */
   1208    /* Otherwise, reject the font immediately. */
   1209    if ( !( p->flags & BDF_START_ ) )
   1210    {
   1211      if ( ft_strncmp( line, "STARTFONT", 9 ) != 0 )
   1212      {
   1213        error = FT_THROW( Missing_Startfont_Field );
   1214        goto Exit;
   1215      }
   1216 
   1217      p->flags |= BDF_START_;
   1218 
   1219      if ( FT_NEW( p->font ) )
   1220        goto Exit;
   1221 
   1222      p->font->memory = memory;
   1223 
   1224      goto Exit;
   1225    }
   1226 
   1227    /* Point at the font being constructed. */
   1228    font = p->font;
   1229 
   1230    /* Check for a comment. */
   1231    if ( ft_strncmp( line, "COMMENT", 7 ) == 0 )
   1232    {
   1233      if ( p->flags & BDF_KEEP_COMMENTS )
   1234        error = bdf_add_comment_( font, line, linelen );
   1235 
   1236      goto Exit;
   1237    }
   1238 
   1239    /* Check for the start of the properties. */
   1240    if ( !( p->flags & BDF_PROPS_ )                       &&
   1241         ft_strncmp( line, "STARTPROPERTIES ", 16 ) == 0 )
   1242    {
   1243      line             = bdf_strtok_( line, ' ' );
   1244      font->props_size = bdf_atoul_( line );
   1245 
   1246      if ( font->props_size < 2 )
   1247        font->props_size = 2;
   1248 
   1249      /* We need at least 4 bytes per property. */
   1250      if ( font->props_size > p->size / 4 )
   1251      {
   1252        font->props_size = 0;
   1253 
   1254        FT_ERROR(( "bdf_parse_start_: " ERRMSG5, lineno, "STARTPROPERTIES" ));
   1255        error = FT_THROW( Invalid_Argument );
   1256        goto Exit;
   1257      }
   1258 
   1259      if ( FT_NEW_ARRAY( font->props, font->props_size ) )
   1260      {
   1261        font->props_size = 0;
   1262        goto Exit;
   1263      }
   1264 
   1265      if ( FT_QNEW( font->internal ) )
   1266        goto Exit;
   1267      error = ft_hash_str_init( font->internal, memory );
   1268      if ( error )
   1269        goto Exit;
   1270 
   1271      /* preset common properties */
   1272      {
   1273        bdf_property_t*  prop    = (bdf_property_t*)bdf_properties_;
   1274        FT_Hash          proptbl = &font->proptbl;
   1275        size_t           i;
   1276 
   1277 
   1278        error = ft_hash_str_init( proptbl, memory );
   1279        if ( error )
   1280          goto Exit;
   1281        for ( i = 0; i < num_bdf_properties_; i++, prop++ )
   1282        {
   1283          error = ft_hash_str_insert( prop->name, i, proptbl, memory );
   1284          if ( error )
   1285            goto Exit;
   1286        }
   1287      }
   1288 
   1289      p->flags |= BDF_PROPS_;
   1290 
   1291      *(bdf_line_func_t_*)next = bdf_parse_properties_;
   1292 
   1293      goto Exit;
   1294    }
   1295 
   1296    /* Check for the FONTBOUNDINGBOX field. */
   1297    if ( ft_strncmp( line, "FONTBOUNDINGBOX ", 16 ) == 0 )
   1298    {
   1299      line               = bdf_strtok_( line, ' ' );
   1300      font->bbx.width    = bdf_atous_( line );
   1301      line               = bdf_strtok_( line, ' ' );
   1302      font->bbx.height   = bdf_atous_( line );
   1303      line               = bdf_strtok_( line, ' ' );
   1304      font->bbx.x_offset = bdf_atos_( line );
   1305      line               = bdf_strtok_( line, ' ' );
   1306      font->bbx.y_offset = bdf_atos_( line );
   1307 
   1308      font->bbx.ascent  = (short)( font->bbx.height +
   1309                                      font->bbx.y_offset );
   1310 
   1311      font->bbx.descent = (short)( -font->bbx.y_offset );
   1312 
   1313      p->flags |= BDF_FONT_BBX_;
   1314 
   1315      goto Exit;
   1316    }
   1317 
   1318    /* The next thing to check for is the FONT field. */
   1319    if ( ft_strncmp( line, "FONT ", 5 ) == 0 )
   1320    {
   1321      int  i;
   1322 
   1323 
   1324      line = bdf_strtok_( line, ' ' );
   1325 
   1326      /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
   1327      FT_FREE( font->name );
   1328 
   1329      if ( FT_STRDUP( font->name, line ) )
   1330        goto Exit;
   1331 
   1332      /* If the font name is an XLFD name, set the spacing to the one in */
   1333      /* the font name after the 11th dash.                              */
   1334      for ( i = 0; i < 11; i++ )
   1335      {
   1336        while ( *line && *line != '-' )
   1337          line++;
   1338        if ( *line )
   1339          line++;
   1340      }
   1341 
   1342      switch ( *line )
   1343      {
   1344      case 'C':
   1345      case 'c':
   1346        font->spacing = BDF_CHARCELL;
   1347        break;
   1348      case 'M':
   1349      case 'm':
   1350        font->spacing = BDF_MONOWIDTH;
   1351        break;
   1352      case 'P':
   1353      case 'p':
   1354      default:
   1355        font->spacing = BDF_PROPORTIONAL;
   1356        break;
   1357      }
   1358 
   1359      p->flags |= BDF_FONT_NAME_;
   1360 
   1361      goto Exit;
   1362    }
   1363 
   1364    /* Check for the SIZE field. */
   1365    if ( ft_strncmp( line, "SIZE ", 5 ) == 0 )
   1366    {
   1367      line               = bdf_strtok_( line, ' ' );
   1368      font->point_size   = bdf_atoul_( line );
   1369      line               = bdf_strtok_( line, ' ' );
   1370      font->resolution_x = bdf_atoul_( line );
   1371      line               = bdf_strtok_( line, ' ' );
   1372      font->resolution_y = bdf_atoul_( line );
   1373 
   1374      /* Check for the bits per pixel field. */
   1375      line = bdf_strtok_( line, ' ' );
   1376      if ( *line )
   1377      {
   1378        unsigned short bpp;
   1379 
   1380 
   1381        bpp = bdf_atous_( line );
   1382 
   1383        /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
   1384        if ( bpp > 4 )
   1385          font->bpp = 8;
   1386        else if ( bpp > 2 )
   1387          font->bpp = 4;
   1388        else if ( bpp > 1 )
   1389          font->bpp = 2;
   1390        else
   1391          font->bpp = 1;
   1392 
   1393        if ( font->bpp != bpp )
   1394          FT_TRACE2(( "bdf_parse_start_: " ACMSG11, font->bpp ));
   1395      }
   1396      else
   1397        font->bpp = 1;
   1398 
   1399      p->flags |= BDF_SIZE_;
   1400 
   1401      goto Exit;
   1402    }
   1403 
   1404    /* Check for the CHARS field */
   1405    if ( ft_strncmp( line, "CHARS ", 6 ) == 0 )
   1406    {
   1407      /* Check the header for completeness before parsing glyphs. */
   1408      if ( !( p->flags & BDF_FONT_NAME_ ) )
   1409      {
   1410        /* Missing the FONT field. */
   1411        FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONT" ));
   1412        error = FT_THROW( Missing_Font_Field );
   1413        goto Exit;
   1414      }
   1415      if ( !( p->flags & BDF_SIZE_ ) )
   1416      {
   1417        /* Missing the SIZE field. */
   1418        FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "SIZE" ));
   1419        error = FT_THROW( Missing_Size_Field );
   1420        goto Exit;
   1421      }
   1422      if ( !( p->flags & BDF_FONT_BBX_ ) )
   1423      {
   1424        /* Missing the FONTBOUNDINGBOX field. */
   1425        FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
   1426        error = FT_THROW( Missing_Fontboundingbox_Field );
   1427        goto Exit;
   1428      }
   1429 
   1430      line   = bdf_strtok_( line, ' ' );
   1431      p->cnt = font->glyphs_size = bdf_atoul_( line );
   1432 
   1433      /* We need at least 20 bytes per glyph. */
   1434      if ( p->cnt > p->size / 20 )
   1435      {
   1436        p->cnt = font->glyphs_size = p->size / 20;
   1437        FT_TRACE2(( "bdf_parse_start_: " ACMSG17, p->cnt ));
   1438      }
   1439 
   1440      /* Make sure the number of glyphs is non-zero. */
   1441      if ( p->cnt == 0 )
   1442        font->glyphs_size = 64;
   1443 
   1444      /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
   1445      /* number of code points available in Unicode).                 */
   1446      if ( p->cnt >= 0x110000UL )
   1447      {
   1448        FT_ERROR(( "bdf_parse_start_: " ERRMSG5, lineno, "CHARS" ));
   1449        error = FT_THROW( Invalid_Argument );
   1450        goto Exit;
   1451      }
   1452 
   1453      if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
   1454        goto Exit;
   1455 
   1456      p->flags |= BDF_GLYPHS_;
   1457 
   1458      *(bdf_line_func_t_*)next = bdf_parse_glyphs_;
   1459 
   1460      goto Exit;
   1461    }
   1462 
   1463    FT_ERROR(( "bdf_parse_start_: " ERRMSG9, lineno ));
   1464    error = FT_THROW( Invalid_File_Format );
   1465 
   1466  Exit:
   1467    return error;
   1468  }
   1469 
   1470 
   1471  static FT_Error
   1472  bdf_readstream_( FT_Stream       stream,
   1473                   bdf_parse_t_*   p,
   1474                   unsigned long*  lno )
   1475  {
   1476    bdf_line_func_t_  cb = bdf_parse_start_;
   1477    unsigned long     lineno, buf_size;
   1478    unsigned long     bytes, start, end, cursor, avail;
   1479    char*             buf    = NULL;
   1480    FT_Memory         memory = stream->memory;
   1481    FT_Error          error  = FT_Err_Ok;
   1482 
   1483 
   1484    /* initial size and allocation of the input buffer */
   1485    buf_size = 1024;
   1486 
   1487    if ( FT_QALLOC( buf, buf_size ) )
   1488      goto Exit;
   1489 
   1490    lineno = 1;
   1491    start  = 0;
   1492    cursor = 0;
   1493 
   1494  Refill:
   1495    bytes = FT_Stream_TryRead( stream,
   1496                               (FT_Byte*)buf + cursor, buf_size - cursor );
   1497    avail = cursor + bytes;
   1498 
   1499    while ( bytes )
   1500    {
   1501      /* try to find the start of the line */
   1502      while ( start < avail && buf[start] < ' ' )
   1503        start++;
   1504 
   1505      /* try to find the end of the line */
   1506      end = start + 1;
   1507      while (   end < avail && buf[end] >= ' ' )
   1508        end++;
   1509 
   1510      /* if we hit the end of the buffer, try shifting its content */
   1511      /* or even resizing it                                       */
   1512      if ( end >= avail )
   1513      {
   1514        if ( start == 0 )
   1515        {
   1516          /* this line is definitely too long; try resizing the input */
   1517          /* buffer a bit to handle it.                               */
   1518          FT_ULong  new_size;
   1519 
   1520 
   1521          if ( buf_size >= 65536UL )  /* limit ourselves to 64KByte */
   1522          {
   1523            FT_ERROR(( "bdf_readstream_: " ERRMSG6, lineno ));
   1524            error = FT_THROW( Invalid_File_Format );
   1525 
   1526            goto Exit;
   1527          }
   1528 
   1529          new_size = buf_size * 4;
   1530          if ( FT_QREALLOC( buf, buf_size, new_size ) )
   1531            goto Exit;
   1532 
   1533          cursor   = avail;
   1534          buf_size = new_size;
   1535        }
   1536        else
   1537        {
   1538          cursor = avail - start;
   1539 
   1540          FT_MEM_MOVE( buf, buf + start, cursor );
   1541 
   1542          start  = 0;
   1543        }
   1544        goto Refill;
   1545      }
   1546 
   1547      /* NUL-terminate the line. */
   1548      buf[end] = 0;
   1549 
   1550      if ( buf[start] != '#' )
   1551      {
   1552        error = (*cb)( buf + start, end - start, lineno, p, (void*)&cb );
   1553        if ( error )
   1554          break;
   1555      }
   1556 
   1557      lineno  += 1;
   1558      start    = end + 1;
   1559    }
   1560 
   1561    *lno = lineno;
   1562 
   1563  Exit:
   1564    FT_FREE( buf );
   1565    return error;
   1566  }
   1567 
   1568 
   1569  /**************************************************************************
   1570   *
   1571   * API.
   1572   *
   1573   */
   1574 
   1575 
   1576  FT_LOCAL_DEF( FT_Error )
   1577  bdf_load_font( FT_Stream       stream,
   1578                 FT_Memory       memory,
   1579                 unsigned long   flags,
   1580                 bdf_font_t*    *font )
   1581  {
   1582    unsigned long  lineno = 0; /* make compiler happy */
   1583    bdf_parse_t_   *p     = NULL;
   1584 
   1585    FT_Error  error = FT_Err_Ok;
   1586 
   1587 
   1588    if ( FT_NEW( p ) )
   1589      goto Exit;
   1590 
   1591    p->flags  = flags;   /* comments, metrics, unencoded */
   1592    p->minlb  = 32767;
   1593    p->size   = stream->size;
   1594    p->memory = memory;  /* only during font creation */
   1595 
   1596    error = bdf_readstream_( stream, p, &lineno );
   1597    if ( error )
   1598      goto Fail;
   1599 
   1600    if ( p->font )
   1601    {
   1602      /* If the number of glyphs loaded is not that of the original count, */
   1603      /* indicate the difference.                                          */
   1604      if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
   1605      {
   1606        FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
   1607                    p->font->glyphs_used + p->font->unencoded_used ));
   1608      }
   1609 
   1610      /* Once the font has been loaded, adjust the overall font metrics if */
   1611      /* necessary.                                                        */
   1612      if ( p->flags & BDF_CORRECT_METRICS &&
   1613           ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
   1614      {
   1615        if ( p->maxrb - p->minlb != p->font->bbx.width )
   1616        {
   1617          FT_TRACE2(( "bdf_load_font: " ACMSG3,
   1618                      p->font->bbx.width, p->maxrb - p->minlb ));
   1619          p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
   1620        }
   1621 
   1622        if ( p->font->bbx.x_offset != p->minlb )
   1623        {
   1624          FT_TRACE2(( "bdf_load_font: " ACMSG4,
   1625                      p->font->bbx.x_offset, p->minlb ));
   1626          p->font->bbx.x_offset = p->minlb;
   1627        }
   1628 
   1629        if ( p->font->bbx.ascent != p->maxas )
   1630        {
   1631          FT_TRACE2(( "bdf_load_font: " ACMSG5,
   1632                      p->font->bbx.ascent, p->maxas ));
   1633          p->font->bbx.ascent = p->maxas;
   1634        }
   1635 
   1636        if ( p->font->bbx.descent != p->maxds )
   1637        {
   1638          FT_TRACE2(( "bdf_load_font: " ACMSG6,
   1639                      p->font->bbx.descent, p->maxds ));
   1640          p->font->bbx.descent  = p->maxds;
   1641          p->font->bbx.y_offset = (short)( -p->maxds );
   1642        }
   1643 
   1644        if ( p->maxas + p->maxds != p->font->bbx.height )
   1645        {
   1646          FT_TRACE2(( "bdf_load_font: " ACMSG7,
   1647                      p->font->bbx.height, p->maxas + p->maxds ));
   1648          p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
   1649        }
   1650      }
   1651    }
   1652 
   1653    if ( p->flags & BDF_START_ )
   1654    {
   1655      /* The ENDFONT field was never reached or did not exist. */
   1656      if ( !( p->flags & BDF_GLYPHS_ ) )
   1657      {
   1658        /* Error happened while parsing header. */
   1659        FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
   1660        error = FT_THROW( Corrupted_Font_Header );
   1661        goto Fail;
   1662      }
   1663      else
   1664      {
   1665        /* Error happened when parsing glyphs. */
   1666        FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
   1667        error = FT_THROW( Corrupted_Font_Glyphs );
   1668        goto Fail;
   1669      }
   1670    }
   1671 
   1672    if ( !p->font && !error )
   1673      error = FT_THROW( Invalid_File_Format );
   1674 
   1675    *font = p->font;
   1676 
   1677  Exit:
   1678    if ( p )
   1679    {
   1680      FT_FREE( p->glyph_name );
   1681      FT_FREE( p );
   1682    }
   1683 
   1684    return error;
   1685 
   1686  Fail:
   1687    bdf_free_font( p->font );
   1688 
   1689    FT_FREE( p->font );
   1690 
   1691    goto Exit;
   1692  }
   1693 
   1694 
   1695  FT_LOCAL_DEF( void )
   1696  bdf_free_font( bdf_font_t*  font )
   1697  {
   1698    bdf_property_t*  prop;
   1699    unsigned long    i;
   1700    bdf_glyph_t*     glyphs;
   1701    FT_Memory        memory;
   1702 
   1703 
   1704    if ( font == NULL )
   1705      return;
   1706 
   1707    memory = font->memory;
   1708 
   1709    FT_FREE( font->name );
   1710 
   1711    /* Free up the internal hash table of property names. */
   1712    if ( font->internal )
   1713    {
   1714      ft_hash_str_free( font->internal, memory );
   1715      FT_FREE( font->internal );
   1716    }
   1717 
   1718    /* Free up the comment info. */
   1719    FT_FREE( font->comments );
   1720 
   1721    /* Free up the properties. */
   1722    for ( i = 0; i < font->props_size; i++ )
   1723    {
   1724      if ( font->props[i].format == BDF_ATOM )
   1725        FT_FREE( font->props[i].value.atom );
   1726    }
   1727 
   1728    FT_FREE( font->props );
   1729 
   1730    /* Free up the character info. */
   1731    for ( i = 0, glyphs = font->glyphs;
   1732          i < font->glyphs_used; i++, glyphs++ )
   1733    {
   1734      FT_FREE( glyphs->name );
   1735      FT_FREE( glyphs->bitmap );
   1736    }
   1737 
   1738    for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
   1739          i++, glyphs++ )
   1740    {
   1741      FT_FREE( glyphs->name );
   1742      FT_FREE( glyphs->bitmap );
   1743    }
   1744 
   1745    FT_FREE( font->glyphs );
   1746    FT_FREE( font->unencoded );
   1747 
   1748    /* bdf_cleanup */
   1749    ft_hash_str_free( &(font->proptbl), memory );
   1750 
   1751    /* Free up the user defined properties. */
   1752    for ( prop = font->user_props, i = 0;
   1753          i < font->nuser_props; i++, prop++ )
   1754      FT_FREE( prop->name );
   1755 
   1756    FT_FREE( font->user_props );
   1757 
   1758    /* FREE( font ); */ /* XXX Fixme */
   1759  }
   1760 
   1761 
   1762  FT_LOCAL_DEF( bdf_property_t * )
   1763  bdf_get_font_property( bdf_font_t*  font,
   1764                         const char*  name )
   1765  {
   1766    size_t*  propid;
   1767 
   1768 
   1769    if ( font == NULL || font->props_size == 0 || name == NULL || *name == 0 )
   1770      return 0;
   1771 
   1772    propid = ft_hash_str_lookup( name, font->internal );
   1773 
   1774    return propid ? ( font->props + *propid ) : NULL;
   1775  }
   1776 
   1777 
   1778 /* END */