text:
/*
 * Copyright 2000 Computing Research Labs, New Mexico State University
 * Copyright 2001-2014
 *   Francesco Zappa Nardelli
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

  /**************************************************************************
   *
   * This file is based on bdf.c,v 1.22 2000/03/16 20:08:50
   *
   * taken from Mark Leisher's xmbdfed package
   *
   */

#include <ft2build.h>

#include FT_FREETYPE_H
#include FT_INTERNAL_DEBUG_H
#include FT_INTERNAL_STREAM_H
#include FT_INTERNAL_OBJECTS_H

#include "bdf.h"
#include "bdferror.h"

  /**************************************************************************
   *
   * The macro FT_COMPONENT is used in trace mode.  It is an implicit
   * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
   * messages during execution.
   */
#undef  FT_COMPONENT
#define FT_COMPONENT  bdflib

  /**************************************************************************
   *
   * Default BDF font options.
   *
   */

  static const bdf_options_t  _bdf_opts =
  {
    1,                /* Correct metrics.               */
    1,                /* Preserve unencoded glyphs.     */
    0,                /* Preserve comments.             */
    BDF_PROPORTIONAL  /* Default spacing.               */
  };

  /**************************************************************************
   *
   * Builtin BDF font properties.
   *
   */

  /* List of most properties that might appear in a font.  Doesn't include */
  /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts.           */

  static const bdf_property_t  _bdf_properties[] =
  {
    { "ADD_STYLE_NAME",          BDF_ATOM,     1, { 0 } },
    { "AVERAGE_WIDTH",           BDF_INTEGER,  1, { 0 } },
    { "AVG_CAPITAL_WIDTH",       BDF_INTEGER,  1, { 0 } },
    { "AVG_LOWERCASE_WIDTH",     BDF_INTEGER,  1, { 0 } },
    { "CAP_HEIGHT",              BDF_INTEGER,  1, { 0 } },
    { "CHARSET_COLLECTIONS",     BDF_ATOM,     1, { 0 } },
    { "CHARSET_ENCODING",        BDF_ATOM,     1, { 0 } },
    { "CHARSET_REGISTRY",        BDF_ATOM,     1, { 0 } },
    { "COMMENT",                 BDF_ATOM,     1, { 0 } },
    { "COPYRIGHT",               BDF_ATOM,     1, { 0 } },
    { "DEFAULT_CHAR",            BDF_CARDINAL, 1, { 0 } },
    { "DESTINATION",             BDF_CARDINAL, 1, { 0 } },
    { "DEVICE_FONT_NAME",        BDF_ATOM,     1, { 0 } },
    { "END_SPACE",               BDF_INTEGER,  1, { 0 } },
    { "FACE_NAME",               BDF_ATOM,     1, { 0 } },
    { "FAMILY_NAME",             BDF_ATOM,     1, { 0 } },
    { "FIGURE_WIDTH",            BDF_INTEGER,  1, { 0 } },
    { "FONT",                    BDF_ATOM,     1, { 0 } },
    { "FONTNAME_REGISTRY",       BDF_ATOM,     1, { 0 } },
    { "FONT_ASCENT",             BDF_INTEGER,  1, { 0 } },
    { "FONT_DESCENT",            BDF_INTEGER,  1, { 0 } },
    { "FOUNDRY",                 BDF_ATOM,     1, { 0 } },
    { "FULL_NAME",               BDF_ATOM,     1, { 0 } },
    { "ITALIC_ANGLE",            BDF_INTEGER,  1, { 0 } },
    { "MAX_SPACE",               BDF_INTEGER,  1, { 0 } },
    { "MIN_SPACE",               BDF_INTEGER,  1, { 0 } },
    { "NORM_SPACE",              BDF_INTEGER,  1, { 0 } },
    { "NOTICE",                  BDF_ATOM,     1, { 0 } },
    { "PIXEL_SIZE",              BDF_INTEGER,  1, { 0 } },
    { "POINT_SIZE",              BDF_INTEGER,  1, { 0 } },
    { "QUAD_WIDTH",              BDF_INTEGER,  1, { 0 } },
    { "RAW_ASCENT",              BDF_INTEGER,  1, { 0 } },
    { "RAW_AVERAGE_WIDTH",       BDF_INTEGER,  1, { 0 } },
    { "RAW_AVG_CAPITAL_WIDTH",   BDF_INTEGER,  1, { 0 } },
    { "RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER,  1, { 0 } },
    { "RAW_CAP_HEIGHT",          BDF_INTEGER,  1, { 0 } },
    { "RAW_DESCENT",             BDF_INTEGER,  1, { 0 } },
    { "RAW_END_SPACE",           BDF_INTEGER,  1, { 0 } },
    { "RAW_FIGURE_WIDTH",        BDF_INTEGER,  1, { 0 } },
    { "RAW_MAX_SPACE",           BDF_INTEGER,  1, { 0 } },
    { "RAW_MIN_SPACE",           BDF_INTEGER,  1, { 0 } },
    { "RAW_NORM_SPACE",          BDF_INTEGER,  1, { 0 } },
    { "RAW_PIXEL_SIZE",          BDF_INTEGER,  1, { 0 } },
    { "RAW_POINT_SIZE",          BDF_INTEGER,  1, { 0 } },
    { "RAW_PIXELSIZE",           BDF_INTEGER,  1, { 0 } },
    { "RAW_POINTSIZE",           BDF_INTEGER,  1, { 0 } },
    { "RAW_QUAD_WIDTH",          BDF_INTEGER,  1, { 0 } },
    { "RAW_SMALL_CAP_SIZE",      BDF_INTEGER,  1, { 0 } },
    { "RAW_STRIKEOUT_ASCENT",    BDF_INTEGER,  1, { 0 } },
    { "RAW_STRIKEOUT_DESCENT",   BDF_INTEGER,  1, { 0 } },
    { "RAW_SUBSCRIPT_SIZE",      BDF_INTEGER,  1, { 0 } },
    { "RAW_SUBSCRIPT_X",         BDF_INTEGER,  1, { 0 } },
    { "RAW_SUBSCRIPT_Y",         BDF_INTEGER,  1, { 0 } },
    { "RAW_SUPERSCRIPT_SIZE",    BDF_INTEGER,  1, { 0 } },
    { "RAW_SUPERSCRIPT_X",       BDF_INTEGER,  1, { 0 } },
    { "RAW_SUPERSCRIPT_Y",       BDF_INTEGER,  1, { 0 } },
    { "RAW_UNDERLINE_POSITION",  BDF_INTEGER,  1, { 0 } },
    { "RAW_UNDERLINE_THICKNESS", BDF_INTEGER,  1, { 0 } },
    { "RAW_X_HEIGHT",            BDF_INTEGER,  1, { 0 } },
    { "RELATIVE_SETWIDTH",       BDF_CARDINAL, 1, { 0 } },
    { "RELATIVE_WEIGHT",         BDF_CARDINAL, 1, { 0 } },
    { "RESOLUTION",              BDF_INTEGER,  1, { 0 } },
    { "RESOLUTION_X",            BDF_CARDINAL, 1, { 0 } },
    { "RESOLUTION_Y",            BDF_CARDINAL, 1, { 0 } },
    { "SETWIDTH_NAME",           BDF_ATOM,     1, { 0 } },
    { "SLANT",                   BDF_ATOM,     1, { 0 } },
    { "SMALL_CAP_SIZE",          BDF_INTEGER,  1, { 0 } },
    { "SPACING",                 BDF_ATOM,     1, { 0 } },
    { "STRIKEOUT_ASCENT",        BDF_INTEGER,  1, { 0 } },
    { "STRIKEOUT_DESCENT",       BDF_INTEGER,  1, { 0 } },
    { "SUBSCRIPT_SIZE",          BDF_INTEGER,  1, { 0 } },
    { "SUBSCRIPT_X",             BDF_INTEGER,  1, { 0 } },
    { "SUBSCRIPT_Y",             BDF_INTEGER,  1, { 0 } },
    { "SUPERSCRIPT_SIZE",        BDF_INTEGER,  1, { 0 } },
    { "SUPERSCRIPT_X",           BDF_INTEGER,  1, { 0 } },
    { "SUPERSCRIPT_Y",           BDF_INTEGER,  1, { 0 } },
    { "UNDERLINE_POSITION",      BDF_INTEGER,  1, { 0 } },
    { "UNDERLINE_THICKNESS",     BDF_INTEGER,  1, { 0 } },
    { "WEIGHT",                  BDF_CARDINAL, 1, { 0 } },
    { "WEIGHT_NAME",             BDF_ATOM,     1, { 0 } },
    { "X_HEIGHT",                BDF_INTEGER,  1, { 0 } },
    { "_MULE_BASELINE_OFFSET",   BDF_INTEGER,  1, { 0 } },
    { "_MULE_RELATIVE_COMPOSE",  BDF_INTEGER,  1, { 0 } },
  };

  static const unsigned long
  _num_bdf_properties = sizeof ( _bdf_properties ) /
                        sizeof ( _bdf_properties[0] );

  /* An auxiliary macro to parse properties, to be used in conditionals. */
  /* It behaves like `strncmp' but also tests the following character    */
  /* whether it is a whitespace or NULL.                                 */
  /* `property' is a constant string of length `n' to compare with.      */
#define _bdf_strncmp( name, property, n )      \
          ( ft_strncmp( name, property, n ) || \
            !( name[n] == ' '  ||              \
               name[n] == '\0' ||              \
               name[n] == '\n' ||              \
               name[n] == '\r' ||              \
               name[n] == '\t' )            )

  /* Auto correction messages. */
#define ACMSG1   "FONT_ASCENT property missing.  " \
                 "Added `FONT_ASCENT %hd'.\n"
#define ACMSG2   "FONT_DESCENT property missing.  " \
                 "Added `FONT_DESCENT %hd'.\n"
#define ACMSG3   "Font width != actual width.  Old: %hd New: %hd.\n"
#define ACMSG4   "Font left bearing != actual left bearing.  " \
                 "Old: %hd New: %hd.\n"
#define ACMSG5   "Font ascent != actual ascent.  Old: %hd New: %hd.\n"
#define ACMSG6   "Font descent != actual descent.  Old: %hd New: %hd.\n"
#define ACMSG7   "Font height != actual height. Old: %hd New: %hd.\n"
#define ACMSG8   "Glyph scalable width (SWIDTH) adjustments made.\n"
#define ACMSG9   "SWIDTH field missing at line %ld.  Set automatically.\n"
#define ACMSG10  "DWIDTH field missing at line %ld.  Set to glyph width.\n"
#define ACMSG11  "SIZE bits per pixel field adjusted to %hd.\n"
#define ACMSG13  "Glyph %lu extra rows removed.\n"
#define ACMSG14  "Glyph %lu extra columns removed.\n"
#define ACMSG15  "Incorrect glyph count: %ld indicated but %ld found.\n"
#define ACMSG16  "Glyph %lu missing columns padded with zero bits.\n"
#define ACMSG17  "Adjusting number of glyphs to %ld.\n"

  /* Error messages. */
#define ERRMSG1  "[line %ld] Missing `%s' line.\n"
#define ERRMSG2  "[line %ld] Font header corrupted or missing fields.\n"
#define ERRMSG3  "[line %ld] Font glyphs corrupted or missing fields.\n"
#define ERRMSG4  "[line %ld] BBX too big.\n"
#define ERRMSG5  "[line %ld] `%s' value too big.\n"
#define ERRMSG6  "[line %ld] Input line too long.\n"
#define ERRMSG7  "[line %ld] Font name too long.\n"
#define ERRMSG8  "[line %ld] Invalid `%s' value.\n"
#define ERRMSG9  "[line %ld] Invalid keyword.\n"

  /* Debug messages. */
#define DBGMSG1  "  [%6ld] %s" /* no \n */
#define DBGMSG2  " (0x%lX)\n"

  /**************************************************************************
   *
   * Utility types and functions.
   *
   */

  /* Function type for parsing lines of a BDF font. */

  typedef FT_Error
  (*_bdf_line_func_t)( char*          line,
                       unsigned long  linelen,
                       unsigned long  lineno,
                       void*          call_data,
                       void*          client_data );

  /* List structure for splitting lines into fields. */

  typedef struct  _bdf_list_t_
  {
    char**         field;
    unsigned long  size;
    unsigned long  used;
    FT_Memory      memory;

  } _bdf_list_t;

  /* Structure used while loading BDF fonts. */

  typedef struct  _bdf_parse_t_
  {
    unsigned long   flags;
    unsigned long   cnt;
    unsigned long   row;

    short           minlb;
    short           maxlb;
    short           maxrb;
    short           maxas;
    short           maxds;

    short           rbearing;

    char*           glyph_name;
    long            glyph_enc;

    bdf_font_t*     font;
    bdf_options_t*  opts;

    _bdf_list_t     list;

    FT_Memory       memory;
    unsigned long   size;        /* the stream size */

  } _bdf_parse_t;

#define setsbit( m, cc ) \
          ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
#define sbitset( m, cc ) \
          ( m[(FT_Byte)(cc) >> 3]  & ( 1 << ( (cc) & 7 ) ) )

  static void
  _bdf_list_init( _bdf_list_t*  list,
                  FT_Memory     memory )
  {
    FT_ZERO( list );
    list->memory = memory;
  }

  static void
  _bdf_list_done( _bdf_list_t*  list )
  {
    FT_Memory  memory = list->memory;

    if ( memory )
    {
      FT_FREE( list->field );
      FT_ZERO( list );
    }
  }

  static FT_Error
  _bdf_list_ensure( _bdf_list_t*   list,
                    unsigned long  num_items ) /* same as _bdf_list_t.used */
  {
    FT_Error  error = FT_Err_Ok;

    if ( num_items > list->size )
    {
      unsigned long  oldsize = list->size; /* same as _bdf_list_t.size */
      unsigned long  newsize = oldsize + ( oldsize >> 1 ) + 5;
      unsigned long  bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
      FT_Memory      memory  = list->memory;

      if ( oldsize == bigsize )
      {
        error = FT_THROW( Out_Of_Memory );
        goto Exit;
      }
      else if ( newsize < oldsize || newsize > bigsize )
        newsize = bigsize;

      if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
        goto Exit;

      list->size = newsize;
    }

  Exit:
    return error;
  }

  static void
  _bdf_list_shift( _bdf_list_t*   list,
                   unsigned long  n )
  {
    unsigned long  i, u;

    if ( list == 0 || list->used == 0 || n == 0 )
      return;

    if ( n >= list->used )
    {
      list->used = 0;
      return;
    }

    for ( u = n, i = 0; u < list->used; i++, u++ )
      list->field[i] = list->field[u];
    list->used -= n;
  }

  /* An empty string for empty fields. */

  static const char  empty[] = "";      /* XXX eliminate this */

  static char *
  _bdf_list_join( _bdf_list_t*    list,
                  int             c,
                  unsigned long  *alen )
  {
    unsigned long  i, j;
    char*          dp;

    *alen = 0;

    if ( list == 0 || list->used == 0 )
      return 0;

    dp = list->field[0];
    for ( i = j = 0; i < list->used; i++ )
    {
      char*  fp = list->field[i];

      while ( *fp )
        dp[j++] = *fp++;

      if ( i + 1 < list->used )
        dp[j++] = (char)c;
    }
    if ( dp != empty )
      dp[j] = 0;

    *alen = j;
    return dp;
  }

  /* The code below ensures that we have at least 4 + 1 `field' */
  /* elements in `list' (which are possibly NULL) so that we    */
  /* don't have to check the number of fields in most cases.    */

  static FT_Error
  _bdf_list_split( _bdf_list_t*   list,
                   const char*    separators,
                   char*          line,
                   unsigned long  linelen )
  {
    unsigned long  final_empty;
    int            mult;
    const char     *sp, *end;
    char           *ep;
    char           seps[32];
    FT_Error       error = FT_Err_Ok;

    /* Initialize the list. */
    list->used = 0;
    if ( list->size )
    {
      list->field[0] = (char*)empty;
      list->field[1] = (char*)empty;
      list->field[2] = (char*)empty;
      list->field[3] = (char*)empty;
      list->field[4] = (char*)empty;
    }

    /* If the line is empty, then simply return. */
    if ( linelen == 0 || line[0] == 0 )
      goto Exit;

    /* In the original code, if the `separators' parameter is NULL or */
    /* empty, the list is split into individual bytes.  We don't need */
    /* this, so an error is signaled.                                 */
    if ( separators == 0 || *separators == 0 )
    {
      error = FT_THROW( Invalid_Argument );
      goto Exit;
    }

    /* Prepare the separator bitmap. */
    FT_MEM_ZERO( seps, 32 );

    /* If the very last character of the separator string is a plus, then */
    /* set the `mult' flag to indicate that multiple separators should be */
    /* collapsed into one.                                                */
    for ( mult = 0, sp = separators; sp && *sp; sp++ )
    {
      if ( *sp == '+' && *( sp + 1 ) == 0 )
        mult = 1;
      else
        setsbit( seps, *sp );
    }

    /* Break the line up into fields. */
    for ( final_empty = 0, sp = ep = line, end = sp + linelen;
          sp < end && *sp; )
    {
      /* Collect everything that is not a separator. */
      for ( ; *ep && !sbitset( seps, *ep ); ep++ )
        ;

      /* Resize the list if necessary. */
      if ( list->used == list->size )
      {
        error = _bdf_list_ensure( list, list->used + 1 );
        if ( error )
          goto Exit;
      }

      /* Assign the field appropriately. */
      list->field[list->used++] = ( ep > sp ) ? (char*)sp : (char*)empty;

      sp = ep;

      if ( mult )
      {
        /* If multiple separators should be collapsed, do it now by */
        /* setting all the separator characters to 0.               */
        for ( ; *ep && sbitset( seps, *ep ); ep++ )
          *ep = 0;
      }
      else if ( *ep != 0 )
        /* Don't collapse multiple separators by making them 0, so just */
        /* make the one encountered 0.                                  */
        *ep++ = 0;

      final_empty = ( ep > sp && *ep == 0 );
      sp = ep;
    }

    /* Finally, NULL-terminate the list. */
    if ( list->used + final_empty >= list->size )
    {
      error = _bdf_list_ensure( list, list->used + final_empty + 1 );
      if ( error )
        goto Exit;
    }

    if ( final_empty )
      list->field[list->used++] = (char*)empty;

    list->field[list->used] = 0;

  Exit:
    return error;
  }

#define NO_SKIP  256  /* this value cannot be stored in a 'char' */

  static FT_Error
  _bdf_readstream( FT_Stream         stream,
                   _bdf_line_func_t  callback,
                   void*             client_data,
                   unsigned long    *lno )
  {
    _bdf_line_func_t  cb;
    unsigned long     lineno, buf_size;
    int               refill, hold, to_skip;
    ptrdiff_t         bytes, start, end, cursor, avail;
    char*             buf    = NULL;
    FT_Memory         memory = stream->memory;
    FT_Error          error  = FT_Err_Ok;

    if ( callback == 0 )
    {
      error = FT_THROW( Invalid_Argument );
      goto Exit;
    }

    /* initial size and allocation of the input buffer */
    buf_size = 1024;

    if ( FT_NEW_ARRAY( buf, buf_size ) )
      goto Exit;

    cb      = callback;
    lineno  = 1;
    buf[0]  = 0;
    start   = 0;
    avail   = 0;
    cursor  = 0;
    refill  = 1;
    to_skip = NO_SKIP;
    bytes   = 0;        /* make compiler happy */

    for (;;)
    {
      if ( refill )
      {
        bytes  = (ptrdiff_t)FT_Stream_TryRead(
                   stream, (FT_Byte*)buf + cursor,
                   buf_size - (unsigned long)cursor );
        avail  = cursor + bytes;
        cursor = 0;
        refill = 0;
      }

      end = start;

      /* should we skip an optional character like \n or \r? */
      if ( start < avail && buf[start] == to_skip )
      {
        start  += 1;
        to_skip = NO_SKIP;
        continue;
      }

      /* try to find the end of the line */
      while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
        end++;

      /* if we hit the end of the buffer, try shifting its content */
      /* or even resizing it                                       */
      if ( end >= avail )
      {
        if ( bytes == 0 )  /* last line in file doesn't end in \r or \n */
          break;           /* ignore it then exit                       */

        if ( start == 0 )
        {
          /* this line is definitely too long; try resizing the input */
          /* buffer a bit to handle it.                               */
          FT_ULong  new_size;

          if ( buf_size >= 65536UL )  /* limit ourselves to 64KByte */
          {
            FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
            error = FT_THROW( Invalid_Argument );
            goto Exit;
          }

          new_size = buf_size * 2;
          if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
            goto Exit;

          cursor   = (ptrdiff_t)buf_size;
          buf_size = new_size;
        }
        else
        {
          bytes = avail - start;

          FT_MEM_MOVE( buf, buf + start, bytes );

          cursor = bytes;
          avail -= bytes;
          start  = 0;
        }
        refill = 1;
        continue;
      }

      /* Temporarily NUL-terminate the line. */
      hold     = buf[end];
      buf[end] = 0;

      /* XXX: Use encoding independent value for 0x1A */
      if ( buf[start] != '#' && buf[start] != 0x1A && end > start )
      {
        error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
                       (void*)&cb, client_data );
        /* Redo if we have encountered CHARS without properties. */
        if ( error == -1 )
          error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
                         (void*)&cb, client_data );
        if ( error )
          break;
      }

      lineno  += 1;
      buf[end] = (char)hold;
      start    = end + 1;

      if ( hold == '\n' )
        to_skip = '\r';
      else if ( hold == '\r' )
        to_skip = '\n';
      else
        to_skip = NO_SKIP;
    }

    *lno = lineno;

  Exit:
    FT_FREE( buf );
    return error;
  }

  /* XXX: make this work with EBCDIC also */

  static const unsigned char  a2i[128] =
  {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  };

  static const unsigned char  ddigits[32] =
  {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  };

  static const unsigned char  hdigits[32] =
  {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
    0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  };

  /* Routine to convert a decimal ASCII string to an unsigned long integer. */
  static unsigned long
  _bdf_atoul( const char*  s )
  {
    unsigned long  v;

    if ( s == 0 || *s == 0 )
      return 0;

    for ( v = 0; sbitset( ddigits, *s ); s++ )
    {
      if ( v < ( FT_ULONG_MAX - 9 ) / 10 )
        v = v * 10 + a2i[(int)*s];
      else
      {
        v = FT_ULONG_MAX;
        break;
      }
    }

    return v;
  }

  /* Routine to convert a decimal ASCII string to a signed long integer. */
  static long
  _bdf_atol( const char*  s )
  {
    long  v, neg;

    if ( s == 0 || *s == 0 )
      return 0;

    /* Check for a minus sign. */
    neg = 0;
    if ( *s == '-' )
    {
      s++;
      neg = 1;
    }

    for ( v = 0; sbitset( ddigits, *s ); s++ )
    {
      if ( v < ( FT_LONG_MAX - 9 ) / 10 )
        v = v * 10 + a2i[(int)*s];
      else
      {
        v = FT_LONG_MAX;
        break;
      }
    }

    return ( !neg ) ? v : -v;
  }

  /* Routine to convert a decimal ASCII string to an unsigned short integer. */
  static unsigned short
  _bdf_atous( const char*  s )
  {
    unsigned short  v;

    if ( s == 0 || *s == 0 )
      return 0;

    for ( v = 0; sbitset( ddigits, *s ); s++ )
    {
      if ( v < ( FT_USHORT_MAX - 9 ) / 10 )
        v = (unsigned short)( v * 10 + a2i[(int)*s] );
      else
      {
        v = FT_USHORT_MAX;
        break;
      }
    }

    return v;
  }

  /* Routine to convert a decimal ASCII string to a signed short integer. */
  static short
  _bdf_atos( const char*  s )
  {
    short  v, neg;

    if ( s == 0 || *s == 0 )
      return 0;

    /* Check for a minus. */
    neg = 0;
    if ( *s == '-' )
    {
      s++;
      neg = 1;
    }

    for ( v = 0; sbitset( ddigits, *s ); s++ )
    {
      if ( v < ( SHRT_MAX - 9 ) / 10 )
        v = (short)( v * 10 + a2i[(int)*s] );
      else
      {
        v = SHRT_MAX;
        break;
      }
    }

    return (short)( ( !neg ) ? v : -v );
  }

  /* Routine to compare two glyphs by encoding so they can be sorted. */
  static int
  by_encoding( const void*  a,
               const void*  b )
  {
    bdf_glyph_t  *c1, *c2;

    c1 = (bdf_glyph_t *)a;
    c2 = (bdf_glyph_t *)b;

    if ( c1->encoding < c2->encoding )
      return -1;

    if ( c1->encoding > c2->encoding )
      return 1;

    return 0;
  }

  static FT_Error
  bdf_create_property( const char*  name,
                       int          format,
                       bdf_font_t*  font )
  {
    size_t           n;
    bdf_property_t*  p;
    FT_Memory        memory = font->memory;
    FT_Error         error  = FT_Err_Ok;

    /* First check whether the property has        */
    /* already been added or not.  If it has, then */
    /* simply ignore it.                           */
    if ( ft_hash_str_lookup( name, &(font->proptbl) ) )
      goto Exit;

    if ( FT_RENEW_ARRAY( font->user_props,
                         font->nuser_props,
                         font->nuser_props + 1 ) )
      goto Exit;

    p = font->user_props + font->nuser_props;
    FT_ZERO( p );

    n = ft_strlen( name ) + 1;
    if ( n > FT_ULONG_MAX )
      return FT_THROW( Invalid_Argument );

    if ( FT_NEW_ARRAY( p->name, n ) )
      goto Exit;

    FT_MEM_COPY( (char *)p->name, name, n );

    p->format  = format;
    p->builtin = 0;

    n = _num_bdf_properties + font->nuser_props;

    error = ft_hash_str_insert( p->name, n, &(font->proptbl), memory );
    if ( error )
      goto Exit;

    font->nuser_props++;

  Exit:
    return error;
  }

  FT_LOCAL_DEF( bdf_property_t* )
  bdf_get_property( char*        name,
                    bdf_font_t*  font )
  {
    size_t*  propid;

    if ( name == 0 || *name == 0 )
      return 0;

    if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL )
      return 0;

    if ( *propid >= _num_bdf_properties )
      return font->user_props + ( *propid - _num_bdf_properties );

    return (bdf_property_t*)_bdf_properties + *propid;
  }

  /**************************************************************************
   *
   * BDF font file parsing flags and functions.
   *
   */

  /* Parse flags. */

#define BDF_START_      0x0001U
#define BDF_FONT_NAME_  0x0002U
#define BDF_SIZE_       0x0004U
#define BDF_FONT_BBX_   0x0008U
#define BDF_PROPS_      0x0010U
#define BDF_GLYPHS_     0x0020U
#define BDF_GLYPH_      0x0040U
#define BDF_ENCODING_   0x0080U
#define BDF_SWIDTH_     0x0100U
#define BDF_DWIDTH_     0x0200U
#define BDF_BBX_        0x0400U
#define BDF_BITMAP_     0x0800U

#define BDF_SWIDTH_ADJ_  0x1000U

#define BDF_GLYPH_BITS_ ( BDF_GLYPH_    | \
                          BDF_ENCODING_ | \
                          BDF_SWIDTH_   | \
                          BDF_DWIDTH_   | \
                          BDF_BBX_      | \
                          BDF_BITMAP_   )

#define BDF_GLYPH_WIDTH_CHECK_   0x40000000UL
#define BDF_GLYPH_HEIGHT_CHECK_  0x80000000UL

  static FT_Error
  _bdf_add_comment( bdf_font_t*    font,
                    char*          comment,
                    unsigned long  len )
  {
    char*      cp;
    FT_Memory  memory = font->memory;
    FT_Error   error  = FT_Err_Ok;

    if ( FT_RENEW_ARRAY( font->comments,
                         font->comments_len,
                         font->comments_len + len + 1 ) )
      goto Exit;

    cp = font->comments + font->comments_len;

    FT_MEM_COPY( cp, comment, len );
    cp[len] = '\n';

    font->comments_len += len + 1;

  Exit:
    return error;
  }

  /* Set the spacing from the font name if it exists, or set it to the */
  /* default specified in the options.                                 */
  static FT_Error
  _bdf_set_default_spacing( bdf_font_t*     font,
                            bdf_options_t*  opts,
                            unsigned long   lineno )
  {
    size_t       len;
    char         name[256];
    _bdf_list_t  list;
    FT_Memory    memory;
    FT_Error     error = FT_Err_Ok;

    FT_UNUSED( lineno );        /* only used in debug mode */

    if ( font == 0 || font->name == 0 || font->name[0] == 0 )
    {
      error = FT_THROW( Invalid_Argument );
      goto Exit;
    }

    memory = font->memory;

    _bdf_list_init( &list, memory );

    font->spacing = opts->font_spacing;

    len = ft_strlen( font->name ) + 1;
    /* Limit ourselves to 256 characters in the font name. */
    if ( len >= 256 )
    {
      FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
      error = FT_THROW( Invalid_Argument );
      goto Exit;
    }

    FT_MEM_COPY( name, font->name, len );

    error = _bdf_list_split( &list, "-", name, (unsigned long)len );
    if ( error )
      goto Fail;

    if ( list.used == 15 )
    {
      switch ( list.field[11][0] )
      {
      case 'C':
      case 'c':
        font->spacing = BDF_CHARCELL;
        break;
      case 'M':
      case 'm':
        font->spacing = BDF_MONOWIDTH;
        break;
      case 'P':
      case 'p':
        font->spacing = BDF_PROPORTIONAL;
        break;
      }
    }

  Fail:
    _bdf_list_done( &list );

  Exit:
    return error;
  }

  /* Determine whether the property is an atom or not.  If it is, then */
  /* clean it up so the double quotes are removed if they exist.       */
  static int
  _bdf_is_atom( char*          line,
                unsigned long  linelen,
                char**         name,
                char**         value,
                bdf_font_t*    font )
  {
    int              hold;
    char             *sp, *ep;
    bdf_property_t*  p;

    *name = sp = ep = line;

    while ( *ep && *ep != ' ' && *ep != '\t' )
      ep++;

    hold = -1;
    if ( *ep )
    {
      hold = *ep;
      *ep  = 0;
    }

    p = bdf_get_property( sp, font );

    /* Restore the character that was saved before any return can happen. */
    if ( hold != -1 )
      *ep = (char)hold;

    /* If the property exists and is not an atom, just return here. */
    if ( p && p->format != BDF_ATOM )
      return 0;

    /* The property is an atom.  Trim all leading and trailing whitespace */
    /* and double quotes for the atom value.                              */
    sp = ep;
    ep = line + linelen;

    /* Trim the leading whitespace if it exists. */
    if ( *sp )
      *sp++ = 0;
    while ( *sp                           &&
            ( *sp == ' ' || *sp == '\t' ) )
      sp++;

    /* Trim the leading double quote if it exists. */
    if ( *sp == '"' )
      sp++;
    *value = sp;

    /* Trim the trailing whitespace if it exists. */
    while ( ep > sp                                       &&
            ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
      *--ep = 0;

    /* Trim the trailing double quote if it exists. */
    if ( ep > sp && *( ep - 1 ) == '"' )
      *--ep = 0;

    return 1;
  }

  static FT_Error
  _bdf_add_property( bdf_font_t*    font,
                     const char*    name,
                     char*          value,
                     unsigned long  lineno )
  {
    size_t*         propid;
    bdf_property_t  *prop, *fp;
    FT_Memory       memory = font->memory;
    FT_Error        error  = FT_Err_Ok;

    FT_UNUSED( lineno );        /* only used in debug mode */

    /* First, check whether the property already exists in the font. */
    if ( ( propid = ft_hash_str_lookup( name,
                                        (FT_Hash)font->internal ) ) != NULL )
    {
      /* The property already exists in the font, so simply replace */
      /* the value of the property with the current value.          */
      fp = font->props + *propid;

      switch ( fp->format )
      {
      case BDF_ATOM:
        /* Delete the current atom if it exists. */
        FT_FREE( fp->value.atom );

        if ( value && value[0] != 0 )
        {
          if ( FT_STRDUP( fp->value.atom, value ) )
            goto Exit;
        }
        break;

      case BDF_INTEGER:
        fp->value.l = _bdf_atol( value );
        break;

      case BDF_CARDINAL:
        fp->value.ul = _bdf_atoul( value );
        break;

      default:
        ;
      }

      goto Exit;
    }

    /* See whether this property type exists yet or not. */
    /* If not, create it.                                */
    propid = ft_hash_str_lookup( name, &(font->proptbl) );
    if ( !propid )
    {
      error = bdf_create_property( name, BDF_ATOM, font );
      if ( error )
        goto Exit;
      propid = ft_hash_str_lookup( name, &(font->proptbl) );
    }

    /* Allocate another property if this is overflowing. */
    if ( font->props_used == font->props_size )
    {
      if ( font->props_size == 0 )
      {
        if ( FT_NEW_ARRAY( font->props, 1 ) )
          goto Exit;
      }
      else
      {
        if ( FT_RENEW_ARRAY( font->props,
                             font->props_size,
                             font->props_size + 1 ) )
          goto Exit;
      }

      fp = font->props + font->props_size;
      FT_ZERO( fp );
      font->props_size++;
    }

    if ( *propid >= _num_bdf_properties )
      prop = font->user_props + ( *propid - _num_bdf_properties );
    else
      prop = (bdf_property_t*)_bdf_properties + *propid;

    fp = font->props + font->props_used;

    fp->name    = prop->name;
    fp->format  = prop->format;
    fp->builtin = prop->builtin;

    switch ( prop->format )
    {
    case BDF_ATOM:
      fp->value.atom = 0;
      if ( value != 0 && value[0] )
      {
        if ( FT_STRDUP( fp->value.atom, value ) )
          goto Exit;
      }
      break;

    case BDF_INTEGER:
      fp->value.l = _bdf_atol( value );
      break;

    case BDF_CARDINAL:
      fp->value.ul = _bdf_atoul( value );
      break;
    }

    /* If the property happens to be a comment, then it doesn't need */
    /* to be added to the internal hash table.                       */
    if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 )
    {
      /* Add the property to the font property table. */
      error = ft_hash_str_insert( fp->name,
                                  font->props_used,
                                  (FT_Hash)font->internal,
                                  memory );
      if ( error )
        goto Exit;
    }

    font->props_used++;

    /* Some special cases need to be handled here.  The DEFAULT_CHAR       */
    /* property needs to be located if it exists in the property list, the */
    /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are        */
    /* present, and the SPACING property should override the default       */
    /* spacing.                                                            */
    if ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 )
      font->default_char = fp->value.ul;
    else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 )
      font->font_ascent = fp->value.l;
    else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 )
      font->font_descent = fp->value.l;
    else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 )
    {
      if ( !fp->value.atom )
      {
        FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
        error = FT_THROW( Invalid_File_Format );
        goto Exit;
      }

      if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
        font->spacing = BDF_PROPORTIONAL;
      else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
        font->spacing = BDF_MONOWIDTH;
      else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
        font->spacing = BDF_CHARCELL;
    }

  Exit:
    return error;
  }

  static const unsigned char nibble_mask[8] =
  {
    0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
  };

  static FT_Error
  _bdf_parse_end( char*          line,
                  unsigned long  linelen,
                  unsigned long  lineno,
                  void*          call_data,
                  void*          client_data )
  {
    /* a no-op; we ignore everything after `ENDFONT' */

    FT_UNUSED( line );
    FT_UNUSED( linelen );
    FT_UNUSED( lineno );
    FT_UNUSED( call_data );
    FT_UNUSED( client_data );

    return FT_Err_Ok;
  }

  /* Actually parse the glyph info and bitmaps. */
  static FT_Error
  _bdf_parse_glyphs( char*          line,
                     unsigned long  linelen,
                     unsigned long  lineno,
                     void*          call_data,
                     void*          client_data )
  {
    int                c, mask_index;
    char*              s;
    unsigned char*     bp;
    unsigned long      i, slen, nibbles;

    _bdf_line_func_t*  next;
    _bdf_parse_t*      p;
    bdf_glyph_t*       glyph;
    bdf_font_t*        font;

    FT_Memory          memory;
    FT_Error           error = FT_Err_Ok;

    FT_UNUSED( lineno );        /* only used in debug mode */

    next = (_bdf_line_func_t *)call_data;
    p    = (_bdf_parse_t *)    client_data;

    font   = p->font;
    memory = font->memory;

    /* Check for a comment. */
    if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
    {
      linelen -= 7;

      s = line + 7;
      if ( *s != 0 )
      {
        s++;
        linelen--;
      }
      error = _bdf_add_comment( p->font, s, linelen );
      goto Exit;
    }

    /* The very first thing expected is the number of glyphs. */
    if ( !( p->flags & BDF_GLYPHS_ ) )
    {
      if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 )
      {
        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
        error = FT_THROW( Missing_Chars_Field );
        goto Exit;
      }

      error = _bdf_list_split( &p->list, " +", line, linelen );
      if ( error )
        goto Exit;
      p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1] );

      /* We need at least 20 bytes per glyph. */
      if ( p->cnt > p->size / 20 )
      {
        p->cnt = font->glyphs_size = p->size / 20;
        FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG17, p->cnt ));
      }

      /* Make sure the number of glyphs is non-zero. */
      if ( p->cnt == 0 )
        font->glyphs_size = 64;

      /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
      /* number of code points available in Unicode).                 */
      if ( p->cnt >= 0x110000UL )
      {
        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
        error = FT_THROW( Invalid_Argument );
        goto Exit;
      }

      if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
        goto Exit;

      p->flags |= BDF_GLYPHS_;

      goto Exit;
    }

    /* Check for the ENDFONT field. */
    if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 )
    {
      if ( p->flags & BDF_GLYPH_BITS_ )
      {
        /* Missing ENDCHAR field. */
        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
        error = FT_THROW( Corrupted_Font_Glyphs );
        goto Exit;
      }

      /* Sort the glyphs by encoding. */
      ft_qsort( (char *)font->glyphs,
                font->glyphs_used,
                sizeof ( bdf_glyph_t ),
                by_encoding );

      p->flags &= ~BDF_START_;
      *next     = _bdf_parse_end;

      goto Exit;
    }

    /* Check for the ENDCHAR field. */
    if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 )
    {
      p->glyph_enc = 0;
      p->flags    &= ~BDF_GLYPH_BITS_;

      goto Exit;
    }

    /* Check whether a glyph is being scanned but should be */
    /* ignored because it is an unencoded glyph.            */
    if ( ( p->flags & BDF_GLYPH_ )     &&
         p->glyph_enc            == -1 &&
         p->opts->keep_unencoded == 0  )
      goto Exit;

    /* Check for the STARTCHAR field. */
    if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 )
    {
      if ( p->flags & BDF_GLYPH_BITS_ )
      {
        /* Missing ENDCHAR field. */
        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" ));
        error = FT_THROW( Missing_Startchar_Field );
        goto Exit;
      }

      /* Set the character name in the parse info first until the */
      /* encoding can be checked for an unencoded character.      */
      FT_FREE( p->glyph_name );

      error = _bdf_list_split( &p->list, " +", line, linelen );
      if ( error )
        goto Exit;

      _bdf_list_shift( &p->list, 1 );

      s = _bdf_list_join( &p->list, ' ', &slen );

      if ( !s )
      {
        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
        error = FT_THROW( Invalid_File_Format );
        goto Exit;
      }

      if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
        goto Exit;

      FT_MEM_COPY( p->glyph_name, s, slen + 1 );

      p->flags |= BDF_GLYPH_;

      FT_TRACE4(( DBGMSG1, lineno, s ));

      goto Exit;
    }

    /* Check for the ENCODING field. */
    if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 )
    {
      if ( !( p->flags & BDF_GLYPH_ ) )
      {
        /* Missing STARTCHAR field. */
        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
        error = FT_THROW( Missing_Startchar_Field );
        goto Exit;
      }

      error = _bdf_list_split( &p->list, " +", line, linelen );
      if ( error )
        goto Exit;

      p->glyph_enc = _bdf_atol( p->list.field[1] );

      /* Normalize negative encoding values.  The specification only */
      /* allows -1, but we can be more generous here.                */
      if ( p->glyph_enc < -1 )
        p->glyph_enc = -1;

      /* Check for alternative encoding format. */
      if ( p->glyph_enc == -1 && p->list.used > 2 )
        p->glyph_enc = _bdf_atol( p->list.field[2] );

      if ( p->glyph_enc < -1 || p->glyph_enc >= 0x110000L )
        p->glyph_enc = -1;

      FT_TRACE4(( DBGMSG2, p->glyph_enc ));

      if ( p->glyph_enc >= 0 )
      {
        /* Make sure there are enough glyphs allocated in case the */
        /* number of characters happen to be wrong.                */
        if ( font->glyphs_used == font->glyphs_size )
        {
          if ( FT_RENEW_ARRAY( font->glyphs,
                               font->glyphs_size,
                               font->glyphs_size + 64 ) )
            goto Exit;

          font->glyphs_size += 64;
        }

        glyph           = font->glyphs + font->glyphs_used++;
        glyph->name     = p->glyph_name;
        glyph->encoding = (unsigned long)p->glyph_enc;

        /* Reset the initial glyph info. */
        p->glyph_name = NULL;
      }
      else
      {
        /* Unencoded glyph.  Check whether it should */
        /* be added or not.                          */
        if ( p->opts->keep_unencoded != 0 )
        {
          /* Allocate the next unencoded glyph. */
          if ( font->unencoded_used == font->unencoded_size )
          {
            if ( FT_RENEW_ARRAY( font->unencoded ,
                                 font->unencoded_size,
                                 font->unencoded_size + 4 ) )
              goto Exit;

            font->unencoded_size += 4;
          }

          glyph           = font->unencoded + font->unencoded_used;
          glyph->name     = p->glyph_name;
          glyph->encoding = font->unencoded_used++;

          /* Reset the initial glyph info. */
          p->glyph_name = NULL;
        }
        else
        {
          /* Free up the glyph name if the unencoded shouldn't be */
          /* kept.                                                */
          FT_FREE( p->glyph_name );
        }

        p->glyph_name = NULL;
      }

      /* Clear the flags that might be added when width and height are */
      /* checked for consistency.                                      */
      p->flags &= ~( BDF_GLYPH_WIDTH_CHECK_ | BDF_GLYPH_HEIGHT_CHECK_ );

      p->flags |= BDF_ENCODING_;

      goto Exit;
    }

    if ( !( p->flags & BDF_ENCODING_ ) )
      goto Missing_Encoding;

    /* Point at the glyph being constructed. */
    if ( p->glyph_enc == -1 )
      glyph = font->unencoded + ( font->unencoded_used - 1 );
    else
      glyph = font->glyphs + ( font->glyphs_used - 1 );

    /* Check whether a bitmap is being constructed. */
    if ( p->flags & BDF_BITMAP_ )
    {
      /* If there are more rows than are specified in the glyph metrics, */
      /* ignore the remaining lines.                                     */
      if ( p->row >= (unsigned long)glyph->bbx.height )
      {
        if ( !( p->flags & BDF_GLYPH_HEIGHT_CHECK_ ) )
        {
          FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
          p->flags |= BDF_GLYPH_HEIGHT_CHECK_;
        }

        goto Exit;
      }

      /* Only collect the number of nibbles indicated by the glyph     */
      /* metrics.  If there are more columns, they are simply ignored. */
      nibbles = glyph->bpr << 1;
      bp      = glyph->bitmap + p->row * glyph->bpr;

      for ( i = 0; i < nibbles; i++ )
      {
        c = line[i];
        if ( !sbitset( hdigits, c ) )
          break;
        *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
        if ( i + 1 < nibbles && ( i & 1 ) )
          *++bp = 0;
      }

      /* If any line has not enough columns,            */
      /* indicate they have been padded with zero bits. */
      if ( i < nibbles                            &&
           !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
      {
        FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
        p->flags       |= BDF_GLYPH_WIDTH_CHECK_;
      }

      /* Remove possible garbage at the right. */
      mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
      if ( glyph->bbx.width )
        *bp &= nibble_mask[mask_index];

      /* If any line has extra columns, indicate they have been removed. */
      if ( i == nibbles                           &&
           sbitset( hdigits, line[nibbles] )      &&
           !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
      {
        FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
        p->flags       |= BDF_GLYPH_WIDTH_CHECK_;
      }

      p->row++;
      goto Exit;
    }

    /* Expect the SWIDTH (scalable width) field next. */
    if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 )
    {
      error = _bdf_list_split( &p->list, " +", line, linelen );
      if ( error )
        goto Exit;

      glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1] );
      p->flags |= BDF_SWIDTH_;

      goto Exit;
    }

    /* Expect the DWIDTH (scalable width) field next. */
    if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 )
    {
      error = _bdf_list_split( &p->list, " +", line, linelen );
      if ( error )
        goto Exit;

      glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1] );

      if ( !( p->flags & BDF_SWIDTH_ ) )
      {
        /* Missing SWIDTH field.  Emit an auto correction message and set */
        /* the scalable width from the device width.                      */
        FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));

        glyph->swidth = (unsigned short)FT_MulDiv(
                          glyph->dwidth, 72000L,
                          (FT_Long)( font->point_size *
                                     font->resolution_x ) );
      }

      p->flags |= BDF_DWIDTH_;
      goto Exit;
    }

    /* Expect the BBX field next. */
    if ( _bdf_strncmp( line, "BBX", 3 ) == 0 )
    {
      error = _bdf_list_split( &p->list, " +", line, linelen );
      if ( error )
        goto Exit;

      glyph->bbx.width    = _bdf_atous( p->list.field[1] );
      glyph->bbx.height   = _bdf_atous( p->list.field[2] );
      glyph->bbx.x_offset = _bdf_atos( p->list.field[3] );
      glyph->bbx.y_offset = _bdf_atos( p->list.field[4] );

      /* Generate the ascent and descent of the character. */
      glyph->bbx.ascent  = (short)( glyph->bbx.height + glyph->bbx.y_offset );
      glyph->bbx.descent = (short)( -glyph->bbx.y_offset );

      /* Determine the overall font bounding box as the characters are */
      /* loaded so corrections can be done later if indicated.         */
      p->maxas    = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
      p->maxds    = (short)FT_MAX( glyph->bbx.descent, p->maxds );

      p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );

      p->maxrb    = (short)FT_MAX( p->rbearing, p->maxrb );
      p->minlb    = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
      p->maxlb    = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );

      if ( !( p->flags & BDF_DWIDTH_ ) )
      {
        /* Missing DWIDTH field.  Emit an auto correction message and set */
        /* the device width to the glyph width.                           */
        FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
        glyph->dwidth = glyph->bbx.width;
      }

      /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
      /* value if necessary.                                            */
      if ( p->opts->correct_metrics != 0 )
      {
        /* Determine the point size of the glyph. */
        unsigned short  sw = (unsigned short)FT_MulDiv(
                               glyph->dwidth, 72000L,
                               (FT_Long)( font->point_size *
                                          font->resolution_x ) );

        if ( sw != glyph->swidth )
        {
          glyph->swidth = sw;

          p->flags       |= BDF_SWIDTH_ADJ_;
        }
      }

      p->flags |= BDF_BBX_;
      goto Exit;
    }

    /* And finally, gather up the bitmap. */
    if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 )
    {
      unsigned long  bitmap_size;

      if ( !( p->flags & BDF_BBX_ ) )
      {
        /* Missing BBX field. */
        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
        error = FT_THROW( Missing_Bbx_Field );
        goto Exit;
      }

      /* Allocate enough space for the bitmap. */
      glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;

      bitmap_size = glyph->bpr * glyph->bbx.height;
      if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
      {
        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
        error = FT_THROW( Bbx_Too_Big );
        goto Exit;
      }
      else
        glyph->bytes = (unsigned short)bitmap_size;

      if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
        goto Exit;

      p->row    = 0;
      p->flags |= BDF_BITMAP_;

      goto Exit;
    }

    FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
    error = FT_THROW( Invalid_File_Format );
    goto Exit;

  Missing_Encoding:
    /* Missing ENCODING field. */
    FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
    error = FT_THROW( Missing_Encoding_Field );

  Exit:
    if ( error && ( p->flags & BDF_GLYPH_ ) )
      FT_FREE( p->glyph_name );

    return error;
  }

  /* Load the font properties. */
  static FT_Error
  _bdf_parse_properties( char*          line,
                         unsigned long  linelen,
                         unsigned long  lineno,
                         void*          call_data,
                         void*          client_data )
  {
    unsigned long      vlen;
    _bdf_line_func_t*  next;
    _bdf_parse_t*      p;
    char*              name;
    char*              value;
    char               nbuf[128];
    FT_Error           error = FT_Err_Ok;

    FT_UNUSED( lineno );

    next = (_bdf_line_func_t *)call_data;
    p    = (_bdf_parse_t *)    client_data;

    /* Check for the end of the properties. */
    if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
    {
      /* If the FONT_ASCENT or FONT_DESCENT properties have not been      */
      /* encountered yet, then make sure they are added as properties and */
      /* make sure they are set from the font bounding box info.          */
      /*                                                                  */
      /* This is *always* done regardless of the options, because X11     */
      /* requires these two fields to compile fonts.                      */
      if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
      {
        p->font->font_ascent = p->font->bbx.ascent;
        ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
        error = _bdf_add_property( p->font, "FONT_ASCENT",
                                   nbuf, lineno );
        if ( error )
          goto Exit;

        FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
      }

      if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
      {
        p->font->font_descent = p->font->bbx.descent;
        ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
        error = _bdf_add_property( p->font, "FONT_DESCENT",
                                   nbuf, lineno );
        if ( error )
          goto Exit;

        FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
      }

      p->flags &= ~BDF_PROPS_;
      *next     = _bdf_parse_glyphs;

      goto Exit;
    }

    /* Ignore the _XFREE86_GLYPH_RANGES properties. */
    if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
      goto Exit;

    /* Handle COMMENT fields and properties in a special way to preserve */
    /* the spacing.                                                      */
    if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
    {
      name = value = line;
      value += 7;
      if ( *value )
        *value++ = 0;
      error = _bdf_add_property( p->font, name, value, lineno );
      if ( error )
        goto Exit;
    }
    else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
    {
      error = _bdf_add_property( p->font, name, value, lineno );
      if ( error )
        goto Exit;
    }
    else
    {
      error = _bdf_list_split( &p->list, " +", line, linelen );
      if ( error )
        goto Exit;
      name = p->list.field[0];

      _bdf_list_shift( &p->list, 1 );
      value = _bdf_list_join( &p->list, ' ', &vlen );

      error = _bdf_add_property( p->font, name, value, lineno );
      if ( error )
        goto Exit;
    }

  Exit:
    return error;
  }

  /* Load the font header. */
  static FT_Error
  _bdf_parse_start( char*          line,
                    unsigned long  linelen,
                    unsigned long  lineno,
                    void*          call_data,
                    void*          client_data )
  {
    unsigned long      slen;
    _bdf_line_func_t*  next;
    _bdf_parse_t*      p;
    bdf_font_t*        font;
    char               *s;

    FT_Memory          memory = NULL;
    FT_Error           error  = FT_Err_Ok;

    FT_UNUSED( lineno );            /* only used in debug mode */

    next = (_bdf_line_func_t *)call_data;
    p    = (_bdf_parse_t *)    client_data;

    if ( p->font )
      memory = p->font->memory;

    /* Check for a comment.  This is done to handle those fonts that have */
    /* comments before the STARTFONT line for some reason.                */
    if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
    {
      if ( p->opts->keep_comments != 0 && p->font != 0 )
      {
        linelen -= 7;

        s = line + 7;
        if ( *s != 0 )
        {
          s++;
          linelen--;
        }

        error = _bdf_add_comment( p->font, s, linelen );
        if ( error )
          goto Exit;
        /* here font is not defined! */
      }

      goto Exit;
    }

    if ( !( p->flags & BDF_START_ ) )
    {
      memory = p->memory;

      if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 )
      {
        /* we don't emit an error message since this code gets */
        /* explicitly caught one level higher                  */
        error = FT_THROW( Missing_Startfont_Field );
        goto Exit;
      }

      p->flags = BDF_START_;
      font = p->font = 0;

      if ( FT_NEW( font ) )
        goto Exit;
      p->font = font;

      font->memory = p->memory;
      p->memory    = 0;

      { /* setup */
        size_t           i;
        bdf_property_t*  prop;

        error = ft_hash_str_init( &(font->proptbl), memory );
        if ( error )
          goto Exit;
        for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
              i < _num_bdf_properties; i++, prop++ )
        {
          error = ft_hash_str_insert( prop->name, i,
                                      &(font->proptbl), memory );
          if ( error )
            goto Exit;
        }
      }

      if ( FT_ALLOC( p->font->internal, sizeof ( FT_HashRec ) ) )
        goto Exit;
      error = ft_hash_str_init( (FT_Hash)p->font->internal, memory );
      if ( error )
        goto Exit;
      p->font->spacing      = p->opts->font_spacing;
      p->font->default_char = ~0UL;

      goto Exit;
    }

    /* Check for the start of the properties. */
    if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 )
    {
      if ( !( p->flags & BDF_FONT_BBX_ ) )
      {
        /* Missing the FONTBOUNDINGBOX field. */
        FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
        error = FT_THROW( Missing_Fontboundingbox_Field );
        goto Exit;
      }

      error = _bdf_list_split( &p->list, " +", line, linelen );
      if ( error )
        goto Exit;

      /* at this point, `p->font' can't be NULL */
      p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1] );
      /* We need at least 4 bytes per property. */
      if ( p->cnt > p->size / 4 )
      {
        p->font->props_size = 0;

        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "STARTPROPERTIES" ));
        error = FT_THROW( Invalid_Argument );
        goto Exit;
      }

      if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
      {
        p->font->props_size = 0;
        goto Exit;
      }

      p->flags |= BDF_PROPS_;
      *next     = _bdf_parse_properties;

      goto Exit;
    }

    /* Check for the FONTBOUNDINGBOX field. */
    if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
    {
      if ( !( p->flags & BDF_SIZE_ ) )
      {
        /* Missing the SIZE field. */
        FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
        error = FT_THROW( Missing_Size_Field );
        goto Exit;
      }

      error = _bdf_list_split( &p->list, " +", line, linelen );
      if ( error )
        goto Exit;

      p->font->bbx.width  = _bdf_atous( p->list.field[1] );
      p->font->bbx.height = _bdf_atous( p->list.field[2] );

      p->font->bbx.x_offset = _bdf_atos( p->list.field[3] );
      p->font->bbx.y_offset = _bdf_atos( p->list.field[4] );

      p->font->bbx.ascent  = (short)( p->font->bbx.height +
                                      p->font->bbx.y_offset );

      p->font->bbx.descent = (short)( -p->font->bbx.y_offset );

      p->flags |= BDF_FONT_BBX_;

      goto Exit;
    }

    /* The next thing to check for is the FONT field. */
    if ( _bdf_strncmp( line, "FONT", 4 ) == 0 )
    {
      error = _bdf_list_split( &p->list, " +", line, linelen );
      if ( error )
        goto Exit;
      _bdf_list_shift( &p->list, 1 );

      s = _bdf_list_join( &p->list, ' ', &slen );

      if ( !s )
      {
        FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
        error = FT_THROW( Invalid_File_Format );
        goto Exit;
      }

      /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
      FT_FREE( p->font->name );

      if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
        goto Exit;
      FT_MEM_COPY( p->font->name, s, slen + 1 );

      /* If the font name is an XLFD name, set the spacing to the one in  */
      /* the font name.  If there is no spacing fall back on the default. */
      error = _bdf_set_default_spacing( p->font, p->opts, lineno );
      if ( error )
        goto Exit;

      p->flags |= BDF_FONT_NAME_;

      goto Exit;
    }

    /* Check for the SIZE field. */
    if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 )
    {
      if ( !( p->flags & BDF_FONT_NAME_ ) )
      {
        /* Missing the FONT field. */
        FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
        error = FT_THROW( Missing_Font_Field );
        goto Exit;
      }

      error = _bdf_list_split( &p->list, " +", line, linelen );
      if ( error )
        goto Exit;

      p->font->point_size   = _bdf_atoul( p->list.field[1] );
      p->font->resolution_x = _bdf_atoul( p->list.field[2] );
      p->font->resolution_y = _bdf_atoul( p->list.field[3] );

      /* Check for the bits per pixel field. */
      if ( p->list.used == 5 )
      {
        unsigned short bpp;

        bpp = (unsigned short)_bdf_atos( p->list.field[4] );

        /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
        if ( bpp > 4 )
          p->font->bpp = 8;
        else if ( bpp > 2 )
          p->font->bpp = 4;
        else if ( bpp > 1 )
          p->font->bpp = 2;
        else
          p->font->bpp = 1;

        if ( p->font->bpp != bpp )
          FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
      }
      else
        p->font->bpp = 1;

      p->flags |= BDF_SIZE_;

      goto Exit;
    }

    /* Check for the CHARS field -- font properties are optional */
    if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
    {
      char  nbuf[128];

      if ( !( p->flags & BDF_FONT_BBX_ ) )
      {
        /* Missing the FONTBOUNDINGBOX field. */
        FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
        error = FT_THROW( Missing_Fontboundingbox_Field );
        goto Exit;
      }

      /* Add the two standard X11 properties which are required */
      /* for compiling fonts.                                   */
      p->font->font_ascent = p->font->bbx.ascent;
      ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
      error = _bdf_add_property( p->font, "FONT_ASCENT",
                                 nbuf, lineno );
      if ( error )
        goto Exit;
      FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));

      p->font->font_descent = p->font->bbx.descent;
      ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
      error = _bdf_add_property( p->font, "FONT_DESCENT",
                                 nbuf, lineno );
      if ( error )
        goto Exit;
      FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));

      *next = _bdf_parse_glyphs;

      /* A special return value. */
      error = -1;
      goto Exit;
    }

    FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
    error = FT_THROW( Invalid_File_Format );

  Exit:
    return error;
  }

  /**************************************************************************
   *
   * API.
   *
   */

  FT_LOCAL_DEF( FT_Error )
  bdf_load_font( FT_Stream       stream,
                 FT_Memory       extmemory,
                 bdf_options_t*  opts,
                 bdf_font_t*    *font )
  {
    unsigned long  lineno = 0; /* make compiler happy */
    _bdf_parse_t   *p     = NULL;

    FT_Memory  memory = extmemory; /* needed for FT_NEW */
    FT_Error   error  = FT_Err_Ok;

    if ( FT_NEW( p ) )
      goto Exit;

    memory    = NULL;
    p->opts   = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
    p->minlb  = 32767;
    p->size   = stream->size;
    p->memory = extmemory;  /* only during font creation */

    _bdf_list_init( &p->list, extmemory );

    error = _bdf_readstream( stream, _bdf_parse_start,
                             (void *)p, &lineno );
    if ( error )
      goto Fail;

    if ( p->font != 0 )
    {
      /* If the font is not proportional, set the font's monowidth */
      /* field to the width of the font bounding box.              */

      if ( p->font->spacing != BDF_PROPORTIONAL )
        p->font->monowidth = p->font->bbx.width;

      /* If the number of glyphs loaded is not that of the original count, */
      /* indicate the difference.                                          */
      if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
      {
        FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
                    p->font->glyphs_used + p->font->unencoded_used ));
      }

      /* Once the font has been loaded, adjust the overall font metrics if */
      /* necessary.                                                        */
      if ( p->opts->correct_metrics != 0 &&
           ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
      {
        if ( p->maxrb - p->minlb != p->font->bbx.width )
        {
          FT_TRACE2(( "bdf_load_font: " ACMSG3,
                      p->font->bbx.width, p->maxrb - p->minlb ));
          p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
        }

        if ( p->font->bbx.x_offset != p->minlb )
        {
          FT_TRACE2(( "bdf_load_font: " ACMSG4,
                      p->font->bbx.x_offset, p->minlb ));
          p->font->bbx.x_offset = p->minlb;
        }

        if ( p->font->bbx.ascent != p->maxas )
        {
          FT_TRACE2(( "bdf_load_font: " ACMSG5,
                      p->font->bbx.ascent, p->maxas ));
          p->font->bbx.ascent = p->maxas;
        }

        if ( p->font->bbx.descent != p->maxds )
        {
          FT_TRACE2(( "bdf_load_font: " ACMSG6,
                      p->font->bbx.descent, p->maxds ));
          p->font->bbx.descent  = p->maxds;
          p->font->bbx.y_offset = (short)( -p->maxds );
        }

        if ( p->maxas + p->maxds != p->font->bbx.height )
        {
          FT_TRACE2(( "bdf_load_font: " ACMSG7,
                      p->font->bbx.height, p->maxas + p->maxds ));
          p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
        }

        if ( p->flags & BDF_SWIDTH_ADJ_ )
          FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
      }
    }

    if ( p->flags & BDF_START_ )
    {
      /* The ENDFONT field was never reached or did not exist. */
      if ( !( p->flags & BDF_GLYPHS_ ) )
      {
        /* Error happened while parsing header. */
        FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
        error = FT_THROW( Corrupted_Font_Header );
        goto Fail;
      }
      else
      {
        /* Error happened when parsing glyphs. */
        FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
        error = FT_THROW( Corrupted_Font_Glyphs );
        goto Fail;
      }
    }

    if ( p->font != 0 )
    {
      /* Make sure the comments are NULL terminated if they exist. */
      memory = p->font->memory;

      if ( p->font->comments_len > 0 )
      {
        if ( FT_RENEW_ARRAY( p->font->comments,
                             p->font->comments_len,
                             p->font->comments_len + 1 ) )
          goto Fail;

        p->font->comments[p->font->comments_len] = 0;
      }
    }
    else if ( !error )
      error = FT_THROW( Invalid_File_Format );

    *font = p->font;

  Exit:
    if ( p )
    {
      _bdf_list_done( &p->list );

      memory = extmemory;

      FT_FREE( p->glyph_name );
      FT_FREE( p );
    }

    return error;

  Fail:
    bdf_free_font( p->font );

    memory = extmemory;

    FT_FREE( p->font );

    goto Exit;
  }

  FT_LOCAL_DEF( void )
  bdf_free_font( bdf_font_t*  font )
  {
    bdf_property_t*  prop;
    unsigned long    i;
    bdf_glyph_t*     glyphs;
    FT_Memory        memory;

    if ( font == 0 )
      return;

    memory = font->memory;

    FT_FREE( font->name );

    /* Free up the internal hash table of property names. */
    if ( font->internal )
    {
      ft_hash_str_free( (FT_Hash)font->internal, memory );
      FT_FREE( font->internal );
    }

    /* Free up the comment info. */
    FT_FREE( font->comments );

    /* Free up the properties. */
    for ( i = 0; i < font->props_size; i++ )
    {
      if ( font->props[i].format == BDF_ATOM )
        FT_FREE( font->props[i].value.atom );
    }

    FT_FREE( font->props );

    /* Free up the character info. */
    for ( i = 0, glyphs = font->glyphs;
          i < font->glyphs_used; i++, glyphs++ )
    {
      FT_FREE( glyphs->name );
      FT_FREE( glyphs->bitmap );
    }

    for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
          i++, glyphs++ )
    {
      FT_FREE( glyphs->name );
      FT_FREE( glyphs->bitmap );
    }

    FT_FREE( font->glyphs );
    FT_FREE( font->unencoded );

    /* bdf_cleanup */
    ft_hash_str_free( &(font->proptbl), memory );

    /* Free up the user defined properties. */
    for ( prop = font->user_props, i = 0;
          i < font->nuser_props; i++, prop++ )
    {
      FT_FREE( prop->name );
      if ( prop->format == BDF_ATOM )
        FT_FREE( prop->value.atom );
    }

    FT_FREE( font->user_props );

    /* FREE( font ); */ /* XXX Fixme */
  }

  FT_LOCAL_DEF( bdf_property_t * )
  bdf_get_font_property( bdf_font_t*  font,
                         const char*  name )
  {
    size_t*  propid;

    if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
      return 0;

    propid = ft_hash_str_lookup( name, (FT_Hash)font->internal );

    return propid ? ( font->props + *propid ) : 0;
  }

/* END */


text:
/*  bdfdrivr.h

    FreeType font driver for bdf fonts

  Copyright (C) 2001, 2002, 2003, 2004 by
  Francesco Zappa Nardelli

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifndef BDFDRIVR_H_
#define BDFDRIVR_H_

#include <ft2build.h>
#include FT_INTERNAL_DRIVER_H

#include "bdf.h"

FT_BEGIN_HEADER

  typedef struct  BDF_encoding_el_
  {
    FT_ULong   enc;
    FT_UShort  glyph;

  } BDF_encoding_el;

  typedef struct  BDF_FaceRec_
  {
    FT_FaceRec        root;

    char*             charset_encoding;
    char*             charset_registry;

    bdf_font_t*       bdffont;

    BDF_encoding_el*  en_table;

    FT_UInt           default_glyph;

  } BDF_FaceRec, *BDF_Face;

  FT_EXPORT_VAR( const FT_Driver_ClassRec )  bdf_driver_class;

FT_END_HEADER

#endif /* BDFDRIVR_H_ */

/* END */

repo_language: C

mime_type: text/x-c


text:
#
# FreeType 2 bdf driver configuration rules
#

# Copyright (C) 2001, 2002, 2003, 2008 by
# Francesco Zappa Nardelli
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

# bdf driver directory
#
BDF_DIR := $(SRC_DIR)/bdf

BDF_COMPILE := $(CC) $(ANSIFLAGS)                            \
                     $I$(subst /,$(COMPILER_SEP),$(BDF_DIR)) \
                     $(INCLUDE_FLAGS)                        \
                     $(FT_CFLAGS)

# bdf driver sources (i.e., C files)
#
BDF_DRV_SRC := $(BDF_DIR)/bdflib.c \
               $(BDF_DIR)/bdfdrivr.c

# bdf driver headers
#
BDF_DRV_H := $(BDF_DIR)/bdf.h \
             $(BDF_DIR)/bdfdrivr.h \
             $(BDF_DIR)/bdferror.h

# bdf driver object(s)
#
#   BDF_DRV_OBJ_M is used during `multi' builds
#   BDF_DRV_OBJ_S is used during `single' builds
#
BDF_DRV_OBJ_M := $(BDF_DRV_SRC:$(BDF_DIR)/%.c=$(OBJ_DIR)/%.$O)
BDF_DRV_OBJ_S := $(OBJ_DIR)/bdf.$O

# bdf driver source file for single build
#
BDF_DRV_SRC_S := $(BDF_DIR)/bdf.c

# bdf driver - single object
#
$(BDF_DRV_OBJ_S): $(BDF_DRV_SRC_S) $(BDF_DRV_SRC) $(FREETYPE_H) $(BDF_DRV_H)
	$(BDF_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(BDF_DRV_SRC_S))

# bdf driver - multiple objects
#
$(OBJ_DIR)/%.$O: $(BDF_DIR)/%.c $(FREETYPE_H) $(BDF_DRV_H)
	$(BDF_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<)

# update main driver object lists
#
DRV_OBJS_S += $(BDF_DRV_OBJ_S)
DRV_OBJS_M += $(BDF_DRV_OBJ_M)

# EOF


text:
/* inffixed.h -- table for decoding fixed codes
 * Generated automatically by the maketree.c program
 */

/* WARNING: this file should *not* be used by applications. It is
   part of the implementation of the compression library and is
   subject to change. Applications should only use zlib.h.
 */

local const uInt fixed_bl = 9;
local const uInt fixed_bd = 5;
local const inflate_huft fixed_tl[] = {
    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},
    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},
    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},
    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},
    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},
    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},
    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},
    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},
    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},
    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},
    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},
    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},
    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},
    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},
    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},
    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},
    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},
    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},
    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},
    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},
    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},
    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},
    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},
    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},
    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},
    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},
    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188},
    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252},
    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},
    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},
    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},
    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},
    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},
    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},
    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},
    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},
    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},
    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},
    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},
    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},
    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},
    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},
    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},
    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},
    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},
    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},
    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},
    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},
    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},
    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},
    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},
    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},
    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},
    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},
    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190},
    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254},
    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},
    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},
    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},
    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},
    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},
    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},
    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},
    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},
    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},
    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},
    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},
    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},
    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},
    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},
    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},
    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},
    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},
    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},
    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},
    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},
    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},
    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},
    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},
    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},
    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},
    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},
    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189},
    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253},
    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},
    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},
    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},
    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},
    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},
    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},
    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},
    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},
    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},
    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},
    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},
    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},
    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},
    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},
    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},
    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},
    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},
    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},
    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},
    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},
    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},
    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},
    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},
    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},
    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},
    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},
    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},
    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}
  };
local const inflate_huft fixed_td[] = {
    {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},
    {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},
    {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},
    {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},
    {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},
    {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},
    {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},
    {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}
  };


text:
/* infutil.h -- types and macros common to blocks and codes
 * Copyright (C) 1995-2002 Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* WARNING: this file should *not* be used by applications. It is
   part of the implementation of the compression library and is
   subject to change. Applications should only use zlib.h.
 */

#ifndef _INFUTIL_H
#define _INFUTIL_H

typedef enum {
      TYPE,     /* get type bits (3, including end bit) */
      LENS,     /* get lengths for stored */
      STORED,   /* processing stored block */
      TABLE,    /* get table lengths */
      BTREE,    /* get bit lengths tree for a dynamic block */
      DTREE,    /* get length, distance trees for a dynamic block */
      CODES,    /* processing fixed or dynamic block */
      DRY,      /* output remaining window bytes */
      DONE,     /* finished last block, done */
      BAD}      /* got a data error--stuck here */
inflate_block_mode;

/* inflate blocks semi-private state */
struct inflate_blocks_state {

  /* mode */
  inflate_block_mode  mode;     /* current inflate_block mode */

  /* mode dependent information */
  union {
    uInt left;          /* if STORED, bytes left to copy */
    struct {
      uInt table;               /* table lengths (14 bits) */
      uInt index;               /* index into blens (or border) */
      uIntf *blens;             /* bit lengths of codes */
      uInt bb;                  /* bit length tree depth */
      inflate_huft *tb;         /* bit length decoding tree */
    } trees;            /* if DTREE, decoding info for trees */
    struct {
      inflate_codes_statef
         *codes;
    } decode;           /* if CODES, current state */
  } sub;                /* submode */
  uInt last;            /* true if this block is the last block */

  /* mode independent information */
  uInt bitk;            /* bits in bit buffer */
  uLong bitb;           /* bit buffer */
  inflate_huft *hufts;  /* single malloc for tree space */
  Bytef *window;        /* sliding window */
  Bytef *end;           /* one byte after sliding window */
  Bytef *read;          /* window read pointer */
  Bytef *write;         /* window write pointer */
  check_func checkfn;   /* check function */
  uLong check;          /* check on output */

};

/* defines for inflate input/output */
/*   update pointers and return */
#define UPDBITS {s->bitb=b;s->bitk=k;}
#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
#define UPDOUT {s->write=q;}
#define UPDATE {UPDBITS UPDIN UPDOUT}
#define LEAVE {UPDATE return inflate_flush(s,z,r);}
/*   get bytes and bits */
#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
#define NEXTBYTE (n--,*p++)
#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
#define DUMPBITS(j) {b>>=(j);k-=(j);}
/*   output bytes */
#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
/*   load local pointers */
#define LOAD {LOADIN LOADOUT}

/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
#ifndef NO_INFLATE_MASK
local const uInt inflate_mask[17];
#endif

/* copy as much as possible from the sliding window to the output area */
local int inflate_flush OF((
    inflate_blocks_statef *,
    z_streamp ,
    int));

#endif


text:
/* zconf.h -- configuration of the zlib compression library
 * Copyright (C) 1995-2002 Jean-loup Gailly.
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* @(#) $Id$ */

#ifndef _ZCONF_H
#define _ZCONF_H

/*
 * If you *really* need a unique prefix for all types and library functions,
 * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
 */
#ifdef Z_PREFIX
#  define deflateInit_         z_deflateInit_
#  define deflate              z_deflate
#  define deflateEnd           z_deflateEnd
#  define inflateInit_         z_inflateInit_
#  define inflate              z_inflate
#  define inflateEnd           z_inflateEnd
#  define deflateInit2_        z_deflateInit2_
#  define deflateSetDictionary z_deflateSetDictionary
#  define deflateCopy          z_deflateCopy
#  define deflateReset         z_deflateReset
#  define deflateParams        z_deflateParams
#  define inflateInit2_        z_inflateInit2_
#  define inflateSetDictionary z_inflateSetDictionary
#  define inflateSync          z_inflateSync
#  define inflateSyncPoint     z_inflateSyncPoint
#  define inflateReset         z_inflateReset
#  define compress             z_compress
#  define compress2            z_compress2
#  define uncompress           z_uncompress
#  define adler32              z_adler32
#  define crc32                z_crc32
#  define get_crc_table        z_get_crc_table

#  define Byte   z_Byte
#  define uInt   z_uInt
#  define uLong  z_uLong
#  define Bytef  z_Bytef
#  define charf  z_charf
#  define intf   z_intf
#  define uIntf  z_uIntf
#  define uLongf z_uLongf
#  define voidpf z_voidpf
#  define voidp  z_voidp
#endif

#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
#  define WIN32
#endif
#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
#  ifndef __32BIT__
#    define __32BIT__
#  endif
#endif
#if defined(__MSDOS__) && !defined(MSDOS)
#  define MSDOS
#endif

/* WinCE doesn't have errno.h */
#ifdef _WIN32_WCE
#  define NO_ERRNO_H
#endif

/*
 * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
 * than 64k bytes at a time (needed on systems with 16-bit int).
 */
#if defined(MSDOS) && !defined(__32BIT__)
#  define MAXSEG_64K
#endif
#ifdef MSDOS
#  define UNALIGNED_OK
#endif

#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32))  && !defined(STDC)
#  define STDC
#endif
#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__)
#  ifndef STDC
#    define STDC
#  endif
#endif

#ifndef STDC
#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
#    define const
#  endif
#endif

/* Some Mac compilers merge all .h files incorrectly: */
#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
#  define NO_DUMMY_DECL
#endif

/* Old Borland C and LCC incorrectly complains about missing returns: */
#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500)
#  define NEED_DUMMY_RETURN
#endif

#if defined(__LCC__)
#  define  NEED_DUMMY_RETURN
#endif

/* Maximum value for memLevel in deflateInit2 */
#ifndef MAX_MEM_LEVEL
#  ifdef MAXSEG_64K
#    define MAX_MEM_LEVEL 8
#  else
#    define MAX_MEM_LEVEL 9
#  endif
#endif

/* Maximum value for windowBits in deflateInit2 and inflateInit2.
 * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
 * created by gzip. (Files created by minigzip can still be extracted by
 * gzip.)
 */
#ifndef MAX_WBITS
#  define MAX_WBITS   15 /* 32K LZ77 window */
#endif

/* The memory requirements for deflate are (in bytes):
            (1 << (windowBits+2)) +  (1 << (memLevel+9))
 that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
 plus a few kilobytes for small objects. For example, if you want to reduce
 the default memory requirements from 256K to 128K, compile with
     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
 Of course this will generally degrade compression (there's no free lunch).

   The memory requirements for inflate are (in bytes) 1 << windowBits
 that is, 32K for windowBits=15 (default value) plus a few kilobytes
 for small objects.
*/

                        /* Type declarations */

#ifndef OF /* function prototypes */
#  ifdef STDC
#    define OF(args)  args
#  else
#    define OF(args)  ()
#  endif
#endif

/* The following definitions for FAR are needed only for MSDOS mixed
 * model programming (small or medium model with some far allocations).
 * This was tested only with MSC; for other MSDOS compilers you may have
 * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
 * just define FAR to be empty.
 */
#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
   /* MSC small or medium model */
#  define SMALL_MEDIUM
#  ifdef _MSC_VER
#    define FAR _far
#  else
#    define FAR far
#  endif
#endif
#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
#  ifndef __32BIT__
#    define SMALL_MEDIUM
#    define FAR _far
#  endif
#endif

/* Compile with -DZLIB_DLL for Windows DLL support */
#if defined(ZLIB_DLL)
#  if defined(_WINDOWS) || defined(WINDOWS)
#    ifdef FAR
#      undef FAR
#    endif
#    include <windows.h>
#    define ZEXPORT(x)  x WINAPI
#    ifdef WIN32
#      define ZEXPORTVA(x)  x WINAPIV
#    else
#      define ZEXPORTVA(x)  x FAR _cdecl _export
#    endif
#  endif
#  if defined (__BORLANDC__)
#    if (__BORLANDC__ >= 0x0500) && defined (WIN32)
#      include <windows.h>
#      define ZEXPORT(x) x __declspec(dllexport) WINAPI
#      define ZEXPORTRVA(x)  x __declspec(dllexport) WINAPIV
#    else
#      if defined (_Windows) && defined (__DLL__)
#        define ZEXPORT(x) x _export
#        define ZEXPORTVA(x) x _export
#      endif
#    endif
#  endif
#endif

#ifndef ZEXPORT
#  define ZEXPORT(x)   static x
#endif
#ifndef ZEXPORTVA
#  define ZEXPORTVA(x)   static x
#endif
#ifndef ZEXTERN
#  define ZEXTERN(x) static x
#endif
#ifndef ZEXTERNDEF
#  define ZEXTERNDEF(x)  static x
#endif

#ifndef FAR
#   define FAR
#endif

#if !defined(MACOS) && !defined(TARGET_OS_MAC)
typedef unsigned char  Byte;  /* 8 bits */
#endif
typedef unsigned int   uInt;  /* 16 bits or more */
typedef unsigned long  uLong; /* 32 bits or more */

#ifdef SMALL_MEDIUM
   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
#  define Bytef Byte FAR
#else
   typedef Byte  FAR Bytef;
#endif
typedef char  FAR charf;
typedef int   FAR intf;
typedef uInt  FAR uIntf;
typedef uLong FAR uLongf;

#ifdef STDC
   typedef void FAR *voidpf;
   typedef void     *voidp;
#else
   typedef Byte FAR *voidpf;
   typedef Byte     *voidp;
#endif

#ifdef HAVE_UNISTD_H
#  include <sys/types.h> /* for off_t */
#  include <unistd.h>    /* for SEEK_* and off_t */
#  define z_off_t  off_t
#endif
#ifndef SEEK_SET
#  define SEEK_SET        0       /* Seek from beginning of file.  */
#  define SEEK_CUR        1       /* Seek from current position.  */
#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
#endif
#ifndef z_off_t
#  define  z_off_t long
#endif

/* MVS linker does not support external names larger than 8 bytes */
#if defined(__MVS__)
#   pragma map(deflateInit_,"DEIN")
#   pragma map(deflateInit2_,"DEIN2")
#   pragma map(deflateEnd,"DEEND")
#   pragma map(inflateInit_,"ININ")
#   pragma map(inflateInit2_,"ININ2")
#   pragma map(inflateEnd,"INEND")
#   pragma map(inflateSync,"INSY")
#   pragma map(inflateSetDictionary,"INSEDI")
#   pragma map(inflate_blocks,"INBL")
#   pragma map(inflate_blocks_new,"INBLNE")
#   pragma map(inflate_blocks_free,"INBLFR")
#   pragma map(inflate_blocks_reset,"INBLRE")
#   pragma map(inflate_codes_free,"INCOFR")
#   pragma map(inflate_codes,"INCO")
#   pragma map(inflate_fast,"INFA")
#   pragma map(inflate_flush,"INFLU")
#   pragma map(inflate_mask,"INMA")
#   pragma map(inflate_set_dictionary,"INSEDI2")
#   pragma map(inflate_copyright,"INCOPY")
#   pragma map(inflate_trees_bits,"INTRBI")
#   pragma map(inflate_trees_dynamic,"INTRDY")
#   pragma map(inflate_trees_fixed,"INTRFI")
#   pragma map(inflate_trees_free,"INTRFR")
#endif

#endif /* _ZCONF_H */


text:
/* inftrees.h -- header to use inftrees.c
 * Copyright (C) 1995-2002 Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* WARNING: this file should *not* be used by applications. It is
   part of the implementation of the compression library and is
   subject to change. Applications should only use zlib.h.
 */

/* Huffman code lookup table entry--this entry is four bytes for machines
   that have 16-bit pointers (e.g. PC's in the small or medium model). */

#ifndef _INFTREES_H
#define _INFTREES_H

typedef struct inflate_huft_s FAR inflate_huft;

struct inflate_huft_s {
  union {
    struct {
      Byte Exop;        /* number of extra bits or operation */
      Byte Bits;        /* number of bits in this code or subcode */
    } what;
    uInt pad;           /* pad structure to a power of 2 (4 bytes for */
  } word;               /*  16-bit, 8 bytes for 32-bit int's) */
  uInt base;            /* literal, length base, distance base,
                           or table offset */
};

/* Maximum size of dynamic tree.  The maximum found in a long but non-
   exhaustive search was 1004 huft structures (850 for length/literals
   and 154 for distances, the latter actually the result of an
   exhaustive search).  The actual maximum is not known, but the
   value below is more than safe. */
#define MANY 1440

local  int inflate_trees_bits OF((
    uIntf *,                    /* 19 code lengths */
    uIntf *,                    /* bits tree desired/actual depth */
    inflate_huft * FAR *,       /* bits tree result */
    inflate_huft *,             /* space for trees */
    z_streamp));                /* for messages */

local  int inflate_trees_dynamic OF((
    uInt,                       /* number of literal/length codes */
    uInt,                       /* number of distance codes */
    uIntf *,                    /* that many (total) code lengths */
    uIntf *,                    /* literal desired/actual bit depth */
    uIntf *,                    /* distance desired/actual bit depth */
    inflate_huft * FAR *,       /* literal/length tree result */
    inflate_huft * FAR *,       /* distance tree result */
    inflate_huft *,             /* space for trees */
    z_streamp));                /* for messages */

local  int inflate_trees_fixed OF((
    uIntf *,                    /* literal desired/actual bit depth */
    uIntf *,                    /* distance desired/actual bit depth */
    const inflate_huft * FAR *, /* literal/length tree result */
    const inflate_huft * FAR *, /* distance tree result */
    z_streamp));                /* for memory allocation */

#endif /* _INFTREES_H */


text:
/* infcodes.h -- header to use infcodes.c
 * Copyright (C) 1995-2002 Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* WARNING: this file should *not* be used by applications. It is
   part of the implementation of the compression library and is
   subject to change. Applications should only use zlib.h.
 */

#ifndef _INFCODES_H
#define _INFCODES_H

struct inflate_codes_state;
typedef struct inflate_codes_state FAR inflate_codes_statef;

local inflate_codes_statef *inflate_codes_new OF((
    uInt, uInt,
    inflate_huft *, inflate_huft *,
    z_streamp ));

local int inflate_codes OF((
    inflate_blocks_statef *,
    z_streamp ,
    int));

local void inflate_codes_free OF((
    inflate_codes_statef *,
    z_streamp ));

#endif /* _INFCODES_H */


text:
/* inflate_util.c -- data and routines common to blocks and codes
 * Copyright (C) 1995-2002 Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

#include "zutil.h"
#include "infblock.h"
#include "inftrees.h"
#include "infcodes.h"
#include "infutil.h"

/* And'ing with mask[n] masks the lower n bits */
local const uInt inflate_mask[17] = {
    0x0000,
    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
};

/* copy as much as possible from the sliding window to the output area */
local int inflate_flush( /* s, z, r) */
inflate_blocks_statef *s,
z_streamp z,
int r )
{
  uInt n;
  Bytef *p;
  Bytef *q;

  /* local copies of source and destination pointers */
  p = z->next_out;
  q = s->read;

  /* compute number of bytes to copy as far as end of window */
  n = (uInt)((q <= s->write ? s->write : s->end) - q);
  if (n > z->avail_out) n = z->avail_out;
  if (n && r == Z_BUF_ERROR) r = Z_OK;

  /* update counters */
  z->avail_out -= n;
  z->total_out += n;

  /* update check information */
  if (s->checkfn != Z_NULL)
    z->adler = s->check = (*s->checkfn)(s->check, q, n);

  /* copy as far as end of window */
  zmemcpy(p, q, n);
  p += n;
  q += n;

  /* see if more to copy at beginning of window */
  if (q == s->end)
  {
    /* wrap pointers */
    q = s->window;
    if (s->write == s->end)
      s->write = s->window;

    /* compute bytes to copy */
    n = (uInt)(s->write - q);
    if (n > z->avail_out) n = z->avail_out;
    if (n && r == Z_BUF_ERROR) r = Z_OK;

    /* update counters */
    z->avail_out -= n;
    z->total_out += n;

    /* update check information */
    if (s->checkfn != Z_NULL)
      z->adler = s->check = (*s->checkfn)(s->check, q, n);

    /* copy */
    zmemcpy(p, q, n);
    p += n;
    q += n;
  }

  /* update pointers */
  z->next_out = p;
  s->read = q;

  /* done */
  return r;
}