(root)/
freetype-2.13.2/
src/
bdf/
bdflib.c
       1  /*
       2   * Copyright 2000 Computing Research Labs, New Mexico State University
       3   * Copyright 2001-2014
       4   *   Francesco Zappa Nardelli
       5   *
       6   * Permission is hereby granted, free of charge, to any person obtaining a
       7   * copy of this software and associated documentation files (the "Software"),
       8   * to deal in the Software without restriction, including without limitation
       9   * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      10   * and/or sell copies of the Software, and to permit persons to whom the
      11   * Software is furnished to do so, subject to the following conditions:
      12   *
      13   * The above copyright notice and this permission notice shall be included in
      14   * all copies or substantial portions of the Software.
      15   *
      16   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      17   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      18   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      19   * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
      20   * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
      21   * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
      22   * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      23   */
      24  
      25    /**************************************************************************
      26     *
      27     * This file is based on bdf.c,v 1.22 2000/03/16 20:08:50
      28     *
      29     * taken from Mark Leisher's xmbdfed package
      30     *
      31     */
      32  
      33  
      34  
      35  #include <freetype/freetype.h>
      36  #include <freetype/internal/ftdebug.h>
      37  #include <freetype/internal/ftstream.h>
      38  #include <freetype/internal/ftobjs.h>
      39  
      40  #include "bdf.h"
      41  #include "bdferror.h"
      42  
      43  
      44    /**************************************************************************
      45     *
      46     * The macro FT_COMPONENT is used in trace mode.  It is an implicit
      47     * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
      48     * messages during execution.
      49     */
      50  #undef  FT_COMPONENT
      51  #define FT_COMPONENT  bdflib
      52  
      53  
      54  #define BUFSIZE  128
      55  
      56  
      57    /**************************************************************************
      58     *
      59     * Default BDF font options.
      60     *
      61     */
      62  
      63  
      64    static const bdf_options_t  bdf_opts_ =
      65    {
      66      1,                /* Correct metrics.               */
      67      1,                /* Preserve unencoded glyphs.     */
      68      0,                /* Preserve comments.             */
      69      BDF_PROPORTIONAL  /* Default spacing.               */
      70    };
      71  
      72  
      73    /**************************************************************************
      74     *
      75     * Builtin BDF font properties.
      76     *
      77     */
      78  
      79    /* List of most properties that might appear in a font.  Doesn't include */
      80    /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts.           */
      81  
      82    static const bdf_property_t  bdf_properties_[] =
      83    {
      84      { "ADD_STYLE_NAME",          BDF_ATOM,     1, { 0 } },
      85      { "AVERAGE_WIDTH",           BDF_INTEGER,  1, { 0 } },
      86      { "AVG_CAPITAL_WIDTH",       BDF_INTEGER,  1, { 0 } },
      87      { "AVG_LOWERCASE_WIDTH",     BDF_INTEGER,  1, { 0 } },
      88      { "CAP_HEIGHT",              BDF_INTEGER,  1, { 0 } },
      89      { "CHARSET_COLLECTIONS",     BDF_ATOM,     1, { 0 } },
      90      { "CHARSET_ENCODING",        BDF_ATOM,     1, { 0 } },
      91      { "CHARSET_REGISTRY",        BDF_ATOM,     1, { 0 } },
      92      { "COMMENT",                 BDF_ATOM,     1, { 0 } },
      93      { "COPYRIGHT",               BDF_ATOM,     1, { 0 } },
      94      { "DEFAULT_CHAR",            BDF_CARDINAL, 1, { 0 } },
      95      { "DESTINATION",             BDF_CARDINAL, 1, { 0 } },
      96      { "DEVICE_FONT_NAME",        BDF_ATOM,     1, { 0 } },
      97      { "END_SPACE",               BDF_INTEGER,  1, { 0 } },
      98      { "FACE_NAME",               BDF_ATOM,     1, { 0 } },
      99      { "FAMILY_NAME",             BDF_ATOM,     1, { 0 } },
     100      { "FIGURE_WIDTH",            BDF_INTEGER,  1, { 0 } },
     101      { "FONT",                    BDF_ATOM,     1, { 0 } },
     102      { "FONTNAME_REGISTRY",       BDF_ATOM,     1, { 0 } },
     103      { "FONT_ASCENT",             BDF_INTEGER,  1, { 0 } },
     104      { "FONT_DESCENT",            BDF_INTEGER,  1, { 0 } },
     105      { "FOUNDRY",                 BDF_ATOM,     1, { 0 } },
     106      { "FULL_NAME",               BDF_ATOM,     1, { 0 } },
     107      { "ITALIC_ANGLE",            BDF_INTEGER,  1, { 0 } },
     108      { "MAX_SPACE",               BDF_INTEGER,  1, { 0 } },
     109      { "MIN_SPACE",               BDF_INTEGER,  1, { 0 } },
     110      { "NORM_SPACE",              BDF_INTEGER,  1, { 0 } },
     111      { "NOTICE",                  BDF_ATOM,     1, { 0 } },
     112      { "PIXEL_SIZE",              BDF_INTEGER,  1, { 0 } },
     113      { "POINT_SIZE",              BDF_INTEGER,  1, { 0 } },
     114      { "QUAD_WIDTH",              BDF_INTEGER,  1, { 0 } },
     115      { "RAW_ASCENT",              BDF_INTEGER,  1, { 0 } },
     116      { "RAW_AVERAGE_WIDTH",       BDF_INTEGER,  1, { 0 } },
     117      { "RAW_AVG_CAPITAL_WIDTH",   BDF_INTEGER,  1, { 0 } },
     118      { "RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER,  1, { 0 } },
     119      { "RAW_CAP_HEIGHT",          BDF_INTEGER,  1, { 0 } },
     120      { "RAW_DESCENT",             BDF_INTEGER,  1, { 0 } },
     121      { "RAW_END_SPACE",           BDF_INTEGER,  1, { 0 } },
     122      { "RAW_FIGURE_WIDTH",        BDF_INTEGER,  1, { 0 } },
     123      { "RAW_MAX_SPACE",           BDF_INTEGER,  1, { 0 } },
     124      { "RAW_MIN_SPACE",           BDF_INTEGER,  1, { 0 } },
     125      { "RAW_NORM_SPACE",          BDF_INTEGER,  1, { 0 } },
     126      { "RAW_PIXEL_SIZE",          BDF_INTEGER,  1, { 0 } },
     127      { "RAW_POINT_SIZE",          BDF_INTEGER,  1, { 0 } },
     128      { "RAW_PIXELSIZE",           BDF_INTEGER,  1, { 0 } },
     129      { "RAW_POINTSIZE",           BDF_INTEGER,  1, { 0 } },
     130      { "RAW_QUAD_WIDTH",          BDF_INTEGER,  1, { 0 } },
     131      { "RAW_SMALL_CAP_SIZE",      BDF_INTEGER,  1, { 0 } },
     132      { "RAW_STRIKEOUT_ASCENT",    BDF_INTEGER,  1, { 0 } },
     133      { "RAW_STRIKEOUT_DESCENT",   BDF_INTEGER,  1, { 0 } },
     134      { "RAW_SUBSCRIPT_SIZE",      BDF_INTEGER,  1, { 0 } },
     135      { "RAW_SUBSCRIPT_X",         BDF_INTEGER,  1, { 0 } },
     136      { "RAW_SUBSCRIPT_Y",         BDF_INTEGER,  1, { 0 } },
     137      { "RAW_SUPERSCRIPT_SIZE",    BDF_INTEGER,  1, { 0 } },
     138      { "RAW_SUPERSCRIPT_X",       BDF_INTEGER,  1, { 0 } },
     139      { "RAW_SUPERSCRIPT_Y",       BDF_INTEGER,  1, { 0 } },
     140      { "RAW_UNDERLINE_POSITION",  BDF_INTEGER,  1, { 0 } },
     141      { "RAW_UNDERLINE_THICKNESS", BDF_INTEGER,  1, { 0 } },
     142      { "RAW_X_HEIGHT",            BDF_INTEGER,  1, { 0 } },
     143      { "RELATIVE_SETWIDTH",       BDF_CARDINAL, 1, { 0 } },
     144      { "RELATIVE_WEIGHT",         BDF_CARDINAL, 1, { 0 } },
     145      { "RESOLUTION",              BDF_INTEGER,  1, { 0 } },
     146      { "RESOLUTION_X",            BDF_CARDINAL, 1, { 0 } },
     147      { "RESOLUTION_Y",            BDF_CARDINAL, 1, { 0 } },
     148      { "SETWIDTH_NAME",           BDF_ATOM,     1, { 0 } },
     149      { "SLANT",                   BDF_ATOM,     1, { 0 } },
     150      { "SMALL_CAP_SIZE",          BDF_INTEGER,  1, { 0 } },
     151      { "SPACING",                 BDF_ATOM,     1, { 0 } },
     152      { "STRIKEOUT_ASCENT",        BDF_INTEGER,  1, { 0 } },
     153      { "STRIKEOUT_DESCENT",       BDF_INTEGER,  1, { 0 } },
     154      { "SUBSCRIPT_SIZE",          BDF_INTEGER,  1, { 0 } },
     155      { "SUBSCRIPT_X",             BDF_INTEGER,  1, { 0 } },
     156      { "SUBSCRIPT_Y",             BDF_INTEGER,  1, { 0 } },
     157      { "SUPERSCRIPT_SIZE",        BDF_INTEGER,  1, { 0 } },
     158      { "SUPERSCRIPT_X",           BDF_INTEGER,  1, { 0 } },
     159      { "SUPERSCRIPT_Y",           BDF_INTEGER,  1, { 0 } },
     160      { "UNDERLINE_POSITION",      BDF_INTEGER,  1, { 0 } },
     161      { "UNDERLINE_THICKNESS",     BDF_INTEGER,  1, { 0 } },
     162      { "WEIGHT",                  BDF_CARDINAL, 1, { 0 } },
     163      { "WEIGHT_NAME",             BDF_ATOM,     1, { 0 } },
     164      { "X_HEIGHT",                BDF_INTEGER,  1, { 0 } },
     165      { "_MULE_BASELINE_OFFSET",   BDF_INTEGER,  1, { 0 } },
     166      { "_MULE_RELATIVE_COMPOSE",  BDF_INTEGER,  1, { 0 } },
     167    };
     168  
     169    static const unsigned long
     170    num_bdf_properties_ = sizeof ( bdf_properties_ ) /
     171                          sizeof ( bdf_properties_[0] );
     172  
     173  
     174    /* An auxiliary macro to parse properties, to be used in conditionals. */
     175    /* It behaves like `strncmp' but also tests the following character    */
     176    /* whether it is a whitespace or null.                                 */
     177    /* `property' is a constant string of length `n' to compare with.      */
     178  #define _bdf_strncmp( name, property, n )      \
     179            ( ft_strncmp( name, property, n ) || \
     180              !( name[n] == ' '  ||              \
     181                 name[n] == '\0' ||              \
     182                 name[n] == '\n' ||              \
     183                 name[n] == '\r' ||              \
     184                 name[n] == '\t' )            )
     185  
     186    /* Auto correction messages. */
     187  #define ACMSG1   "FONT_ASCENT property missing.  " \
     188                   "Added `FONT_ASCENT %hd'.\n"
     189  #define ACMSG2   "FONT_DESCENT property missing.  " \
     190                   "Added `FONT_DESCENT %hd'.\n"
     191  #define ACMSG3   "Font width != actual width.  Old: %d New: %d.\n"
     192  #define ACMSG4   "Font left bearing != actual left bearing.  " \
     193                   "Old: %hd New: %hd.\n"
     194  #define ACMSG5   "Font ascent != actual ascent.  Old: %hd New: %hd.\n"
     195  #define ACMSG6   "Font descent != actual descent.  Old: %d New: %d.\n"
     196  #define ACMSG7   "Font height != actual height. Old: %d New: %d.\n"
     197  #define ACMSG8   "Glyph scalable width (SWIDTH) adjustments made.\n"
     198  #define ACMSG9   "SWIDTH field missing at line %ld.  Set automatically.\n"
     199  #define ACMSG10  "DWIDTH field missing at line %ld.  Set to glyph width.\n"
     200  #define ACMSG11  "SIZE bits per pixel field adjusted to %hd.\n"
     201  #define ACMSG13  "Glyph %lu extra rows removed.\n"
     202  #define ACMSG14  "Glyph %lu extra columns removed.\n"
     203  #define ACMSG15  "Incorrect glyph count: %ld indicated but %ld found.\n"
     204  #define ACMSG16  "Glyph %lu missing columns padded with zero bits.\n"
     205  #define ACMSG17  "Adjusting number of glyphs to %ld.\n"
     206  
     207    /* Error messages. */
     208  #define ERRMSG1  "[line %ld] Missing `%s' line.\n"
     209  #define ERRMSG2  "[line %ld] Font header corrupted or missing fields.\n"
     210  #define ERRMSG3  "[line %ld] Font glyphs corrupted or missing fields.\n"
     211  #define ERRMSG4  "[line %ld] BBX too big.\n"
     212  #define ERRMSG5  "[line %ld] `%s' value too big.\n"
     213  #define ERRMSG6  "[line %ld] Input line too long.\n"
     214  #define ERRMSG7  "[line %ld] Font name too long.\n"
     215  #define ERRMSG8  "[line %ld] Invalid `%s' value.\n"
     216  #define ERRMSG9  "[line %ld] Invalid keyword.\n"
     217  
     218    /* Debug messages. */
     219  #define DBGMSG1  "  [%6ld] %s" /* no \n */
     220  #define DBGMSG2  " (0x%lX)\n"
     221  
     222  
     223    /**************************************************************************
     224     *
     225     * Utility types and functions.
     226     *
     227     */
     228  
     229  
     230    /* Function type for parsing lines of a BDF font. */
     231  
     232    typedef FT_Error
     233    (*bdf_line_func_t_)( char*          line,
     234                         unsigned long  linelen,
     235                         unsigned long  lineno,
     236                         void*          call_data,
     237                         void*          client_data );
     238  
     239  
     240    /* List structure for splitting lines into fields. */
     241  
     242    typedef struct  bdf_list_t__
     243    {
     244      char**         field;
     245      unsigned long  size;
     246      unsigned long  used;
     247      FT_Memory      memory;
     248  
     249    } bdf_list_t_;
     250  
     251  
     252    /* Structure used while loading BDF fonts. */
     253  
     254    typedef struct  bdf_parse_t__
     255    {
     256      unsigned long   flags;
     257      unsigned long   cnt;
     258      unsigned long   row;
     259  
     260      short           minlb;
     261      short           maxlb;
     262      short           maxrb;
     263      short           maxas;
     264      short           maxds;
     265  
     266      short           rbearing;
     267  
     268      char*           glyph_name;
     269      long            glyph_enc;
     270  
     271      bdf_font_t*     font;
     272      bdf_options_t*  opts;
     273  
     274      bdf_list_t_     list;
     275  
     276      FT_Memory       memory;
     277      unsigned long   size;        /* the stream size */
     278  
     279    } bdf_parse_t_;
     280  
     281  
     282  #define setsbit( m, cc ) \
     283            ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
     284  #define sbitset( m, cc ) \
     285            ( m[(FT_Byte)(cc) >> 3]  & ( 1 << ( (cc) & 7 ) ) )
     286  
     287  
     288    static void
     289    bdf_list_init_( bdf_list_t_*  list,
     290                    FT_Memory     memory )
     291    {
     292      FT_ZERO( list );
     293      list->memory = memory;
     294    }
     295  
     296  
     297    static void
     298    bdf_list_done_( bdf_list_t_*  list )
     299    {
     300      FT_Memory  memory = list->memory;
     301  
     302  
     303      if ( memory )
     304      {
     305        FT_FREE( list->field );
     306        FT_ZERO( list );
     307      }
     308    }
     309  
     310  
     311    static FT_Error
     312    bdf_list_ensure_( bdf_list_t_*   list,
     313                      unsigned long  num_items ) /* same as bdf_list_t_.used */
     314    {
     315      FT_Error  error = FT_Err_Ok;
     316  
     317  
     318      if ( num_items > list->size )
     319      {
     320        unsigned long  oldsize = list->size; /* same as bdf_list_t_.size */
     321        unsigned long  newsize = oldsize + ( oldsize >> 1 ) + 5;
     322        unsigned long  bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
     323        FT_Memory      memory  = list->memory;
     324  
     325  
     326        if ( oldsize == bigsize )
     327        {
     328          error = FT_THROW( Out_Of_Memory );
     329          goto Exit;
     330        }
     331        else if ( newsize < oldsize || newsize > bigsize )
     332          newsize = bigsize;
     333  
     334        if ( FT_QRENEW_ARRAY( list->field, oldsize, newsize ) )
     335          goto Exit;
     336  
     337        list->size = newsize;
     338      }
     339  
     340    Exit:
     341      return error;
     342    }
     343  
     344  
     345    static void
     346    bdf_list_shift_( bdf_list_t_*   list,
     347                     unsigned long  n )
     348    {
     349      unsigned long  i, u;
     350  
     351  
     352      if ( list == NULL || list->used == 0 || n == 0 )
     353        return;
     354  
     355      if ( n >= list->used )
     356      {
     357        list->used = 0;
     358        return;
     359      }
     360  
     361      for ( u = n, i = 0; u < list->used; i++, u++ )
     362        list->field[i] = list->field[u];
     363      list->used -= n;
     364    }
     365  
     366  
     367    /* An empty string for empty fields. */
     368  
     369    static const char  empty[] = "";      /* XXX eliminate this */
     370  
     371  
     372    static char *
     373    bdf_list_join_( bdf_list_t_*    list,
     374                    int             c,
     375                    unsigned long  *alen )
     376    {
     377      unsigned long  i, j;
     378      char*          dp;
     379  
     380  
     381      *alen = 0;
     382  
     383      if ( list == NULL || list->used == 0 )
     384        return NULL;
     385  
     386      dp = list->field[0];
     387      for ( i = j = 0; i < list->used; i++ )
     388      {
     389        char*  fp = list->field[i];
     390  
     391  
     392        while ( *fp )
     393          dp[j++] = *fp++;
     394  
     395        if ( i + 1 < list->used )
     396          dp[j++] = (char)c;
     397      }
     398      if ( dp != empty )
     399        dp[j] = 0;
     400  
     401      *alen = j;
     402      return dp;
     403    }
     404  
     405  
     406    /* The code below ensures that we have at least 4 + 1 `field' */
     407    /* elements in `list' (which are possibly NULL) so that we    */
     408    /* don't have to check the number of fields in most cases.    */
     409  
     410    static FT_Error
     411    bdf_list_split_( bdf_list_t_*   list,
     412                     const char*    separators,
     413                     char*          line,
     414                     unsigned long  linelen )
     415    {
     416      unsigned long  final_empty;
     417      int            mult;
     418      const char     *sp, *end;
     419      char           *ep;
     420      char           seps[32];
     421      FT_Error       error = FT_Err_Ok;
     422  
     423  
     424      /* Initialize the list. */
     425      list->used = 0;
     426      if ( list->size )
     427      {
     428        list->field[0] = (char*)empty;
     429        list->field[1] = (char*)empty;
     430        list->field[2] = (char*)empty;
     431        list->field[3] = (char*)empty;
     432        list->field[4] = (char*)empty;
     433      }
     434  
     435      /* If the line is empty, then simply return. */
     436      if ( linelen == 0 || line[0] == 0 )
     437        goto Exit;
     438  
     439      /* In the original code, if the `separators' parameter is NULL or */
     440      /* empty, the list is split into individual bytes.  We don't need */
     441      /* this, so an error is signaled.                                 */
     442      if ( separators == NULL || *separators == 0 )
     443      {
     444        error = FT_THROW( Invalid_Argument );
     445        goto Exit;
     446      }
     447  
     448      /* Prepare the separator bitmap. */
     449      FT_MEM_ZERO( seps, 32 );
     450  
     451      /* If the very last character of the separator string is a plus, then */
     452      /* set the `mult' flag to indicate that multiple separators should be */
     453      /* collapsed into one.                                                */
     454      for ( mult = 0, sp = separators; sp && *sp; sp++ )
     455      {
     456        if ( *sp == '+' && *( sp + 1 ) == 0 )
     457          mult = 1;
     458        else
     459          setsbit( seps, *sp );
     460      }
     461  
     462      /* Break the line up into fields. */
     463      for ( final_empty = 0, sp = ep = line, end = sp + linelen;
     464            sp < end && *sp; )
     465      {
     466        /* Collect everything that is not a separator. */
     467        for ( ; *ep && !sbitset( seps, *ep ); ep++ )
     468          ;
     469  
     470        /* Resize the list if necessary. */
     471        if ( list->used == list->size )
     472        {
     473          error = bdf_list_ensure_( list, list->used + 1 );
     474          if ( error )
     475            goto Exit;
     476        }
     477  
     478        /* Assign the field appropriately. */
     479        list->field[list->used++] = ( ep > sp ) ? (char*)sp : (char*)empty;
     480  
     481        sp = ep;
     482  
     483        if ( mult )
     484        {
     485          /* If multiple separators should be collapsed, do it now by */
     486          /* setting all the separator characters to 0.               */
     487          for ( ; *ep && sbitset( seps, *ep ); ep++ )
     488            *ep = 0;
     489        }
     490        else if ( *ep != 0 )
     491          /* Don't collapse multiple separators by making them 0, so just */
     492          /* make the one encountered 0.                                  */
     493          *ep++ = 0;
     494  
     495        final_empty = ( ep > sp && *ep == 0 );
     496        sp = ep;
     497      }
     498  
     499      /* Finally, NULL-terminate the list. */
     500      if ( list->used + final_empty >= list->size )
     501      {
     502        error = bdf_list_ensure_( list, list->used + final_empty + 1 );
     503        if ( error )
     504          goto Exit;
     505      }
     506  
     507      if ( final_empty )
     508        list->field[list->used++] = (char*)empty;
     509  
     510      list->field[list->used] = NULL;
     511  
     512    Exit:
     513      return error;
     514    }
     515  
     516  
     517  #define NO_SKIP  256  /* this value cannot be stored in a 'char' */
     518  
     519  
     520    static FT_Error
     521    bdf_readstream_( FT_Stream         stream,
     522                     bdf_line_func_t_  callback,
     523                     void*             client_data,
     524                     unsigned long    *lno )
     525    {
     526      bdf_line_func_t_  cb;
     527      unsigned long     lineno, buf_size;
     528      int               refill, hold, to_skip;
     529      ptrdiff_t         bytes, start, end, cursor, avail;
     530      char*             buf    = NULL;
     531      FT_Memory         memory = stream->memory;
     532      FT_Error          error  = FT_Err_Ok;
     533  
     534  
     535      if ( callback == NULL )
     536      {
     537        error = FT_THROW( Invalid_Argument );
     538        goto Exit;
     539      }
     540  
     541      /* initial size and allocation of the input buffer */
     542      buf_size = 1024;
     543  
     544      if ( FT_QALLOC( buf, buf_size ) )
     545        goto Exit;
     546  
     547      cb      = callback;
     548      lineno  = 1;
     549      buf[0]  = 0;
     550      start   = 0;
     551      avail   = 0;
     552      cursor  = 0;
     553      refill  = 1;
     554      to_skip = NO_SKIP;
     555      bytes   = 0;        /* make compiler happy */
     556  
     557      for (;;)
     558      {
     559        if ( refill )
     560        {
     561          bytes  = (ptrdiff_t)FT_Stream_TryRead(
     562                     stream, (FT_Byte*)buf + cursor,
     563                     buf_size - (unsigned long)cursor );
     564          avail  = cursor + bytes;
     565          cursor = 0;
     566          refill = 0;
     567        }
     568  
     569        end = start;
     570  
     571        /* should we skip an optional character like \n or \r? */
     572        if ( start < avail && buf[start] == to_skip )
     573        {
     574          start  += 1;
     575          to_skip = NO_SKIP;
     576          continue;
     577        }
     578  
     579        /* try to find the end of the line */
     580        while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
     581          end++;
     582  
     583        /* if we hit the end of the buffer, try shifting its content */
     584        /* or even resizing it                                       */
     585        if ( end >= avail )
     586        {
     587          if ( bytes == 0 )
     588          {
     589            /* last line in file doesn't end in \r or \n; */
     590            /* ignore it then exit                        */
     591            if ( lineno == 1 )
     592              error = FT_THROW( Missing_Startfont_Field );
     593            break;
     594          }
     595  
     596          if ( start == 0 )
     597          {
     598            /* this line is definitely too long; try resizing the input */
     599            /* buffer a bit to handle it.                               */
     600            FT_ULong  new_size;
     601  
     602  
     603            if ( buf_size >= 65536UL )  /* limit ourselves to 64KByte */
     604            {
     605              if ( lineno == 1 )
     606                error = FT_THROW( Missing_Startfont_Field );
     607              else
     608              {
     609                FT_ERROR(( "bdf_readstream_: " ERRMSG6, lineno ));
     610                error = FT_THROW( Invalid_Argument );
     611              }
     612              goto Exit;
     613            }
     614  
     615            new_size = buf_size * 2;
     616            if ( FT_QREALLOC( buf, buf_size, new_size ) )
     617              goto Exit;
     618  
     619            cursor   = avail;
     620            buf_size = new_size;
     621          }
     622          else
     623          {
     624            bytes = avail - start;
     625  
     626            FT_MEM_MOVE( buf, buf + start, bytes );
     627  
     628            cursor = bytes;
     629            start  = 0;
     630          }
     631          refill = 1;
     632          continue;
     633        }
     634  
     635        /* Temporarily NUL-terminate the line. */
     636        hold     = buf[end];
     637        buf[end] = 0;
     638  
     639        /* XXX: Use encoding independent value for 0x1A */
     640        if ( buf[start] != '#' && buf[start] != 0x1A && end > start )
     641        {
     642          error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
     643                         (void*)&cb, client_data );
     644          /* Redo if we have encountered CHARS without properties. */
     645          if ( error == -1 )
     646            error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
     647                           (void*)&cb, client_data );
     648          if ( error )
     649            break;
     650        }
     651  
     652        lineno  += 1;
     653        buf[end] = (char)hold;
     654        start    = end + 1;
     655  
     656        if ( hold == '\n' )
     657          to_skip = '\r';
     658        else if ( hold == '\r' )
     659          to_skip = '\n';
     660        else
     661          to_skip = NO_SKIP;
     662      }
     663  
     664      *lno = lineno;
     665  
     666    Exit:
     667      FT_FREE( buf );
     668      return error;
     669    }
     670  
     671  
     672    /* XXX: make this work with EBCDIC also */
     673  
     674    static const unsigned char  a2i[128] =
     675    {
     676      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     677      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     678      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     679      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     680      0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
     681      0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
     682      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     683      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     684      0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
     685      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     686      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     687    };
     688  
     689    static const unsigned char  ddigits[32] =
     690    {
     691      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
     692      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     693      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     694      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     695    };
     696  
     697    static const unsigned char  hdigits[32] =
     698    {
     699      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
     700      0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00,
     701      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     702      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     703    };
     704  
     705  
     706    /* Routine to convert a decimal ASCII string to an unsigned long integer. */
     707    static unsigned long
     708    bdf_atoul_( const char*  s )
     709    {
     710      unsigned long  v;
     711  
     712  
     713      if ( s == NULL || *s == 0 )
     714        return 0;
     715  
     716      for ( v = 0; sbitset( ddigits, *s ); s++ )
     717      {
     718        if ( v < ( FT_ULONG_MAX - 9 ) / 10 )
     719          v = v * 10 + a2i[(int)*s];
     720        else
     721        {
     722          v = FT_ULONG_MAX;
     723          break;
     724        }
     725      }
     726  
     727      return v;
     728    }
     729  
     730  
     731    /* Routine to convert a decimal ASCII string to a signed long integer. */
     732    static long
     733    bdf_atol_( const char*  s )
     734    {
     735      long  v, neg;
     736  
     737  
     738      if ( s == NULL || *s == 0 )
     739        return 0;
     740  
     741      /* Check for a minus sign. */
     742      neg = 0;
     743      if ( *s == '-' )
     744      {
     745        s++;
     746        neg = 1;
     747      }
     748  
     749      for ( v = 0; sbitset( ddigits, *s ); s++ )
     750      {
     751        if ( v < ( FT_LONG_MAX - 9 ) / 10 )
     752          v = v * 10 + a2i[(int)*s];
     753        else
     754        {
     755          v = FT_LONG_MAX;
     756          break;
     757        }
     758      }
     759  
     760      return ( !neg ) ? v : -v;
     761    }
     762  
     763  
     764    /* Routine to convert a decimal ASCII string to an unsigned short integer. */
     765    static unsigned short
     766    bdf_atous_( const char*  s )
     767    {
     768      unsigned short  v;
     769  
     770  
     771      if ( s == NULL || *s == 0 )
     772        return 0;
     773  
     774      for ( v = 0; sbitset( ddigits, *s ); s++ )
     775      {
     776        if ( v < ( FT_USHORT_MAX - 9 ) / 10 )
     777          v = (unsigned short)( v * 10 + a2i[(int)*s] );
     778        else
     779        {
     780          v = FT_USHORT_MAX;
     781          break;
     782        }
     783      }
     784  
     785      return v;
     786    }
     787  
     788  
     789    /* Routine to convert a decimal ASCII string to a signed short integer. */
     790    static short
     791    bdf_atos_( const char*  s )
     792    {
     793      short  v, neg;
     794  
     795  
     796      if ( s == NULL || *s == 0 )
     797        return 0;
     798  
     799      /* Check for a minus. */
     800      neg = 0;
     801      if ( *s == '-' )
     802      {
     803        s++;
     804        neg = 1;
     805      }
     806  
     807      for ( v = 0; sbitset( ddigits, *s ); s++ )
     808      {
     809        if ( v < ( SHRT_MAX - 9 ) / 10 )
     810          v = (short)( v * 10 + a2i[(int)*s] );
     811        else
     812        {
     813          v = SHRT_MAX;
     814          break;
     815        }
     816      }
     817  
     818      return (short)( ( !neg ) ? v : -v );
     819    }
     820  
     821  
     822    /* Routine to compare two glyphs by encoding so they can be sorted. */
     823    FT_COMPARE_DEF( int )
     824    by_encoding( const void*  a,
     825                 const void*  b )
     826    {
     827      bdf_glyph_t  *c1, *c2;
     828  
     829  
     830      c1 = (bdf_glyph_t *)a;
     831      c2 = (bdf_glyph_t *)b;
     832  
     833      if ( c1->encoding < c2->encoding )
     834        return -1;
     835  
     836      if ( c1->encoding > c2->encoding )
     837        return 1;
     838  
     839      return 0;
     840    }
     841  
     842  
     843    static FT_Error
     844    bdf_create_property( const char*  name,
     845                         int          format,
     846                         bdf_font_t*  font )
     847    {
     848      size_t           n;
     849      bdf_property_t*  p;
     850      FT_Memory        memory = font->memory;
     851      FT_Error         error  = FT_Err_Ok;
     852  
     853  
     854      /* First check whether the property has        */
     855      /* already been added or not.  If it has, then */
     856      /* simply ignore it.                           */
     857      if ( ft_hash_str_lookup( name, &(font->proptbl) ) )
     858        goto Exit;
     859  
     860      if ( FT_QRENEW_ARRAY( font->user_props,
     861                            font->nuser_props,
     862                            font->nuser_props + 1 ) )
     863        goto Exit;
     864  
     865      p = font->user_props + font->nuser_props;
     866  
     867      n = ft_strlen( name ) + 1;
     868      if ( n > FT_LONG_MAX )
     869        return FT_THROW( Invalid_Argument );
     870  
     871      if ( FT_QALLOC( p->name, n ) )
     872        goto Exit;
     873  
     874      FT_MEM_COPY( (char *)p->name, name, n );
     875  
     876      p->format     = format;
     877      p->builtin    = 0;
     878      p->value.atom = NULL;  /* nothing is ever stored here */
     879  
     880      n = num_bdf_properties_ + font->nuser_props;
     881  
     882      error = ft_hash_str_insert( p->name, n, &(font->proptbl), memory );
     883      if ( error )
     884        goto Exit;
     885  
     886      font->nuser_props++;
     887  
     888    Exit:
     889      return error;
     890    }
     891  
     892  
     893    static bdf_property_t*
     894    bdf_get_property( const char*  name,
     895                      bdf_font_t*  font )
     896    {
     897      size_t*  propid;
     898  
     899  
     900      if ( name == NULL || *name == 0 )
     901        return NULL;
     902  
     903      if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL )
     904        return NULL;
     905  
     906      if ( *propid >= num_bdf_properties_ )
     907        return font->user_props + ( *propid - num_bdf_properties_ );
     908  
     909      return (bdf_property_t*)bdf_properties_ + *propid;
     910    }
     911  
     912  
     913    /**************************************************************************
     914     *
     915     * BDF font file parsing flags and functions.
     916     *
     917     */
     918  
     919  
     920    /* Parse flags. */
     921  
     922  #define BDF_START_      0x0001U
     923  #define BDF_FONT_NAME_  0x0002U
     924  #define BDF_SIZE_       0x0004U
     925  #define BDF_FONT_BBX_   0x0008U
     926  #define BDF_PROPS_      0x0010U
     927  #define BDF_GLYPHS_     0x0020U
     928  #define BDF_GLYPH_      0x0040U
     929  #define BDF_ENCODING_   0x0080U
     930  #define BDF_SWIDTH_     0x0100U
     931  #define BDF_DWIDTH_     0x0200U
     932  #define BDF_BBX_        0x0400U
     933  #define BDF_BITMAP_     0x0800U
     934  
     935  #define BDF_SWIDTH_ADJ_  0x1000U
     936  
     937  #define BDF_GLYPH_BITS_ ( BDF_GLYPH_    | \
     938                            BDF_ENCODING_ | \
     939                            BDF_SWIDTH_   | \
     940                            BDF_DWIDTH_   | \
     941                            BDF_BBX_      | \
     942                            BDF_BITMAP_   )
     943  
     944  #define BDF_GLYPH_WIDTH_CHECK_   0x40000000UL
     945  #define BDF_GLYPH_HEIGHT_CHECK_  0x80000000UL
     946  
     947  
     948    static FT_Error
     949    bdf_add_comment_( bdf_font_t*    font,
     950                      const char*    comment,
     951                      unsigned long  len )
     952    {
     953      char*      cp;
     954      FT_Memory  memory = font->memory;
     955      FT_Error   error  = FT_Err_Ok;
     956  
     957  
     958      if ( FT_QRENEW_ARRAY( font->comments,
     959                            font->comments_len,
     960                            font->comments_len + len + 1 ) )
     961        goto Exit;
     962  
     963      cp = font->comments + font->comments_len;
     964  
     965      FT_MEM_COPY( cp, comment, len );
     966      cp[len] = '\0';
     967  
     968      font->comments_len += len + 1;
     969  
     970    Exit:
     971      return error;
     972    }
     973  
     974  
     975    /* Set the spacing from the font name if it exists, or set it to the */
     976    /* default specified in the options.                                 */
     977    static FT_Error
     978    bdf_set_default_spacing_( bdf_font_t*     font,
     979                              bdf_options_t*  opts,
     980                              unsigned long   lineno )
     981    {
     982      size_t       len;
     983      char         name[256];
     984      bdf_list_t_  list;
     985      FT_Memory    memory;
     986      FT_Error     error = FT_Err_Ok;
     987  
     988      FT_UNUSED( lineno );        /* only used in debug mode */
     989  
     990  
     991      if ( font == NULL || font->name == NULL || font->name[0] == 0 )
     992      {
     993        error = FT_THROW( Invalid_Argument );
     994        goto Exit;
     995      }
     996  
     997      memory = font->memory;
     998  
     999      bdf_list_init_( &list, memory );
    1000  
    1001      font->spacing = opts->font_spacing;
    1002  
    1003      len = ft_strlen( font->name ) + 1;
    1004      /* Limit ourselves to 256 characters in the font name. */
    1005      if ( len >= 256 )
    1006      {
    1007        FT_ERROR(( "bdf_set_default_spacing_: " ERRMSG7, lineno ));
    1008        error = FT_THROW( Invalid_Argument );
    1009        goto Exit;
    1010      }
    1011  
    1012      FT_MEM_COPY( name, font->name, len );
    1013  
    1014      error = bdf_list_split_( &list, "-", name, (unsigned long)len );
    1015      if ( error )
    1016        goto Fail;
    1017  
    1018      if ( list.used == 15 )
    1019      {
    1020        switch ( list.field[11][0] )
    1021        {
    1022        case 'C':
    1023        case 'c':
    1024          font->spacing = BDF_CHARCELL;
    1025          break;
    1026        case 'M':
    1027        case 'm':
    1028          font->spacing = BDF_MONOWIDTH;
    1029          break;
    1030        case 'P':
    1031        case 'p':
    1032          font->spacing = BDF_PROPORTIONAL;
    1033          break;
    1034        }
    1035      }
    1036  
    1037    Fail:
    1038      bdf_list_done_( &list );
    1039  
    1040    Exit:
    1041      return error;
    1042    }
    1043  
    1044  
    1045    /* Determine whether the property is an atom or not.  If it is, then */
    1046    /* clean it up so the double quotes are removed if they exist.       */
    1047    static int
    1048    bdf_is_atom_( char*          line,
    1049                  unsigned long  linelen,
    1050                  char**         name,
    1051                  char**         value,
    1052                  bdf_font_t*    font )
    1053    {
    1054      int              hold;
    1055      char             *sp, *ep;
    1056      bdf_property_t*  p;
    1057  
    1058  
    1059      sp = ep = line;
    1060  
    1061      while ( *ep && *ep != ' ' && *ep != '\t' )
    1062        ep++;
    1063  
    1064      hold = *ep;
    1065      *ep  = '\0';
    1066  
    1067      p = bdf_get_property( sp, font );
    1068  
    1069      /* If the property exists and is not an atom, just return here. */
    1070      if ( p && p->format != BDF_ATOM )
    1071      {
    1072        *ep = (char)hold;  /* Undo NUL-termination. */
    1073        return 0;
    1074      }
    1075  
    1076      *name = sp;
    1077  
    1078      /* The property is an atom.  Trim all leading and trailing whitespace */
    1079      /* and double quotes for the atom value.                              */
    1080      sp = ep;
    1081      ep = line + linelen;
    1082  
    1083      /* Trim the leading whitespace if it exists. */
    1084      if ( sp < ep )
    1085        do
    1086           sp++;
    1087        while ( *sp == ' ' || *sp == '\t' );
    1088  
    1089      /* Trim the leading double quote if it exists. */
    1090      if ( *sp == '"' )
    1091        sp++;
    1092  
    1093      *value = sp;
    1094  
    1095      /* Trim the trailing whitespace if it exists. */
    1096      if ( sp < ep )
    1097        do
    1098          *ep-- = '\0';
    1099        while ( *ep == ' ' || *ep  == '\t' );
    1100  
    1101      /* Trim the trailing double quote if it exists. */
    1102      if ( *ep  == '"' )
    1103        *ep = '\0';
    1104  
    1105      return 1;
    1106    }
    1107  
    1108  
    1109    static FT_Error
    1110    bdf_add_property_( bdf_font_t*    font,
    1111                       const char*    name,
    1112                       char*          value,
    1113                       unsigned long  lineno )
    1114    {
    1115      size_t*         propid;
    1116      bdf_property_t  *prop, *fp;
    1117      FT_Memory       memory = font->memory;
    1118      FT_Error        error  = FT_Err_Ok;
    1119  
    1120      FT_UNUSED( lineno );        /* only used in debug mode */
    1121  
    1122  
    1123      /* First, check whether the property already exists in the font. */
    1124      if ( ( propid = ft_hash_str_lookup( name,
    1125                                          (FT_Hash)font->internal ) ) != NULL )
    1126      {
    1127        /* The property already exists in the font, so simply replace */
    1128        /* the value of the property with the current value.          */
    1129        fp = font->props + *propid;
    1130  
    1131        switch ( fp->format )
    1132        {
    1133        case BDF_ATOM:
    1134          /* Delete the current atom if it exists. */
    1135          FT_FREE( fp->value.atom );
    1136  
    1137          if ( value && value[0] != 0 )
    1138          {
    1139            if ( FT_STRDUP( fp->value.atom, value ) )
    1140              goto Exit;
    1141          }
    1142          break;
    1143  
    1144        case BDF_INTEGER:
    1145          fp->value.l = bdf_atol_( value );
    1146          break;
    1147  
    1148        case BDF_CARDINAL:
    1149          fp->value.ul = bdf_atoul_( value );
    1150          break;
    1151  
    1152        default:
    1153          ;
    1154        }
    1155  
    1156        goto Exit;
    1157      }
    1158  
    1159      /* See whether this property type exists yet or not. */
    1160      /* If not, create it.                                */
    1161      propid = ft_hash_str_lookup( name, &(font->proptbl) );
    1162      if ( !propid )
    1163      {
    1164        error = bdf_create_property( name, BDF_ATOM, font );
    1165        if ( error )
    1166          goto Exit;
    1167        propid = ft_hash_str_lookup( name, &(font->proptbl) );
    1168      }
    1169  
    1170      /* Allocate another property if this is overflowing. */
    1171      if ( font->props_used == font->props_size )
    1172      {
    1173        if ( FT_QRENEW_ARRAY( font->props,
    1174                              font->props_size,
    1175                              font->props_size + 1 ) )
    1176          goto Exit;
    1177  
    1178        font->props_size++;
    1179      }
    1180  
    1181      if ( *propid >= num_bdf_properties_ )
    1182        prop = font->user_props + ( *propid - num_bdf_properties_ );
    1183      else
    1184        prop = (bdf_property_t*)bdf_properties_ + *propid;
    1185  
    1186      fp = font->props + font->props_used;
    1187  
    1188      fp->name    = prop->name;
    1189      fp->format  = prop->format;
    1190      fp->builtin = prop->builtin;
    1191  
    1192      switch ( prop->format )
    1193      {
    1194      case BDF_ATOM:
    1195        fp->value.atom = NULL;
    1196        if ( value && value[0] )
    1197        {
    1198          if ( FT_STRDUP( fp->value.atom, value ) )
    1199            goto Exit;
    1200        }
    1201        break;
    1202  
    1203      case BDF_INTEGER:
    1204        fp->value.l = bdf_atol_( value );
    1205        break;
    1206  
    1207      case BDF_CARDINAL:
    1208        fp->value.ul = bdf_atoul_( value );
    1209        break;
    1210      }
    1211  
    1212      /* If the property happens to be a comment, then it doesn't need */
    1213      /* to be added to the internal hash table.                       */
    1214      if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 )
    1215      {
    1216        /* Add the property to the font property table. */
    1217        error = ft_hash_str_insert( fp->name,
    1218                                    font->props_used,
    1219                                    (FT_Hash)font->internal,
    1220                                    memory );
    1221        if ( error )
    1222          goto Exit;
    1223      }
    1224  
    1225      font->props_used++;
    1226  
    1227      /* Some special cases need to be handled here.  The DEFAULT_CHAR       */
    1228      /* property needs to be located if it exists in the property list, the */
    1229      /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are        */
    1230      /* present, and the SPACING property should override the default       */
    1231      /* spacing.                                                            */
    1232      if ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 )
    1233        font->default_char = fp->value.ul;
    1234      else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 )
    1235        font->font_ascent = fp->value.l;
    1236      else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 )
    1237        font->font_descent = fp->value.l;
    1238      else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 )
    1239      {
    1240        if ( !fp->value.atom )
    1241        {
    1242          FT_ERROR(( "bdf_add_property_: " ERRMSG8, lineno, "SPACING" ));
    1243          error = FT_THROW( Invalid_File_Format );
    1244          goto Exit;
    1245        }
    1246  
    1247        if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
    1248          font->spacing = BDF_PROPORTIONAL;
    1249        else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
    1250          font->spacing = BDF_MONOWIDTH;
    1251        else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
    1252          font->spacing = BDF_CHARCELL;
    1253      }
    1254  
    1255    Exit:
    1256      return error;
    1257    }
    1258  
    1259  
    1260    static const unsigned char nibble_mask[8] =
    1261    {
    1262      0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
    1263    };
    1264  
    1265  
    1266    static FT_Error
    1267    bdf_parse_end_( char*          line,
    1268                    unsigned long  linelen,
    1269                    unsigned long  lineno,
    1270                    void*          call_data,
    1271                    void*          client_data )
    1272    {
    1273      /* a no-op; we ignore everything after `ENDFONT' */
    1274  
    1275      FT_UNUSED( line );
    1276      FT_UNUSED( linelen );
    1277      FT_UNUSED( lineno );
    1278      FT_UNUSED( call_data );
    1279      FT_UNUSED( client_data );
    1280  
    1281      return FT_Err_Ok;
    1282    }
    1283  
    1284  
    1285    /* Actually parse the glyph info and bitmaps. */
    1286    static FT_Error
    1287    bdf_parse_glyphs_( char*          line,
    1288                       unsigned long  linelen,
    1289                       unsigned long  lineno,
    1290                       void*          call_data,
    1291                       void*          client_data )
    1292    {
    1293      int                c, mask_index;
    1294      char*              s;
    1295      unsigned char*     bp;
    1296      unsigned long      i, slen, nibbles;
    1297  
    1298      bdf_line_func_t_*  next;
    1299      bdf_parse_t_*      p;
    1300      bdf_glyph_t*       glyph;
    1301      bdf_font_t*        font;
    1302  
    1303      FT_Memory          memory;
    1304      FT_Error           error = FT_Err_Ok;
    1305  
    1306      FT_UNUSED( lineno );        /* only used in debug mode */
    1307  
    1308  
    1309      next = (bdf_line_func_t_ *)call_data;
    1310      p    = (bdf_parse_t_ *)    client_data;
    1311  
    1312      font   = p->font;
    1313      memory = font->memory;
    1314  
    1315      /* Check for a comment. */
    1316      if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
    1317      {
    1318        if ( p->opts->keep_comments )
    1319        {
    1320          linelen -= 7;
    1321  
    1322          s = line + 7;
    1323          if ( *s != 0 )
    1324          {
    1325            s++;
    1326            linelen--;
    1327          }
    1328          error = bdf_add_comment_( p->font, s, linelen );
    1329        }
    1330        goto Exit;
    1331      }
    1332  
    1333      /* The very first thing expected is the number of glyphs. */
    1334      if ( !( p->flags & BDF_GLYPHS_ ) )
    1335      {
    1336        if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 )
    1337        {
    1338          FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "CHARS" ));
    1339          error = FT_THROW( Missing_Chars_Field );
    1340          goto Exit;
    1341        }
    1342  
    1343        error = bdf_list_split_( &p->list, " +", line, linelen );
    1344        if ( error )
    1345          goto Exit;
    1346        p->cnt = font->glyphs_size = bdf_atoul_( p->list.field[1] );
    1347  
    1348        /* We need at least 20 bytes per glyph. */
    1349        if ( p->cnt > p->size / 20 )
    1350        {
    1351          p->cnt = font->glyphs_size = p->size / 20;
    1352          FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG17, p->cnt ));
    1353        }
    1354  
    1355        /* Make sure the number of glyphs is non-zero. */
    1356        if ( p->cnt == 0 )
    1357          font->glyphs_size = 64;
    1358  
    1359        /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
    1360        /* number of code points available in Unicode).                 */
    1361        if ( p->cnt >= 0x110000UL )
    1362        {
    1363          FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG5, lineno, "CHARS" ));
    1364          error = FT_THROW( Invalid_Argument );
    1365          goto Exit;
    1366        }
    1367  
    1368        if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
    1369          goto Exit;
    1370  
    1371        p->flags |= BDF_GLYPHS_;
    1372  
    1373        goto Exit;
    1374      }
    1375  
    1376      /* Check for the ENDFONT field. */
    1377      if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 )
    1378      {
    1379        if ( p->flags & BDF_GLYPH_BITS_ )
    1380        {
    1381          /* Missing ENDCHAR field. */
    1382          FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" ));
    1383          error = FT_THROW( Corrupted_Font_Glyphs );
    1384          goto Exit;
    1385        }
    1386  
    1387        /* Sort the glyphs by encoding. */
    1388        ft_qsort( (char *)font->glyphs,
    1389                  font->glyphs_used,
    1390                  sizeof ( bdf_glyph_t ),
    1391                  by_encoding );
    1392  
    1393        p->flags &= ~BDF_START_;
    1394        *next     = bdf_parse_end_;
    1395  
    1396        goto Exit;
    1397      }
    1398  
    1399      /* Check for the ENDCHAR field. */
    1400      if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 )
    1401      {
    1402        p->glyph_enc = 0;
    1403        p->flags    &= ~BDF_GLYPH_BITS_;
    1404  
    1405        goto Exit;
    1406      }
    1407  
    1408      /* Check whether a glyph is being scanned but should be */
    1409      /* ignored because it is an unencoded glyph.            */
    1410      if ( ( p->flags & BDF_GLYPH_ )     &&
    1411           p->glyph_enc            == -1 &&
    1412           p->opts->keep_unencoded == 0  )
    1413        goto Exit;
    1414  
    1415      /* Check for the STARTCHAR field. */
    1416      if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 )
    1417      {
    1418        if ( p->flags & BDF_GLYPH_BITS_ )
    1419        {
    1420          /* Missing ENDCHAR field. */
    1421          FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" ));
    1422          error = FT_THROW( Missing_Startchar_Field );
    1423          goto Exit;
    1424        }
    1425  
    1426        /* Set the character name in the parse info first until the */
    1427        /* encoding can be checked for an unencoded character.      */
    1428        FT_FREE( p->glyph_name );
    1429  
    1430        error = bdf_list_split_( &p->list, " +", line, linelen );
    1431        if ( error )
    1432          goto Exit;
    1433  
    1434        bdf_list_shift_( &p->list, 1 );
    1435  
    1436        s = bdf_list_join_( &p->list, ' ', &slen );
    1437  
    1438        if ( !s )
    1439        {
    1440          FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG8, lineno, "STARTCHAR" ));
    1441          error = FT_THROW( Invalid_File_Format );
    1442          goto Exit;
    1443        }
    1444  
    1445        if ( FT_QALLOC( p->glyph_name, slen + 1 ) )
    1446          goto Exit;
    1447  
    1448        FT_MEM_COPY( p->glyph_name, s, slen + 1 );
    1449  
    1450        p->flags |= BDF_GLYPH_;
    1451  
    1452        FT_TRACE4(( DBGMSG1, lineno, s ));
    1453  
    1454        goto Exit;
    1455      }
    1456  
    1457      /* Check for the ENCODING field. */
    1458      if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 )
    1459      {
    1460        if ( !( p->flags & BDF_GLYPH_ ) )
    1461        {
    1462          /* Missing STARTCHAR field. */
    1463          FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "STARTCHAR" ));
    1464          error = FT_THROW( Missing_Startchar_Field );
    1465          goto Exit;
    1466        }
    1467  
    1468        error = bdf_list_split_( &p->list, " +", line, linelen );
    1469        if ( error )
    1470          goto Exit;
    1471  
    1472        p->glyph_enc = bdf_atol_( p->list.field[1] );
    1473  
    1474        /* Normalize negative encoding values.  The specification only */
    1475        /* allows -1, but we can be more generous here.                */
    1476        if ( p->glyph_enc < -1 )
    1477          p->glyph_enc = -1;
    1478  
    1479        /* Check for alternative encoding format. */
    1480        if ( p->glyph_enc == -1 && p->list.used > 2 )
    1481          p->glyph_enc = bdf_atol_( p->list.field[2] );
    1482  
    1483        if ( p->glyph_enc < -1 || p->glyph_enc >= 0x110000L )
    1484          p->glyph_enc = -1;
    1485  
    1486        FT_TRACE4(( DBGMSG2, p->glyph_enc ));
    1487  
    1488        if ( p->glyph_enc >= 0 )
    1489        {
    1490          /* Make sure there are enough glyphs allocated in case the */
    1491          /* number of characters happen to be wrong.                */
    1492          if ( font->glyphs_used == font->glyphs_size )
    1493          {
    1494            if ( FT_RENEW_ARRAY( font->glyphs,
    1495                                 font->glyphs_size,
    1496                                 font->glyphs_size + 64 ) )
    1497              goto Exit;
    1498  
    1499            font->glyphs_size += 64;
    1500          }
    1501  
    1502          glyph           = font->glyphs + font->glyphs_used++;
    1503          glyph->name     = p->glyph_name;
    1504          glyph->encoding = (unsigned long)p->glyph_enc;
    1505  
    1506          /* Reset the initial glyph info. */
    1507          p->glyph_name = NULL;
    1508        }
    1509        else
    1510        {
    1511          /* Unencoded glyph.  Check whether it should */
    1512          /* be added or not.                          */
    1513          if ( p->opts->keep_unencoded )
    1514          {
    1515            /* Allocate the next unencoded glyph. */
    1516            if ( font->unencoded_used == font->unencoded_size )
    1517            {
    1518              if ( FT_RENEW_ARRAY( font->unencoded ,
    1519                                   font->unencoded_size,
    1520                                   font->unencoded_size + 4 ) )
    1521                goto Exit;
    1522  
    1523              font->unencoded_size += 4;
    1524            }
    1525  
    1526            glyph           = font->unencoded + font->unencoded_used;
    1527            glyph->name     = p->glyph_name;
    1528            glyph->encoding = font->unencoded_used++;
    1529  
    1530            /* Reset the initial glyph info. */
    1531            p->glyph_name = NULL;
    1532          }
    1533          else
    1534          {
    1535            /* Free up the glyph name if the unencoded shouldn't be */
    1536            /* kept.                                                */
    1537            FT_FREE( p->glyph_name );
    1538          }
    1539        }
    1540  
    1541        /* Clear the flags that might be added when width and height are */
    1542        /* checked for consistency.                                      */
    1543        p->flags &= ~( BDF_GLYPH_WIDTH_CHECK_ | BDF_GLYPH_HEIGHT_CHECK_ );
    1544  
    1545        p->flags |= BDF_ENCODING_;
    1546  
    1547        goto Exit;
    1548      }
    1549  
    1550      if ( !( p->flags & BDF_ENCODING_ ) )
    1551        goto Missing_Encoding;
    1552  
    1553      /* Point at the glyph being constructed. */
    1554      if ( p->glyph_enc == -1 )
    1555        glyph = font->unencoded + ( font->unencoded_used - 1 );
    1556      else
    1557        glyph = font->glyphs + ( font->glyphs_used - 1 );
    1558  
    1559      /* Check whether a bitmap is being constructed. */
    1560      if ( p->flags & BDF_BITMAP_ )
    1561      {
    1562        /* If there are more rows than are specified in the glyph metrics, */
    1563        /* ignore the remaining lines.                                     */
    1564        if ( p->row >= (unsigned long)glyph->bbx.height )
    1565        {
    1566          if ( !( p->flags & BDF_GLYPH_HEIGHT_CHECK_ ) )
    1567          {
    1568            FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG13, glyph->encoding ));
    1569            p->flags |= BDF_GLYPH_HEIGHT_CHECK_;
    1570          }
    1571  
    1572          goto Exit;
    1573        }
    1574  
    1575        /* Only collect the number of nibbles indicated by the glyph     */
    1576        /* metrics.  If there are more columns, they are simply ignored. */
    1577        nibbles = glyph->bpr << 1;
    1578        bp      = glyph->bitmap + p->row * glyph->bpr;
    1579  
    1580        for ( i = 0; i < nibbles; i++ )
    1581        {
    1582          c = line[i];
    1583          if ( !sbitset( hdigits, c ) )
    1584            break;
    1585          *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
    1586          if ( i + 1 < nibbles && ( i & 1 ) )
    1587            *++bp = 0;
    1588        }
    1589  
    1590        /* If any line has not enough columns,            */
    1591        /* indicate they have been padded with zero bits. */
    1592        if ( i < nibbles                            &&
    1593             !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
    1594        {
    1595          FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG16, glyph->encoding ));
    1596          p->flags       |= BDF_GLYPH_WIDTH_CHECK_;
    1597        }
    1598  
    1599        /* Remove possible garbage at the right. */
    1600        mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
    1601        if ( glyph->bbx.width )
    1602          *bp &= nibble_mask[mask_index];
    1603  
    1604        /* If any line has extra columns, indicate they have been removed. */
    1605        if ( i == nibbles                           &&
    1606             sbitset( hdigits, line[nibbles] )      &&
    1607             !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
    1608        {
    1609          FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG14, glyph->encoding ));
    1610          p->flags       |= BDF_GLYPH_WIDTH_CHECK_;
    1611        }
    1612  
    1613        p->row++;
    1614        goto Exit;
    1615      }
    1616  
    1617      /* Expect the SWIDTH (scalable width) field next. */
    1618      if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 )
    1619      {
    1620        error = bdf_list_split_( &p->list, " +", line, linelen );
    1621        if ( error )
    1622          goto Exit;
    1623  
    1624        glyph->swidth = bdf_atous_( p->list.field[1] );
    1625        p->flags |= BDF_SWIDTH_;
    1626  
    1627        goto Exit;
    1628      }
    1629  
    1630      /* Expect the DWIDTH (device width) field next. */
    1631      if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 )
    1632      {
    1633        error = bdf_list_split_( &p->list, " +", line, linelen );
    1634        if ( error )
    1635          goto Exit;
    1636  
    1637        glyph->dwidth = bdf_atous_( p->list.field[1] );
    1638  
    1639        if ( !( p->flags & BDF_SWIDTH_ ) )
    1640        {
    1641          /* Missing SWIDTH field.  Emit an auto correction message and set */
    1642          /* the scalable width from the device width.                      */
    1643          FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG9, lineno ));
    1644  
    1645          glyph->swidth = (unsigned short)FT_MulDiv(
    1646                            glyph->dwidth, 72000L,
    1647                            (FT_Long)( font->point_size *
    1648                                       font->resolution_x ) );
    1649        }
    1650  
    1651        p->flags |= BDF_DWIDTH_;
    1652        goto Exit;
    1653      }
    1654  
    1655      /* Expect the BBX field next. */
    1656      if ( _bdf_strncmp( line, "BBX", 3 ) == 0 )
    1657      {
    1658        error = bdf_list_split_( &p->list, " +", line, linelen );
    1659        if ( error )
    1660          goto Exit;
    1661  
    1662        glyph->bbx.width    = bdf_atous_( p->list.field[1] );
    1663        glyph->bbx.height   = bdf_atous_( p->list.field[2] );
    1664        glyph->bbx.x_offset = bdf_atos_( p->list.field[3] );
    1665        glyph->bbx.y_offset = bdf_atos_( p->list.field[4] );
    1666  
    1667        /* Generate the ascent and descent of the character. */
    1668        glyph->bbx.ascent  = (short)( glyph->bbx.height + glyph->bbx.y_offset );
    1669        glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
    1670  
    1671        /* Determine the overall font bounding box as the characters are */
    1672        /* loaded so corrections can be done later if indicated.         */
    1673        p->maxas    = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
    1674        p->maxds    = (short)FT_MAX( glyph->bbx.descent, p->maxds );
    1675  
    1676        p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
    1677  
    1678        p->maxrb    = (short)FT_MAX( p->rbearing, p->maxrb );
    1679        p->minlb    = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
    1680        p->maxlb    = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
    1681  
    1682        if ( !( p->flags & BDF_DWIDTH_ ) )
    1683        {
    1684          /* Missing DWIDTH field.  Emit an auto correction message and set */
    1685          /* the device width to the glyph width.                           */
    1686          FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG10, lineno ));
    1687          glyph->dwidth = glyph->bbx.width;
    1688        }
    1689  
    1690        /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
    1691        /* value if necessary.                                            */
    1692        if ( p->opts->correct_metrics )
    1693        {
    1694          /* Determine the point size of the glyph. */
    1695          unsigned short  sw = (unsigned short)FT_MulDiv(
    1696                                 glyph->dwidth, 72000L,
    1697                                 (FT_Long)( font->point_size *
    1698                                            font->resolution_x ) );
    1699  
    1700  
    1701          if ( sw != glyph->swidth )
    1702          {
    1703            glyph->swidth = sw;
    1704  
    1705            p->flags       |= BDF_SWIDTH_ADJ_;
    1706          }
    1707        }
    1708  
    1709        p->flags |= BDF_BBX_;
    1710        goto Exit;
    1711      }
    1712  
    1713      /* And finally, gather up the bitmap. */
    1714      if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 )
    1715      {
    1716        unsigned long  bitmap_size;
    1717  
    1718  
    1719        if ( !( p->flags & BDF_BBX_ ) )
    1720        {
    1721          /* Missing BBX field. */
    1722          FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "BBX" ));
    1723          error = FT_THROW( Missing_Bbx_Field );
    1724          goto Exit;
    1725        }
    1726  
    1727        /* Allocate enough space for the bitmap. */
    1728        glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
    1729  
    1730        bitmap_size = glyph->bpr * glyph->bbx.height;
    1731        if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
    1732        {
    1733          FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG4, lineno ));
    1734          error = FT_THROW( Bbx_Too_Big );
    1735          goto Exit;
    1736        }
    1737        else
    1738          glyph->bytes = (unsigned short)bitmap_size;
    1739  
    1740        if ( FT_ALLOC( glyph->bitmap, glyph->bytes ) )
    1741          goto Exit;
    1742  
    1743        p->row    = 0;
    1744        p->flags |= BDF_BITMAP_;
    1745  
    1746        goto Exit;
    1747      }
    1748  
    1749      FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG9, lineno ));
    1750      error = FT_THROW( Invalid_File_Format );
    1751      goto Exit;
    1752  
    1753    Missing_Encoding:
    1754      /* Missing ENCODING field. */
    1755      FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENCODING" ));
    1756      error = FT_THROW( Missing_Encoding_Field );
    1757  
    1758    Exit:
    1759      if ( error && ( p->flags & BDF_GLYPH_ ) )
    1760        FT_FREE( p->glyph_name );
    1761  
    1762      return error;
    1763    }
    1764  
    1765  
    1766    /* Load the font properties. */
    1767    static FT_Error
    1768    bdf_parse_properties_( char*          line,
    1769                           unsigned long  linelen,
    1770                           unsigned long  lineno,
    1771                           void*          call_data,
    1772                           void*          client_data )
    1773    {
    1774      unsigned long      vlen;
    1775      bdf_line_func_t_*  next;
    1776      bdf_parse_t_*      p;
    1777      char*              name;
    1778      char*              value;
    1779      char               nbuf[BUFSIZE];
    1780      FT_Error           error = FT_Err_Ok;
    1781  
    1782      FT_UNUSED( lineno );
    1783  
    1784  
    1785      next = (bdf_line_func_t_ *)call_data;
    1786      p    = (bdf_parse_t_ *)    client_data;
    1787  
    1788      /* Check for the end of the properties. */
    1789      if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
    1790      {
    1791        /* If the FONT_ASCENT or FONT_DESCENT properties have not been      */
    1792        /* encountered yet, then make sure they are added as properties and */
    1793        /* make sure they are set from the font bounding box info.          */
    1794        /*                                                                  */
    1795        /* This is *always* done regardless of the options, because X11     */
    1796        /* requires these two fields to compile fonts.                      */
    1797        if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
    1798        {
    1799          p->font->font_ascent = p->font->bbx.ascent;
    1800          ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.ascent );
    1801          error = bdf_add_property_( p->font, "FONT_ASCENT",
    1802                                     nbuf, lineno );
    1803          if ( error )
    1804            goto Exit;
    1805  
    1806          FT_TRACE2(( "bdf_parse_properties_: " ACMSG1, p->font->bbx.ascent ));
    1807        }
    1808  
    1809        if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
    1810        {
    1811          p->font->font_descent = p->font->bbx.descent;
    1812          ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.descent );
    1813          error = bdf_add_property_( p->font, "FONT_DESCENT",
    1814                                     nbuf, lineno );
    1815          if ( error )
    1816            goto Exit;
    1817  
    1818          FT_TRACE2(( "bdf_parse_properties_: " ACMSG2, p->font->bbx.descent ));
    1819        }
    1820  
    1821        p->flags &= ~BDF_PROPS_;
    1822        *next     = bdf_parse_glyphs_;
    1823  
    1824        goto Exit;
    1825      }
    1826  
    1827      /* Ignore the _XFREE86_GLYPH_RANGES properties. */
    1828      if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
    1829        goto Exit;
    1830  
    1831      /* Handle COMMENT fields and properties in a special way to preserve */
    1832      /* the spacing.                                                      */
    1833      if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
    1834      {
    1835        name = value = line;
    1836        value += 7;
    1837        if ( *value )
    1838          *value++ = 0;
    1839        error = bdf_add_property_( p->font, name, value, lineno );
    1840        if ( error )
    1841          goto Exit;
    1842      }
    1843      else if ( bdf_is_atom_( line, linelen, &name, &value, p->font ) )
    1844      {
    1845        error = bdf_add_property_( p->font, name, value, lineno );
    1846        if ( error )
    1847          goto Exit;
    1848      }
    1849      else
    1850      {
    1851        error = bdf_list_split_( &p->list, " +", line, linelen );
    1852        if ( error )
    1853          goto Exit;
    1854        name = p->list.field[0];
    1855  
    1856        bdf_list_shift_( &p->list, 1 );
    1857        value = bdf_list_join_( &p->list, ' ', &vlen );
    1858  
    1859        error = bdf_add_property_( p->font, name, value, lineno );
    1860        if ( error )
    1861          goto Exit;
    1862      }
    1863  
    1864    Exit:
    1865      return error;
    1866    }
    1867  
    1868  
    1869    /* Load the font header. */
    1870    static FT_Error
    1871    bdf_parse_start_( char*          line,
    1872                      unsigned long  linelen,
    1873                      unsigned long  lineno,
    1874                      void*          call_data,
    1875                      void*          client_data )
    1876    {
    1877      unsigned long      slen;
    1878      bdf_line_func_t_*  next;
    1879      bdf_parse_t_*      p;
    1880      bdf_font_t*        font;
    1881      char               *s;
    1882  
    1883      FT_Memory          memory = NULL;
    1884      FT_Error           error  = FT_Err_Ok;
    1885  
    1886      FT_UNUSED( lineno );            /* only used in debug mode */
    1887  
    1888  
    1889      next = (bdf_line_func_t_ *)call_data;
    1890      p    = (bdf_parse_t_ *)    client_data;
    1891  
    1892      if ( p->font )
    1893        memory = p->font->memory;
    1894  
    1895      /* Check for a comment.  This is done to handle those fonts that have */
    1896      /* comments before the STARTFONT line for some reason.                */
    1897      if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
    1898      {
    1899        if ( p->opts->keep_comments && p->font )
    1900        {
    1901          linelen -= 7;
    1902  
    1903          s = line + 7;
    1904          if ( *s != 0 )
    1905          {
    1906            s++;
    1907            linelen--;
    1908          }
    1909          error = bdf_add_comment_( p->font, s, linelen );
    1910        }
    1911        goto Exit;
    1912      }
    1913  
    1914      if ( !( p->flags & BDF_START_ ) )
    1915      {
    1916        memory = p->memory;
    1917  
    1918        if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 )
    1919        {
    1920          /* we don't emit an error message since this code gets */
    1921          /* explicitly caught one level higher                  */
    1922          error = FT_THROW( Missing_Startfont_Field );
    1923          goto Exit;
    1924        }
    1925  
    1926        p->flags = BDF_START_;
    1927        font = p->font = NULL;
    1928  
    1929        if ( FT_NEW( font ) )
    1930          goto Exit;
    1931        p->font = font;
    1932  
    1933        font->memory = p->memory;
    1934  
    1935        { /* setup */
    1936          size_t           i;
    1937          bdf_property_t*  prop;
    1938  
    1939  
    1940          error = ft_hash_str_init( &(font->proptbl), memory );
    1941          if ( error )
    1942            goto Exit;
    1943          for ( i = 0, prop = (bdf_property_t*)bdf_properties_;
    1944                i < num_bdf_properties_; i++, prop++ )
    1945          {
    1946            error = ft_hash_str_insert( prop->name, i,
    1947                                        &(font->proptbl), memory );
    1948            if ( error )
    1949              goto Exit;
    1950          }
    1951        }
    1952  
    1953        if ( FT_QALLOC( p->font->internal, sizeof ( FT_HashRec ) ) )
    1954          goto Exit;
    1955        error = ft_hash_str_init( (FT_Hash)p->font->internal, memory );
    1956        if ( error )
    1957          goto Exit;
    1958        p->font->spacing      = p->opts->font_spacing;
    1959        p->font->default_char = ~0UL;
    1960  
    1961        goto Exit;
    1962      }
    1963  
    1964      /* Check for the start of the properties. */
    1965      if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 )
    1966      {
    1967        if ( !( p->flags & BDF_FONT_BBX_ ) )
    1968        {
    1969          /* Missing the FONTBOUNDINGBOX field. */
    1970          FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
    1971          error = FT_THROW( Missing_Fontboundingbox_Field );
    1972          goto Exit;
    1973        }
    1974  
    1975        error = bdf_list_split_( &p->list, " +", line, linelen );
    1976        if ( error )
    1977          goto Exit;
    1978  
    1979        /* at this point, `p->font' can't be NULL */
    1980        p->cnt = p->font->props_size = bdf_atoul_( p->list.field[1] );
    1981        /* We need at least 4 bytes per property. */
    1982        if ( p->cnt > p->size / 4 )
    1983        {
    1984          p->font->props_size = 0;
    1985  
    1986          FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG5, lineno, "STARTPROPERTIES" ));
    1987          error = FT_THROW( Invalid_Argument );
    1988          goto Exit;
    1989        }
    1990  
    1991        if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
    1992        {
    1993          p->font->props_size = 0;
    1994          goto Exit;
    1995        }
    1996  
    1997        p->flags |= BDF_PROPS_;
    1998        *next     = bdf_parse_properties_;
    1999  
    2000        goto Exit;
    2001      }
    2002  
    2003      /* Check for the FONTBOUNDINGBOX field. */
    2004      if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
    2005      {
    2006        if ( !( p->flags & BDF_SIZE_ ) )
    2007        {
    2008          /* Missing the SIZE field. */
    2009          FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "SIZE" ));
    2010          error = FT_THROW( Missing_Size_Field );
    2011          goto Exit;
    2012        }
    2013  
    2014        error = bdf_list_split_( &p->list, " +", line, linelen );
    2015        if ( error )
    2016          goto Exit;
    2017  
    2018        p->font->bbx.width  = bdf_atous_( p->list.field[1] );
    2019        p->font->bbx.height = bdf_atous_( p->list.field[2] );
    2020  
    2021        p->font->bbx.x_offset = bdf_atos_( p->list.field[3] );
    2022        p->font->bbx.y_offset = bdf_atos_( p->list.field[4] );
    2023  
    2024        p->font->bbx.ascent  = (short)( p->font->bbx.height +
    2025                                        p->font->bbx.y_offset );
    2026  
    2027        p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
    2028  
    2029        p->flags |= BDF_FONT_BBX_;
    2030  
    2031        goto Exit;
    2032      }
    2033  
    2034      /* The next thing to check for is the FONT field. */
    2035      if ( _bdf_strncmp( line, "FONT", 4 ) == 0 )
    2036      {
    2037        error = bdf_list_split_( &p->list, " +", line, linelen );
    2038        if ( error )
    2039          goto Exit;
    2040        bdf_list_shift_( &p->list, 1 );
    2041  
    2042        s = bdf_list_join_( &p->list, ' ', &slen );
    2043  
    2044        if ( !s )
    2045        {
    2046          FT_ERROR(( "bdf_parse_start_: " ERRMSG8, lineno, "FONT" ));
    2047          error = FT_THROW( Invalid_File_Format );
    2048          goto Exit;
    2049        }
    2050  
    2051        /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
    2052        FT_FREE( p->font->name );
    2053  
    2054        if ( FT_QALLOC( p->font->name, slen + 1 ) )
    2055          goto Exit;
    2056        FT_MEM_COPY( p->font->name, s, slen + 1 );
    2057  
    2058        /* If the font name is an XLFD name, set the spacing to the one in  */
    2059        /* the font name.  If there is no spacing fall back on the default. */
    2060        error = bdf_set_default_spacing_( p->font, p->opts, lineno );
    2061        if ( error )
    2062          goto Exit;
    2063  
    2064        p->flags |= BDF_FONT_NAME_;
    2065  
    2066        goto Exit;
    2067      }
    2068  
    2069      /* Check for the SIZE field. */
    2070      if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 )
    2071      {
    2072        if ( !( p->flags & BDF_FONT_NAME_ ) )
    2073        {
    2074          /* Missing the FONT field. */
    2075          FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONT" ));
    2076          error = FT_THROW( Missing_Font_Field );
    2077          goto Exit;
    2078        }
    2079  
    2080        error = bdf_list_split_( &p->list, " +", line, linelen );
    2081        if ( error )
    2082          goto Exit;
    2083  
    2084        p->font->point_size   = bdf_atoul_( p->list.field[1] );
    2085        p->font->resolution_x = bdf_atoul_( p->list.field[2] );
    2086        p->font->resolution_y = bdf_atoul_( p->list.field[3] );
    2087  
    2088        /* Check for the bits per pixel field. */
    2089        if ( p->list.used == 5 )
    2090        {
    2091          unsigned short bpp;
    2092  
    2093  
    2094          bpp = bdf_atous_( p->list.field[4] );
    2095  
    2096          /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
    2097          if ( bpp > 4 )
    2098            p->font->bpp = 8;
    2099          else if ( bpp > 2 )
    2100            p->font->bpp = 4;
    2101          else if ( bpp > 1 )
    2102            p->font->bpp = 2;
    2103          else
    2104            p->font->bpp = 1;
    2105  
    2106          if ( p->font->bpp != bpp )
    2107            FT_TRACE2(( "bdf_parse_start_: " ACMSG11, p->font->bpp ));
    2108        }
    2109        else
    2110          p->font->bpp = 1;
    2111  
    2112        p->flags |= BDF_SIZE_;
    2113  
    2114        goto Exit;
    2115      }
    2116  
    2117      /* Check for the CHARS field -- font properties are optional */
    2118      if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
    2119      {
    2120        char  nbuf[BUFSIZE];
    2121  
    2122  
    2123        if ( !( p->flags & BDF_FONT_BBX_ ) )
    2124        {
    2125          /* Missing the FONTBOUNDINGBOX field. */
    2126          FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
    2127          error = FT_THROW( Missing_Fontboundingbox_Field );
    2128          goto Exit;
    2129        }
    2130  
    2131        /* Add the two standard X11 properties which are required */
    2132        /* for compiling fonts.                                   */
    2133        p->font->font_ascent = p->font->bbx.ascent;
    2134        ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.ascent );
    2135        error = bdf_add_property_( p->font, "FONT_ASCENT",
    2136                                   nbuf, lineno );
    2137        if ( error )
    2138          goto Exit;
    2139        FT_TRACE2(( "bdf_parse_properties_: " ACMSG1, p->font->bbx.ascent ));
    2140  
    2141        p->font->font_descent = p->font->bbx.descent;
    2142        ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.descent );
    2143        error = bdf_add_property_( p->font, "FONT_DESCENT",
    2144                                   nbuf, lineno );
    2145        if ( error )
    2146          goto Exit;
    2147        FT_TRACE2(( "bdf_parse_properties_: " ACMSG2, p->font->bbx.descent ));
    2148  
    2149        *next = bdf_parse_glyphs_;
    2150  
    2151        /* A special return value. */
    2152        error = -1;
    2153        goto Exit;
    2154      }
    2155  
    2156      FT_ERROR(( "bdf_parse_start_: " ERRMSG9, lineno ));
    2157      error = FT_THROW( Invalid_File_Format );
    2158  
    2159    Exit:
    2160      return error;
    2161    }
    2162  
    2163  
    2164    /**************************************************************************
    2165     *
    2166     * API.
    2167     *
    2168     */
    2169  
    2170  
    2171    FT_LOCAL_DEF( FT_Error )
    2172    bdf_load_font( FT_Stream       stream,
    2173                   FT_Memory       memory,
    2174                   bdf_options_t*  opts,
    2175                   bdf_font_t*    *font )
    2176    {
    2177      unsigned long  lineno = 0; /* make compiler happy */
    2178      bdf_parse_t_   *p     = NULL;
    2179  
    2180      FT_Error  error = FT_Err_Ok;
    2181  
    2182  
    2183      if ( FT_NEW( p ) )
    2184        goto Exit;
    2185  
    2186      p->opts   = (bdf_options_t*)( opts ? opts : &bdf_opts_ );
    2187      p->minlb  = 32767;
    2188      p->size   = stream->size;
    2189      p->memory = memory;  /* only during font creation */
    2190  
    2191      bdf_list_init_( &p->list, memory );
    2192  
    2193      error = bdf_readstream_( stream, bdf_parse_start_,
    2194                               (void *)p, &lineno );
    2195      if ( error )
    2196        goto Fail;
    2197  
    2198      if ( p->font )
    2199      {
    2200        /* If the font is not proportional, set the font's monowidth */
    2201        /* field to the width of the font bounding box.              */
    2202  
    2203        if ( p->font->spacing != BDF_PROPORTIONAL )
    2204          p->font->monowidth = p->font->bbx.width;
    2205  
    2206        /* If the number of glyphs loaded is not that of the original count, */
    2207        /* indicate the difference.                                          */
    2208        if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
    2209        {
    2210          FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
    2211                      p->font->glyphs_used + p->font->unencoded_used ));
    2212        }
    2213  
    2214        /* Once the font has been loaded, adjust the overall font metrics if */
    2215        /* necessary.                                                        */
    2216        if ( p->opts->correct_metrics != 0 &&
    2217             ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
    2218        {
    2219          if ( p->maxrb - p->minlb != p->font->bbx.width )
    2220          {
    2221            FT_TRACE2(( "bdf_load_font: " ACMSG3,
    2222                        p->font->bbx.width, p->maxrb - p->minlb ));
    2223            p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
    2224          }
    2225  
    2226          if ( p->font->bbx.x_offset != p->minlb )
    2227          {
    2228            FT_TRACE2(( "bdf_load_font: " ACMSG4,
    2229                        p->font->bbx.x_offset, p->minlb ));
    2230            p->font->bbx.x_offset = p->minlb;
    2231          }
    2232  
    2233          if ( p->font->bbx.ascent != p->maxas )
    2234          {
    2235            FT_TRACE2(( "bdf_load_font: " ACMSG5,
    2236                        p->font->bbx.ascent, p->maxas ));
    2237            p->font->bbx.ascent = p->maxas;
    2238          }
    2239  
    2240          if ( p->font->bbx.descent != p->maxds )
    2241          {
    2242            FT_TRACE2(( "bdf_load_font: " ACMSG6,
    2243                        p->font->bbx.descent, p->maxds ));
    2244            p->font->bbx.descent  = p->maxds;
    2245            p->font->bbx.y_offset = (short)( -p->maxds );
    2246          }
    2247  
    2248          if ( p->maxas + p->maxds != p->font->bbx.height )
    2249          {
    2250            FT_TRACE2(( "bdf_load_font: " ACMSG7,
    2251                        p->font->bbx.height, p->maxas + p->maxds ));
    2252            p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
    2253          }
    2254  
    2255          if ( p->flags & BDF_SWIDTH_ADJ_ )
    2256            FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
    2257        }
    2258      }
    2259  
    2260      if ( p->flags & BDF_START_ )
    2261      {
    2262        /* The ENDFONT field was never reached or did not exist. */
    2263        if ( !( p->flags & BDF_GLYPHS_ ) )
    2264        {
    2265          /* Error happened while parsing header. */
    2266          FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
    2267          error = FT_THROW( Corrupted_Font_Header );
    2268          goto Fail;
    2269        }
    2270        else
    2271        {
    2272          /* Error happened when parsing glyphs. */
    2273          FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
    2274          error = FT_THROW( Corrupted_Font_Glyphs );
    2275          goto Fail;
    2276        }
    2277      }
    2278  
    2279      if ( !p->font && !error )
    2280        error = FT_THROW( Invalid_File_Format );
    2281  
    2282      *font = p->font;
    2283  
    2284    Exit:
    2285      if ( p )
    2286      {
    2287        bdf_list_done_( &p->list );
    2288  
    2289        FT_FREE( p->glyph_name );
    2290        FT_FREE( p );
    2291      }
    2292  
    2293      return error;
    2294  
    2295    Fail:
    2296      bdf_free_font( p->font );
    2297  
    2298      FT_FREE( p->font );
    2299  
    2300      goto Exit;
    2301    }
    2302  
    2303  
    2304    FT_LOCAL_DEF( void )
    2305    bdf_free_font( bdf_font_t*  font )
    2306    {
    2307      bdf_property_t*  prop;
    2308      unsigned long    i;
    2309      bdf_glyph_t*     glyphs;
    2310      FT_Memory        memory;
    2311  
    2312  
    2313      if ( font == NULL )
    2314        return;
    2315  
    2316      memory = font->memory;
    2317  
    2318      FT_FREE( font->name );
    2319  
    2320      /* Free up the internal hash table of property names. */
    2321      if ( font->internal )
    2322      {
    2323        ft_hash_str_free( (FT_Hash)font->internal, memory );
    2324        FT_FREE( font->internal );
    2325      }
    2326  
    2327      /* Free up the comment info. */
    2328      FT_FREE( font->comments );
    2329  
    2330      /* Free up the properties. */
    2331      for ( i = 0; i < font->props_size; i++ )
    2332      {
    2333        if ( font->props[i].format == BDF_ATOM )
    2334          FT_FREE( font->props[i].value.atom );
    2335      }
    2336  
    2337      FT_FREE( font->props );
    2338  
    2339      /* Free up the character info. */
    2340      for ( i = 0, glyphs = font->glyphs;
    2341            i < font->glyphs_used; i++, glyphs++ )
    2342      {
    2343        FT_FREE( glyphs->name );
    2344        FT_FREE( glyphs->bitmap );
    2345      }
    2346  
    2347      for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
    2348            i++, glyphs++ )
    2349      {
    2350        FT_FREE( glyphs->name );
    2351        FT_FREE( glyphs->bitmap );
    2352      }
    2353  
    2354      FT_FREE( font->glyphs );
    2355      FT_FREE( font->unencoded );
    2356  
    2357      /* bdf_cleanup */
    2358      ft_hash_str_free( &(font->proptbl), memory );
    2359  
    2360      /* Free up the user defined properties. */
    2361      for ( prop = font->user_props, i = 0;
    2362            i < font->nuser_props; i++, prop++ )
    2363        FT_FREE( prop->name );
    2364  
    2365      FT_FREE( font->user_props );
    2366  
    2367      /* FREE( font ); */ /* XXX Fixme */
    2368    }
    2369  
    2370  
    2371    FT_LOCAL_DEF( bdf_property_t * )
    2372    bdf_get_font_property( bdf_font_t*  font,
    2373                           const char*  name )
    2374    {
    2375      size_t*  propid;
    2376  
    2377  
    2378      if ( font == NULL || font->props_size == 0 || name == NULL || *name == 0 )
    2379        return 0;
    2380  
    2381      propid = ft_hash_str_lookup( name, (FT_Hash)font->internal );
    2382  
    2383      return propid ? ( font->props + *propid ) : 0;
    2384    }
    2385  
    2386  
    2387  /* END */