bdflib.c

Go to the documentation of this file.
00001 /*
00002  * Copyright 2000 Computing Research Labs, New Mexico State University
00003  * Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009
00004  *   Francesco Zappa Nardelli
00005  *
00006  * Permission is hereby granted, free of charge, to any person obtaining a
00007  * copy of this software and associated documentation files (the "Software"),
00008  * to deal in the Software without restriction, including without limitation
00009  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00010  * and/or sell copies of the Software, and to permit persons to whom the
00011  * Software is furnished to do so, subject to the following conditions:
00012  *
00013  * The above copyright notice and this permission notice shall be included in
00014  * all copies or substantial portions of the Software.
00015  *
00016  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00017  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00018  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
00019  * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
00020  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
00021  * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
00022  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00023  */
00024 
00025   /*************************************************************************/
00026   /*                                                                       */
00027   /*  This file is based on bdf.c,v 1.22 2000/03/16 20:08:50               */
00028   /*                                                                       */
00029   /*  taken from Mark Leisher's xmbdfed package                            */
00030   /*                                                                       */
00031   /*************************************************************************/
00032 
00033 
00034 #include <ft2build.h>
00035 
00036 #include FT_FREETYPE_H
00037 #include FT_INTERNAL_DEBUG_H
00038 #include FT_INTERNAL_STREAM_H
00039 #include FT_INTERNAL_OBJECTS_H
00040 
00041 #include "bdf.h"
00042 #include "bdferror.h"
00043 
00044 
00045   /*************************************************************************/
00046   /*                                                                       */
00047   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
00048   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
00049   /* messages during execution.                                            */
00050   /*                                                                       */
00051 #undef  FT_COMPONENT
00052 #define FT_COMPONENT  trace_bdflib
00053 
00054 
00055   /*************************************************************************/
00056   /*                                                                       */
00057   /* Default BDF font options.                                             */
00058   /*                                                                       */
00059   /*************************************************************************/
00060 
00061 
00062   static const bdf_options_t  _bdf_opts =
00063   {
00064     1,                /* Correct metrics.               */
00065     1,                /* Preserve unencoded glyphs.     */
00066     0,                /* Preserve comments.             */
00067     BDF_PROPORTIONAL  /* Default spacing.               */
00068   };
00069 
00070 
00071   /*************************************************************************/
00072   /*                                                                       */
00073   /* Builtin BDF font properties.                                          */
00074   /*                                                                       */
00075   /*************************************************************************/
00076 
00077   /* List of most properties that might appear in a font.  Doesn't include */
00078   /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts.           */
00079 
00080   static const bdf_property_t  _bdf_properties[] =
00081   {
00082     { (char *)"ADD_STYLE_NAME",          BDF_ATOM,     1, { 0 } },
00083     { (char *)"AVERAGE_WIDTH",           BDF_INTEGER,  1, { 0 } },
00084     { (char *)"AVG_CAPITAL_WIDTH",       BDF_INTEGER,  1, { 0 } },
00085     { (char *)"AVG_LOWERCASE_WIDTH",     BDF_INTEGER,  1, { 0 } },
00086     { (char *)"CAP_HEIGHT",              BDF_INTEGER,  1, { 0 } },
00087     { (char *)"CHARSET_COLLECTIONS",     BDF_ATOM,     1, { 0 } },
00088     { (char *)"CHARSET_ENCODING",        BDF_ATOM,     1, { 0 } },
00089     { (char *)"CHARSET_REGISTRY",        BDF_ATOM,     1, { 0 } },
00090     { (char *)"COMMENT",                 BDF_ATOM,     1, { 0 } },
00091     { (char *)"COPYRIGHT",               BDF_ATOM,     1, { 0 } },
00092     { (char *)"DEFAULT_CHAR",            BDF_CARDINAL, 1, { 0 } },
00093     { (char *)"DESTINATION",             BDF_CARDINAL, 1, { 0 } },
00094     { (char *)"DEVICE_FONT_NAME",        BDF_ATOM,     1, { 0 } },
00095     { (char *)"END_SPACE",               BDF_INTEGER,  1, { 0 } },
00096     { (char *)"FACE_NAME",               BDF_ATOM,     1, { 0 } },
00097     { (char *)"FAMILY_NAME",             BDF_ATOM,     1, { 0 } },
00098     { (char *)"FIGURE_WIDTH",            BDF_INTEGER,  1, { 0 } },
00099     { (char *)"FONT",                    BDF_ATOM,     1, { 0 } },
00100     { (char *)"FONTNAME_REGISTRY",       BDF_ATOM,     1, { 0 } },
00101     { (char *)"FONT_ASCENT",             BDF_INTEGER,  1, { 0 } },
00102     { (char *)"FONT_DESCENT",            BDF_INTEGER,  1, { 0 } },
00103     { (char *)"FOUNDRY",                 BDF_ATOM,     1, { 0 } },
00104     { (char *)"FULL_NAME",               BDF_ATOM,     1, { 0 } },
00105     { (char *)"ITALIC_ANGLE",            BDF_INTEGER,  1, { 0 } },
00106     { (char *)"MAX_SPACE",               BDF_INTEGER,  1, { 0 } },
00107     { (char *)"MIN_SPACE",               BDF_INTEGER,  1, { 0 } },
00108     { (char *)"NORM_SPACE",              BDF_INTEGER,  1, { 0 } },
00109     { (char *)"NOTICE",                  BDF_ATOM,     1, { 0 } },
00110     { (char *)"PIXEL_SIZE",              BDF_INTEGER,  1, { 0 } },
00111     { (char *)"POINT_SIZE",              BDF_INTEGER,  1, { 0 } },
00112     { (char *)"QUAD_WIDTH",              BDF_INTEGER,  1, { 0 } },
00113     { (char *)"RAW_ASCENT",              BDF_INTEGER,  1, { 0 } },
00114     { (char *)"RAW_AVERAGE_WIDTH",       BDF_INTEGER,  1, { 0 } },
00115     { (char *)"RAW_AVG_CAPITAL_WIDTH",   BDF_INTEGER,  1, { 0 } },
00116     { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER,  1, { 0 } },
00117     { (char *)"RAW_CAP_HEIGHT",          BDF_INTEGER,  1, { 0 } },
00118     { (char *)"RAW_DESCENT",             BDF_INTEGER,  1, { 0 } },
00119     { (char *)"RAW_END_SPACE",           BDF_INTEGER,  1, { 0 } },
00120     { (char *)"RAW_FIGURE_WIDTH",        BDF_INTEGER,  1, { 0 } },
00121     { (char *)"RAW_MAX_SPACE",           BDF_INTEGER,  1, { 0 } },
00122     { (char *)"RAW_MIN_SPACE",           BDF_INTEGER,  1, { 0 } },
00123     { (char *)"RAW_NORM_SPACE",          BDF_INTEGER,  1, { 0 } },
00124     { (char *)"RAW_PIXEL_SIZE",          BDF_INTEGER,  1, { 0 } },
00125     { (char *)"RAW_POINT_SIZE",          BDF_INTEGER,  1, { 0 } },
00126     { (char *)"RAW_PIXELSIZE",           BDF_INTEGER,  1, { 0 } },
00127     { (char *)"RAW_POINTSIZE",           BDF_INTEGER,  1, { 0 } },
00128     { (char *)"RAW_QUAD_WIDTH",          BDF_INTEGER,  1, { 0 } },
00129     { (char *)"RAW_SMALL_CAP_SIZE",      BDF_INTEGER,  1, { 0 } },
00130     { (char *)"RAW_STRIKEOUT_ASCENT",    BDF_INTEGER,  1, { 0 } },
00131     { (char *)"RAW_STRIKEOUT_DESCENT",   BDF_INTEGER,  1, { 0 } },
00132     { (char *)"RAW_SUBSCRIPT_SIZE",      BDF_INTEGER,  1, { 0 } },
00133     { (char *)"RAW_SUBSCRIPT_X",         BDF_INTEGER,  1, { 0 } },
00134     { (char *)"RAW_SUBSCRIPT_Y",         BDF_INTEGER,  1, { 0 } },
00135     { (char *)"RAW_SUPERSCRIPT_SIZE",    BDF_INTEGER,  1, { 0 } },
00136     { (char *)"RAW_SUPERSCRIPT_X",       BDF_INTEGER,  1, { 0 } },
00137     { (char *)"RAW_SUPERSCRIPT_Y",       BDF_INTEGER,  1, { 0 } },
00138     { (char *)"RAW_UNDERLINE_POSITION",  BDF_INTEGER,  1, { 0 } },
00139     { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER,  1, { 0 } },
00140     { (char *)"RAW_X_HEIGHT",            BDF_INTEGER,  1, { 0 } },
00141     { (char *)"RELATIVE_SETWIDTH",       BDF_CARDINAL, 1, { 0 } },
00142     { (char *)"RELATIVE_WEIGHT",         BDF_CARDINAL, 1, { 0 } },
00143     { (char *)"RESOLUTION",              BDF_INTEGER,  1, { 0 } },
00144     { (char *)"RESOLUTION_X",            BDF_CARDINAL, 1, { 0 } },
00145     { (char *)"RESOLUTION_Y",            BDF_CARDINAL, 1, { 0 } },
00146     { (char *)"SETWIDTH_NAME",           BDF_ATOM,     1, { 0 } },
00147     { (char *)"SLANT",                   BDF_ATOM,     1, { 0 } },
00148     { (char *)"SMALL_CAP_SIZE",          BDF_INTEGER,  1, { 0 } },
00149     { (char *)"SPACING",                 BDF_ATOM,     1, { 0 } },
00150     { (char *)"STRIKEOUT_ASCENT",        BDF_INTEGER,  1, { 0 } },
00151     { (char *)"STRIKEOUT_DESCENT",       BDF_INTEGER,  1, { 0 } },
00152     { (char *)"SUBSCRIPT_SIZE",          BDF_INTEGER,  1, { 0 } },
00153     { (char *)"SUBSCRIPT_X",             BDF_INTEGER,  1, { 0 } },
00154     { (char *)"SUBSCRIPT_Y",             BDF_INTEGER,  1, { 0 } },
00155     { (char *)"SUPERSCRIPT_SIZE",        BDF_INTEGER,  1, { 0 } },
00156     { (char *)"SUPERSCRIPT_X",           BDF_INTEGER,  1, { 0 } },
00157     { (char *)"SUPERSCRIPT_Y",           BDF_INTEGER,  1, { 0 } },
00158     { (char *)"UNDERLINE_POSITION",      BDF_INTEGER,  1, { 0 } },
00159     { (char *)"UNDERLINE_THICKNESS",     BDF_INTEGER,  1, { 0 } },
00160     { (char *)"WEIGHT",                  BDF_CARDINAL, 1, { 0 } },
00161     { (char *)"WEIGHT_NAME",             BDF_ATOM,     1, { 0 } },
00162     { (char *)"X_HEIGHT",                BDF_INTEGER,  1, { 0 } },
00163     { (char *)"_MULE_BASELINE_OFFSET",   BDF_INTEGER,  1, { 0 } },
00164     { (char *)"_MULE_RELATIVE_COMPOSE",  BDF_INTEGER,  1, { 0 } },
00165   };
00166 
00167   static const unsigned long
00168   _num_bdf_properties = sizeof ( _bdf_properties ) /
00169                         sizeof ( _bdf_properties[0] );
00170 
00171 
00172   /*************************************************************************/
00173   /*                                                                       */
00174   /* Hash table utilities for the properties.                              */
00175   /*                                                                       */
00176   /*************************************************************************/
00177 
00178   /* XXX: Replace this with FreeType's hash functions */
00179 
00180 
00181 #define INITIAL_HT_SIZE  241
00182 
00183   typedef void
00184   (*hash_free_func)( hashnode  node );
00185 
00186   static hashnode*
00187   hash_bucket( const char*  key,
00188                hashtable*   ht )
00189   {
00190     const char*    kp  = key;
00191     unsigned long  res = 0;
00192     hashnode*      bp  = ht->table, *ndp;
00193 
00194 
00195     /* Mocklisp hash function. */
00196     while ( *kp )
00197       res = ( res << 5 ) - res + *kp++;
00198 
00199     ndp = bp + ( res % ht->size );
00200     while ( *ndp )
00201     {
00202       kp = (*ndp)->key;
00203       if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
00204         break;
00205       ndp--;
00206       if ( ndp < bp )
00207         ndp = bp + ( ht->size - 1 );
00208     }
00209 
00210     return ndp;
00211   }
00212 
00213 
00214   static FT_Error
00215   hash_rehash( hashtable*  ht,
00216                FT_Memory   memory )
00217   {
00218     hashnode*  obp = ht->table, *bp, *nbp;
00219     int        i, sz = ht->size;
00220     FT_Error   error = BDF_Err_Ok;
00221 
00222 
00223     ht->size <<= 1;
00224     ht->limit  = ht->size / 3;
00225 
00226     if ( FT_NEW_ARRAY( ht->table, ht->size ) )
00227       goto Exit;
00228 
00229     for ( i = 0, bp = obp; i < sz; i++, bp++ )
00230     {
00231       if ( *bp )
00232       {
00233         nbp = hash_bucket( (*bp)->key, ht );
00234         *nbp = *bp;
00235       }
00236     }
00237     FT_FREE( obp );
00238 
00239   Exit:
00240     return error;
00241   }
00242 
00243 
00244   static FT_Error
00245   hash_init( hashtable*  ht,
00246              FT_Memory   memory )
00247   {
00248     int       sz = INITIAL_HT_SIZE;
00249     FT_Error  error = BDF_Err_Ok;
00250 
00251 
00252     ht->size  = sz;
00253     ht->limit = sz / 3;
00254     ht->used  = 0;
00255 
00256     if ( FT_NEW_ARRAY( ht->table, sz ) )
00257       goto Exit;
00258 
00259   Exit:
00260     return error;
00261   }
00262 
00263 
00264   static void
00265   hash_free( hashtable*  ht,
00266              FT_Memory   memory )
00267   {
00268     if ( ht != 0 )
00269     {
00270       int        i, sz = ht->size;
00271       hashnode*  bp = ht->table;
00272 
00273 
00274       for ( i = 0; i < sz; i++, bp++ )
00275         FT_FREE( *bp );
00276 
00277       FT_FREE( ht->table );
00278     }
00279   }
00280 
00281 
00282   static FT_Error
00283   hash_insert( char*       key,
00284                size_t      data,
00285                hashtable*  ht,
00286                FT_Memory   memory )
00287   {
00288     hashnode  nn, *bp = hash_bucket( key, ht );
00289     FT_Error  error = BDF_Err_Ok;
00290 
00291 
00292     nn = *bp;
00293     if ( !nn )
00294     {
00295       if ( FT_NEW( nn ) )
00296         goto Exit;
00297       *bp = nn;
00298 
00299       nn->key  = key;
00300       nn->data = data;
00301 
00302       if ( ht->used >= ht->limit )
00303       {
00304         error = hash_rehash( ht, memory );
00305         if ( error )
00306           goto Exit;
00307       }
00308       ht->used++;
00309     }
00310     else
00311       nn->data = data;
00312 
00313   Exit:
00314     return error;
00315   }
00316 
00317 
00318   static hashnode
00319   hash_lookup( const char* key,
00320                hashtable*  ht )
00321   {
00322     hashnode *np = hash_bucket( key, ht );
00323 
00324 
00325     return *np;
00326   }
00327 
00328 
00329   /*************************************************************************/
00330   /*                                                                       */
00331   /* Utility types and functions.                                          */
00332   /*                                                                       */
00333   /*************************************************************************/
00334 
00335 
00336   /* Function type for parsing lines of a BDF font. */
00337 
00338   typedef FT_Error
00339   (*_bdf_line_func_t)( char*          line,
00340                        unsigned long  linelen,
00341                        unsigned long  lineno,
00342                        void*          call_data,
00343                        void*          client_data );
00344 
00345 
00346   /* List structure for splitting lines into fields. */
00347 
00348   typedef struct  _bdf_list_t_
00349   {
00350     char**         field;
00351     unsigned long  size;
00352     unsigned long  used;
00353     FT_Memory      memory;
00354 
00355   } _bdf_list_t;
00356 
00357 
00358   /* Structure used while loading BDF fonts. */
00359 
00360   typedef struct  _bdf_parse_t_
00361   {
00362     unsigned long   flags;
00363     unsigned long   cnt;
00364     unsigned long   row;
00365 
00366     short           minlb;
00367     short           maxlb;
00368     short           maxrb;
00369     short           maxas;
00370     short           maxds;
00371 
00372     short           rbearing;
00373 
00374     char*           glyph_name;
00375     long            glyph_enc;
00376 
00377     bdf_font_t*     font;
00378     bdf_options_t*  opts;
00379 
00380     unsigned long   have[2048];
00381     _bdf_list_t     list;
00382 
00383     FT_Memory       memory;
00384 
00385   } _bdf_parse_t;
00386 
00387 
00388 #define setsbit( m, cc ) \
00389           ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
00390 #define sbitset( m, cc ) \
00391           ( m[(FT_Byte)(cc) >> 3]  & ( 1 << ( (cc) & 7 ) ) )
00392 
00393 
00394   static void
00395   _bdf_list_init( _bdf_list_t*  list,
00396                   FT_Memory     memory )
00397   {
00398     FT_ZERO( list );
00399     list->memory = memory;
00400   }
00401 
00402 
00403   static void
00404   _bdf_list_done( _bdf_list_t*  list )
00405   {
00406     FT_Memory  memory = list->memory;
00407 
00408 
00409     if ( memory )
00410     {
00411       FT_FREE( list->field );
00412       FT_ZERO( list );
00413     }
00414   }
00415 
00416 
00417   static FT_Error
00418   _bdf_list_ensure( _bdf_list_t*   list,
00419                     unsigned long  num_items ) /* same as _bdf_list_t.used */
00420   {
00421     FT_Error  error = BDF_Err_Ok;
00422 
00423 
00424     if ( num_items > list->size )
00425     {
00426       unsigned long  oldsize = list->size; /* same as _bdf_list_t.size */
00427       unsigned long  newsize = oldsize + ( oldsize >> 1 ) + 4;
00428       unsigned long  bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
00429       FT_Memory      memory  = list->memory;
00430 
00431 
00432       if ( oldsize == bigsize )
00433       {
00434         error = BDF_Err_Out_Of_Memory;
00435         goto Exit;
00436       }
00437       else if ( newsize < oldsize || newsize > bigsize )
00438         newsize = bigsize;
00439 
00440       if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
00441         goto Exit;
00442 
00443       list->size = newsize;
00444     }
00445 
00446   Exit:
00447     return error;
00448   }
00449 
00450 
00451   static void
00452   _bdf_list_shift( _bdf_list_t*   list,
00453                    unsigned long  n )
00454   {
00455     unsigned long  i, u;
00456 
00457 
00458     if ( list == 0 || list->used == 0 || n == 0 )
00459       return;
00460 
00461     if ( n >= list->used )
00462     {
00463       list->used = 0;
00464       return;
00465     }
00466 
00467     for ( u = n, i = 0; u < list->used; i++, u++ )
00468       list->field[i] = list->field[u];
00469     list->used -= n;
00470   }
00471 
00472 
00473   static char *
00474   _bdf_list_join( _bdf_list_t*    list,
00475                   int             c,
00476                   unsigned long  *alen )
00477   {
00478     unsigned long  i, j;
00479     char           *fp, *dp;
00480 
00481 
00482     *alen = 0;
00483 
00484     if ( list == 0 || list->used == 0 )
00485       return 0;
00486 
00487     dp = list->field[0];
00488     for ( i = j = 0; i < list->used; i++ )
00489     {
00490       fp = list->field[i];
00491       while ( *fp )
00492         dp[j++] = *fp++;
00493 
00494       if ( i + 1 < list->used )
00495         dp[j++] = (char)c;
00496     }
00497     dp[j] = 0;
00498 
00499     *alen = j;
00500     return dp;
00501   }
00502 
00503 
00504   /* An empty string for empty fields. */
00505 
00506   static const char  empty[1] = { 0 };      /* XXX eliminate this */
00507 
00508 
00509   static FT_Error
00510   _bdf_list_split( _bdf_list_t*   list,
00511                    char*          separators,
00512                    char*          line,
00513                    unsigned long  linelen )
00514   {
00515     int       mult, final_empty;
00516     char      *sp, *ep, *end;
00517     char      seps[32];
00518     FT_Error  error = BDF_Err_Ok;
00519 
00520 
00521     /* Initialize the list. */
00522     list->used = 0;
00523 
00524     /* If the line is empty, then simply return. */
00525     if ( linelen == 0 || line[0] == 0 )
00526       goto Exit;
00527 
00528     /* In the original code, if the `separators' parameter is NULL or */
00529     /* empty, the list is split into individual bytes.  We don't need */
00530     /* this, so an error is signaled.                                 */
00531     if ( separators == 0 || *separators == 0 )
00532     {
00533       error = BDF_Err_Invalid_Argument;
00534       goto Exit;
00535     }
00536 
00537     /* Prepare the separator bitmap. */
00538     FT_MEM_ZERO( seps, 32 );
00539 
00540     /* If the very last character of the separator string is a plus, then */
00541     /* set the `mult' flag to indicate that multiple separators should be */
00542     /* collapsed into one.                                                */
00543     for ( mult = 0, sp = separators; sp && *sp; sp++ )
00544     {
00545       if ( *sp == '+' && *( sp + 1 ) == 0 )
00546         mult = 1;
00547       else
00548         setsbit( seps, *sp );
00549     }
00550 
00551     /* Break the line up into fields. */
00552     for ( final_empty = 0, sp = ep = line, end = sp + linelen;
00553           sp < end && *sp; )
00554     {
00555       /* Collect everything that is not a separator. */
00556       for ( ; *ep && !sbitset( seps, *ep ); ep++ )
00557         ;
00558 
00559       /* Resize the list if necessary. */
00560       if ( list->used == list->size )
00561       {
00562         error = _bdf_list_ensure( list, list->used + 1 );
00563         if ( error )
00564           goto Exit;
00565       }
00566 
00567       /* Assign the field appropriately. */
00568       list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
00569 
00570       sp = ep;
00571 
00572       if ( mult )
00573       {
00574         /* If multiple separators should be collapsed, do it now by */
00575         /* setting all the separator characters to 0.               */
00576         for ( ; *ep && sbitset( seps, *ep ); ep++ )
00577           *ep = 0;
00578       }
00579       else if ( *ep != 0 )
00580         /* Don't collapse multiple separators by making them 0, so just */
00581         /* make the one encountered 0.                                  */
00582         *ep++ = 0;
00583 
00584       final_empty = ( ep > sp && *ep == 0 );
00585       sp = ep;
00586     }
00587 
00588     /* Finally, NULL-terminate the list. */
00589     if ( list->used + final_empty >= list->size )
00590     {
00591       error = _bdf_list_ensure( list, list->used + final_empty + 1 );
00592       if ( error )
00593         goto Exit;
00594     }
00595 
00596     if ( final_empty )
00597       list->field[list->used++] = (char*)empty;
00598 
00599     list->field[list->used] = 0;
00600 
00601   Exit:
00602     return error;
00603   }
00604 
00605 
00606 #define NO_SKIP  256  /* this value cannot be stored in a 'char' */
00607 
00608 
00609   static FT_Error
00610   _bdf_readstream( FT_Stream         stream,
00611                    _bdf_line_func_t  callback,
00612                    void*             client_data,
00613                    unsigned long    *lno )
00614   {
00615     _bdf_line_func_t  cb;
00616     unsigned long     lineno, buf_size;
00617     int               refill, hold, to_skip;
00618     ptrdiff_t         bytes, start, end, cursor, avail;
00619     char*             buf = 0;
00620     FT_Memory         memory = stream->memory;
00621     FT_Error          error = BDF_Err_Ok;
00622 
00623 
00624     if ( callback == 0 )
00625     {
00626       error = BDF_Err_Invalid_Argument;
00627       goto Exit;
00628     }
00629 
00630     /* initial size and allocation of the input buffer */
00631     buf_size = 1024;
00632 
00633     if ( FT_NEW_ARRAY( buf, buf_size ) )
00634       goto Exit;
00635 
00636     cb      = callback;
00637     lineno  = 1;
00638     buf[0]  = 0;
00639     start   = 0;
00640     end     = 0;
00641     avail   = 0;
00642     cursor  = 0;
00643     refill  = 1;
00644     to_skip = NO_SKIP;
00645     bytes   = 0;        /* make compiler happy */
00646 
00647     for (;;)
00648     {
00649       if ( refill )
00650       {
00651         bytes  = (ptrdiff_t)FT_Stream_TryRead( stream, (FT_Byte*)buf + cursor,
00652                                                (FT_ULong)(buf_size - cursor) );
00653         avail  = cursor + bytes;
00654         cursor = 0;
00655         refill = 0;
00656       }
00657 
00658       end = start;
00659 
00660       /* should we skip an optional character like \n or \r? */
00661       if ( start < avail && buf[start] == to_skip )
00662       {
00663         start  += 1;
00664         to_skip = NO_SKIP;
00665         continue;
00666       }
00667 
00668       /* try to find the end of the line */
00669       while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
00670         end++;
00671 
00672       /* if we hit the end of the buffer, try shifting its content */
00673       /* or even resizing it                                       */
00674       if ( end >= avail )
00675       {
00676         if ( bytes == 0 )  /* last line in file doesn't end in \r or \n */
00677           break;           /* ignore it then exit                       */
00678 
00679         if ( start == 0 )
00680         {
00681           /* this line is definitely too long; try resizing the input */
00682           /* buffer a bit to handle it.                               */
00683           FT_ULong  new_size;
00684 
00685 
00686           if ( buf_size >= 65536UL )  /* limit ourselves to 64KByte */
00687           {
00688             error = BDF_Err_Invalid_Argument;
00689             goto Exit;
00690           }
00691 
00692           new_size = buf_size * 2;
00693           if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
00694             goto Exit;
00695 
00696           cursor   = buf_size;
00697           buf_size = new_size;
00698         }
00699         else
00700         {
00701           bytes = avail - start;
00702 
00703           FT_MEM_COPY( buf, buf + start, bytes );
00704 
00705           cursor = bytes;
00706           avail -= bytes;
00707           start  = 0;
00708         }
00709         refill = 1;
00710         continue;
00711       }
00712 
00713       /* Temporarily NUL-terminate the line. */
00714       hold     = buf[end];
00715       buf[end] = 0;
00716 
00717       /* XXX: Use encoding independent value for 0x1a */
00718       if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
00719       {
00720         error = (*cb)( buf + start, end - start, lineno,
00721                        (void*)&cb, client_data );
00722         if ( error )
00723           break;
00724       }
00725 
00726       lineno  += 1;
00727       buf[end] = (char)hold;
00728       start    = end + 1;
00729 
00730       if ( hold == '\n' )
00731         to_skip = '\r';
00732       else if ( hold == '\r' )
00733         to_skip = '\n';
00734       else
00735         to_skip = NO_SKIP;
00736     }
00737 
00738     *lno = lineno;
00739 
00740   Exit:
00741     FT_FREE( buf );
00742     return error;
00743   }
00744 
00745 
00746   /* XXX: make this work with EBCDIC also */
00747 
00748   static const unsigned char  a2i[128] =
00749   {
00750     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00751     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00752     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00753     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00754     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
00755     0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
00756     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00757     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00758     0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
00759     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00760     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
00761   };
00762 
00763   static const unsigned char  odigits[32] =
00764   {
00765     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
00766     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00767     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00768     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00769   };
00770 
00771   static const unsigned char  ddigits[32] =
00772   {
00773     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
00774     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00775     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00776     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00777   };
00778 
00779   static const unsigned char  hdigits[32] =
00780   {
00781     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
00782     0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
00783     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00784     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00785   };
00786 
00787 
00788 #define isdigok( m, d )  (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
00789 
00790 
00791   /* Routine to convert an ASCII string into an unsigned long integer. */
00792   static unsigned long
00793   _bdf_atoul( char*   s,
00794               char**  end,
00795               int     base )
00796   {
00797     unsigned long         v;
00798     const unsigned char*  dmap;
00799 
00800 
00801     if ( s == 0 || *s == 0 )
00802       return 0;
00803 
00804     /* Make sure the radix is something recognizable.  Default to 10. */
00805     switch ( base )
00806     {
00807     case 8:
00808       dmap = odigits;
00809       break;
00810     case 16:
00811       dmap = hdigits;
00812       break;
00813     default:
00814       base = 10;
00815       dmap = ddigits;
00816       break;
00817     }
00818 
00819     /* Check for the special hex prefix. */
00820     if ( *s == '0'                                  &&
00821          ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
00822     {
00823       base = 16;
00824       dmap = hdigits;
00825       s   += 2;
00826     }
00827 
00828     for ( v = 0; isdigok( dmap, *s ); s++ )
00829       v = v * base + a2i[(int)*s];
00830 
00831     if ( end != 0 )
00832       *end = s;
00833 
00834     return v;
00835   }
00836 
00837 
00838   /* Routine to convert an ASCII string into an signed long integer. */
00839   static long
00840   _bdf_atol( char*   s,
00841              char**  end,
00842              int     base )
00843   {
00844     long                  v, neg;
00845     const unsigned char*  dmap;
00846 
00847 
00848     if ( s == 0 || *s == 0 )
00849       return 0;
00850 
00851     /* Make sure the radix is something recognizable.  Default to 10. */
00852     switch ( base )
00853     {
00854     case 8:
00855       dmap = odigits;
00856       break;
00857     case 16:
00858       dmap = hdigits;
00859       break;
00860     default:
00861       base = 10;
00862       dmap = ddigits;
00863       break;
00864     }
00865 
00866     /* Check for a minus sign. */
00867     neg = 0;
00868     if ( *s == '-' )
00869     {
00870       s++;
00871       neg = 1;
00872     }
00873 
00874     /* Check for the special hex prefix. */
00875     if ( *s == '0'                                  &&
00876          ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
00877     {
00878       base = 16;
00879       dmap = hdigits;
00880       s   += 2;
00881     }
00882 
00883     for ( v = 0; isdigok( dmap, *s ); s++ )
00884       v = v * base + a2i[(int)*s];
00885 
00886     if ( end != 0 )
00887       *end = s;
00888 
00889     return ( !neg ) ? v : -v;
00890   }
00891 
00892 
00893   /* Routine to convert an ASCII string into an signed short integer. */
00894   static short
00895   _bdf_atos( char*   s,
00896              char**  end,
00897              int     base )
00898   {
00899     short                 v, neg;
00900     const unsigned char*  dmap;
00901 
00902 
00903     if ( s == 0 || *s == 0 )
00904       return 0;
00905 
00906     /* Make sure the radix is something recognizable.  Default to 10. */
00907     switch ( base )
00908     {
00909     case 8:
00910       dmap = odigits;
00911       break;
00912     case 16:
00913       dmap = hdigits;
00914       break;
00915     default:
00916       base = 10;
00917       dmap = ddigits;
00918       break;
00919     }
00920 
00921     /* Check for a minus. */
00922     neg = 0;
00923     if ( *s == '-' )
00924     {
00925       s++;
00926       neg = 1;
00927     }
00928 
00929     /* Check for the special hex prefix. */
00930     if ( *s == '0'                                  &&
00931          ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
00932     {
00933       base = 16;
00934       dmap = hdigits;
00935       s   += 2;
00936     }
00937 
00938     for ( v = 0; isdigok( dmap, *s ); s++ )
00939       v = (short)( v * base + a2i[(int)*s] );
00940 
00941     if ( end != 0 )
00942       *end = s;
00943 
00944     return (short)( ( !neg ) ? v : -v );
00945   }
00946 
00947 
00948   /* Routine to compare two glyphs by encoding so they can be sorted. */
00949   static int
00950   by_encoding( const void*  a,
00951                const void*  b )
00952   {
00953     bdf_glyph_t  *c1, *c2;
00954 
00955 
00956     c1 = (bdf_glyph_t *)a;
00957     c2 = (bdf_glyph_t *)b;
00958 
00959     if ( c1->encoding < c2->encoding )
00960       return -1;
00961 
00962     if ( c1->encoding > c2->encoding )
00963       return 1;
00964 
00965     return 0;
00966   }
00967 
00968 
00969   static FT_Error
00970   bdf_create_property( char*        name,
00971                        int          format,
00972                        bdf_font_t*  font )
00973   {
00974     size_t           n;
00975     bdf_property_t*  p;
00976     FT_Memory        memory = font->memory;
00977     FT_Error         error = BDF_Err_Ok;
00978 
00979 
00980     /* First check to see if the property has      */
00981     /* already been added or not.  If it has, then */
00982     /* simply ignore it.                           */
00983     if ( hash_lookup( name, &(font->proptbl) ) )
00984       goto Exit;
00985 
00986     if ( FT_RENEW_ARRAY( font->user_props,
00987                          font->nuser_props,
00988                          font->nuser_props + 1 ) )
00989       goto Exit;
00990 
00991     p = font->user_props + font->nuser_props;
00992     FT_ZERO( p );
00993 
00994     n = ft_strlen( name ) + 1;
00995     if ( n > FT_ULONG_MAX )
00996       return BDF_Err_Invalid_Argument;
00997 
00998     if ( FT_NEW_ARRAY( p->name, n ) )
00999       goto Exit;
01000 
01001     FT_MEM_COPY( (char *)p->name, name, n );
01002 
01003     p->format  = format;
01004     p->builtin = 0;
01005 
01006     n = _num_bdf_properties + font->nuser_props;
01007 
01008     error = hash_insert( p->name, n, &(font->proptbl), memory );
01009     if ( error )
01010       goto Exit;
01011 
01012     font->nuser_props++;
01013 
01014   Exit:
01015     return error;
01016   }
01017 
01018 
01019   FT_LOCAL_DEF( bdf_property_t * )
01020   bdf_get_property( char*        name,
01021                     bdf_font_t*  font )
01022   {
01023     hashnode  hn;
01024     size_t    propid;
01025 
01026 
01027     if ( name == 0 || *name == 0 )
01028       return 0;
01029 
01030     if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
01031       return 0;
01032 
01033     propid = hn->data;
01034     if ( propid >= _num_bdf_properties )
01035       return font->user_props + ( propid - _num_bdf_properties );
01036 
01037     return (bdf_property_t*)_bdf_properties + propid;
01038   }
01039 
01040 
01041   /*************************************************************************/
01042   /*                                                                       */
01043   /* BDF font file parsing flags and functions.                            */
01044   /*                                                                       */
01045   /*************************************************************************/
01046 
01047 
01048   /* Parse flags. */
01049 
01050 #define _BDF_START      0x0001
01051 #define _BDF_FONT_NAME  0x0002
01052 #define _BDF_SIZE       0x0004
01053 #define _BDF_FONT_BBX   0x0008
01054 #define _BDF_PROPS      0x0010
01055 #define _BDF_GLYPHS     0x0020
01056 #define _BDF_GLYPH      0x0040
01057 #define _BDF_ENCODING   0x0080
01058 #define _BDF_SWIDTH     0x0100
01059 #define _BDF_DWIDTH     0x0200
01060 #define _BDF_BBX        0x0400
01061 #define _BDF_BITMAP     0x0800
01062 
01063 #define _BDF_SWIDTH_ADJ  0x1000
01064 
01065 #define _BDF_GLYPH_BITS ( _BDF_GLYPH    | \
01066                           _BDF_ENCODING | \
01067                           _BDF_SWIDTH   | \
01068                           _BDF_DWIDTH   | \
01069                           _BDF_BBX      | \
01070                           _BDF_BITMAP   )
01071 
01072 #define _BDF_GLYPH_WIDTH_CHECK   0x40000000UL
01073 #define _BDF_GLYPH_HEIGHT_CHECK  0x80000000UL
01074 
01075 
01076   /* Auto correction messages. */
01077 #define ACMSG1   "FONT_ASCENT property missing.  " \
01078                  "Added \"FONT_ASCENT %hd\".\n"
01079 #define ACMSG2   "FONT_DESCENT property missing.  " \
01080                  "Added \"FONT_DESCENT %hd\".\n"
01081 #define ACMSG3   "Font width != actual width.  Old: %hd New: %hd.\n"
01082 #define ACMSG4   "Font left bearing != actual left bearing.  " \
01083                  "Old: %hd New: %hd.\n"
01084 #define ACMSG5   "Font ascent != actual ascent.  Old: %hd New: %hd.\n"
01085 #define ACMSG6   "Font descent != actual descent.  Old: %hd New: %hd.\n"
01086 #define ACMSG7   "Font height != actual height. Old: %hd New: %hd.\n"
01087 #define ACMSG8   "Glyph scalable width (SWIDTH) adjustments made.\n"
01088 #define ACMSG9   "SWIDTH field missing at line %ld.  Set automatically.\n"
01089 #define ACMSG10  "DWIDTH field missing at line %ld.  Set to glyph width.\n"
01090 #define ACMSG11  "SIZE bits per pixel field adjusted to %hd.\n"
01091 #define ACMSG12  "Duplicate encoding %ld (%s) changed to unencoded.\n"
01092 #define ACMSG13  "Glyph %ld extra rows removed.\n"
01093 #define ACMSG14  "Glyph %ld extra columns removed.\n"
01094 #define ACMSG15  "Incorrect glyph count: %ld indicated but %ld found.\n"
01095 
01096   /* Error messages. */
01097 #define ERRMSG1  "[line %ld] Missing \"%s\" line.\n"
01098 #define ERRMSG2  "[line %ld] Font header corrupted or missing fields.\n"
01099 #define ERRMSG3  "[line %ld] Font glyphs corrupted or missing fields.\n"
01100 #define ERRMSG4  "[line %ld] BBX too big.\n"
01101 
01102 
01103   static FT_Error
01104   _bdf_add_comment( bdf_font_t*    font,
01105                     char*          comment,
01106                     unsigned long  len )
01107   {
01108     char*      cp;
01109     FT_Memory  memory = font->memory;
01110     FT_Error   error = BDF_Err_Ok;
01111 
01112 
01113     if ( FT_RENEW_ARRAY( font->comments,
01114                          font->comments_len,
01115                          font->comments_len + len + 1 ) )
01116       goto Exit;
01117 
01118     cp = font->comments + font->comments_len;
01119 
01120     FT_MEM_COPY( cp, comment, len );
01121     cp[len] = '\n';
01122 
01123     font->comments_len += len + 1;
01124 
01125   Exit:
01126     return error;
01127   }
01128 
01129 
01130   /* Set the spacing from the font name if it exists, or set it to the */
01131   /* default specified in the options.                                 */
01132   static FT_Error
01133   _bdf_set_default_spacing( bdf_font_t*     font,
01134                             bdf_options_t*  opts )
01135   {
01136     size_t       len;
01137     char         name[256];
01138     _bdf_list_t  list;
01139     FT_Memory    memory;
01140     FT_Error     error = BDF_Err_Ok;
01141 
01142 
01143     if ( font == 0 || font->name == 0 || font->name[0] == 0 )
01144     {
01145       error = BDF_Err_Invalid_Argument;
01146       goto Exit;
01147     }
01148 
01149     memory = font->memory;
01150 
01151     _bdf_list_init( &list, memory );
01152 
01153     font->spacing = opts->font_spacing;
01154 
01155     len = ft_strlen( font->name ) + 1;
01156     /* Limit ourselves to 256 characters in the font name. */
01157     if ( len >= 256 )
01158     {
01159       error = BDF_Err_Invalid_Argument;
01160       goto Exit;
01161     }
01162 
01163     FT_MEM_COPY( name, font->name, len );
01164 
01165     error = _bdf_list_split( &list, (char *)"-", name, len );
01166     if ( error )
01167       goto Fail;
01168 
01169     if ( list.used == 15 )
01170     {
01171       switch ( list.field[11][0] )
01172       {
01173       case 'C':
01174       case 'c':
01175         font->spacing = BDF_CHARCELL;
01176         break;
01177       case 'M':
01178       case 'm':
01179         font->spacing = BDF_MONOWIDTH;
01180         break;
01181       case 'P':
01182       case 'p':
01183         font->spacing = BDF_PROPORTIONAL;
01184         break;
01185       }
01186     }
01187 
01188   Fail:
01189     _bdf_list_done( &list );
01190 
01191   Exit:
01192     return error;
01193   }
01194 
01195 
01196   /* Determine whether the property is an atom or not.  If it is, then */
01197   /* clean it up so the double quotes are removed if they exist.       */
01198   static int
01199   _bdf_is_atom( char*          line,
01200                 unsigned long  linelen,
01201                 char**         name,
01202                 char**         value,
01203                 bdf_font_t*    font )
01204   {
01205     int              hold;
01206     char             *sp, *ep;
01207     bdf_property_t*  p;
01208 
01209 
01210     *name = sp = ep = line;
01211 
01212     while ( *ep && *ep != ' ' && *ep != '\t' )
01213       ep++;
01214 
01215     hold = -1;
01216     if ( *ep )
01217     {
01218       hold = *ep;
01219       *ep  = 0;
01220     }
01221 
01222     p = bdf_get_property( sp, font );
01223 
01224     /* Restore the character that was saved before any return can happen. */
01225     if ( hold != -1 )
01226       *ep = (char)hold;
01227 
01228     /* If the property exists and is not an atom, just return here. */
01229     if ( p && p->format != BDF_ATOM )
01230       return 0;
01231 
01232     /* The property is an atom.  Trim all leading and trailing whitespace */
01233     /* and double quotes for the atom value.                              */
01234     sp = ep;
01235     ep = line + linelen;
01236 
01237     /* Trim the leading whitespace if it exists. */
01238     *sp++ = 0;
01239     while ( *sp                           &&
01240             ( *sp == ' ' || *sp == '\t' ) )
01241       sp++;
01242 
01243     /* Trim the leading double quote if it exists. */
01244     if ( *sp == '"' )
01245       sp++;
01246     *value = sp;
01247 
01248     /* Trim the trailing whitespace if it exists. */
01249     while ( ep > sp                                       &&
01250             ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
01251       *--ep = 0;
01252 
01253     /* Trim the trailing double quote if it exists. */
01254     if ( ep > sp && *( ep - 1 ) == '"' )
01255       *--ep = 0;
01256 
01257     return 1;
01258   }
01259 
01260 
01261   static FT_Error
01262   _bdf_add_property( bdf_font_t*  font,
01263                      char*        name,
01264                      char*        value )
01265   {
01266     size_t          propid;
01267     hashnode        hn;
01268     bdf_property_t  *prop, *fp;
01269     FT_Memory       memory = font->memory;
01270     FT_Error        error = BDF_Err_Ok;
01271 
01272 
01273     /* First, check to see if the property already exists in the font. */
01274     if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
01275     {
01276       /* The property already exists in the font, so simply replace */
01277       /* the value of the property with the current value.          */
01278       fp = font->props + hn->data;
01279 
01280       switch ( fp->format )
01281       {
01282       case BDF_ATOM:
01283         /* Delete the current atom if it exists. */
01284         FT_FREE( fp->value.atom );
01285 
01286         if ( value && value[0] != 0 )
01287         {
01288           if ( FT_STRDUP( fp->value.atom, value ) )
01289             goto Exit;
01290         }
01291         break;
01292 
01293       case BDF_INTEGER:
01294         fp->value.l = _bdf_atol( value, 0, 10 );
01295         break;
01296 
01297       case BDF_CARDINAL:
01298         fp->value.ul = _bdf_atoul( value, 0, 10 );
01299         break;
01300 
01301       default:
01302         ;
01303       }
01304 
01305       goto Exit;
01306     }
01307 
01308     /* See whether this property type exists yet or not. */
01309     /* If not, create it.                                */
01310     hn = hash_lookup( name, &(font->proptbl) );
01311     if ( hn == 0 )
01312     {
01313       error = bdf_create_property( name, BDF_ATOM, font );
01314       if ( error )
01315         goto Exit;
01316       hn = hash_lookup( name, &(font->proptbl) );
01317     }
01318 
01319     /* Allocate another property if this is overflow. */
01320     if ( font->props_used == font->props_size )
01321     {
01322       if ( font->props_size == 0 )
01323       {
01324         if ( FT_NEW_ARRAY( font->props, 1 ) )
01325           goto Exit;
01326       }
01327       else
01328       {
01329         if ( FT_RENEW_ARRAY( font->props,
01330                              font->props_size,
01331                              font->props_size + 1 ) )
01332           goto Exit;
01333       }
01334 
01335       fp = font->props + font->props_size;
01336       FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
01337       font->props_size++;
01338     }
01339 
01340     propid = hn->data;
01341     if ( propid >= _num_bdf_properties )
01342       prop = font->user_props + ( propid - _num_bdf_properties );
01343     else
01344       prop = (bdf_property_t*)_bdf_properties + propid;
01345 
01346     fp = font->props + font->props_used;
01347 
01348     fp->name    = prop->name;
01349     fp->format  = prop->format;
01350     fp->builtin = prop->builtin;
01351 
01352     switch ( prop->format )
01353     {
01354     case BDF_ATOM:
01355       fp->value.atom = 0;
01356       if ( value != 0 && value[0] )
01357       {
01358         if ( FT_STRDUP( fp->value.atom, value ) )
01359           goto Exit;
01360       }
01361       break;
01362 
01363     case BDF_INTEGER:
01364       fp->value.l = _bdf_atol( value, 0, 10 );
01365       break;
01366 
01367     case BDF_CARDINAL:
01368       fp->value.ul = _bdf_atoul( value, 0, 10 );
01369       break;
01370     }
01371 
01372     /* If the property happens to be a comment, then it doesn't need */
01373     /* to be added to the internal hash table.                       */
01374     if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) {
01375       /* Add the property to the font property table. */
01376       error = hash_insert( fp->name,
01377                            font->props_used,
01378                            (hashtable *)font->internal,
01379                            memory );
01380       if ( error )
01381         goto Exit;
01382     }
01383 
01384     font->props_used++;
01385 
01386     /* Some special cases need to be handled here.  The DEFAULT_CHAR       */
01387     /* property needs to be located if it exists in the property list, the */
01388     /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are        */
01389     /* present, and the SPACING property should override the default       */
01390     /* spacing.                                                            */
01391     if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
01392       font->default_char = fp->value.l;
01393     else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
01394       font->font_ascent = fp->value.l;
01395     else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
01396       font->font_descent = fp->value.l;
01397     else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
01398     {
01399       if ( !fp->value.atom )
01400       {
01401         error = BDF_Err_Invalid_File_Format;
01402         goto Exit;
01403       }
01404 
01405       if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
01406         font->spacing = BDF_PROPORTIONAL;
01407       else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
01408         font->spacing = BDF_MONOWIDTH;
01409       else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
01410         font->spacing = BDF_CHARCELL;
01411     }
01412 
01413   Exit:
01414     return error;
01415   }
01416 
01417 
01418   static const unsigned char nibble_mask[8] =
01419   {
01420     0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
01421   };
01422 
01423 
01424   /* Actually parse the glyph info and bitmaps. */
01425   static FT_Error
01426   _bdf_parse_glyphs( char*          line,
01427                      unsigned long  linelen,
01428                      unsigned long  lineno,
01429                      void*          call_data,
01430                      void*          client_data )
01431   {
01432     int                c, mask_index;
01433     char*              s;
01434     unsigned char*     bp;
01435     unsigned long      i, slen, nibbles;
01436 
01437     _bdf_parse_t*      p;
01438     bdf_glyph_t*       glyph;
01439     bdf_font_t*        font;
01440 
01441     FT_Memory          memory;
01442     FT_Error           error = BDF_Err_Ok;
01443 
01444     FT_UNUSED( call_data );
01445     FT_UNUSED( lineno );        /* only used in debug mode */
01446 
01447 
01448     p = (_bdf_parse_t *)client_data;
01449 
01450     font   = p->font;
01451     memory = font->memory;
01452 
01453     /* Check for a comment. */
01454     if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
01455     {
01456       linelen -= 7;
01457 
01458       s = line + 7;
01459       if ( *s != 0 )
01460       {
01461         s++;
01462         linelen--;
01463       }
01464       error = _bdf_add_comment( p->font, s, linelen );
01465       goto Exit;
01466     }
01467 
01468     /* The very first thing expected is the number of glyphs. */
01469     if ( !( p->flags & _BDF_GLYPHS ) )
01470     {
01471       if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
01472       {
01473         FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
01474         error = BDF_Err_Missing_Chars_Field;
01475         goto Exit;
01476       }
01477 
01478       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
01479       if ( error )
01480         goto Exit;
01481       p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
01482 
01483       /* Make sure the number of glyphs is non-zero. */
01484       if ( p->cnt == 0 )
01485         font->glyphs_size = 64;
01486 
01487       /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
01488       /* number of code points available in Unicode).                 */
01489       if ( p->cnt >= 1114112UL )
01490       {
01491         error = BDF_Err_Invalid_Argument;
01492         goto Exit;
01493       }
01494 
01495       if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
01496         goto Exit;
01497 
01498       p->flags |= _BDF_GLYPHS;
01499 
01500       goto Exit;
01501     }
01502 
01503     /* Check for the ENDFONT field. */
01504     if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
01505     {
01506       /* Sort the glyphs by encoding. */
01507       ft_qsort( (char *)font->glyphs,
01508                 font->glyphs_used,
01509                 sizeof ( bdf_glyph_t ),
01510                 by_encoding );
01511 
01512       p->flags &= ~_BDF_START;
01513 
01514       goto Exit;
01515     }
01516 
01517     /* Check for the ENDCHAR field. */
01518     if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
01519     {
01520       p->glyph_enc = 0;
01521       p->flags    &= ~_BDF_GLYPH_BITS;
01522 
01523       goto Exit;
01524     }
01525 
01526     /* Check to see whether a glyph is being scanned but should be */
01527     /* ignored because it is an unencoded glyph.                   */
01528     if ( ( p->flags & _BDF_GLYPH )     &&
01529          p->glyph_enc            == -1 &&
01530          p->opts->keep_unencoded == 0  )
01531       goto Exit;
01532 
01533     /* Check for the STARTCHAR field. */
01534     if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
01535     {
01536       /* Set the character name in the parse info first until the */
01537       /* encoding can be checked for an unencoded character.      */
01538       FT_FREE( p->glyph_name );
01539 
01540       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
01541       if ( error )
01542         goto Exit;
01543 
01544       _bdf_list_shift( &p->list, 1 );
01545 
01546       s = _bdf_list_join( &p->list, ' ', &slen );
01547 
01548       if ( !s )
01549       {
01550         error = BDF_Err_Invalid_File_Format;
01551         goto Exit;
01552       }
01553 
01554       if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
01555         goto Exit;
01556 
01557       FT_MEM_COPY( p->glyph_name, s, slen + 1 );
01558 
01559       p->flags |= _BDF_GLYPH;
01560 
01561       goto Exit;
01562     }
01563 
01564     /* Check for the ENCODING field. */
01565     if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
01566     {
01567       if ( !( p->flags & _BDF_GLYPH ) )
01568       {
01569         /* Missing STARTCHAR field. */
01570         FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
01571         error = BDF_Err_Missing_Startchar_Field;
01572         goto Exit;
01573       }
01574 
01575       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
01576       if ( error )
01577         goto Exit;
01578 
01579       p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
01580 
01581       /* Check that the encoding is in the range [0,65536] because        */
01582       /* otherwise p->have (a bitmap with static size) overflows.         */
01583       if ( (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
01584       {
01585         error = BDF_Err_Invalid_File_Format;
01586         goto Exit;
01587       }
01588 
01589       /* Check to see whether this encoding has already been encountered. */
01590       /* If it has then change it to unencoded so it gets added if        */
01591       /* indicated.                                                       */
01592       if ( p->glyph_enc >= 0 )
01593       {
01594         if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
01595         {
01596           /* Emit a message saying a glyph has been moved to the */
01597           /* unencoded area.                                     */
01598           FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
01599                       p->glyph_enc, p->glyph_name ));
01600           p->glyph_enc = -1;
01601           font->modified = 1;
01602         }
01603         else
01604           _bdf_set_glyph_modified( p->have, p->glyph_enc );
01605       }
01606 
01607       if ( p->glyph_enc >= 0 )
01608       {
01609         /* Make sure there are enough glyphs allocated in case the */
01610         /* number of characters happen to be wrong.                */
01611         if ( font->glyphs_used == font->glyphs_size )
01612         {
01613           if ( FT_RENEW_ARRAY( font->glyphs,
01614                                font->glyphs_size,
01615                                font->glyphs_size + 64 ) )
01616             goto Exit;
01617 
01618           font->glyphs_size += 64;
01619         }
01620 
01621         glyph           = font->glyphs + font->glyphs_used++;
01622         glyph->name     = p->glyph_name;
01623         glyph->encoding = p->glyph_enc;
01624 
01625         /* Reset the initial glyph info. */
01626         p->glyph_name = 0;
01627       }
01628       else
01629       {
01630         /* Unencoded glyph.  Check to see whether it should */
01631         /* be added or not.                                 */
01632         if ( p->opts->keep_unencoded != 0 )
01633         {
01634           /* Allocate the next unencoded glyph. */
01635           if ( font->unencoded_used == font->unencoded_size )
01636           {
01637             if ( FT_RENEW_ARRAY( font->unencoded ,
01638                                  font->unencoded_size,
01639                                  font->unencoded_size + 4 ) )
01640               goto Exit;
01641 
01642             font->unencoded_size += 4;
01643           }
01644 
01645           glyph           = font->unencoded + font->unencoded_used;
01646           glyph->name     = p->glyph_name;
01647           glyph->encoding = font->unencoded_used++;
01648         }
01649         else
01650           /* Free up the glyph name if the unencoded shouldn't be */
01651           /* kept.                                                */
01652           FT_FREE( p->glyph_name );
01653 
01654         p->glyph_name = 0;
01655       }
01656 
01657       /* Clear the flags that might be added when width and height are */
01658       /* checked for consistency.                                      */
01659       p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
01660 
01661       p->flags |= _BDF_ENCODING;
01662 
01663       goto Exit;
01664     }
01665 
01666     /* Point at the glyph being constructed. */
01667     if ( p->glyph_enc == -1 )
01668       glyph = font->unencoded + ( font->unencoded_used - 1 );
01669     else
01670       glyph = font->glyphs + ( font->glyphs_used - 1 );
01671 
01672     /* Check to see whether a bitmap is being constructed. */
01673     if ( p->flags & _BDF_BITMAP )
01674     {
01675       /* If there are more rows than are specified in the glyph metrics, */
01676       /* ignore the remaining lines.                                     */
01677       if ( p->row >= (unsigned long)glyph->bbx.height )
01678       {
01679         if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
01680         {
01681           FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
01682           p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
01683           font->modified = 1;
01684         }
01685 
01686         goto Exit;
01687       }
01688 
01689       /* Only collect the number of nibbles indicated by the glyph     */
01690       /* metrics.  If there are more columns, they are simply ignored. */
01691       nibbles = glyph->bpr << 1;
01692       bp      = glyph->bitmap + p->row * glyph->bpr;
01693 
01694       for ( i = 0; i < nibbles; i++ )
01695       {
01696         c = line[i];
01697         *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
01698         if ( i + 1 < nibbles && ( i & 1 ) )
01699           *++bp = 0;
01700       }
01701 
01702       /* Remove possible garbage at the right. */
01703       mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
01704       if ( glyph->bbx.width )
01705         *bp &= nibble_mask[mask_index];
01706 
01707       /* If any line has extra columns, indicate they have been removed. */
01708       if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
01709            !( p->flags & _BDF_GLYPH_WIDTH_CHECK )                   )
01710       {
01711         FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
01712         p->flags       |= _BDF_GLYPH_WIDTH_CHECK;
01713         font->modified  = 1;
01714       }
01715 
01716       p->row++;
01717       goto Exit;
01718     }
01719 
01720     /* Expect the SWIDTH (scalable width) field next. */
01721     if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
01722     {
01723       if ( !( p->flags & _BDF_ENCODING ) )
01724       {
01725         /* Missing ENCODING field. */
01726         FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
01727         error = BDF_Err_Missing_Encoding_Field;
01728         goto Exit;
01729       }
01730 
01731       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
01732       if ( error )
01733         goto Exit;
01734 
01735       glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
01736       p->flags |= _BDF_SWIDTH;
01737 
01738       goto Exit;
01739     }
01740 
01741     /* Expect the DWIDTH (scalable width) field next. */
01742     if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
01743     {
01744       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
01745       if ( error )
01746         goto Exit;
01747 
01748       glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
01749 
01750       if ( !( p->flags & _BDF_SWIDTH ) )
01751       {
01752         /* Missing SWIDTH field.  Emit an auto correction message and set */
01753         /* the scalable width from the device width.                      */
01754         FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
01755 
01756         glyph->swidth = (unsigned short)FT_MulDiv(
01757                           glyph->dwidth, 72000L,
01758                           (FT_Long)( font->point_size *
01759                                      font->resolution_x ) );
01760       }
01761 
01762       p->flags |= _BDF_DWIDTH;
01763       goto Exit;
01764     }
01765 
01766     /* Expect the BBX field next. */
01767     if ( ft_memcmp( line, "BBX", 3 ) == 0 )
01768     {
01769       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
01770       if ( error )
01771         goto Exit;
01772 
01773       glyph->bbx.width    = _bdf_atos( p->list.field[1], 0, 10 );
01774       glyph->bbx.height   = _bdf_atos( p->list.field[2], 0, 10 );
01775       glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
01776       glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
01777 
01778       /* Generate the ascent and descent of the character. */
01779       glyph->bbx.ascent  = (short)( glyph->bbx.height + glyph->bbx.y_offset );
01780       glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
01781 
01782       /* Determine the overall font bounding box as the characters are */
01783       /* loaded so corrections can be done later if indicated.         */
01784       p->maxas    = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
01785       p->maxds    = (short)FT_MAX( glyph->bbx.descent, p->maxds );
01786 
01787       p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
01788 
01789       p->maxrb    = (short)FT_MAX( p->rbearing, p->maxrb );
01790       p->minlb    = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
01791       p->maxlb    = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
01792 
01793       if ( !( p->flags & _BDF_DWIDTH ) )
01794       {
01795         /* Missing DWIDTH field.  Emit an auto correction message and set */
01796         /* the device width to the glyph width.                           */
01797         FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
01798         glyph->dwidth = glyph->bbx.width;
01799       }
01800 
01801       /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
01802       /* value if necessary.                                            */
01803       if ( p->opts->correct_metrics != 0 )
01804       {
01805         /* Determine the point size of the glyph. */
01806         unsigned short  sw = (unsigned short)FT_MulDiv(
01807                                glyph->dwidth, 72000L,
01808                                (FT_Long)( font->point_size *
01809                                           font->resolution_x ) );
01810 
01811 
01812         if ( sw != glyph->swidth )
01813         {
01814           glyph->swidth = sw;
01815 
01816           if ( p->glyph_enc == -1 )
01817             _bdf_set_glyph_modified( font->umod,
01818                                      font->unencoded_used - 1 );
01819           else
01820             _bdf_set_glyph_modified( font->nmod, glyph->encoding );
01821 
01822           p->flags       |= _BDF_SWIDTH_ADJ;
01823           font->modified  = 1;
01824         }
01825       }
01826 
01827       p->flags |= _BDF_BBX;
01828       goto Exit;
01829     }
01830 
01831     /* And finally, gather up the bitmap. */
01832     if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
01833     {
01834       unsigned long  bitmap_size;
01835 
01836 
01837       if ( !( p->flags & _BDF_BBX ) )
01838       {
01839         /* Missing BBX field. */
01840         FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
01841         error = BDF_Err_Missing_Bbx_Field;
01842         goto Exit;
01843       }
01844 
01845       /* Allocate enough space for the bitmap. */
01846       glyph->bpr   = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
01847 
01848       bitmap_size = glyph->bpr * glyph->bbx.height;
01849       if ( bitmap_size > 0xFFFFU )
01850       {
01851         FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
01852         error = BDF_Err_Bbx_Too_Big;
01853         goto Exit;
01854       }
01855       else
01856         glyph->bytes = (unsigned short)bitmap_size;
01857 
01858       if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
01859         goto Exit;
01860 
01861       p->row    = 0;
01862       p->flags |= _BDF_BITMAP;
01863 
01864       goto Exit;
01865     }
01866 
01867     error = BDF_Err_Invalid_File_Format;
01868 
01869   Exit:
01870     return error;
01871   }
01872 
01873 
01874   /* Load the font properties. */
01875   static FT_Error
01876   _bdf_parse_properties( char*          line,
01877                          unsigned long  linelen,
01878                          unsigned long  lineno,
01879                          void*          call_data,
01880                          void*          client_data )
01881   {
01882     unsigned long      vlen;
01883     _bdf_line_func_t*  next;
01884     _bdf_parse_t*      p;
01885     char*              name;
01886     char*              value;
01887     char               nbuf[128];
01888     FT_Error           error = BDF_Err_Ok;
01889 
01890     FT_UNUSED( lineno );
01891 
01892 
01893     next = (_bdf_line_func_t *)call_data;
01894     p    = (_bdf_parse_t *)    client_data;
01895 
01896     /* Check for the end of the properties. */
01897     if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
01898     {
01899       /* If the FONT_ASCENT or FONT_DESCENT properties have not been      */
01900       /* encountered yet, then make sure they are added as properties and */
01901       /* make sure they are set from the font bounding box info.          */
01902       /*                                                                  */
01903       /* This is *always* done regardless of the options, because X11     */
01904       /* requires these two fields to compile fonts.                      */
01905       if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
01906       {
01907         p->font->font_ascent = p->font->bbx.ascent;
01908         ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
01909         error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
01910         if ( error )
01911           goto Exit;
01912 
01913         FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
01914         p->font->modified = 1;
01915       }
01916 
01917       if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
01918       {
01919         p->font->font_descent = p->font->bbx.descent;
01920         ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
01921         error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
01922         if ( error )
01923           goto Exit;
01924 
01925         FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
01926         p->font->modified = 1;
01927       }
01928 
01929       p->flags &= ~_BDF_PROPS;
01930       *next     = _bdf_parse_glyphs;
01931 
01932       goto Exit;
01933     }
01934 
01935     /* Ignore the _XFREE86_GLYPH_RANGES properties. */
01936     if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
01937       goto Exit;
01938 
01939     /* Handle COMMENT fields and properties in a special way to preserve */
01940     /* the spacing.                                                      */
01941     if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
01942     {
01943       name = value = line;
01944       value += 7;
01945       if ( *value )
01946         *value++ = 0;
01947       error = _bdf_add_property( p->font, name, value );
01948       if ( error )
01949         goto Exit;
01950     }
01951     else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
01952     {
01953       error = _bdf_add_property( p->font, name, value );
01954       if ( error )
01955         goto Exit;
01956     }
01957     else
01958     {
01959       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
01960       if ( error )
01961         goto Exit;
01962       name = p->list.field[0];
01963 
01964       _bdf_list_shift( &p->list, 1 );
01965       value = _bdf_list_join( &p->list, ' ', &vlen );
01966 
01967       error = _bdf_add_property( p->font, name, value );
01968       if ( error )
01969         goto Exit;
01970     }
01971 
01972   Exit:
01973     return error;
01974   }
01975 
01976 
01977   /* Load the font header. */
01978   static FT_Error
01979   _bdf_parse_start( char*          line,
01980                     unsigned long  linelen,
01981                     unsigned long  lineno,
01982                     void*          call_data,
01983                     void*          client_data )
01984   {
01985     unsigned long      slen;
01986     _bdf_line_func_t*  next;
01987     _bdf_parse_t*      p;
01988     bdf_font_t*        font;
01989     char               *s;
01990 
01991     FT_Memory          memory = NULL;
01992     FT_Error           error  = BDF_Err_Ok;
01993 
01994     FT_UNUSED( lineno );            /* only used in debug mode */
01995 
01996 
01997     next = (_bdf_line_func_t *)call_data;
01998     p    = (_bdf_parse_t *)    client_data;
01999 
02000     if ( p->font )
02001       memory = p->font->memory;
02002 
02003     /* Check for a comment.  This is done to handle those fonts that have */
02004     /* comments before the STARTFONT line for some reason.                */
02005     if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
02006     {
02007       if ( p->opts->keep_comments != 0 && p->font != 0 )
02008       {
02009         linelen -= 7;
02010 
02011         s = line + 7;
02012         if ( *s != 0 )
02013         {
02014           s++;
02015           linelen--;
02016         }
02017 
02018         error = _bdf_add_comment( p->font, s, linelen );
02019         if ( error )
02020           goto Exit;
02021         /* here font is not defined! */
02022       }
02023 
02024       goto Exit;
02025     }
02026 
02027     if ( !( p->flags & _BDF_START ) )
02028     {
02029       memory = p->memory;
02030 
02031       if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
02032       {
02033         /* No STARTFONT field is a good indication of a problem. */
02034         error = BDF_Err_Missing_Startfont_Field;
02035         goto Exit;
02036       }
02037 
02038       p->flags = _BDF_START;
02039       font = p->font = 0;
02040 
02041       if ( FT_NEW( font ) )
02042         goto Exit;
02043       p->font = font;
02044 
02045       font->memory = p->memory;
02046       p->memory    = 0;
02047 
02048       { /* setup */
02049         size_t           i;
02050         bdf_property_t*  prop;
02051 
02052 
02053         error = hash_init( &(font->proptbl), memory );
02054         if ( error )
02055           goto Exit;
02056         for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
02057               i < _num_bdf_properties; i++, prop++ )
02058         {
02059           error = hash_insert( prop->name, i,
02060                                &(font->proptbl), memory );
02061           if ( error )
02062             goto Exit;
02063         }
02064       }
02065 
02066       if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
02067         goto Exit;
02068       error = hash_init( (hashtable *)p->font->internal,memory );
02069       if ( error )
02070         goto Exit;
02071       p->font->spacing      = p->opts->font_spacing;
02072       p->font->default_char = -1;
02073 
02074       goto Exit;
02075     }
02076 
02077     /* Check for the start of the properties. */
02078     if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
02079     {
02080       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
02081       if ( error )
02082         goto Exit;
02083       /* at this point, `p->font' can't be NULL */
02084       p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
02085 
02086       if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
02087         goto Exit;
02088 
02089       p->flags |= _BDF_PROPS;
02090       *next     = _bdf_parse_properties;
02091 
02092       goto Exit;
02093     }
02094 
02095     /* Check for the FONTBOUNDINGBOX field. */
02096     if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
02097     {
02098       if ( !(p->flags & _BDF_SIZE ) )
02099       {
02100         /* Missing the SIZE field. */
02101         FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
02102         error = BDF_Err_Missing_Size_Field;
02103         goto Exit;
02104       }
02105 
02106       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
02107       if ( error )
02108         goto Exit;
02109 
02110       p->font->bbx.width  = _bdf_atos( p->list.field[1], 0, 10 );
02111       p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
02112 
02113       p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
02114       p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
02115 
02116       p->font->bbx.ascent  = (short)( p->font->bbx.height +
02117                                       p->font->bbx.y_offset );
02118 
02119       p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
02120 
02121       p->flags |= _BDF_FONT_BBX;
02122 
02123       goto Exit;
02124     }
02125 
02126     /* The next thing to check for is the FONT field. */
02127     if ( ft_memcmp( line, "FONT", 4 ) == 0 )
02128     {
02129       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
02130       if ( error )
02131         goto Exit;
02132       _bdf_list_shift( &p->list, 1 );
02133 
02134       s = _bdf_list_join( &p->list, ' ', &slen );
02135 
02136       if ( !s )
02137       {
02138         error = BDF_Err_Invalid_File_Format;
02139         goto Exit;
02140       }
02141 
02142       if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
02143         goto Exit;
02144       FT_MEM_COPY( p->font->name, s, slen + 1 );
02145 
02146       /* If the font name is an XLFD name, set the spacing to the one in  */
02147       /* the font name.  If there is no spacing fall back on the default. */
02148       error = _bdf_set_default_spacing( p->font, p->opts );
02149       if ( error )
02150         goto Exit;
02151 
02152       p->flags |= _BDF_FONT_NAME;
02153 
02154       goto Exit;
02155     }
02156 
02157     /* Check for the SIZE field. */
02158     if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
02159     {
02160       if ( !( p->flags & _BDF_FONT_NAME ) )
02161       {
02162         /* Missing the FONT field. */
02163         FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
02164         error = BDF_Err_Missing_Font_Field;
02165         goto Exit;
02166       }
02167 
02168       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
02169       if ( error )
02170         goto Exit;
02171 
02172       p->font->point_size   = _bdf_atoul( p->list.field[1], 0, 10 );
02173       p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
02174       p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
02175 
02176       /* Check for the bits per pixel field. */
02177       if ( p->list.used == 5 )
02178       {
02179         unsigned short bitcount, i, shift;
02180 
02181 
02182         p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
02183 
02184         /* Only values 1, 2, 4, 8 are allowed. */
02185         shift = p->font->bpp;
02186         bitcount = 0;
02187         for ( i = 0; shift > 0; i++ )
02188         {
02189           if ( shift & 1 )
02190             bitcount = i;
02191           shift >>= 1;
02192         }
02193 
02194         shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
02195 
02196         if ( p->font->bpp > shift || p->font->bpp != shift )
02197         {
02198           /* select next higher value */
02199           p->font->bpp = (unsigned short)( shift << 1 );
02200           FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
02201         }
02202       }
02203       else
02204         p->font->bpp = 1;
02205 
02206       p->flags |= _BDF_SIZE;
02207 
02208       goto Exit;
02209     }
02210 
02211     error = BDF_Err_Invalid_File_Format;
02212 
02213   Exit:
02214     return error;
02215   }
02216 
02217 
02218   /*************************************************************************/
02219   /*                                                                       */
02220   /* API.                                                                  */
02221   /*                                                                       */
02222   /*************************************************************************/
02223 
02224 
02225   FT_LOCAL_DEF( FT_Error )
02226   bdf_load_font( FT_Stream       stream,
02227                  FT_Memory       extmemory,
02228                  bdf_options_t*  opts,
02229                  bdf_font_t*    *font )
02230   {
02231     unsigned long  lineno = 0; /* make compiler happy */
02232     _bdf_parse_t   *p;
02233 
02234     FT_Memory      memory = extmemory;
02235     FT_Error       error  = BDF_Err_Ok;
02236 
02237 
02238     if ( FT_NEW( p ) )
02239       goto Exit;
02240 
02241     memory    = NULL;
02242     p->opts   = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
02243     p->minlb  = 32767;
02244     p->memory = extmemory;  /* only during font creation */
02245 
02246     _bdf_list_init( &p->list, extmemory );
02247 
02248     error = _bdf_readstream( stream, _bdf_parse_start,
02249                              (void *)p, &lineno );
02250     if ( error )
02251       goto Fail;
02252 
02253     if ( p->font != 0 )
02254     {
02255       /* If the font is not proportional, set the font's monowidth */
02256       /* field to the width of the font bounding box.              */
02257       memory = p->font->memory;
02258 
02259       if ( p->font->spacing != BDF_PROPORTIONAL )
02260         p->font->monowidth = p->font->bbx.width;
02261 
02262       /* If the number of glyphs loaded is not that of the original count, */
02263       /* indicate the difference.                                          */
02264       if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
02265       {
02266         FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
02267                     p->font->glyphs_used + p->font->unencoded_used ));
02268         p->font->modified = 1;
02269       }
02270 
02271       /* Once the font has been loaded, adjust the overall font metrics if */
02272       /* necessary.                                                        */
02273       if ( p->opts->correct_metrics != 0 &&
02274            ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
02275       {
02276         if ( p->maxrb - p->minlb != p->font->bbx.width )
02277         {
02278           FT_TRACE2(( "bdf_load_font: " ACMSG3,
02279                       p->font->bbx.width, p->maxrb - p->minlb ));
02280           p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
02281           p->font->modified  = 1;
02282         }
02283 
02284         if ( p->font->bbx.x_offset != p->minlb )
02285         {
02286           FT_TRACE2(( "bdf_load_font: " ACMSG4,
02287                       p->font->bbx.x_offset, p->minlb ));
02288           p->font->bbx.x_offset = p->minlb;
02289           p->font->modified     = 1;
02290         }
02291 
02292         if ( p->font->bbx.ascent != p->maxas )
02293         {
02294           FT_TRACE2(( "bdf_load_font: " ACMSG5,
02295                       p->font->bbx.ascent, p->maxas ));
02296           p->font->bbx.ascent = p->maxas;
02297           p->font->modified   = 1;
02298         }
02299 
02300         if ( p->font->bbx.descent != p->maxds )
02301         {
02302           FT_TRACE2(( "bdf_load_font: " ACMSG6,
02303                       p->font->bbx.descent, p->maxds ));
02304           p->font->bbx.descent  = p->maxds;
02305           p->font->bbx.y_offset = (short)( -p->maxds );
02306           p->font->modified     = 1;
02307         }
02308 
02309         if ( p->maxas + p->maxds != p->font->bbx.height )
02310         {
02311           FT_TRACE2(( "bdf_load_font: " ACMSG7,
02312                       p->font->bbx.height, p->maxas + p->maxds ));
02313           p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
02314         }
02315 
02316         if ( p->flags & _BDF_SWIDTH_ADJ )
02317           FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
02318       }
02319     }
02320 
02321     if ( p->flags & _BDF_START )
02322     {
02323       {
02324         /* The ENDFONT field was never reached or did not exist. */
02325         if ( !( p->flags & _BDF_GLYPHS ) )
02326         {
02327           /* Error happened while parsing header. */
02328           FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
02329           error = BDF_Err_Corrupted_Font_Header;
02330           goto Exit;
02331         }
02332         else
02333         {
02334           /* Error happened when parsing glyphs. */
02335           FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
02336           error = BDF_Err_Corrupted_Font_Glyphs;
02337           goto Exit;
02338         }
02339       }
02340     }
02341 
02342     if ( p->font != 0 )
02343     {
02344       /* Make sure the comments are NULL terminated if they exist. */
02345       memory = p->font->memory;
02346 
02347       if ( p->font->comments_len > 0 ) {
02348         if ( FT_RENEW_ARRAY( p->font->comments,
02349                              p->font->comments_len,
02350                              p->font->comments_len + 1 ) )
02351           goto Fail;
02352 
02353         p->font->comments[p->font->comments_len] = 0;
02354       }
02355     }
02356     else if ( error == BDF_Err_Ok )
02357       error = BDF_Err_Invalid_File_Format;
02358 
02359     *font = p->font;
02360 
02361   Exit:
02362     if ( p )
02363     {
02364       _bdf_list_done( &p->list );
02365 
02366       memory = extmemory;
02367 
02368       FT_FREE( p );
02369     }
02370 
02371     return error;
02372 
02373   Fail:
02374     bdf_free_font( p->font );
02375 
02376     memory = extmemory;
02377 
02378     FT_FREE( p->font );
02379 
02380     goto Exit;
02381   }
02382 
02383 
02384   FT_LOCAL_DEF( void )
02385   bdf_free_font( bdf_font_t*  font )
02386   {
02387     bdf_property_t*  prop;
02388     unsigned long    i;
02389     bdf_glyph_t*     glyphs;
02390     FT_Memory        memory;
02391 
02392 
02393     if ( font == 0 )
02394       return;
02395 
02396     memory = font->memory;
02397 
02398     FT_FREE( font->name );
02399 
02400     /* Free up the internal hash table of property names. */
02401     if ( font->internal )
02402     {
02403       hash_free( (hashtable *)font->internal, memory );
02404       FT_FREE( font->internal );
02405     }
02406 
02407     /* Free up the comment info. */
02408     FT_FREE( font->comments );
02409 
02410     /* Free up the properties. */
02411     for ( i = 0; i < font->props_size; i++ )
02412     {
02413       if ( font->props[i].format == BDF_ATOM )
02414         FT_FREE( font->props[i].value.atom );
02415     }
02416 
02417     FT_FREE( font->props );
02418 
02419     /* Free up the character info. */
02420     for ( i = 0, glyphs = font->glyphs;
02421           i < font->glyphs_used; i++, glyphs++ )
02422     {
02423       FT_FREE( glyphs->name );
02424       FT_FREE( glyphs->bitmap );
02425     }
02426 
02427     for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
02428           i++, glyphs++ )
02429     {
02430       FT_FREE( glyphs->name );
02431       FT_FREE( glyphs->bitmap );
02432     }
02433 
02434     FT_FREE( font->glyphs );
02435     FT_FREE( font->unencoded );
02436 
02437     /* Free up the overflow storage if it was used. */
02438     for ( i = 0, glyphs = font->overflow.glyphs;
02439           i < font->overflow.glyphs_used; i++, glyphs++ )
02440     {
02441       FT_FREE( glyphs->name );
02442       FT_FREE( glyphs->bitmap );
02443     }
02444 
02445     FT_FREE( font->overflow.glyphs );
02446 
02447     /* bdf_cleanup */
02448     hash_free( &(font->proptbl), memory );
02449 
02450     /* Free up the user defined properties. */
02451     for (prop = font->user_props, i = 0;
02452          i < font->nuser_props; i++, prop++ )
02453     {
02454       FT_FREE( prop->name );
02455       if ( prop->format == BDF_ATOM )
02456         FT_FREE( prop->value.atom );
02457     }
02458 
02459     FT_FREE( font->user_props );
02460 
02461     /* FREE( font ); */ /* XXX Fixme */
02462   }
02463 
02464 
02465   FT_LOCAL_DEF( bdf_property_t * )
02466   bdf_get_font_property( bdf_font_t*  font,
02467                          const char*  name )
02468   {
02469     hashnode  hn;
02470 
02471 
02472     if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
02473       return 0;
02474 
02475     hn = hash_lookup( name, (hashtable *)font->internal );
02476 
02477     return hn ? ( font->props + hn->data ) : 0;
02478   }
02479 
02480 
02481 /* END */

Generated on Tue Jul 5 14:13:44 2011 for ROOT_528-00b_version by  doxygen 1.5.1