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