ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

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, 2010
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   /* An empty string for empty fields. */
00474 
00475   static const char  empty[1] = { 0 };      /* XXX eliminate this */
00476 
00477 
00478   static char *
00479   _bdf_list_join( _bdf_list_t*    list,
00480                   int             c,
00481                   unsigned long  *alen )
00482   {
00483     unsigned long  i, j;
00484     char           *fp, *dp;
00485 
00486 
00487     *alen = 0;
00488 
00489     if ( list == 0 || list->used == 0 )
00490       return 0;
00491 
00492     dp = list->field[0];
00493     for ( i = j = 0; i < list->used; i++ )
00494     {
00495       fp = list->field[i];
00496       while ( *fp )
00497         dp[j++] = *fp++;
00498 
00499       if ( i + 1 < list->used )
00500         dp[j++] = (char)c;
00501     }
00502     if ( dp != empty )
00503       dp[j] = 0;
00504 
00505     *alen = j;
00506     return dp;
00507   }
00508 
00509 
00510   static FT_Error
00511   _bdf_list_split( _bdf_list_t*   list,
00512                    char*          separators,
00513                    char*          line,
00514                    unsigned long  linelen )
00515   {
00516     int       mult, final_empty;
00517     char      *sp, *ep, *end;
00518     char      seps[32];
00519     FT_Error  error = BDF_Err_Ok;
00520 
00521 
00522     /* Initialize the list. */
00523     list->used = 0;
00524 
00525     /* If the line is empty, then simply return. */
00526     if ( linelen == 0 || line[0] == 0 )
00527       goto Exit;
00528 
00529     /* In the original code, if the `separators' parameter is NULL or */
00530     /* empty, the list is split into individual bytes.  We don't need */
00531     /* this, so an error is signaled.                                 */
00532     if ( separators == 0 || *separators == 0 )
00533     {
00534       error = BDF_Err_Invalid_Argument;
00535       goto Exit;
00536     }
00537 
00538     /* Prepare the separator bitmap. */
00539     FT_MEM_ZERO( seps, 32 );
00540 
00541     /* If the very last character of the separator string is a plus, then */
00542     /* set the `mult' flag to indicate that multiple separators should be */
00543     /* collapsed into one.                                                */
00544     for ( mult = 0, sp = separators; sp && *sp; sp++ )
00545     {
00546       if ( *sp == '+' && *( sp + 1 ) == 0 )
00547         mult = 1;
00548       else
00549         setsbit( seps, *sp );
00550     }
00551 
00552     /* Break the line up into fields. */
00553     for ( final_empty = 0, sp = ep = line, end = sp + linelen;
00554           sp < end && *sp; )
00555     {
00556       /* Collect everything that is not a separator. */
00557       for ( ; *ep && !sbitset( seps, *ep ); ep++ )
00558         ;
00559 
00560       /* Resize the list if necessary. */
00561       if ( list->used == list->size )
00562       {
00563         error = _bdf_list_ensure( list, list->used + 1 );
00564         if ( error )
00565           goto Exit;
00566       }
00567 
00568       /* Assign the field appropriately. */
00569       list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
00570 
00571       sp = ep;
00572 
00573       if ( mult )
00574       {
00575         /* If multiple separators should be collapsed, do it now by */
00576         /* setting all the separator characters to 0.               */
00577         for ( ; *ep && sbitset( seps, *ep ); ep++ )
00578           *ep = 0;
00579       }
00580       else if ( *ep != 0 )
00581         /* Don't collapse multiple separators by making them 0, so just */
00582         /* make the one encountered 0.                                  */
00583         *ep++ = 0;
00584 
00585       final_empty = ( ep > sp && *ep == 0 );
00586       sp = ep;
00587     }
00588 
00589     /* Finally, NULL-terminate the list. */
00590     if ( list->used + final_empty >= list->size )
00591     {
00592       error = _bdf_list_ensure( list, list->used + final_empty + 1 );
00593       if ( error )
00594         goto Exit;
00595     }
00596 
00597     if ( final_empty )
00598       list->field[list->used++] = (char*)empty;
00599 
00600     list->field[list->used] = 0;
00601 
00602   Exit:
00603     return error;
00604   }
00605 
00606 
00607 #define NO_SKIP  256  /* this value cannot be stored in a 'char' */
00608 
00609 
00610   static FT_Error
00611   _bdf_readstream( FT_Stream         stream,
00612                    _bdf_line_func_t  callback,
00613                    void*             client_data,
00614                    unsigned long    *lno )
00615   {
00616     _bdf_line_func_t  cb;
00617     unsigned long     lineno, buf_size;
00618     int               refill, hold, to_skip;
00619     ptrdiff_t         bytes, start, end, cursor, avail;
00620     char*             buf = 0;
00621     FT_Memory         memory = stream->memory;
00622     FT_Error          error = BDF_Err_Ok;
00623 
00624 
00625     if ( callback == 0 )
00626     {
00627       error = BDF_Err_Invalid_Argument;
00628       goto Exit;
00629     }
00630 
00631     /* initial size and allocation of the input buffer */
00632     buf_size = 1024;
00633 
00634     if ( FT_NEW_ARRAY( buf, buf_size ) )
00635       goto Exit;
00636 
00637     cb      = callback;
00638     lineno  = 1;
00639     buf[0]  = 0;
00640     start   = 0;
00641     end     = 0;
00642     avail   = 0;
00643     cursor  = 0;
00644     refill  = 1;
00645     to_skip = NO_SKIP;
00646     bytes   = 0;        /* make compiler happy */
00647 
00648     for (;;)
00649     {
00650       if ( refill )
00651       {
00652         bytes  = (ptrdiff_t)FT_Stream_TryRead(
00653                    stream, (FT_Byte*)buf + cursor,
00654                    (FT_ULong)( buf_size - cursor ) );
00655         avail  = cursor + bytes;
00656         cursor = 0;
00657         refill = 0;
00658       }
00659 
00660       end = start;
00661 
00662       /* should we skip an optional character like \n or \r? */
00663       if ( start < avail && buf[start] == to_skip )
00664       {
00665         start  += 1;
00666         to_skip = NO_SKIP;
00667         continue;
00668       }
00669 
00670       /* try to find the end of the line */
00671       while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
00672         end++;
00673 
00674       /* if we hit the end of the buffer, try shifting its content */
00675       /* or even resizing it                                       */
00676       if ( end >= avail )
00677       {
00678         if ( bytes == 0 )  /* last line in file doesn't end in \r or \n */
00679           break;           /* ignore it then exit                       */
00680 
00681         if ( start == 0 )
00682         {
00683           /* this line is definitely too long; try resizing the input */
00684           /* buffer a bit to handle it.                               */
00685           FT_ULong  new_size;
00686 
00687 
00688           if ( buf_size >= 65536UL )  /* limit ourselves to 64KByte */
00689           {
00690             error = BDF_Err_Invalid_Argument;
00691             goto Exit;
00692           }
00693 
00694           new_size = buf_size * 2;
00695           if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
00696             goto Exit;
00697 
00698           cursor   = buf_size;
00699           buf_size = new_size;
00700         }
00701         else
00702         {
00703           bytes = avail - start;
00704 
00705           FT_MEM_COPY( buf, buf + start, bytes );
00706 
00707           cursor = bytes;
00708           avail -= bytes;
00709           start  = 0;
00710         }
00711         refill = 1;
00712         continue;
00713       }
00714 
00715       /* Temporarily NUL-terminate the line. */
00716       hold     = buf[end];
00717       buf[end] = 0;
00718 
00719       /* XXX: Use encoding independent value for 0x1a */
00720       if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
00721       {
00722         error = (*cb)( buf + start, end - start, lineno,
00723                        (void*)&cb, client_data );
00724         /* Redo if we have encountered CHARS without properties. */
00725         if ( error == -1 )
00726           error = (*cb)( buf + start, end - start, lineno,
00727                          (void*)&cb, client_data );
00728         if ( error )
00729           break;
00730       }
00731 
00732       lineno  += 1;
00733       buf[end] = (char)hold;
00734       start    = end + 1;
00735 
00736       if ( hold == '\n' )
00737         to_skip = '\r';
00738       else if ( hold == '\r' )
00739         to_skip = '\n';
00740       else
00741         to_skip = NO_SKIP;
00742     }
00743 
00744     *lno = lineno;
00745 
00746   Exit:
00747     FT_FREE( buf );
00748     return error;
00749   }
00750 
00751 
00752   /* XXX: make this work with EBCDIC also */
00753 
00754   static const unsigned char  a2i[128] =
00755   {
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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00759     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00760     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
00761     0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
00762     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00763     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00764     0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
00765     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00766     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
00767   };
00768 
00769   static const unsigned char  odigits[32] =
00770   {
00771     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
00772     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00773     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00774     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00775   };
00776 
00777   static const unsigned char  ddigits[32] =
00778   {
00779     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
00780     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00781     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00782     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00783   };
00784 
00785   static const unsigned char  hdigits[32] =
00786   {
00787     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
00788     0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
00789     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00790     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00791   };
00792 
00793 
00794 #define isdigok( m, d )  (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
00795 
00796 
00797   /* Routine to convert an ASCII string into an unsigned long integer. */
00798   static unsigned long
00799   _bdf_atoul( char*   s,
00800               char**  end,
00801               int     base )
00802   {
00803     unsigned long         v;
00804     const unsigned char*  dmap;
00805 
00806 
00807     if ( s == 0 || *s == 0 )
00808       return 0;
00809 
00810     /* Make sure the radix is something recognizable.  Default to 10. */
00811     switch ( base )
00812     {
00813     case 8:
00814       dmap = odigits;
00815       break;
00816     case 16:
00817       dmap = hdigits;
00818       break;
00819     default:
00820       base = 10;
00821       dmap = ddigits;
00822       break;
00823     }
00824 
00825     /* Check for the special hex prefix. */
00826     if ( *s == '0'                                  &&
00827          ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
00828     {
00829       base = 16;
00830       dmap = hdigits;
00831       s   += 2;
00832     }
00833 
00834     for ( v = 0; isdigok( dmap, *s ); s++ )
00835       v = v * base + a2i[(int)*s];
00836 
00837     if ( end != 0 )
00838       *end = s;
00839 
00840     return v;
00841   }
00842 
00843 
00844   /* Routine to convert an ASCII string into an signed long integer. */
00845   static long
00846   _bdf_atol( char*   s,
00847              char**  end,
00848              int     base )
00849   {
00850     long                  v, neg;
00851     const unsigned char*  dmap;
00852 
00853 
00854     if ( s == 0 || *s == 0 )
00855       return 0;
00856 
00857     /* Make sure the radix is something recognizable.  Default to 10. */
00858     switch ( base )
00859     {
00860     case 8:
00861       dmap = odigits;
00862       break;
00863     case 16:
00864       dmap = hdigits;
00865       break;
00866     default:
00867       base = 10;
00868       dmap = ddigits;
00869       break;
00870     }
00871 
00872     /* Check for a minus sign. */
00873     neg = 0;
00874     if ( *s == '-' )
00875     {
00876       s++;
00877       neg = 1;
00878     }
00879 
00880     /* Check for the special hex prefix. */
00881     if ( *s == '0'                                  &&
00882          ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
00883     {
00884       base = 16;
00885       dmap = hdigits;
00886       s   += 2;
00887     }
00888 
00889     for ( v = 0; isdigok( dmap, *s ); s++ )
00890       v = v * base + a2i[(int)*s];
00891 
00892     if ( end != 0 )
00893       *end = s;
00894 
00895     return ( !neg ) ? v : -v;
00896   }
00897 
00898 
00899   /* Routine to convert an ASCII string into an signed short integer. */
00900   static short
00901   _bdf_atos( char*   s,
00902              char**  end,
00903              int     base )
00904   {
00905     short                 v, neg;
00906     const unsigned char*  dmap;
00907 
00908 
00909     if ( s == 0 || *s == 0 )
00910       return 0;
00911 
00912     /* Make sure the radix is something recognizable.  Default to 10. */
00913     switch ( base )
00914     {
00915     case 8:
00916       dmap = odigits;
00917       break;
00918     case 16:
00919       dmap = hdigits;
00920       break;
00921     default:
00922       base = 10;
00923       dmap = ddigits;
00924       break;
00925     }
00926 
00927     /* Check for a minus. */
00928     neg = 0;
00929     if ( *s == '-' )
00930     {
00931       s++;
00932       neg = 1;
00933     }
00934 
00935     /* Check for the special hex prefix. */
00936     if ( *s == '0'                                  &&
00937          ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
00938     {
00939       base = 16;
00940       dmap = hdigits;
00941       s   += 2;
00942     }
00943 
00944     for ( v = 0; isdigok( dmap, *s ); s++ )
00945       v = (short)( v * base + a2i[(int)*s] );
00946 
00947     if ( end != 0 )
00948       *end = s;
00949 
00950     return (short)( ( !neg ) ? v : -v );
00951   }
00952 
00953 
00954   /* Routine to compare two glyphs by encoding so they can be sorted. */
00955   static int
00956   by_encoding( const void*  a,
00957                const void*  b )
00958   {
00959     bdf_glyph_t  *c1, *c2;
00960 
00961 
00962     c1 = (bdf_glyph_t *)a;
00963     c2 = (bdf_glyph_t *)b;
00964 
00965     if ( c1->encoding < c2->encoding )
00966       return -1;
00967 
00968     if ( c1->encoding > c2->encoding )
00969       return 1;
00970 
00971     return 0;
00972   }
00973 
00974 
00975   static FT_Error
00976   bdf_create_property( char*        name,
00977                        int          format,
00978                        bdf_font_t*  font )
00979   {
00980     size_t           n;
00981     bdf_property_t*  p;
00982     FT_Memory        memory = font->memory;
00983     FT_Error         error = BDF_Err_Ok;
00984 
00985 
00986     /* First check to see if the property has      */
00987     /* already been added or not.  If it has, then */
00988     /* simply ignore it.                           */
00989     if ( hash_lookup( name, &(font->proptbl) ) )
00990       goto Exit;
00991 
00992     if ( FT_RENEW_ARRAY( font->user_props,
00993                          font->nuser_props,
00994                          font->nuser_props + 1 ) )
00995       goto Exit;
00996 
00997     p = font->user_props + font->nuser_props;
00998     FT_ZERO( p );
00999 
01000     n = ft_strlen( name ) + 1;
01001     if ( n > FT_ULONG_MAX )
01002       return BDF_Err_Invalid_Argument;
01003 
01004     if ( FT_NEW_ARRAY( p->name, n ) )
01005       goto Exit;
01006 
01007     FT_MEM_COPY( (char *)p->name, name, n );
01008 
01009     p->format  = format;
01010     p->builtin = 0;
01011 
01012     n = _num_bdf_properties + font->nuser_props;
01013 
01014     error = hash_insert( p->name, n, &(font->proptbl), memory );
01015     if ( error )
01016       goto Exit;
01017 
01018     font->nuser_props++;
01019 
01020   Exit:
01021     return error;
01022   }
01023 
01024 
01025   FT_LOCAL_DEF( bdf_property_t * )
01026   bdf_get_property( char*        name,
01027                     bdf_font_t*  font )
01028   {
01029     hashnode  hn;
01030     size_t    propid;
01031 
01032 
01033     if ( name == 0 || *name == 0 )
01034       return 0;
01035 
01036     if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
01037       return 0;
01038 
01039     propid = hn->data;
01040     if ( propid >= _num_bdf_properties )
01041       return font->user_props + ( propid - _num_bdf_properties );
01042 
01043     return (bdf_property_t*)_bdf_properties + propid;
01044   }
01045 
01046 
01047   /*************************************************************************/
01048   /*                                                                       */
01049   /* BDF font file parsing flags and functions.                            */
01050   /*                                                                       */
01051   /*************************************************************************/
01052 
01053 
01054   /* Parse flags. */
01055 
01056 #define _BDF_START      0x0001
01057 #define _BDF_FONT_NAME  0x0002
01058 #define _BDF_SIZE       0x0004
01059 #define _BDF_FONT_BBX   0x0008
01060 #define _BDF_PROPS      0x0010
01061 #define _BDF_GLYPHS     0x0020
01062 #define _BDF_GLYPH      0x0040
01063 #define _BDF_ENCODING   0x0080
01064 #define _BDF_SWIDTH     0x0100
01065 #define _BDF_DWIDTH     0x0200
01066 #define _BDF_BBX        0x0400
01067 #define _BDF_BITMAP     0x0800
01068 
01069 #define _BDF_SWIDTH_ADJ  0x1000
01070 
01071 #define _BDF_GLYPH_BITS ( _BDF_GLYPH    | \
01072                           _BDF_ENCODING | \
01073                           _BDF_SWIDTH   | \
01074                           _BDF_DWIDTH   | \
01075                           _BDF_BBX      | \
01076                           _BDF_BITMAP   )
01077 
01078 #define _BDF_GLYPH_WIDTH_CHECK   0x40000000UL
01079 #define _BDF_GLYPH_HEIGHT_CHECK  0x80000000UL
01080 
01081 
01082   /* Auto correction messages. */
01083 #define ACMSG1   "FONT_ASCENT property missing.  " \
01084                  "Added \"FONT_ASCENT %hd\".\n"
01085 #define ACMSG2   "FONT_DESCENT property missing.  " \
01086                  "Added \"FONT_DESCENT %hd\".\n"
01087 #define ACMSG3   "Font width != actual width.  Old: %hd New: %hd.\n"
01088 #define ACMSG4   "Font left bearing != actual left bearing.  " \
01089                  "Old: %hd New: %hd.\n"
01090 #define ACMSG5   "Font ascent != actual ascent.  Old: %hd New: %hd.\n"
01091 #define ACMSG6   "Font descent != actual descent.  Old: %hd New: %hd.\n"
01092 #define ACMSG7   "Font height != actual height. Old: %hd New: %hd.\n"
01093 #define ACMSG8   "Glyph scalable width (SWIDTH) adjustments made.\n"
01094 #define ACMSG9   "SWIDTH field missing at line %ld.  Set automatically.\n"
01095 #define ACMSG10  "DWIDTH field missing at line %ld.  Set to glyph width.\n"
01096 #define ACMSG11  "SIZE bits per pixel field adjusted to %hd.\n"
01097 #define ACMSG12  "Duplicate encoding %ld (%s) changed to unencoded.\n"
01098 #define ACMSG13  "Glyph %ld extra rows removed.\n"
01099 #define ACMSG14  "Glyph %ld extra columns removed.\n"
01100 #define ACMSG15  "Incorrect glyph count: %ld indicated but %ld found.\n"
01101 
01102   /* Error messages. */
01103 #define ERRMSG1  "[line %ld] Missing \"%s\" line.\n"
01104 #define ERRMSG2  "[line %ld] Font header corrupted or missing fields.\n"
01105 #define ERRMSG3  "[line %ld] Font glyphs corrupted or missing fields.\n"
01106 #define ERRMSG4  "[line %ld] BBX too big.\n"
01107 
01108 
01109   static FT_Error
01110   _bdf_add_comment( bdf_font_t*    font,
01111                     char*          comment,
01112                     unsigned long  len )
01113   {
01114     char*      cp;
01115     FT_Memory  memory = font->memory;
01116     FT_Error   error = BDF_Err_Ok;
01117 
01118 
01119     if ( FT_RENEW_ARRAY( font->comments,
01120                          font->comments_len,
01121                          font->comments_len + len + 1 ) )
01122       goto Exit;
01123 
01124     cp = font->comments + font->comments_len;
01125 
01126     FT_MEM_COPY( cp, comment, len );
01127     cp[len] = '\n';
01128 
01129     font->comments_len += len + 1;
01130 
01131   Exit:
01132     return error;
01133   }
01134 
01135 
01136   /* Set the spacing from the font name if it exists, or set it to the */
01137   /* default specified in the options.                                 */
01138   static FT_Error
01139   _bdf_set_default_spacing( bdf_font_t*     font,
01140                             bdf_options_t*  opts )
01141   {
01142     size_t       len;
01143     char         name[256];
01144     _bdf_list_t  list;
01145     FT_Memory    memory;
01146     FT_Error     error = BDF_Err_Ok;
01147 
01148 
01149     if ( font == 0 || font->name == 0 || font->name[0] == 0 )
01150     {
01151       error = BDF_Err_Invalid_Argument;
01152       goto Exit;
01153     }
01154 
01155     memory = font->memory;
01156 
01157     _bdf_list_init( &list, memory );
01158 
01159     font->spacing = opts->font_spacing;
01160 
01161     len = ft_strlen( font->name ) + 1;
01162     /* Limit ourselves to 256 characters in the font name. */
01163     if ( len >= 256 )
01164     {
01165       error = BDF_Err_Invalid_Argument;
01166       goto Exit;
01167     }
01168 
01169     FT_MEM_COPY( name, font->name, len );
01170 
01171     error = _bdf_list_split( &list, (char *)"-", name, len );
01172     if ( error )
01173       goto Fail;
01174 
01175     if ( list.used == 15 )
01176     {
01177       switch ( list.field[11][0] )
01178       {
01179       case 'C':
01180       case 'c':
01181         font->spacing = BDF_CHARCELL;
01182         break;
01183       case 'M':
01184       case 'm':
01185         font->spacing = BDF_MONOWIDTH;
01186         break;
01187       case 'P':
01188       case 'p':
01189         font->spacing = BDF_PROPORTIONAL;
01190         break;
01191       }
01192     }
01193 
01194   Fail:
01195     _bdf_list_done( &list );
01196 
01197   Exit:
01198     return error;
01199   }
01200 
01201 
01202   /* Determine whether the property is an atom or not.  If it is, then */
01203   /* clean it up so the double quotes are removed if they exist.       */
01204   static int
01205   _bdf_is_atom( char*          line,
01206                 unsigned long  linelen,
01207                 char**         name,
01208                 char**         value,
01209                 bdf_font_t*    font )
01210   {
01211     int              hold;
01212     char             *sp, *ep;
01213     bdf_property_t*  p;
01214 
01215 
01216     *name = sp = ep = line;
01217 
01218     while ( *ep && *ep != ' ' && *ep != '\t' )
01219       ep++;
01220 
01221     hold = -1;
01222     if ( *ep )
01223     {
01224       hold = *ep;
01225       *ep  = 0;
01226     }
01227 
01228     p = bdf_get_property( sp, font );
01229 
01230     /* Restore the character that was saved before any return can happen. */
01231     if ( hold != -1 )
01232       *ep = (char)hold;
01233 
01234     /* If the property exists and is not an atom, just return here. */
01235     if ( p && p->format != BDF_ATOM )
01236       return 0;
01237 
01238     /* The property is an atom.  Trim all leading and trailing whitespace */
01239     /* and double quotes for the atom value.                              */
01240     sp = ep;
01241     ep = line + linelen;
01242 
01243     /* Trim the leading whitespace if it exists. */
01244     *sp++ = 0;
01245     while ( *sp                           &&
01246             ( *sp == ' ' || *sp == '\t' ) )
01247       sp++;
01248 
01249     /* Trim the leading double quote if it exists. */
01250     if ( *sp == '"' )
01251       sp++;
01252     *value = sp;
01253 
01254     /* Trim the trailing whitespace if it exists. */
01255     while ( ep > sp                                       &&
01256             ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
01257       *--ep = 0;
01258 
01259     /* Trim the trailing double quote if it exists. */
01260     if ( ep > sp && *( ep - 1 ) == '"' )
01261       *--ep = 0;
01262 
01263     return 1;
01264   }
01265 
01266 
01267   static FT_Error
01268   _bdf_add_property( bdf_font_t*  font,
01269                      char*        name,
01270                      char*        value )
01271   {
01272     size_t          propid;
01273     hashnode        hn;
01274     bdf_property_t  *prop, *fp;
01275     FT_Memory       memory = font->memory;
01276     FT_Error        error = BDF_Err_Ok;
01277 
01278 
01279     /* First, check to see if the property already exists in the font. */
01280     if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
01281     {
01282       /* The property already exists in the font, so simply replace */
01283       /* the value of the property with the current value.          */
01284       fp = font->props + hn->data;
01285 
01286       switch ( fp->format )
01287       {
01288       case BDF_ATOM:
01289         /* Delete the current atom if it exists. */
01290         FT_FREE( fp->value.atom );
01291 
01292         if ( value && value[0] != 0 )
01293         {
01294           if ( FT_STRDUP( fp->value.atom, value ) )
01295             goto Exit;
01296         }
01297         break;
01298 
01299       case BDF_INTEGER:
01300         fp->value.l = _bdf_atol( value, 0, 10 );
01301         break;
01302 
01303       case BDF_CARDINAL:
01304         fp->value.ul = _bdf_atoul( value, 0, 10 );
01305         break;
01306 
01307       default:
01308         ;
01309       }
01310 
01311       goto Exit;
01312     }
01313 
01314     /* See whether this property type exists yet or not. */
01315     /* If not, create it.                                */
01316     hn = hash_lookup( name, &(font->proptbl) );
01317     if ( hn == 0 )
01318     {
01319       error = bdf_create_property( name, BDF_ATOM, font );
01320       if ( error )
01321         goto Exit;
01322       hn = hash_lookup( name, &(font->proptbl) );
01323     }
01324 
01325     /* Allocate another property if this is overflow. */
01326     if ( font->props_used == font->props_size )
01327     {
01328       if ( font->props_size == 0 )
01329       {
01330         if ( FT_NEW_ARRAY( font->props, 1 ) )
01331           goto Exit;
01332       }
01333       else
01334       {
01335         if ( FT_RENEW_ARRAY( font->props,
01336                              font->props_size,
01337                              font->props_size + 1 ) )
01338           goto Exit;
01339       }
01340 
01341       fp = font->props + font->props_size;
01342       FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
01343       font->props_size++;
01344     }
01345 
01346     propid = hn->data;
01347     if ( propid >= _num_bdf_properties )
01348       prop = font->user_props + ( propid - _num_bdf_properties );
01349     else
01350       prop = (bdf_property_t*)_bdf_properties + propid;
01351 
01352     fp = font->props + font->props_used;
01353 
01354     fp->name    = prop->name;
01355     fp->format  = prop->format;
01356     fp->builtin = prop->builtin;
01357 
01358     switch ( prop->format )
01359     {
01360     case BDF_ATOM:
01361       fp->value.atom = 0;
01362       if ( value != 0 && value[0] )
01363       {
01364         if ( FT_STRDUP( fp->value.atom, value ) )
01365           goto Exit;
01366       }
01367       break;
01368 
01369     case BDF_INTEGER:
01370       fp->value.l = _bdf_atol( value, 0, 10 );
01371       break;
01372 
01373     case BDF_CARDINAL:
01374       fp->value.ul = _bdf_atoul( value, 0, 10 );
01375       break;
01376     }
01377 
01378     /* If the property happens to be a comment, then it doesn't need */
01379     /* to be added to the internal hash table.                       */
01380     if ( ft_memcmp( name, "COMMENT", 7 ) != 0 )
01381     {
01382       /* Add the property to the font property table. */
01383       error = hash_insert( fp->name,
01384                            font->props_used,
01385                            (hashtable *)font->internal,
01386                            memory );
01387       if ( error )
01388         goto Exit;
01389     }
01390 
01391     font->props_used++;
01392 
01393     /* Some special cases need to be handled here.  The DEFAULT_CHAR       */
01394     /* property needs to be located if it exists in the property list, the */
01395     /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are        */
01396     /* present, and the SPACING property should override the default       */
01397     /* spacing.                                                            */
01398     if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
01399       font->default_char = fp->value.l;
01400     else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
01401       font->font_ascent = fp->value.l;
01402     else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
01403       font->font_descent = fp->value.l;
01404     else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
01405     {
01406       if ( !fp->value.atom )
01407       {
01408         error = BDF_Err_Invalid_File_Format;
01409         goto Exit;
01410       }
01411 
01412       if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
01413         font->spacing = BDF_PROPORTIONAL;
01414       else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
01415         font->spacing = BDF_MONOWIDTH;
01416       else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
01417         font->spacing = BDF_CHARCELL;
01418     }
01419 
01420   Exit:
01421     return error;
01422   }
01423 
01424 
01425   static const unsigned char nibble_mask[8] =
01426   {
01427     0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
01428   };
01429 
01430 
01431   /* Actually parse the glyph info and bitmaps. */
01432   static FT_Error
01433   _bdf_parse_glyphs( char*          line,
01434                      unsigned long  linelen,
01435                      unsigned long  lineno,
01436                      void*          call_data,
01437                      void*          client_data )
01438   {
01439     int                c, mask_index;
01440     char*              s;
01441     unsigned char*     bp;
01442     unsigned long      i, slen, nibbles;
01443 
01444     _bdf_parse_t*      p;
01445     bdf_glyph_t*       glyph;
01446     bdf_font_t*        font;
01447 
01448     FT_Memory          memory;
01449     FT_Error           error = BDF_Err_Ok;
01450 
01451     FT_UNUSED( call_data );
01452     FT_UNUSED( lineno );        /* only used in debug mode */
01453 
01454 
01455     p = (_bdf_parse_t *)client_data;
01456 
01457     font   = p->font;
01458     memory = font->memory;
01459 
01460     /* Check for a comment. */
01461     if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
01462     {
01463       linelen -= 7;
01464 
01465       s = line + 7;
01466       if ( *s != 0 )
01467       {
01468         s++;
01469         linelen--;
01470       }
01471       error = _bdf_add_comment( p->font, s, linelen );
01472       goto Exit;
01473     }
01474 
01475     /* The very first thing expected is the number of glyphs. */
01476     if ( !( p->flags & _BDF_GLYPHS ) )
01477     {
01478       if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
01479       {
01480         FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
01481         error = BDF_Err_Missing_Chars_Field;
01482         goto Exit;
01483       }
01484 
01485       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
01486       if ( error )
01487         goto Exit;
01488       p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
01489 
01490       /* Make sure the number of glyphs is non-zero. */
01491       if ( p->cnt == 0 )
01492         font->glyphs_size = 64;
01493 
01494       /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
01495       /* number of code points available in Unicode).                 */
01496       if ( p->cnt >= 1114112UL )
01497       {
01498         error = BDF_Err_Invalid_Argument;
01499         goto Exit;
01500       }
01501 
01502       if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
01503         goto Exit;
01504 
01505       p->flags |= _BDF_GLYPHS;
01506 
01507       goto Exit;
01508     }
01509 
01510     /* Check for the ENDFONT field. */
01511     if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
01512     {
01513       /* Sort the glyphs by encoding. */
01514       ft_qsort( (char *)font->glyphs,
01515                 font->glyphs_used,
01516                 sizeof ( bdf_glyph_t ),
01517                 by_encoding );
01518 
01519       p->flags &= ~_BDF_START;
01520 
01521       goto Exit;
01522     }
01523 
01524     /* Check for the ENDCHAR field. */
01525     if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
01526     {
01527       p->glyph_enc = 0;
01528       p->flags    &= ~_BDF_GLYPH_BITS;
01529 
01530       goto Exit;
01531     }
01532 
01533     /* Check to see whether a glyph is being scanned but should be */
01534     /* ignored because it is an unencoded glyph.                   */
01535     if ( ( p->flags & _BDF_GLYPH )     &&
01536          p->glyph_enc            == -1 &&
01537          p->opts->keep_unencoded == 0  )
01538       goto Exit;
01539 
01540     /* Check for the STARTCHAR field. */
01541     if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
01542     {
01543       /* Set the character name in the parse info first until the */
01544       /* encoding can be checked for an unencoded character.      */
01545       FT_FREE( p->glyph_name );
01546 
01547       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
01548       if ( error )
01549         goto Exit;
01550 
01551       _bdf_list_shift( &p->list, 1 );
01552 
01553       s = _bdf_list_join( &p->list, ' ', &slen );
01554 
01555       if ( !s )
01556       {
01557         error = BDF_Err_Invalid_File_Format;
01558         goto Exit;
01559       }
01560 
01561       if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
01562         goto Exit;
01563 
01564       FT_MEM_COPY( p->glyph_name, s, slen + 1 );
01565 
01566       p->flags |= _BDF_GLYPH;
01567 
01568       goto Exit;
01569     }
01570 
01571     /* Check for the ENCODING field. */
01572     if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
01573     {
01574       if ( !( p->flags & _BDF_GLYPH ) )
01575       {
01576         /* Missing STARTCHAR field. */
01577         FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
01578         error = BDF_Err_Missing_Startchar_Field;
01579         goto Exit;
01580       }
01581 
01582       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
01583       if ( error )
01584         goto Exit;
01585 
01586       p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
01587 
01588       /* Check that the encoding is in the range [0,65536] because        */
01589       /* otherwise p->have (a bitmap with static size) overflows.         */
01590       if ( (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
01591       {
01592         error = BDF_Err_Invalid_File_Format;
01593         goto Exit;
01594       }
01595 
01596       /* Check to see whether this encoding has already been encountered. */
01597       /* If it has then change it to unencoded so it gets added if        */
01598       /* indicated.                                                       */
01599       if ( p->glyph_enc >= 0 )
01600       {
01601         if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
01602         {
01603           /* Emit a message saying a glyph has been moved to the */
01604           /* unencoded area.                                     */
01605           FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
01606                       p->glyph_enc, p->glyph_name ));
01607           p->glyph_enc = -1;
01608           font->modified = 1;
01609         }
01610         else
01611           _bdf_set_glyph_modified( p->have, p->glyph_enc );
01612       }
01613 
01614       if ( p->glyph_enc >= 0 )
01615       {
01616         /* Make sure there are enough glyphs allocated in case the */
01617         /* number of characters happen to be wrong.                */
01618         if ( font->glyphs_used == font->glyphs_size )
01619         {
01620           if ( FT_RENEW_ARRAY( font->glyphs,
01621                                font->glyphs_size,
01622                                font->glyphs_size + 64 ) )
01623             goto Exit;
01624 
01625           font->glyphs_size += 64;
01626         }
01627 
01628         glyph           = font->glyphs + font->glyphs_used++;
01629         glyph->name     = p->glyph_name;
01630         glyph->encoding = p->glyph_enc;
01631 
01632         /* Reset the initial glyph info. */
01633         p->glyph_name = 0;
01634       }
01635       else
01636       {
01637         /* Unencoded glyph.  Check to see whether it should */
01638         /* be added or not.                                 */
01639         if ( p->opts->keep_unencoded != 0 )
01640         {
01641           /* Allocate the next unencoded glyph. */
01642           if ( font->unencoded_used == font->unencoded_size )
01643           {
01644             if ( FT_RENEW_ARRAY( font->unencoded ,
01645                                  font->unencoded_size,
01646                                  font->unencoded_size + 4 ) )
01647               goto Exit;
01648 
01649             font->unencoded_size += 4;
01650           }
01651 
01652           glyph           = font->unencoded + font->unencoded_used;
01653           glyph->name     = p->glyph_name;
01654           glyph->encoding = font->unencoded_used++;
01655         }
01656         else
01657           /* Free up the glyph name if the unencoded shouldn't be */
01658           /* kept.                                                */
01659           FT_FREE( p->glyph_name );
01660 
01661         p->glyph_name = 0;
01662       }
01663 
01664       /* Clear the flags that might be added when width and height are */
01665       /* checked for consistency.                                      */
01666       p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
01667 
01668       p->flags |= _BDF_ENCODING;
01669 
01670       goto Exit;
01671     }
01672 
01673     /* Point at the glyph being constructed. */
01674     if ( p->glyph_enc == -1 )
01675       glyph = font->unencoded + ( font->unencoded_used - 1 );
01676     else
01677       glyph = font->glyphs + ( font->glyphs_used - 1 );
01678 
01679     /* Check to see whether a bitmap is being constructed. */
01680     if ( p->flags & _BDF_BITMAP )
01681     {
01682       /* If there are more rows than are specified in the glyph metrics, */
01683       /* ignore the remaining lines.                                     */
01684       if ( p->row >= (unsigned long)glyph->bbx.height )
01685       {
01686         if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
01687         {
01688           FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
01689           p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
01690           font->modified = 1;
01691         }
01692 
01693         goto Exit;
01694       }
01695 
01696       /* Only collect the number of nibbles indicated by the glyph     */
01697       /* metrics.  If there are more columns, they are simply ignored. */
01698       nibbles = glyph->bpr << 1;
01699       bp      = glyph->bitmap + p->row * glyph->bpr;
01700 
01701       for ( i = 0; i < nibbles; i++ )
01702       {
01703         c = line[i];
01704         *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
01705         if ( i + 1 < nibbles && ( i & 1 ) )
01706           *++bp = 0;
01707       }
01708 
01709       /* Remove possible garbage at the right. */
01710       mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
01711       if ( glyph->bbx.width )
01712         *bp &= nibble_mask[mask_index];
01713 
01714       /* If any line has extra columns, indicate they have been removed. */
01715       if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
01716            !( p->flags & _BDF_GLYPH_WIDTH_CHECK )                   )
01717       {
01718         FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
01719         p->flags       |= _BDF_GLYPH_WIDTH_CHECK;
01720         font->modified  = 1;
01721       }
01722 
01723       p->row++;
01724       goto Exit;
01725     }
01726 
01727     /* Expect the SWIDTH (scalable width) field next. */
01728     if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
01729     {
01730       if ( !( p->flags & _BDF_ENCODING ) )
01731       {
01732         /* Missing ENCODING field. */
01733         FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
01734         error = BDF_Err_Missing_Encoding_Field;
01735         goto Exit;
01736       }
01737 
01738       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
01739       if ( error )
01740         goto Exit;
01741 
01742       glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
01743       p->flags |= _BDF_SWIDTH;
01744 
01745       goto Exit;
01746     }
01747 
01748     /* Expect the DWIDTH (scalable width) field next. */
01749     if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
01750     {
01751       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
01752       if ( error )
01753         goto Exit;
01754 
01755       glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
01756 
01757       if ( !( p->flags & _BDF_SWIDTH ) )
01758       {
01759         /* Missing SWIDTH field.  Emit an auto correction message and set */
01760         /* the scalable width from the device width.                      */
01761         FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
01762 
01763         glyph->swidth = (unsigned short)FT_MulDiv(
01764                           glyph->dwidth, 72000L,
01765                           (FT_Long)( font->point_size *
01766                                      font->resolution_x ) );
01767       }
01768 
01769       p->flags |= _BDF_DWIDTH;
01770       goto Exit;
01771     }
01772 
01773     /* Expect the BBX field next. */
01774     if ( ft_memcmp( line, "BBX", 3 ) == 0 )
01775     {
01776       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
01777       if ( error )
01778         goto Exit;
01779 
01780       glyph->bbx.width    = _bdf_atos( p->list.field[1], 0, 10 );
01781       glyph->bbx.height   = _bdf_atos( p->list.field[2], 0, 10 );
01782       glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
01783       glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
01784 
01785       /* Generate the ascent and descent of the character. */
01786       glyph->bbx.ascent  = (short)( glyph->bbx.height + glyph->bbx.y_offset );
01787       glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
01788 
01789       /* Determine the overall font bounding box as the characters are */
01790       /* loaded so corrections can be done later if indicated.         */
01791       p->maxas    = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
01792       p->maxds    = (short)FT_MAX( glyph->bbx.descent, p->maxds );
01793 
01794       p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
01795 
01796       p->maxrb    = (short)FT_MAX( p->rbearing, p->maxrb );
01797       p->minlb    = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
01798       p->maxlb    = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
01799 
01800       if ( !( p->flags & _BDF_DWIDTH ) )
01801       {
01802         /* Missing DWIDTH field.  Emit an auto correction message and set */
01803         /* the device width to the glyph width.                           */
01804         FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
01805         glyph->dwidth = glyph->bbx.width;
01806       }
01807 
01808       /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
01809       /* value if necessary.                                            */
01810       if ( p->opts->correct_metrics != 0 )
01811       {
01812         /* Determine the point size of the glyph. */
01813         unsigned short  sw = (unsigned short)FT_MulDiv(
01814                                glyph->dwidth, 72000L,
01815                                (FT_Long)( font->point_size *
01816                                           font->resolution_x ) );
01817 
01818 
01819         if ( sw != glyph->swidth )
01820         {
01821           glyph->swidth = sw;
01822 
01823           if ( p->glyph_enc == -1 )
01824             _bdf_set_glyph_modified( font->umod,
01825                                      font->unencoded_used - 1 );
01826           else
01827             _bdf_set_glyph_modified( font->nmod, glyph->encoding );
01828 
01829           p->flags       |= _BDF_SWIDTH_ADJ;
01830           font->modified  = 1;
01831         }
01832       }
01833 
01834       p->flags |= _BDF_BBX;
01835       goto Exit;
01836     }
01837 
01838     /* And finally, gather up the bitmap. */
01839     if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
01840     {
01841       unsigned long  bitmap_size;
01842 
01843 
01844       if ( !( p->flags & _BDF_BBX ) )
01845       {
01846         /* Missing BBX field. */
01847         FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
01848         error = BDF_Err_Missing_Bbx_Field;
01849         goto Exit;
01850       }
01851 
01852       /* Allocate enough space for the bitmap. */
01853       glyph->bpr   = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
01854 
01855       bitmap_size = glyph->bpr * glyph->bbx.height;
01856       if ( bitmap_size > 0xFFFFU )
01857       {
01858         FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
01859         error = BDF_Err_Bbx_Too_Big;
01860         goto Exit;
01861       }
01862       else
01863         glyph->bytes = (unsigned short)bitmap_size;
01864 
01865       if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
01866         goto Exit;
01867 
01868       p->row    = 0;
01869       p->flags |= _BDF_BITMAP;
01870 
01871       goto Exit;
01872     }
01873 
01874     error = BDF_Err_Invalid_File_Format;
01875 
01876   Exit:
01877     if ( error && ( p->flags & _BDF_GLYPH ) )
01878       FT_FREE( p->glyph_name );
01879 
01880     return error;
01881   }
01882 
01883 
01884   /* Load the font properties. */
01885   static FT_Error
01886   _bdf_parse_properties( char*          line,
01887                          unsigned long  linelen,
01888                          unsigned long  lineno,
01889                          void*          call_data,
01890                          void*          client_data )
01891   {
01892     unsigned long      vlen;
01893     _bdf_line_func_t*  next;
01894     _bdf_parse_t*      p;
01895     char*              name;
01896     char*              value;
01897     char               nbuf[128];
01898     FT_Error           error = BDF_Err_Ok;
01899 
01900     FT_UNUSED( lineno );
01901 
01902 
01903     next = (_bdf_line_func_t *)call_data;
01904     p    = (_bdf_parse_t *)    client_data;
01905 
01906     /* Check for the end of the properties. */
01907     if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
01908     {
01909       /* If the FONT_ASCENT or FONT_DESCENT properties have not been      */
01910       /* encountered yet, then make sure they are added as properties and */
01911       /* make sure they are set from the font bounding box info.          */
01912       /*                                                                  */
01913       /* This is *always* done regardless of the options, because X11     */
01914       /* requires these two fields to compile fonts.                      */
01915       if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
01916       {
01917         p->font->font_ascent = p->font->bbx.ascent;
01918         ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
01919         error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
01920         if ( error )
01921           goto Exit;
01922 
01923         FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
01924         p->font->modified = 1;
01925       }
01926 
01927       if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
01928       {
01929         p->font->font_descent = p->font->bbx.descent;
01930         ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
01931         error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
01932         if ( error )
01933           goto Exit;
01934 
01935         FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
01936         p->font->modified = 1;
01937       }
01938 
01939       p->flags &= ~_BDF_PROPS;
01940       *next     = _bdf_parse_glyphs;
01941 
01942       goto Exit;
01943     }
01944 
01945     /* Ignore the _XFREE86_GLYPH_RANGES properties. */
01946     if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
01947       goto Exit;
01948 
01949     /* Handle COMMENT fields and properties in a special way to preserve */
01950     /* the spacing.                                                      */
01951     if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
01952     {
01953       name = value = line;
01954       value += 7;
01955       if ( *value )
01956         *value++ = 0;
01957       error = _bdf_add_property( p->font, name, value );
01958       if ( error )
01959         goto Exit;
01960     }
01961     else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
01962     {
01963       error = _bdf_add_property( p->font, name, value );
01964       if ( error )
01965         goto Exit;
01966     }
01967     else
01968     {
01969       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
01970       if ( error )
01971         goto Exit;
01972       name = p->list.field[0];
01973 
01974       _bdf_list_shift( &p->list, 1 );
01975       value = _bdf_list_join( &p->list, ' ', &vlen );
01976 
01977       error = _bdf_add_property( p->font, name, value );
01978       if ( error )
01979         goto Exit;
01980     }
01981 
01982   Exit:
01983     return error;
01984   }
01985 
01986 
01987   /* Load the font header. */
01988   static FT_Error
01989   _bdf_parse_start( char*          line,
01990                     unsigned long  linelen,
01991                     unsigned long  lineno,
01992                     void*          call_data,
01993                     void*          client_data )
01994   {
01995     unsigned long      slen;
01996     _bdf_line_func_t*  next;
01997     _bdf_parse_t*      p;
01998     bdf_font_t*        font;
01999     char               *s;
02000 
02001     FT_Memory          memory = NULL;
02002     FT_Error           error  = BDF_Err_Ok;
02003 
02004     FT_UNUSED( lineno );            /* only used in debug mode */
02005 
02006 
02007     next = (_bdf_line_func_t *)call_data;
02008     p    = (_bdf_parse_t *)    client_data;
02009 
02010     if ( p->font )
02011       memory = p->font->memory;
02012 
02013     /* Check for a comment.  This is done to handle those fonts that have */
02014     /* comments before the STARTFONT line for some reason.                */
02015     if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
02016     {
02017       if ( p->opts->keep_comments != 0 && p->font != 0 )
02018       {
02019         linelen -= 7;
02020 
02021         s = line + 7;
02022         if ( *s != 0 )
02023         {
02024           s++;
02025           linelen--;
02026         }
02027 
02028         error = _bdf_add_comment( p->font, s, linelen );
02029         if ( error )
02030           goto Exit;
02031         /* here font is not defined! */
02032       }
02033 
02034       goto Exit;
02035     }
02036 
02037     if ( !( p->flags & _BDF_START ) )
02038     {
02039       memory = p->memory;
02040 
02041       if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
02042       {
02043         /* No STARTFONT field is a good indication of a problem. */
02044         error = BDF_Err_Missing_Startfont_Field;
02045         goto Exit;
02046       }
02047 
02048       p->flags = _BDF_START;
02049       font = p->font = 0;
02050 
02051       if ( FT_NEW( font ) )
02052         goto Exit;
02053       p->font = font;
02054 
02055       font->memory = p->memory;
02056       p->memory    = 0;
02057 
02058       { /* setup */
02059         size_t           i;
02060         bdf_property_t*  prop;
02061 
02062 
02063         error = hash_init( &(font->proptbl), memory );
02064         if ( error )
02065           goto Exit;
02066         for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
02067               i < _num_bdf_properties; i++, prop++ )
02068         {
02069           error = hash_insert( prop->name, i,
02070                                &(font->proptbl), memory );
02071           if ( error )
02072             goto Exit;
02073         }
02074       }
02075 
02076       if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
02077         goto Exit;
02078       error = hash_init( (hashtable *)p->font->internal,memory );
02079       if ( error )
02080         goto Exit;
02081       p->font->spacing      = p->opts->font_spacing;
02082       p->font->default_char = -1;
02083 
02084       goto Exit;
02085     }
02086 
02087     /* Check for the start of the properties. */
02088     if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
02089     {
02090       if ( !( p->flags & _BDF_FONT_BBX ) )
02091       {
02092         /* Missing the FONTBOUNDINGBOX field. */
02093         FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
02094         error = BDF_Err_Missing_Fontboundingbox_Field;
02095         goto Exit;
02096       }
02097 
02098       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
02099       if ( error )
02100         goto Exit;
02101       /* at this point, `p->font' can't be NULL */
02102       p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
02103 
02104       if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
02105         goto Exit;
02106 
02107       p->flags |= _BDF_PROPS;
02108       *next     = _bdf_parse_properties;
02109 
02110       goto Exit;
02111     }
02112 
02113     /* Check for the FONTBOUNDINGBOX field. */
02114     if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
02115     {
02116       if ( !( p->flags & _BDF_SIZE ) )
02117       {
02118         /* Missing the SIZE field. */
02119         FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
02120         error = BDF_Err_Missing_Size_Field;
02121         goto Exit;
02122       }
02123 
02124       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
02125       if ( error )
02126         goto Exit;
02127 
02128       p->font->bbx.width  = _bdf_atos( p->list.field[1], 0, 10 );
02129       p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
02130 
02131       p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
02132       p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
02133 
02134       p->font->bbx.ascent  = (short)( p->font->bbx.height +
02135                                       p->font->bbx.y_offset );
02136 
02137       p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
02138 
02139       p->flags |= _BDF_FONT_BBX;
02140 
02141       goto Exit;
02142     }
02143 
02144     /* The next thing to check for is the FONT field. */
02145     if ( ft_memcmp( line, "FONT", 4 ) == 0 )
02146     {
02147       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
02148       if ( error )
02149         goto Exit;
02150       _bdf_list_shift( &p->list, 1 );
02151 
02152       s = _bdf_list_join( &p->list, ' ', &slen );
02153 
02154       if ( !s )
02155       {
02156         error = BDF_Err_Invalid_File_Format;
02157         goto Exit;
02158       }
02159 
02160       /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
02161       FT_FREE( p->font->name );
02162 
02163       if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
02164         goto Exit;
02165       FT_MEM_COPY( p->font->name, s, slen + 1 );
02166 
02167       /* If the font name is an XLFD name, set the spacing to the one in  */
02168       /* the font name.  If there is no spacing fall back on the default. */
02169       error = _bdf_set_default_spacing( p->font, p->opts );
02170       if ( error )
02171         goto Exit;
02172 
02173       p->flags |= _BDF_FONT_NAME;
02174 
02175       goto Exit;
02176     }
02177 
02178     /* Check for the SIZE field. */
02179     if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
02180     {
02181       if ( !( p->flags & _BDF_FONT_NAME ) )
02182       {
02183         /* Missing the FONT field. */
02184         FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
02185         error = BDF_Err_Missing_Font_Field;
02186         goto Exit;
02187       }
02188 
02189       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
02190       if ( error )
02191         goto Exit;
02192 
02193       p->font->point_size   = _bdf_atoul( p->list.field[1], 0, 10 );
02194       p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
02195       p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
02196 
02197       /* Check for the bits per pixel field. */
02198       if ( p->list.used == 5 )
02199       {
02200         unsigned short bitcount, i, shift;
02201 
02202 
02203         p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
02204 
02205         /* Only values 1, 2, 4, 8 are allowed. */
02206         shift = p->font->bpp;
02207         bitcount = 0;
02208         for ( i = 0; shift > 0; i++ )
02209         {
02210           if ( shift & 1 )
02211             bitcount = i;
02212           shift >>= 1;
02213         }
02214 
02215         shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
02216 
02217         if ( p->font->bpp > shift || p->font->bpp != shift )
02218         {
02219           /* select next higher value */
02220           p->font->bpp = (unsigned short)( shift << 1 );
02221           FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
02222         }
02223       }
02224       else
02225         p->font->bpp = 1;
02226 
02227       p->flags |= _BDF_SIZE;
02228 
02229       goto Exit;
02230     }
02231 
02232     /* Check for the CHARS field -- font properties are optional */
02233     if ( ft_memcmp( line, "CHARS", 5 ) == 0 )
02234     {
02235       char  nbuf[128];
02236 
02237 
02238       if ( !( p->flags & _BDF_FONT_BBX ) )
02239       {
02240         /* Missing the FONTBOUNDINGBOX field. */
02241         FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
02242         error = BDF_Err_Missing_Fontboundingbox_Field;
02243         goto Exit;
02244       }
02245 
02246       /* Add the two standard X11 properties which are required */
02247       /* for compiling fonts.                                   */
02248       p->font->font_ascent = p->font->bbx.ascent;
02249       ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
02250       error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
02251       if ( error )
02252         goto Exit;
02253       FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
02254 
02255       p->font->font_descent = p->font->bbx.descent;
02256       ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
02257       error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
02258       if ( error )
02259         goto Exit;
02260       FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
02261 
02262       p->font->modified = 1;
02263 
02264       *next = _bdf_parse_glyphs;
02265 
02266       /* A special return value. */
02267       error = -1;
02268       goto Exit;
02269     }
02270 
02271     error = BDF_Err_Invalid_File_Format;
02272 
02273   Exit:
02274     return error;
02275   }
02276 
02277 
02278   /*************************************************************************/
02279   /*                                                                       */
02280   /* API.                                                                  */
02281   /*                                                                       */
02282   /*************************************************************************/
02283 
02284 
02285   FT_LOCAL_DEF( FT_Error )
02286   bdf_load_font( FT_Stream       stream,
02287                  FT_Memory       extmemory,
02288                  bdf_options_t*  opts,
02289                  bdf_font_t*    *font )
02290   {
02291     unsigned long  lineno = 0; /* make compiler happy */
02292     _bdf_parse_t   *p     = NULL;
02293 
02294     FT_Memory      memory = extmemory;
02295     FT_Error       error  = BDF_Err_Ok;
02296 
02297 
02298     if ( FT_NEW( p ) )
02299       goto Exit;
02300 
02301     memory    = NULL;
02302     p->opts   = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
02303     p->minlb  = 32767;
02304     p->memory = extmemory;  /* only during font creation */
02305 
02306     _bdf_list_init( &p->list, extmemory );
02307 
02308     error = _bdf_readstream( stream, _bdf_parse_start,
02309                              (void *)p, &lineno );
02310     if ( error )
02311       goto Fail;
02312 
02313     if ( p->font != 0 )
02314     {
02315       /* If the font is not proportional, set the font's monowidth */
02316       /* field to the width of the font bounding box.              */
02317       memory = p->font->memory;
02318 
02319       if ( p->font->spacing != BDF_PROPORTIONAL )
02320         p->font->monowidth = p->font->bbx.width;
02321 
02322       /* If the number of glyphs loaded is not that of the original count, */
02323       /* indicate the difference.                                          */
02324       if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
02325       {
02326         FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
02327                     p->font->glyphs_used + p->font->unencoded_used ));
02328         p->font->modified = 1;
02329       }
02330 
02331       /* Once the font has been loaded, adjust the overall font metrics if */
02332       /* necessary.                                                        */
02333       if ( p->opts->correct_metrics != 0 &&
02334            ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
02335       {
02336         if ( p->maxrb - p->minlb != p->font->bbx.width )
02337         {
02338           FT_TRACE2(( "bdf_load_font: " ACMSG3,
02339                       p->font->bbx.width, p->maxrb - p->minlb ));
02340           p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
02341           p->font->modified  = 1;
02342         }
02343 
02344         if ( p->font->bbx.x_offset != p->minlb )
02345         {
02346           FT_TRACE2(( "bdf_load_font: " ACMSG4,
02347                       p->font->bbx.x_offset, p->minlb ));
02348           p->font->bbx.x_offset = p->minlb;
02349           p->font->modified     = 1;
02350         }
02351 
02352         if ( p->font->bbx.ascent != p->maxas )
02353         {
02354           FT_TRACE2(( "bdf_load_font: " ACMSG5,
02355                       p->font->bbx.ascent, p->maxas ));
02356           p->font->bbx.ascent = p->maxas;
02357           p->font->modified   = 1;
02358         }
02359 
02360         if ( p->font->bbx.descent != p->maxds )
02361         {
02362           FT_TRACE2(( "bdf_load_font: " ACMSG6,
02363                       p->font->bbx.descent, p->maxds ));
02364           p->font->bbx.descent  = p->maxds;
02365           p->font->bbx.y_offset = (short)( -p->maxds );
02366           p->font->modified     = 1;
02367         }
02368 
02369         if ( p->maxas + p->maxds != p->font->bbx.height )
02370         {
02371           FT_TRACE2(( "bdf_load_font: " ACMSG7,
02372                       p->font->bbx.height, p->maxas + p->maxds ));
02373           p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
02374         }
02375 
02376         if ( p->flags & _BDF_SWIDTH_ADJ )
02377           FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
02378       }
02379     }
02380 
02381     if ( p->flags & _BDF_START )
02382     {
02383       {
02384         /* The ENDFONT field was never reached or did not exist. */
02385         if ( !( p->flags & _BDF_GLYPHS ) )
02386         {
02387           /* Error happened while parsing header. */
02388           FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
02389           error = BDF_Err_Corrupted_Font_Header;
02390           goto Exit;
02391         }
02392         else
02393         {
02394           /* Error happened when parsing glyphs. */
02395           FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
02396           error = BDF_Err_Corrupted_Font_Glyphs;
02397           goto Exit;
02398         }
02399       }
02400     }
02401 
02402     if ( p->font != 0 )
02403     {
02404       /* Make sure the comments are NULL terminated if they exist. */
02405       memory = p->font->memory;
02406 
02407       if ( p->font->comments_len > 0 )
02408       {
02409         if ( FT_RENEW_ARRAY( p->font->comments,
02410                              p->font->comments_len,
02411                              p->font->comments_len + 1 ) )
02412           goto Fail;
02413 
02414         p->font->comments[p->font->comments_len] = 0;
02415       }
02416     }
02417     else if ( error == BDF_Err_Ok )
02418       error = BDF_Err_Invalid_File_Format;
02419 
02420     *font = p->font;
02421 
02422   Exit:
02423     if ( p )
02424     {
02425       _bdf_list_done( &p->list );
02426 
02427       memory = extmemory;
02428 
02429       FT_FREE( p );
02430     }
02431 
02432     return error;
02433 
02434   Fail:
02435     bdf_free_font( p->font );
02436 
02437     memory = extmemory;
02438 
02439     FT_FREE( p->font );
02440 
02441     goto Exit;
02442   }
02443 
02444 
02445   FT_LOCAL_DEF( void )
02446   bdf_free_font( bdf_font_t*  font )
02447   {
02448     bdf_property_t*  prop;
02449     unsigned long    i;
02450     bdf_glyph_t*     glyphs;
02451     FT_Memory        memory;
02452 
02453 
02454     if ( font == 0 )
02455       return;
02456 
02457     memory = font->memory;
02458 
02459     FT_FREE( font->name );
02460 
02461     /* Free up the internal hash table of property names. */
02462     if ( font->internal )
02463     {
02464       hash_free( (hashtable *)font->internal, memory );
02465       FT_FREE( font->internal );
02466     }
02467 
02468     /* Free up the comment info. */
02469     FT_FREE( font->comments );
02470 
02471     /* Free up the properties. */
02472     for ( i = 0; i < font->props_size; i++ )
02473     {
02474       if ( font->props[i].format == BDF_ATOM )
02475         FT_FREE( font->props[i].value.atom );
02476     }
02477 
02478     FT_FREE( font->props );
02479 
02480     /* Free up the character info. */
02481     for ( i = 0, glyphs = font->glyphs;
02482           i < font->glyphs_used; i++, glyphs++ )
02483     {
02484       FT_FREE( glyphs->name );
02485       FT_FREE( glyphs->bitmap );
02486     }
02487 
02488     for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
02489           i++, glyphs++ )
02490     {
02491       FT_FREE( glyphs->name );
02492       FT_FREE( glyphs->bitmap );
02493     }
02494 
02495     FT_FREE( font->glyphs );
02496     FT_FREE( font->unencoded );
02497 
02498     /* Free up the overflow storage if it was used. */
02499     for ( i = 0, glyphs = font->overflow.glyphs;
02500           i < font->overflow.glyphs_used; i++, glyphs++ )
02501     {
02502       FT_FREE( glyphs->name );
02503       FT_FREE( glyphs->bitmap );
02504     }
02505 
02506     FT_FREE( font->overflow.glyphs );
02507 
02508     /* bdf_cleanup */
02509     hash_free( &(font->proptbl), memory );
02510 
02511     /* Free up the user defined properties. */
02512     for ( prop = font->user_props, i = 0;
02513           i < font->nuser_props; i++, prop++ )
02514     {
02515       FT_FREE( prop->name );
02516       if ( prop->format == BDF_ATOM )
02517         FT_FREE( prop->value.atom );
02518     }
02519 
02520     FT_FREE( font->user_props );
02521 
02522     /* FREE( font ); */ /* XXX Fixme */
02523   }
02524 
02525 
02526   FT_LOCAL_DEF( bdf_property_t * )
02527   bdf_get_font_property( bdf_font_t*  font,
02528                          const char*  name )
02529   {
02530     hashnode  hn;
02531 
02532 
02533     if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
02534       return 0;
02535 
02536     hn = hash_lookup( name, (hashtable *)font->internal );
02537 
02538     return hn ? ( font->props + hn->data ) : 0;
02539   }
02540 
02541 
02542 /* END */

Generated on Sat May 26 2012 04:32:39 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.